From 2abb9e8b338b6179833bcade7ed99b1b6dd992b1 Mon Sep 17 00:00:00 2001 From: pvvx Date: Sun, 31 Dec 2023 21:16:48 +0300 Subject: [PATCH] add source --- README.md | 2 +- src/TestTHB2/RTE/Device/ARMCM0/phy6202.ld | 208 + .../RTE/Device/ARMCM0/startup_ARMCM0.c | 309 + .../RTE/Device/ARMCM0/startup_ARMCM0.s | 121 + .../RTE/Device/ARMCM0/system_ARMCM0.c | 60 + src/TestTHB2/RTE/_Target_1/RTE_Components.h | 21 + src/TestTHB2/TestTHB2.uvprojx | 1043 ++ src/TestTHB2/main.c | 264 + src/TestTHB2/ram.ini | 10 + src/TestTHB2/ram_xip.ini | 56 + src/TestTHB2/scatter_load.sct | 65 + .../source/OSAL_SimpleBLEPeripheral.c | 127 + .../source/SimpleBLEPeripheral_Main.c | 58 + src/TestTHB2/source/battery.c | 216 + src/TestTHB2/source/battery.h | 54 + src/TestTHB2/source/bthome_beacon.c | 47 + src/TestTHB2/source/bthome_beacon.h | 151 + src/TestTHB2/source/halPeripheral.c | 245 + src/TestTHB2/source/halPeripheral.h | 42 + src/TestTHB2/source/sbpProfile_ota.c | 459 + src/TestTHB2/source/sbpProfile_ota.h | 135 + src/TestTHB2/source/sensor.h | 70 + src/TestTHB2/source/sensors.c | 174 + src/TestTHB2/source/simpleBLEPeripheral.h | 95 + src/TestTHB2/source/thb2_main.c | 641 ++ src/TestTHB2/source/thservice.c | 391 + src/TestTHB2/source/thservice.h | 115 + src/components/arch/cm0/core_bumbee_m0.h | 88 + src/components/ble/controller/ll.h | 3452 +++++++ src/components/ble/controller/ll_buf.h | 110 + src/components/ble/controller/ll_common.h | 345 + src/components/ble/controller/ll_debug.h | 74 + src/components/ble/controller/ll_def.h | 1569 +++ src/components/ble/controller/ll_enc.h | 97 + src/components/ble/controller/ll_hw_drv.h | 217 + src/components/ble/controller/ll_sleep.h | 96 + src/components/ble/controller/rf_phy_driver.h | 511 + src/components/ble/hci/hci_data.h | 81 + src/components/ble/hci/hci_event.h | 275 + src/components/ble/hci/hci_host.h | 63 + src/components/ble/hci/hci_task.h | 88 + src/components/ble/hci/hci_tl.h | 402 + src/components/ble/host/att_internal.h | 63 + src/components/ble/host/gap_internal.h | 474 + src/components/ble/host/gapgattserver.h | 184 + src/components/ble/host/gatt_internal.h | 87 + src/components/ble/host/gatt_profile_uuid.h | 239 + src/components/ble/host/gattservapp.h | 632 ++ src/components/ble/host/gatttest.h | 152 + src/components/ble/host/l2cap_internal.h | 276 + src/components/ble/host/linkdb.h | 209 + src/components/ble/host/sm_internal.h | 365 + src/components/ble/host/smp.h | 380 + src/components/ble/include/att.h | 1251 +++ src/components/ble/include/bcomdef.h | 251 + src/components/ble/include/gap.h | 1154 +++ src/components/ble/include/gatt.h | 1379 +++ src/components/ble/include/gatt_uuid.h | 139 + src/components/ble/include/hci.h | 3122 ++++++ src/components/ble/include/l2cap.h | 473 + src/components/ble/include/sm.h | 362 + src/components/coremark/core_list_join.c | 2506 +++++ src/components/coremark/core_main.c | 472 + src/components/coremark/core_matrix.c | 779 ++ src/components/coremark/core_portme.c | 148 + src/components/coremark/core_portme.h | 199 + src/components/coremark/core_state.c | 1324 +++ src/components/coremark/core_util.c | 507 + src/components/coremark/coremark.h | 182 + src/components/driver/adc/adc.c | 669 ++ src/components/driver/adc/adc.h | 192 + src/components/driver/adc/readme.txt | 17 + src/components/driver/bsp_button/bsp_button.c | 428 + src/components/driver/bsp_button/bsp_button.h | 80 + .../driver/bsp_button/bsp_button_task.c | 226 + .../driver/bsp_button/bsp_button_task.h | 101 + src/components/driver/bsp_button/bsp_gpio.c | 80 + src/components/driver/bsp_button/bsp_gpio.h | 46 + src/components/driver/clock/clock.c | 248 + src/components/driver/clock/clock.h | 112 + src/components/driver/dma/dma.c | 370 + src/components/driver/dma/dma.h | 367 + src/components/driver/flash/flash.c | 517 + src/components/driver/flash/flash.h | 165 + src/components/driver/gpio/gpio.c | 601 ++ src/components/driver/gpio/gpio.h | 192 + src/components/driver/i2c/i2c.c | 443 + src/components/driver/i2c/i2c.h | 192 + src/components/driver/i2c/i2c_common.c | 298 + src/components/driver/i2c/i2c_common.h | 495 + src/components/driver/i2c/i2c_io.c | 284 + src/components/driver/i2c/i2c_io.h | 49 + src/components/driver/i2c/i2c_s.c | 156 + src/components/driver/i2c/i2c_s.h | 82 + src/components/driver/i2c/i2c_slave.c | 241 + src/components/driver/i2c/i2c_slave.h | 64 + src/components/driver/key/key.c | 202 + src/components/driver/key/key.h | 97 + src/components/driver/kscan/kscan.c | 407 + src/components/driver/kscan/kscan.h | 202 + src/components/driver/led_light/led_light.c | 256 + src/components/driver/led_light/led_light.h | 137 + src/components/driver/log/log.h | 116 + src/components/driver/log/my_printf.c | 439 + src/components/driver/pwm/pwm.c | 297 + src/components/driver/pwm/pwm.h | 355 + src/components/driver/pwrmgr/pwrmgr.c | 530 + src/components/driver/pwrmgr/pwrmgr.h | 74 + src/components/driver/qdec/qdec.c | 279 + src/components/driver/qdec/qdec.h | 160 + src/components/driver/spi/spi.c | 1104 ++ src/components/driver/spi/spi.h | 177 + src/components/driver/spiflash/spiflash.c | 603 ++ src/components/driver/spiflash/spiflash.h | 83 + src/components/driver/timer/timer.c | 154 + src/components/driver/timer/timer.h | 60 + src/components/driver/uart/uart.c | 508 + src/components/driver/uart/uart.h | 158 + src/components/driver/voice/voice.c | 396 + src/components/driver/voice/voice.h | 262 + src/components/driver/watchdog/watchdog.c | 95 + src/components/driver/watchdog/watchdog.h | 59 + .../ethermind/external/crypto/aes/README.txt | 61 + .../ethermind/external/crypto/aes/aes-ccm.c | 240 + .../ethermind/external/crypto/aes/aes.c | 51 + .../ethermind/external/crypto/aes/aes.h | 36 + .../crypto/asm_ecdh_p256/P256-cortex-ecdh.h | 80 + .../asm_ecdh_p256/P256-cortex-m0-ecdh-keil.s | 2954 ++++++ .../ethermind/external/crypto/sha256/sha256.c | 432 + .../ethermind/external/crypto/sha256/sha256.h | 156 + .../meshlibs/phyos/keil/libethermind_ecdh.lib | Bin 0 -> 89784 bytes .../phyos/keil/libethermind_mesh_core.lib | Bin 0 -> 1293720 bytes .../phyos/keil/libethermind_mesh_models.lib | Bin 0 -> 695304 bytes .../phyos/keil/libethermind_utils.lib | Bin 0 -> 301612 bytes .../ethermind/mesh/export/appl/appl_main.c | 82 + .../ethermind/mesh/export/appl/appl_main.h | 69 + .../ethermind/mesh/export/appl/appl_prov.c | 1345 +++ .../ethermind/mesh/export/appl/appl_proxy.c | 346 + .../appl/model/client/appl_config_client.c | 1951 ++++ .../appl/model/client/appl_config_client.h | 198 + .../client/appl_generic_battery_client.c | 233 + .../client/appl_generic_battery_client.h | 60 + ...l_generic_default_transition_time_client.c | 289 + ...l_generic_default_transition_time_client.h | 66 + .../model/client/appl_generic_level_client.c | 545 + .../model/client/appl_generic_level_client.h | 78 + .../client/appl_generic_location_client.c | 408 + .../client/appl_generic_location_client.h | 75 + .../model/client/appl_generic_onoff_client.c | 343 + .../model/client/appl_generic_onoff_client.h | 66 + .../client/appl_generic_power_level_client.c | 508 + .../client/appl_generic_power_level_client.h | 87 + .../client/appl_generic_power_onoff_client.c | 279 + .../client/appl_generic_power_onoff_client.h | 66 + .../client/appl_generic_property_client.c | 685 ++ .../client/appl_generic_property_client.h | 96 + .../appl/model/client/appl_health_client.c | 492 + .../appl/model/client/appl_health_client.h | 90 + .../appl/model/client/appl_light_ctl_client.c | 662 ++ .../appl/model/client/appl_light_ctl_client.h | 93 + .../appl/model/client/appl_light_hsl_client.c | 822 ++ .../appl/model/client/appl_light_hsl_client.h | 105 + .../appl/model/client/appl_light_lc_client.c | 615 ++ .../appl/model/client/appl_light_lc_client.h | 93 + .../client/appl_light_lightness_client.c | 579 ++ .../client/appl_light_lightness_client.h | 96 + .../appl/model/client/appl_light_xyl_client.c | 568 ++ .../appl/model/client/appl_light_xyl_client.h | 87 + .../model/client/appl_main_model_client.c | 154 + .../appl/model/client/appl_scene_client.c | 452 + .../appl/model/client/appl_scene_client.h | 81 + .../appl/model/client/appl_scheduler_client.c | 371 + .../appl/model/client/appl_scheduler_client.h | 72 + .../appl/model/client/appl_sensor_client.c | 980 ++ .../appl/model/client/appl_sensor_client.h | 90 + .../appl/model/client/appl_time_client.c | 455 + .../appl/model/client/appl_time_client.h | 81 + .../model/server/appl_main_model_server.c | 147 + .../model/server/appl_model_server_callback.c | 2345 +++++ .../server/appl_model_server_state_handler.c | 4072 ++++++++ .../model/server/appl_model_state_handler.h | 30 + .../appl_generic_battery_server.c | 153 + .../appl_generic_battery_server.h | 56 + .../appl_model_state_handler.c | 69 + .../appl_model_state_handler.h | 32 + ...l_generic_default_transition_time_server.c | 115 + ...l_generic_default_transition_time_server.h | 36 + .../appl_generic_level_server.c | 271 + .../appl_generic_level_server.h | 73 + .../appl_model_state_handler.c | 317 + .../appl_model_state_handler.h | 32 + .../appl_generic_location_server.c | 183 + .../appl_generic_location_server.h | 59 + .../appl_model_state_handler.c | 90 + .../appl_model_state_handler.h | 32 + .../appl_generic_onoff_server.c | 250 + .../appl_generic_onoff_server.h | 73 + .../appl_model_state_handler.c | 166 + .../appl_model_state_handler.h | 32 + .../appl_generic_power_level_server.c | 621 ++ .../appl_generic_power_level_server.h | 158 + .../appl_model_state_handler.c | 693 ++ .../appl_model_state_handler.h | 32 + .../appl_generic_power_onoff_server.c | 295 + .../appl_generic_power_onoff_server.h | 94 + .../appl_model_state_handler.c | 209 + .../appl_model_state_handler.h | 32 + .../appl_generic_property_server.c | 447 + .../appl_generic_property_server.h | 113 + .../appl_model_state_handler.c | 486 + .../appl_model_state_handler.h | 32 + .../model/server/health/appl_health_server.c | 259 + .../model/server/health/appl_health_server.h | 52 + .../light_ctl_server/appl_light_ctl_server.c | 766 ++ .../light_ctl_server/appl_light_ctl_server.h | 186 + .../appl_model_state_handler.c | 1152 +++ .../appl_model_state_handler.h | 32 + .../light_hsl_server/appl_light_hsl_server.c | 898 ++ .../light_hsl_server/appl_light_hsl_server.h | 228 + .../appl_model_state_handler.c | 1301 +++ .../appl_model_state_handler.h | 32 + .../light_lc_server/appl_light_lc_server.c | 443 + .../light_lc_server/appl_light_lc_server.h | 124 + .../appl_model_state_handler.c | 620 ++ .../appl_model_state_handler.h | 32 + .../appl_light_lightness_server.c | 572 ++ .../appl_light_lightness_server.h | 144 + .../appl_model_state_handler.c | 823 ++ .../appl_model_state_handler.h | 32 + .../light_xyl_server/appl_light_xyl_server.c | 792 ++ .../light_xyl_server/appl_light_xyl_server.h | 208 + .../appl_model_state_handler.c | 1648 +++ .../appl_model_state_handler.h | 32 + .../sensor_server/appl_model_state_handler.c | 601 ++ .../sensor_server/appl_model_state_handler.h | 32 + .../sensor/sensor_server/appl_sensor_server.c | 286 + .../sensor/sensor_server/appl_sensor_server.h | 77 + .../scene_server/appl_model_state_handler.c | 56 + .../scene_server/appl_model_state_handler.h | 32 + .../scene_server/appl_scene_server.c | 171 + .../scene_server/appl_scene_server.h | 50 + .../appl_model_state_handler.c | 84 + .../appl_model_state_handler.h | 32 + .../scheduler_server/appl_scheduler_server.c | 179 + .../scheduler_server/appl_scheduler_server.h | 56 + .../time_server/appl_model_state_handler.c | 138 + .../time_server/appl_model_state_handler.h | 32 + .../time_server/appl_time_server.c | 202 + .../time_server/appl_time_server.h | 56 + .../ethermind/mesh/export/bearer/blebrr.c | 1680 ++++ .../ethermind/mesh/export/bearer/blebrr.h | 148 + .../mesh/export/bearer/blebrr_gatt.c | 241 + .../mesh/export/cbtimer/EXT_cbtimer.c | 1106 +++ .../mesh/export/cbtimer/EXT_cbtimer.h | 166 + .../ethermind/mesh/export/cbtimer/cbtimer.h | 134 + .../ethermind/mesh/export/cli/cli_brr.c | 157 + .../ethermind/mesh/export/cli/cli_core.c | 192 + .../mesh/export/cli/cli_core_network.c | 238 + .../mesh/export/cli/cli_core_provision.c | 269 + .../mesh/export/cli/cli_core_proxy.c | 305 + .../mesh/export/cli/cli_core_transport.c | 300 + .../ethermind/mesh/export/cli/cli_demo.c | 263 + .../mesh/export/cli/cli_inclusion_flags.txt | 49 + .../ethermind/mesh/export/cli/cli_main.c | 279 + .../ethermind/mesh/export/cli/cli_main.h | 300 + .../ethermind/mesh/export/cli/cli_model.c | 47 + .../mesh/export/cli/cli_model_client.c | 97 + .../mesh/export/cli/cli_model_server.c | 519 + .../ethermind/mesh/export/cli/cli_ps.c | 185 + .../cli/model/client/cli_config_client.c | 2126 ++++ .../cli/model/client/cli_config_client.h | 201 + .../model/client/cli_generic_battery_client.c | 236 + .../model/client/cli_generic_battery_client.h | 63 + ...i_generic_default_transition_time_client.c | 290 + ...i_generic_default_transition_time_client.h | 69 + .../model/client/cli_generic_level_client.c | 492 + .../model/client/cli_generic_level_client.h | 81 + .../client/cli_generic_location_client.c | 393 + .../client/cli_generic_location_client.h | 78 + .../model/client/cli_generic_onoff_client.c | 322 + .../model/client/cli_generic_onoff_client.h | 69 + .../client/cli_generic_power_level_client.c | 493 + .../client/cli_generic_power_level_client.h | 90 + .../client/cli_generic_power_onoff_client.c | 286 + .../client/cli_generic_power_onoff_client.h | 69 + .../client/cli_generic_property_client.c | 685 ++ .../client/cli_generic_property_client.h | 99 + .../cli/model/client/cli_health_client.c | 501 + .../cli/model/client/cli_health_client.h | 93 + .../cli/model/client/cli_light_ctl_client.c | 610 ++ .../cli/model/client/cli_light_ctl_client.h | 96 + .../cli/model/client/cli_light_hsl_client.c | 745 ++ .../cli/model/client/cli_light_hsl_client.h | 108 + .../cli/model/client/cli_light_lc_client.c | 604 ++ .../cli/model/client/cli_light_lc_client.h | 96 + .../model/client/cli_light_lightness_client.c | 601 ++ .../model/client/cli_light_lightness_client.h | 99 + .../cli/model/client/cli_light_xyl_client.c | 527 + .../cli/model/client/cli_light_xyl_client.h | 90 + .../cli/model/client/cli_scene_client.c | 441 + .../cli/model/client/cli_scene_client.h | 84 + .../cli/model/client/cli_scheduler_client.c | 398 + .../cli/model/client/cli_scheduler_client.h | 72 + .../cli/model/client/cli_sensor_client.c | 1000 ++ .../cli/model/client/cli_sensor_client.h | 93 + .../export/cli/model/client/cli_time_client.c | 456 + .../export/cli/model/client/cli_time_client.h | 84 + .../mesh/export/climodel/cli_model.c | 461 + .../mesh/export/climodel/cli_model.h | 62 + .../mesh/export/include/MS_access_api.h | 1960 ++++ .../mesh/export/include/MS_assigned_numbers.h | 810 ++ .../mesh/export/include/MS_brr_api.h | 600 ++ .../ethermind/mesh/export/include/MS_common.h | 1039 ++ .../mesh/export/include/MS_config_api.h | 1780 ++++ .../ethermind/mesh/export/include/MS_error.h | 499 + .../export/include/MS_generic_battery_api.h | 292 + .../MS_generic_default_transition_time_api.h | 319 + .../export/include/MS_generic_level_api.h | 487 + .../export/include/MS_generic_location_api.h | 517 + .../export/include/MS_generic_onoff_api.h | 337 + .../include/MS_generic_power_level_api.h | 594 ++ .../include/MS_generic_power_onoff_api.h | 365 + .../export/include/MS_generic_property_api.h | 910 ++ .../export/include/MS_health_client_api.h | 421 + .../export/include/MS_health_server_api.h | 276 + .../mesh/export/include/MS_light_ctl_api.h | 727 ++ .../mesh/export/include/MS_light_hsl_api.h | 963 ++ .../mesh/export/include/MS_light_lc_api.h | 570 ++ .../export/include/MS_light_lightness_api.h | 718 ++ .../mesh/export/include/MS_light_xyl_api.h | 590 ++ .../mesh/export/include/MS_ltrn_api.h | 250 + .../mesh/export/include/MS_model_states.h | 1396 +++ .../mesh/export/include/MS_net_api.h | 849 ++ .../mesh/export/include/MS_prov_api.h | 815 ++ .../mesh/export/include/MS_scene_api.h | 480 + .../mesh/export/include/MS_trn_api.h | 1031 ++ .../mesh/export/include/MS_version.h | 112 + .../mesh/export/include/access_extern.h | 108 + .../mesh/export/include/fsm_defines.h | 107 + .../mesh/export/include/fsm_engine.h | 72 + .../mesh/export/include/ltrn_extern.h | 37 + .../mesh/export/include/net_extern.h | 49 + .../mesh/export/include/net_internal.h | 568 ++ .../mesh/export/platforms/ext/MS_common_pl.c | 68 + .../mesh/export/platforms/ext/MS_common_pl.h | 54 + .../mesh/export/platforms/ext/prov_pl.c | 48 + .../mesh/export/platforms/ext/prov_pl.h | 36 + .../export/sample/appl_sample_example_1.c | 665 ++ .../export/sample/appl_sample_example_10.c | 759 ++ .../export/sample/appl_sample_example_10a.c | 1119 +++ .../export/sample/appl_sample_example_11.c | 1117 +++ .../export/sample/appl_sample_example_5.c | 970 ++ .../export/sample/appl_sample_example_6.c | 1092 ++ .../export/sample/appl_sample_example_7.c | 882 ++ .../export/sample/appl_sample_example_8.c | 1062 ++ .../export/sample/appl_sample_example_9.c | 955 ++ .../ethermind/mesh/export/sample/readme.txt | 10 + .../vendormodel/client/vendormodel_client.c | 445 + .../vendormodel/client/vendormodel_client.h | 108 + .../vendormodel/server/vendormodel_server.c | 335 + .../vendormodel/server/vendormodel_server.h | 85 + .../export/vendormodel/vendormodel_common.h | 75 + .../ethermind/osal/src/phyos/EM_assert.h | 55 + .../ethermind/osal/src/phyos/EM_debug.c | 268 + .../ethermind/osal/src/phyos/EM_debug.h | 25 + .../ethermind/osal/src/phyos/EM_debug_api.h | 186 + .../osal/src/phyos/EM_debug_internal.h | 31 + .../ethermind/osal/src/phyos/EM_os.c | 409 + .../ethermind/osal/src/phyos/EM_os.h | 206 + .../ethermind/osal/src/phyos/EM_timer.c | 985 ++ .../ethermind/osal/src/phyos/EM_timer.h | 166 + .../osal/src/phyos/EM_timer_internal.h | 116 + .../ethermind/platforms/EM_platform.c | 70 + .../ethermind/platforms/EM_platform.h | 51 + .../platforms/interfaces/crypto/cry.c | 549 + .../platforms/interfaces/crypto/cry.h | 270 + .../ethermind/platforms/mesh/MS_features.h | 548 + .../ethermind/platforms/mesh/MS_limits.h | 339 + .../ethermind/platforms/mesh/blebrr_pl.c | 1249 +++ .../ethermind/platforms/mesh/mesh_clients.c | 566 ++ .../ethermind/platforms/mesh/mesh_clients.h | 255 + .../ethermind/platforms/mesh/mesh_services.c | 772 ++ .../ethermind/platforms/mesh/mesh_services.h | 258 + .../platforms/mesh/model_state_handler_pl.c | 180 + .../platforms/mesh/model_state_handler_pl.h | 39 + .../ethermind/utils/include/aes_cmac.h | 109 + .../ethermind/utils/include/aes_cmac_pl.h | 39 + .../ethermind/utils/include/bitarray.h | 194 + .../ethermind/utils/include/btypes.h | 116 + .../ethermind/utils/include/cliface.h | 123 + .../ethermind/utils/include/crypto.h | 105 + src/components/ethermind/utils/include/ecdh.h | 36 + src/components/ethermind/utils/include/mpal.h | 84 + src/components/ethermind/utils/include/nvs.h | 72 + .../ethermind/utils/include/nvsto.h | 287 + src/components/inc/bus_dev.h | 95 + src/components/inc/error.h | 78 + src/components/inc/global_config.h | 207 + src/components/inc/mcu.h | 90 + src/components/inc/mcu_phy_bumbee.h | 850 ++ src/components/inc/types.h | 159 + src/components/inc/version.h | 25 + src/components/libraries/cliface/cliface.c | 388 + src/components/libraries/cliface/cliface.h | 118 + .../libraries/console/phy_console.c | 272 + .../libraries/console/phy_console.h | 28 + src/components/libraries/crc16/crc16.c | 45 + src/components/libraries/crc16/crc16.h | 14 + .../libraries/datetime/app_datetime.c | 227 + .../libraries/datetime/app_datetime.h | 94 + src/components/libraries/fs/fs.c | 831 ++ src/components/libraries/fs/fs.h | 244 + src/components/libraries/fs/fs_test.c | 1440 +++ src/components/libraries/fs/fs_test.h | 38 + .../secure/asm_ecdh_p256/P256-cortex-ecdh.h | 80 + .../asm_ecdh_p256/P256-cortex-m0-ecdh-keil.s | 2954 ++++++ .../libraries/tinycrypt-0.2.8/.gitignore | 5 + .../libraries/tinycrypt-0.2.8/AUTHORS | 15 + .../libraries/tinycrypt-0.2.8/LICENSE | 61 + .../libraries/tinycrypt-0.2.8/Makefile | 21 + .../libraries/tinycrypt-0.2.8/README | 71 + .../libraries/tinycrypt-0.2.8/VERSION | 1 + .../libraries/tinycrypt-0.2.8/config.mk | 35 + .../documentation/tinycrypt.rst | 352 + .../libraries/tinycrypt-0.2.8/lib/Makefile | 39 + .../lib/include/tinycrypt/aes.h | 131 + .../lib/include/tinycrypt/cbc_mode.h | 151 + .../lib/include/tinycrypt/ccm_mode.h | 212 + .../lib/include/tinycrypt/cmac_mode.h | 195 + .../lib/include/tinycrypt/constants.h | 61 + .../lib/include/tinycrypt/ctr_mode.h | 108 + .../lib/include/tinycrypt/ctr_prng.h | 167 + .../lib/include/tinycrypt/ecc.h | 547 + .../lib/include/tinycrypt/ecc_dh.h | 131 + .../lib/include/tinycrypt/ecc_dsa.h | 139 + .../include/tinycrypt/ecc_platform_specific.h | 81 + .../lib/include/tinycrypt/hmac.h | 140 + .../lib/include/tinycrypt/hmac_prng.h | 165 + .../lib/include/tinycrypt/sha256.h | 130 + .../lib/include/tinycrypt/utils.h | 95 + .../tinycrypt-0.2.8/lib/source/aes_decrypt.c | 185 + .../tinycrypt-0.2.8/lib/source/aes_encrypt.c | 223 + .../tinycrypt-0.2.8/lib/source/cbc_mode.c | 121 + .../tinycrypt-0.2.8/lib/source/ccm_mode.c | 290 + .../tinycrypt-0.2.8/lib/source/cmac_mode.c | 268 + .../tinycrypt-0.2.8/lib/source/ctr_mode.c | 92 + .../tinycrypt-0.2.8/lib/source/ctr_prng.c | 305 + .../tinycrypt-0.2.8/lib/source/ecc.c | 993 ++ .../tinycrypt-0.2.8/lib/source/ecc_dh.c | 194 + .../tinycrypt-0.2.8/lib/source/ecc_dsa.c | 307 + .../lib/source/ecc_platform_specific.c | 114 + .../tinycrypt-0.2.8/lib/source/hmac.c | 149 + .../tinycrypt-0.2.8/lib/source/hmac_prng.c | 211 + .../tinycrypt-0.2.8/lib/source/sha256.c | 248 + .../tinycrypt-0.2.8/lib/source/utils.c | 79 + .../libraries/tinycrypt-0.2.8/tests/Makefile | 67 + .../tests/include/test_ecc_utils.h | 100 + .../tests/include/test_utils.h | 129 + .../tinycrypt-0.2.8/tests/test_aes.c | 2348 +++++ .../tinycrypt-0.2.8/tests/test_cbc_mode.c | 176 + .../tinycrypt-0.2.8/tests/test_ccm_mode.c | 573 ++ .../tinycrypt-0.2.8/tests/test_cmac_mode.c | 329 + .../tinycrypt-0.2.8/tests/test_ctr_mode.c | 141 + .../tinycrypt-0.2.8/tests/test_ctr_prng.c | 628 ++ .../tinycrypt-0.2.8/tests/test_ecc_dh.c | 533 + .../tinycrypt-0.2.8/tests/test_ecc_dsa.c | 682 ++ .../tinycrypt-0.2.8/tests/test_ecc_utils.c | 287 + .../tinycrypt-0.2.8/tests/test_hmac.c | 383 + .../tinycrypt-0.2.8/tests/test_hmac_prng.c | 140 + .../tinycrypt-0.2.8/tests/test_sha256.c | 532 + src/components/osal/include/OSAL.h | 270 + src/components/osal/include/OSAL_Clock.h | 111 + src/components/osal/include/OSAL_Memory.h | 126 + src/components/osal/include/OSAL_Nv.h | 83 + src/components/osal/include/OSAL_PwrMgr.h | 112 + src/components/osal/include/OSAL_Tasks.h | 65 + src/components/osal/include/OSAL_Timers.h | 138 + src/components/osal/include/comdef.h | 129 + src/components/osal/include/osal_bufmgr.h | 80 + src/components/osal/include/osal_cbtimer.h | 102 + src/components/osal/include/osal_snv.h | 110 + src/components/osal/snv/osal_snv.c | 113 + .../profiles/AudioProfile/AudioGATTprofile.c | 664 ++ .../profiles/AudioProfile/AudioGATTprofile.h | 143 + src/components/profiles/Batt/battservice.c | 369 + src/components/profiles/Batt/battservice.h | 182 + src/components/profiles/Batt/hiddev.h | 301 + .../profiles/DevInfo/devinfoservice.c | 589 ++ .../profiles/DevInfo/devinfoservice.h | 115 + src/components/profiles/GATT/gattservapp.c | 2519 +++++ src/components/profiles/HID/hiddev.c | 1468 +++ src/components/profiles/HID/hiddev.h | 301 + src/components/profiles/HID/hidkbdservice.c | 969 ++ src/components/profiles/HID/hidkbdservice.h | 189 + src/components/profiles/HIDVoice/hiddev.c | 1356 +++ src/components/profiles/HIDVoice/hiddev.h | 310 + .../profiles/HIDVoice/hidkbdservice.c | 1572 +++ .../profiles/HIDVoice/hidkbdservice.h | 274 + src/components/profiles/Keys/simplekeys.c | 400 + src/components/profiles/Keys/simplekeys.h | 108 + src/components/profiles/Roles/broadcaster.c | 610 ++ src/components/profiles/Roles/broadcaster.h | 186 + src/components/profiles/Roles/central.c | 645 ++ src/components/profiles/Roles/central.h | 271 + src/components/profiles/Roles/gap.c | 203 + src/components/profiles/Roles/gapbondmgr.c | 2293 +++++ src/components/profiles/Roles/gapbondmgr.h | 371 + src/components/profiles/Roles/gapgattserver.c | 957 ++ src/components/profiles/Roles/observer.c | 278 + src/components/profiles/Roles/observer.h | 193 + src/components/profiles/Roles/peripheral.c | 1589 +++ src/components/profiles/Roles/peripheral.h | 406 + .../profiles/Roles/peripheral.h~RF5afb64a.TMP | 402 + .../profiles/Roles/peripheralBroadcaster.c | 1095 ++ .../profiles/Roles/peripheralBroadcaster.h | 206 + .../profiles/ScanParam/scanparamservice.c | 406 + .../profiles/ScanParam/scanparamservice.h | 137 + .../SimpleProfile/simpleGATTprofile_ota.c | 874 ++ .../SimpleProfile/simpleGATTprofile_ota.h | 134 + .../profiles/aliGenie/ali_genie_profile.c | 155 + .../profiles/aliGenie/ali_genie_profile.h | 50 + src/components/profiles/ancs/ancs_attr.c | 619 ++ src/components/profiles/ancs/ancs_attr.h | 30 + src/components/profiles/ancs/ble_ancs.c | 727 ++ src/components/profiles/ancs/ble_ancs.h | 239 + .../profiles/hrs/heartrateservice.c | 479 + .../profiles/hrs/heartrateservice.h | 167 + src/components/profiles/multiRole/multi.c | 2284 +++++ src/components/profiles/multiRole/multi.h | 955 ++ .../profiles/multiRole/multiRoleProfile.c | 556 ++ .../profiles/multiRole/multiRoleProfile.h | 110 + src/components/profiles/ota/ota_flash.c | 477 + src/components/profiles/ota/ota_flash.h | 191 + src/components/profiles/ota/ota_flash_mesh.c | 244 + src/components/profiles/ota/ota_flash_mesh.h | 49 + src/components/profiles/ota/ota_protocol.c | 1136 +++ src/components/profiles/ota/ota_protocol.h | 105 + src/components/profiles/ota/ota_service.c | 302 + src/components/profiles/ota/ota_service.h | 37 + src/components/profiles/ota/otam_protocol.c | 621 ++ src/components/profiles/ota/otam_protocol.h | 61 + .../profiles/ota_app/ota_app_service.c | 581 ++ .../profiles/ota_app/ota_app_service.h | 70 + src/components/profiles/ppsp/core_queu.c | 339 + src/components/profiles/ppsp/core_queu.h | 95 + src/components/profiles/ppsp/list_slst.c | 613 ++ src/components/profiles/ppsp/list_slst.h | 178 + src/components/profiles/ppsp/ppsp_impl.c | 1592 +++ src/components/profiles/ppsp/ppsp_impl.h | 63 + src/components/profiles/ppsp/ppsp_serv.c | 957 ++ src/components/profiles/ppsp/ppsp_serv.h | 132 + src/components/profiles/slb/slb.c | 600 ++ src/components/profiles/slb/slb.h | 91 + src/lib/aoxEst.lib | Bin 0 -> 33830 bytes src/lib/ble_controller/ll.c | 8838 +++++++++++++++++ src/lib/ble_controller/ll_common.c | 4972 ++++++++++ src/lib/ble_controller/ll_enc.c | 719 ++ src/lib/ble_controller/ll_hwItf.c | 7960 +++++++++++++++ src/lib/ble_controller/ll_hw_drv.c | 1885 ++++ src/lib/ble_controller/ll_masterEndCauses.c | 2296 +++++ src/lib/ble_controller/ll_slaveEndCauses.c | 2521 +++++ src/lib/ble_controller/ll_sleep.c | 556 ++ src/lib/ble_controller/rf_phy_driver.c | 2416 +++++ src/lib/ble_host.lib | Bin 0 -> 335968 bytes src/lib/ble_host/att_client.c | 369 + src/lib/ble_host/att_server.c | 394 + src/lib/ble_host/att_util.c | 1819 ++++ src/lib/ble_host/gap_centdevmgr.c | 973 ++ src/lib/ble_host/gap_centlinkmgr.c | 374 + src/lib/ble_host/gap_configmgr.c | 968 ++ src/lib/ble_host/gap_devmgr.c | 239 + src/lib/ble_host/gap_linkmgr.c | 1265 +++ src/lib/ble_host/gap_peridevmgr.c | 1263 +++ src/lib/ble_host/gap_perilinkmgr.c | 142 + src/lib/ble_host/gap_simpletask.c | 391 + src/lib/ble_host/gap_task.c | 540 + src/lib/ble_host/gatt_client.c | 2739 +++++ src/lib/ble_host/gatt_server.c | 1567 +++ src/lib/ble_host/gatt_task.c | 411 + src/lib/ble_host/gatt_uuid.c | 351 + src/lib/ble_host/l2cap_if.c | 347 + src/lib/ble_host/l2cap_task.c | 525 + src/lib/ble_host/l2cap_util.c | 1744 ++++ src/lib/ble_host/linkdb.c | 523 + src/lib/ble_host/sm_intpairing.c | 901 ++ src/lib/ble_host/sm_mgr.c | 1219 +++ src/lib/ble_host/sm_pairing.c | 1215 +++ src/lib/ble_host/sm_rsppairing.c | 923 ++ src/lib/ble_host/sm_task.c | 330 + src/lib/ble_host/smp.c | 720 ++ src/lib/ble_host_multi5.lib | Bin 0 -> 336432 bytes src/lib/phy_font.lib | Bin 0 -> 7886 bytes src/lib/rf.lib | Bin 0 -> 117306 bytes src/lib/rf/patch.c | 8706 ++++++++++++++++ src/lib/rf_mst.lib | Bin 0 -> 77514 bytes src/lib/rflib.h | 22 + src/lib/sec/aes.c | 586 ++ src/lib/sec/aes.h | 69 + src/lib/sec/phy_sec_ext.c | 505 + src/lib/ui_font.h | 28 + src/misc/bb_rom_sym_m0.gcc | 1022 ++ src/misc/bb_rom_sym_m0.txt | 1023 ++ src/misc/generate_gccsymfile.py | 7 + src/misc/jump_function.h | 594 ++ src/misc/jump_table.c | 149 + src/misc/rom_sym_def.h | 901 ++ 606 files changed, 276150 insertions(+), 1 deletion(-) create mode 100644 src/TestTHB2/RTE/Device/ARMCM0/phy6202.ld create mode 100644 src/TestTHB2/RTE/Device/ARMCM0/startup_ARMCM0.c create mode 100644 src/TestTHB2/RTE/Device/ARMCM0/startup_ARMCM0.s create mode 100644 src/TestTHB2/RTE/Device/ARMCM0/system_ARMCM0.c create mode 100644 src/TestTHB2/RTE/_Target_1/RTE_Components.h create mode 100644 src/TestTHB2/TestTHB2.uvprojx create mode 100644 src/TestTHB2/main.c create mode 100644 src/TestTHB2/ram.ini create mode 100644 src/TestTHB2/ram_xip.ini create mode 100644 src/TestTHB2/scatter_load.sct create mode 100644 src/TestTHB2/source/OSAL_SimpleBLEPeripheral.c create mode 100644 src/TestTHB2/source/SimpleBLEPeripheral_Main.c create mode 100644 src/TestTHB2/source/battery.c create mode 100644 src/TestTHB2/source/battery.h create mode 100644 src/TestTHB2/source/bthome_beacon.c create mode 100644 src/TestTHB2/source/bthome_beacon.h create mode 100644 src/TestTHB2/source/halPeripheral.c create mode 100644 src/TestTHB2/source/halPeripheral.h create mode 100644 src/TestTHB2/source/sbpProfile_ota.c create mode 100644 src/TestTHB2/source/sbpProfile_ota.h create mode 100644 src/TestTHB2/source/sensor.h create mode 100644 src/TestTHB2/source/sensors.c create mode 100644 src/TestTHB2/source/simpleBLEPeripheral.h create mode 100644 src/TestTHB2/source/thb2_main.c create mode 100644 src/TestTHB2/source/thservice.c create mode 100644 src/TestTHB2/source/thservice.h create mode 100644 src/components/arch/cm0/core_bumbee_m0.h create mode 100644 src/components/ble/controller/ll.h create mode 100644 src/components/ble/controller/ll_buf.h create mode 100644 src/components/ble/controller/ll_common.h create mode 100644 src/components/ble/controller/ll_debug.h create mode 100644 src/components/ble/controller/ll_def.h create mode 100644 src/components/ble/controller/ll_enc.h create mode 100644 src/components/ble/controller/ll_hw_drv.h create mode 100644 src/components/ble/controller/ll_sleep.h create mode 100644 src/components/ble/controller/rf_phy_driver.h create mode 100644 src/components/ble/hci/hci_data.h create mode 100644 src/components/ble/hci/hci_event.h create mode 100644 src/components/ble/hci/hci_host.h create mode 100644 src/components/ble/hci/hci_task.h create mode 100644 src/components/ble/hci/hci_tl.h create mode 100644 src/components/ble/host/att_internal.h create mode 100644 src/components/ble/host/gap_internal.h create mode 100644 src/components/ble/host/gapgattserver.h create mode 100644 src/components/ble/host/gatt_internal.h create mode 100644 src/components/ble/host/gatt_profile_uuid.h create mode 100644 src/components/ble/host/gattservapp.h create mode 100644 src/components/ble/host/gatttest.h create mode 100644 src/components/ble/host/l2cap_internal.h create mode 100644 src/components/ble/host/linkdb.h create mode 100644 src/components/ble/host/sm_internal.h create mode 100644 src/components/ble/host/smp.h create mode 100644 src/components/ble/include/att.h create mode 100644 src/components/ble/include/bcomdef.h create mode 100644 src/components/ble/include/gap.h create mode 100644 src/components/ble/include/gatt.h create mode 100644 src/components/ble/include/gatt_uuid.h create mode 100644 src/components/ble/include/hci.h create mode 100644 src/components/ble/include/l2cap.h create mode 100644 src/components/ble/include/sm.h create mode 100644 src/components/coremark/core_list_join.c create mode 100644 src/components/coremark/core_main.c create mode 100644 src/components/coremark/core_matrix.c create mode 100644 src/components/coremark/core_portme.c create mode 100644 src/components/coremark/core_portme.h create mode 100644 src/components/coremark/core_state.c create mode 100644 src/components/coremark/core_util.c create mode 100644 src/components/coremark/coremark.h create mode 100644 src/components/driver/adc/adc.c create mode 100644 src/components/driver/adc/adc.h create mode 100644 src/components/driver/adc/readme.txt create mode 100644 src/components/driver/bsp_button/bsp_button.c create mode 100644 src/components/driver/bsp_button/bsp_button.h create mode 100644 src/components/driver/bsp_button/bsp_button_task.c create mode 100644 src/components/driver/bsp_button/bsp_button_task.h create mode 100644 src/components/driver/bsp_button/bsp_gpio.c create mode 100644 src/components/driver/bsp_button/bsp_gpio.h create mode 100644 src/components/driver/clock/clock.c create mode 100644 src/components/driver/clock/clock.h create mode 100644 src/components/driver/dma/dma.c create mode 100644 src/components/driver/dma/dma.h create mode 100644 src/components/driver/flash/flash.c create mode 100644 src/components/driver/flash/flash.h create mode 100644 src/components/driver/gpio/gpio.c create mode 100644 src/components/driver/gpio/gpio.h create mode 100644 src/components/driver/i2c/i2c.c create mode 100644 src/components/driver/i2c/i2c.h create mode 100644 src/components/driver/i2c/i2c_common.c create mode 100644 src/components/driver/i2c/i2c_common.h create mode 100644 src/components/driver/i2c/i2c_io.c create mode 100644 src/components/driver/i2c/i2c_io.h create mode 100644 src/components/driver/i2c/i2c_s.c create mode 100644 src/components/driver/i2c/i2c_s.h create mode 100644 src/components/driver/i2c/i2c_slave.c create mode 100644 src/components/driver/i2c/i2c_slave.h create mode 100644 src/components/driver/key/key.c create mode 100644 src/components/driver/key/key.h create mode 100644 src/components/driver/kscan/kscan.c create mode 100644 src/components/driver/kscan/kscan.h create mode 100644 src/components/driver/led_light/led_light.c create mode 100644 src/components/driver/led_light/led_light.h create mode 100644 src/components/driver/log/log.h create mode 100644 src/components/driver/log/my_printf.c create mode 100644 src/components/driver/pwm/pwm.c create mode 100644 src/components/driver/pwm/pwm.h create mode 100644 src/components/driver/pwrmgr/pwrmgr.c create mode 100644 src/components/driver/pwrmgr/pwrmgr.h create mode 100644 src/components/driver/qdec/qdec.c create mode 100644 src/components/driver/qdec/qdec.h create mode 100644 src/components/driver/spi/spi.c create mode 100644 src/components/driver/spi/spi.h create mode 100644 src/components/driver/spiflash/spiflash.c create mode 100644 src/components/driver/spiflash/spiflash.h create mode 100644 src/components/driver/timer/timer.c create mode 100644 src/components/driver/timer/timer.h create mode 100644 src/components/driver/uart/uart.c create mode 100644 src/components/driver/uart/uart.h create mode 100644 src/components/driver/voice/voice.c create mode 100644 src/components/driver/voice/voice.h create mode 100644 src/components/driver/watchdog/watchdog.c create mode 100644 src/components/driver/watchdog/watchdog.h create mode 100644 src/components/ethermind/external/crypto/aes/README.txt create mode 100644 src/components/ethermind/external/crypto/aes/aes-ccm.c create mode 100644 src/components/ethermind/external/crypto/aes/aes.c create mode 100644 src/components/ethermind/external/crypto/aes/aes.h create mode 100644 src/components/ethermind/external/crypto/asm_ecdh_p256/P256-cortex-ecdh.h create mode 100644 src/components/ethermind/external/crypto/asm_ecdh_p256/P256-cortex-m0-ecdh-keil.s create mode 100644 src/components/ethermind/external/crypto/sha256/sha256.c create mode 100644 src/components/ethermind/external/crypto/sha256/sha256.h create mode 100644 src/components/ethermind/lib/meshlibs/phyos/keil/libethermind_ecdh.lib create mode 100644 src/components/ethermind/lib/meshlibs/phyos/keil/libethermind_mesh_core.lib create mode 100644 src/components/ethermind/lib/meshlibs/phyos/keil/libethermind_mesh_models.lib create mode 100644 src/components/ethermind/lib/meshlibs/phyos/keil/libethermind_utils.lib create mode 100644 src/components/ethermind/mesh/export/appl/appl_main.c create mode 100644 src/components/ethermind/mesh/export/appl/appl_main.h create mode 100644 src/components/ethermind/mesh/export/appl/appl_prov.c create mode 100644 src/components/ethermind/mesh/export/appl/appl_proxy.c create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_config_client.c create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_config_client.h create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_generic_battery_client.c create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_generic_battery_client.h create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_generic_default_transition_time_client.c create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_generic_default_transition_time_client.h create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_generic_level_client.c create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_generic_level_client.h create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_generic_location_client.c create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_generic_location_client.h create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_generic_onoff_client.c create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_generic_onoff_client.h create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_generic_power_level_client.c create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_generic_power_level_client.h create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_generic_power_onoff_client.c create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_generic_power_onoff_client.h create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_generic_property_client.c create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_generic_property_client.h create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_health_client.c create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_health_client.h create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_light_ctl_client.c create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_light_ctl_client.h create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_light_hsl_client.c create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_light_hsl_client.h create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_light_lc_client.c create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_light_lc_client.h create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_light_lightness_client.c create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_light_lightness_client.h create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_light_xyl_client.c create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_light_xyl_client.h create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_main_model_client.c create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_scene_client.c create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_scene_client.h create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_scheduler_client.c create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_scheduler_client.h create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_sensor_client.c create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_sensor_client.h create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_time_client.c create mode 100644 src/components/ethermind/mesh/export/appl/model/client/appl_time_client.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/appl_main_model_server.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/appl_model_server_callback.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/appl_model_server_state_handler.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/appl_model_state_handler.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_battery_server/appl_generic_battery_server.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_battery_server/appl_generic_battery_server.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_battery_server/appl_model_state_handler.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_battery_server/appl_model_state_handler.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_default_transition_time_server/appl_generic_default_transition_time_server.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_default_transition_time_server/appl_generic_default_transition_time_server.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_level_server/appl_generic_level_server.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_level_server/appl_generic_level_server.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_level_server/appl_model_state_handler.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_level_server/appl_model_state_handler.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_location_server/appl_generic_location_server.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_location_server/appl_generic_location_server.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_location_server/appl_model_state_handler.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_location_server/appl_model_state_handler.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_onoff_server/appl_generic_onoff_server.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_onoff_server/appl_generic_onoff_server.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_onoff_server/appl_model_state_handler.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_onoff_server/appl_model_state_handler.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_level_server/appl_generic_power_level_server.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_level_server/appl_generic_power_level_server.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_level_server/appl_model_state_handler.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_level_server/appl_model_state_handler.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_onoff_server/appl_generic_power_onoff_server.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_onoff_server/appl_generic_power_onoff_server.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_onoff_server/appl_model_state_handler.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_onoff_server/appl_model_state_handler.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_property_server/appl_generic_property_server.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_property_server/appl_generic_property_server.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_property_server/appl_model_state_handler.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/generics/generic_property_server/appl_model_state_handler.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/health/appl_health_server.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/health/appl_health_server.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/lighting/light_ctl_server/appl_light_ctl_server.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/lighting/light_ctl_server/appl_light_ctl_server.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/lighting/light_ctl_server/appl_model_state_handler.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/lighting/light_ctl_server/appl_model_state_handler.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/lighting/light_hsl_server/appl_light_hsl_server.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/lighting/light_hsl_server/appl_light_hsl_server.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/lighting/light_hsl_server/appl_model_state_handler.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/lighting/light_hsl_server/appl_model_state_handler.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/lighting/light_lc_server/appl_light_lc_server.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/lighting/light_lc_server/appl_light_lc_server.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/lighting/light_lc_server/appl_model_state_handler.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/lighting/light_lc_server/appl_model_state_handler.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/lighting/light_lightness_server/appl_light_lightness_server.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/lighting/light_lightness_server/appl_light_lightness_server.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/lighting/light_lightness_server/appl_model_state_handler.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/lighting/light_lightness_server/appl_model_state_handler.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/lighting/light_xyl_server/appl_light_xyl_server.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/lighting/light_xyl_server/appl_light_xyl_server.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/lighting/light_xyl_server/appl_model_state_handler.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/lighting/light_xyl_server/appl_model_state_handler.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/sensor/sensor_server/appl_model_state_handler.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/sensor/sensor_server/appl_model_state_handler.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/sensor/sensor_server/appl_sensor_server.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/sensor/sensor_server/appl_sensor_server.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scene_server/appl_model_state_handler.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scene_server/appl_model_state_handler.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scene_server/appl_scene_server.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scene_server/appl_scene_server.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scheduler_server/appl_model_state_handler.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scheduler_server/appl_model_state_handler.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scheduler_server/appl_scheduler_server.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scheduler_server/appl_scheduler_server.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/time_server/appl_model_state_handler.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/time_server/appl_model_state_handler.h create mode 100644 src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/time_server/appl_time_server.c create mode 100644 src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/time_server/appl_time_server.h create mode 100644 src/components/ethermind/mesh/export/bearer/blebrr.c create mode 100644 src/components/ethermind/mesh/export/bearer/blebrr.h create mode 100644 src/components/ethermind/mesh/export/bearer/blebrr_gatt.c create mode 100644 src/components/ethermind/mesh/export/cbtimer/EXT_cbtimer.c create mode 100644 src/components/ethermind/mesh/export/cbtimer/EXT_cbtimer.h create mode 100644 src/components/ethermind/mesh/export/cbtimer/cbtimer.h create mode 100644 src/components/ethermind/mesh/export/cli/cli_brr.c create mode 100644 src/components/ethermind/mesh/export/cli/cli_core.c create mode 100644 src/components/ethermind/mesh/export/cli/cli_core_network.c create mode 100644 src/components/ethermind/mesh/export/cli/cli_core_provision.c create mode 100644 src/components/ethermind/mesh/export/cli/cli_core_proxy.c create mode 100644 src/components/ethermind/mesh/export/cli/cli_core_transport.c create mode 100644 src/components/ethermind/mesh/export/cli/cli_demo.c create mode 100644 src/components/ethermind/mesh/export/cli/cli_inclusion_flags.txt create mode 100644 src/components/ethermind/mesh/export/cli/cli_main.c create mode 100644 src/components/ethermind/mesh/export/cli/cli_main.h create mode 100644 src/components/ethermind/mesh/export/cli/cli_model.c create mode 100644 src/components/ethermind/mesh/export/cli/cli_model_client.c create mode 100644 src/components/ethermind/mesh/export/cli/cli_model_server.c create mode 100644 src/components/ethermind/mesh/export/cli/cli_ps.c create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_config_client.c create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_config_client.h create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_generic_battery_client.c create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_generic_battery_client.h create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_generic_default_transition_time_client.c create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_generic_default_transition_time_client.h create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_generic_level_client.c create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_generic_level_client.h create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_generic_location_client.c create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_generic_location_client.h create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_generic_onoff_client.c create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_generic_onoff_client.h create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_generic_power_level_client.c create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_generic_power_level_client.h create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_generic_power_onoff_client.c create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_generic_power_onoff_client.h create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_generic_property_client.c create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_generic_property_client.h create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_health_client.c create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_health_client.h create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_light_ctl_client.c create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_light_ctl_client.h create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_light_hsl_client.c create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_light_hsl_client.h create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_light_lc_client.c create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_light_lc_client.h create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_light_lightness_client.c create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_light_lightness_client.h create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_light_xyl_client.c create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_light_xyl_client.h create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_scene_client.c create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_scene_client.h create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_scheduler_client.c create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_scheduler_client.h create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_sensor_client.c create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_sensor_client.h create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_time_client.c create mode 100644 src/components/ethermind/mesh/export/cli/model/client/cli_time_client.h create mode 100644 src/components/ethermind/mesh/export/climodel/cli_model.c create mode 100644 src/components/ethermind/mesh/export/climodel/cli_model.h create mode 100644 src/components/ethermind/mesh/export/include/MS_access_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_assigned_numbers.h create mode 100644 src/components/ethermind/mesh/export/include/MS_brr_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_common.h create mode 100644 src/components/ethermind/mesh/export/include/MS_config_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_error.h create mode 100644 src/components/ethermind/mesh/export/include/MS_generic_battery_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_generic_default_transition_time_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_generic_level_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_generic_location_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_generic_onoff_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_generic_power_level_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_generic_power_onoff_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_generic_property_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_health_client_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_health_server_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_light_ctl_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_light_hsl_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_light_lc_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_light_lightness_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_light_xyl_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_ltrn_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_model_states.h create mode 100644 src/components/ethermind/mesh/export/include/MS_net_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_prov_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_scene_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_trn_api.h create mode 100644 src/components/ethermind/mesh/export/include/MS_version.h create mode 100644 src/components/ethermind/mesh/export/include/access_extern.h create mode 100644 src/components/ethermind/mesh/export/include/fsm_defines.h create mode 100644 src/components/ethermind/mesh/export/include/fsm_engine.h create mode 100644 src/components/ethermind/mesh/export/include/ltrn_extern.h create mode 100644 src/components/ethermind/mesh/export/include/net_extern.h create mode 100644 src/components/ethermind/mesh/export/include/net_internal.h create mode 100644 src/components/ethermind/mesh/export/platforms/ext/MS_common_pl.c create mode 100644 src/components/ethermind/mesh/export/platforms/ext/MS_common_pl.h create mode 100644 src/components/ethermind/mesh/export/platforms/ext/prov_pl.c create mode 100644 src/components/ethermind/mesh/export/platforms/ext/prov_pl.h create mode 100644 src/components/ethermind/mesh/export/sample/appl_sample_example_1.c create mode 100644 src/components/ethermind/mesh/export/sample/appl_sample_example_10.c create mode 100644 src/components/ethermind/mesh/export/sample/appl_sample_example_10a.c create mode 100644 src/components/ethermind/mesh/export/sample/appl_sample_example_11.c create mode 100644 src/components/ethermind/mesh/export/sample/appl_sample_example_5.c create mode 100644 src/components/ethermind/mesh/export/sample/appl_sample_example_6.c create mode 100644 src/components/ethermind/mesh/export/sample/appl_sample_example_7.c create mode 100644 src/components/ethermind/mesh/export/sample/appl_sample_example_8.c create mode 100644 src/components/ethermind/mesh/export/sample/appl_sample_example_9.c create mode 100644 src/components/ethermind/mesh/export/sample/readme.txt create mode 100644 src/components/ethermind/mesh/export/vendormodel/client/vendormodel_client.c create mode 100644 src/components/ethermind/mesh/export/vendormodel/client/vendormodel_client.h create mode 100644 src/components/ethermind/mesh/export/vendormodel/server/vendormodel_server.c create mode 100644 src/components/ethermind/mesh/export/vendormodel/server/vendormodel_server.h create mode 100644 src/components/ethermind/mesh/export/vendormodel/vendormodel_common.h create mode 100644 src/components/ethermind/osal/src/phyos/EM_assert.h create mode 100644 src/components/ethermind/osal/src/phyos/EM_debug.c create mode 100644 src/components/ethermind/osal/src/phyos/EM_debug.h create mode 100644 src/components/ethermind/osal/src/phyos/EM_debug_api.h create mode 100644 src/components/ethermind/osal/src/phyos/EM_debug_internal.h create mode 100644 src/components/ethermind/osal/src/phyos/EM_os.c create mode 100644 src/components/ethermind/osal/src/phyos/EM_os.h create mode 100644 src/components/ethermind/osal/src/phyos/EM_timer.c create mode 100644 src/components/ethermind/osal/src/phyos/EM_timer.h create mode 100644 src/components/ethermind/osal/src/phyos/EM_timer_internal.h create mode 100644 src/components/ethermind/platforms/EM_platform.c create mode 100644 src/components/ethermind/platforms/EM_platform.h create mode 100644 src/components/ethermind/platforms/interfaces/crypto/cry.c create mode 100644 src/components/ethermind/platforms/interfaces/crypto/cry.h create mode 100644 src/components/ethermind/platforms/mesh/MS_features.h create mode 100644 src/components/ethermind/platforms/mesh/MS_limits.h create mode 100644 src/components/ethermind/platforms/mesh/blebrr_pl.c create mode 100644 src/components/ethermind/platforms/mesh/mesh_clients.c create mode 100644 src/components/ethermind/platforms/mesh/mesh_clients.h create mode 100644 src/components/ethermind/platforms/mesh/mesh_services.c create mode 100644 src/components/ethermind/platforms/mesh/mesh_services.h create mode 100644 src/components/ethermind/platforms/mesh/model_state_handler_pl.c create mode 100644 src/components/ethermind/platforms/mesh/model_state_handler_pl.h create mode 100644 src/components/ethermind/utils/include/aes_cmac.h create mode 100644 src/components/ethermind/utils/include/aes_cmac_pl.h create mode 100644 src/components/ethermind/utils/include/bitarray.h create mode 100644 src/components/ethermind/utils/include/btypes.h create mode 100644 src/components/ethermind/utils/include/cliface.h create mode 100644 src/components/ethermind/utils/include/crypto.h create mode 100644 src/components/ethermind/utils/include/ecdh.h create mode 100644 src/components/ethermind/utils/include/mpal.h create mode 100644 src/components/ethermind/utils/include/nvs.h create mode 100644 src/components/ethermind/utils/include/nvsto.h create mode 100644 src/components/inc/bus_dev.h create mode 100644 src/components/inc/error.h create mode 100644 src/components/inc/global_config.h create mode 100644 src/components/inc/mcu.h create mode 100644 src/components/inc/mcu_phy_bumbee.h create mode 100644 src/components/inc/types.h create mode 100644 src/components/inc/version.h create mode 100644 src/components/libraries/cliface/cliface.c create mode 100644 src/components/libraries/cliface/cliface.h create mode 100644 src/components/libraries/console/phy_console.c create mode 100644 src/components/libraries/console/phy_console.h create mode 100644 src/components/libraries/crc16/crc16.c create mode 100644 src/components/libraries/crc16/crc16.h create mode 100644 src/components/libraries/datetime/app_datetime.c create mode 100644 src/components/libraries/datetime/app_datetime.h create mode 100644 src/components/libraries/fs/fs.c create mode 100644 src/components/libraries/fs/fs.h create mode 100644 src/components/libraries/fs/fs_test.c create mode 100644 src/components/libraries/fs/fs_test.h create mode 100644 src/components/libraries/secure/asm_ecdh_p256/P256-cortex-ecdh.h create mode 100644 src/components/libraries/secure/asm_ecdh_p256/P256-cortex-m0-ecdh-keil.s create mode 100644 src/components/libraries/tinycrypt-0.2.8/.gitignore create mode 100644 src/components/libraries/tinycrypt-0.2.8/AUTHORS create mode 100644 src/components/libraries/tinycrypt-0.2.8/LICENSE create mode 100644 src/components/libraries/tinycrypt-0.2.8/Makefile create mode 100644 src/components/libraries/tinycrypt-0.2.8/README create mode 100644 src/components/libraries/tinycrypt-0.2.8/VERSION create mode 100644 src/components/libraries/tinycrypt-0.2.8/config.mk create mode 100644 src/components/libraries/tinycrypt-0.2.8/documentation/tinycrypt.rst create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/Makefile create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/aes.h create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/cbc_mode.h create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ccm_mode.h create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/cmac_mode.h create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/constants.h create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ctr_mode.h create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ctr_prng.h create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ecc.h create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ecc_dh.h create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ecc_dsa.h create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ecc_platform_specific.h create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/hmac.h create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/hmac_prng.h create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/sha256.h create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/utils.h create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/source/aes_decrypt.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/source/aes_encrypt.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/source/cbc_mode.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/source/ccm_mode.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/source/cmac_mode.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/source/ctr_mode.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/source/ctr_prng.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/source/ecc.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/source/ecc_dh.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/source/ecc_dsa.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/source/ecc_platform_specific.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/source/hmac.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/source/hmac_prng.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/source/sha256.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/lib/source/utils.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/tests/Makefile create mode 100644 src/components/libraries/tinycrypt-0.2.8/tests/include/test_ecc_utils.h create mode 100644 src/components/libraries/tinycrypt-0.2.8/tests/include/test_utils.h create mode 100644 src/components/libraries/tinycrypt-0.2.8/tests/test_aes.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/tests/test_cbc_mode.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/tests/test_ccm_mode.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/tests/test_cmac_mode.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/tests/test_ctr_mode.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/tests/test_ctr_prng.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/tests/test_ecc_dh.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/tests/test_ecc_dsa.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/tests/test_ecc_utils.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/tests/test_hmac.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/tests/test_hmac_prng.c create mode 100644 src/components/libraries/tinycrypt-0.2.8/tests/test_sha256.c create mode 100644 src/components/osal/include/OSAL.h create mode 100644 src/components/osal/include/OSAL_Clock.h create mode 100644 src/components/osal/include/OSAL_Memory.h create mode 100644 src/components/osal/include/OSAL_Nv.h create mode 100644 src/components/osal/include/OSAL_PwrMgr.h create mode 100644 src/components/osal/include/OSAL_Tasks.h create mode 100644 src/components/osal/include/OSAL_Timers.h create mode 100644 src/components/osal/include/comdef.h create mode 100644 src/components/osal/include/osal_bufmgr.h create mode 100644 src/components/osal/include/osal_cbtimer.h create mode 100644 src/components/osal/include/osal_snv.h create mode 100644 src/components/osal/snv/osal_snv.c create mode 100644 src/components/profiles/AudioProfile/AudioGATTprofile.c create mode 100644 src/components/profiles/AudioProfile/AudioGATTprofile.h create mode 100644 src/components/profiles/Batt/battservice.c create mode 100644 src/components/profiles/Batt/battservice.h create mode 100644 src/components/profiles/Batt/hiddev.h create mode 100644 src/components/profiles/DevInfo/devinfoservice.c create mode 100644 src/components/profiles/DevInfo/devinfoservice.h create mode 100644 src/components/profiles/GATT/gattservapp.c create mode 100644 src/components/profiles/HID/hiddev.c create mode 100644 src/components/profiles/HID/hiddev.h create mode 100644 src/components/profiles/HID/hidkbdservice.c create mode 100644 src/components/profiles/HID/hidkbdservice.h create mode 100644 src/components/profiles/HIDVoice/hiddev.c create mode 100644 src/components/profiles/HIDVoice/hiddev.h create mode 100644 src/components/profiles/HIDVoice/hidkbdservice.c create mode 100644 src/components/profiles/HIDVoice/hidkbdservice.h create mode 100644 src/components/profiles/Keys/simplekeys.c create mode 100644 src/components/profiles/Keys/simplekeys.h create mode 100644 src/components/profiles/Roles/broadcaster.c create mode 100644 src/components/profiles/Roles/broadcaster.h create mode 100644 src/components/profiles/Roles/central.c create mode 100644 src/components/profiles/Roles/central.h create mode 100644 src/components/profiles/Roles/gap.c create mode 100644 src/components/profiles/Roles/gapbondmgr.c create mode 100644 src/components/profiles/Roles/gapbondmgr.h create mode 100644 src/components/profiles/Roles/gapgattserver.c create mode 100644 src/components/profiles/Roles/observer.c create mode 100644 src/components/profiles/Roles/observer.h create mode 100644 src/components/profiles/Roles/peripheral.c create mode 100644 src/components/profiles/Roles/peripheral.h create mode 100644 src/components/profiles/Roles/peripheral.h~RF5afb64a.TMP create mode 100644 src/components/profiles/Roles/peripheralBroadcaster.c create mode 100644 src/components/profiles/Roles/peripheralBroadcaster.h create mode 100644 src/components/profiles/ScanParam/scanparamservice.c create mode 100644 src/components/profiles/ScanParam/scanparamservice.h create mode 100644 src/components/profiles/SimpleProfile/simpleGATTprofile_ota.c create mode 100644 src/components/profiles/SimpleProfile/simpleGATTprofile_ota.h create mode 100644 src/components/profiles/aliGenie/ali_genie_profile.c create mode 100644 src/components/profiles/aliGenie/ali_genie_profile.h create mode 100644 src/components/profiles/ancs/ancs_attr.c create mode 100644 src/components/profiles/ancs/ancs_attr.h create mode 100644 src/components/profiles/ancs/ble_ancs.c create mode 100644 src/components/profiles/ancs/ble_ancs.h create mode 100644 src/components/profiles/hrs/heartrateservice.c create mode 100644 src/components/profiles/hrs/heartrateservice.h create mode 100644 src/components/profiles/multiRole/multi.c create mode 100644 src/components/profiles/multiRole/multi.h create mode 100644 src/components/profiles/multiRole/multiRoleProfile.c create mode 100644 src/components/profiles/multiRole/multiRoleProfile.h create mode 100644 src/components/profiles/ota/ota_flash.c create mode 100644 src/components/profiles/ota/ota_flash.h create mode 100644 src/components/profiles/ota/ota_flash_mesh.c create mode 100644 src/components/profiles/ota/ota_flash_mesh.h create mode 100644 src/components/profiles/ota/ota_protocol.c create mode 100644 src/components/profiles/ota/ota_protocol.h create mode 100644 src/components/profiles/ota/ota_service.c create mode 100644 src/components/profiles/ota/ota_service.h create mode 100644 src/components/profiles/ota/otam_protocol.c create mode 100644 src/components/profiles/ota/otam_protocol.h create mode 100644 src/components/profiles/ota_app/ota_app_service.c create mode 100644 src/components/profiles/ota_app/ota_app_service.h create mode 100644 src/components/profiles/ppsp/core_queu.c create mode 100644 src/components/profiles/ppsp/core_queu.h create mode 100644 src/components/profiles/ppsp/list_slst.c create mode 100644 src/components/profiles/ppsp/list_slst.h create mode 100644 src/components/profiles/ppsp/ppsp_impl.c create mode 100644 src/components/profiles/ppsp/ppsp_impl.h create mode 100644 src/components/profiles/ppsp/ppsp_serv.c create mode 100644 src/components/profiles/ppsp/ppsp_serv.h create mode 100644 src/components/profiles/slb/slb.c create mode 100644 src/components/profiles/slb/slb.h create mode 100644 src/lib/aoxEst.lib create mode 100644 src/lib/ble_controller/ll.c create mode 100644 src/lib/ble_controller/ll_common.c create mode 100644 src/lib/ble_controller/ll_enc.c create mode 100644 src/lib/ble_controller/ll_hwItf.c create mode 100644 src/lib/ble_controller/ll_hw_drv.c create mode 100644 src/lib/ble_controller/ll_masterEndCauses.c create mode 100644 src/lib/ble_controller/ll_slaveEndCauses.c create mode 100644 src/lib/ble_controller/ll_sleep.c create mode 100644 src/lib/ble_controller/rf_phy_driver.c create mode 100644 src/lib/ble_host.lib create mode 100644 src/lib/ble_host/att_client.c create mode 100644 src/lib/ble_host/att_server.c create mode 100644 src/lib/ble_host/att_util.c create mode 100644 src/lib/ble_host/gap_centdevmgr.c create mode 100644 src/lib/ble_host/gap_centlinkmgr.c create mode 100644 src/lib/ble_host/gap_configmgr.c create mode 100644 src/lib/ble_host/gap_devmgr.c create mode 100644 src/lib/ble_host/gap_linkmgr.c create mode 100644 src/lib/ble_host/gap_peridevmgr.c create mode 100644 src/lib/ble_host/gap_perilinkmgr.c create mode 100644 src/lib/ble_host/gap_simpletask.c create mode 100644 src/lib/ble_host/gap_task.c create mode 100644 src/lib/ble_host/gatt_client.c create mode 100644 src/lib/ble_host/gatt_server.c create mode 100644 src/lib/ble_host/gatt_task.c create mode 100644 src/lib/ble_host/gatt_uuid.c create mode 100644 src/lib/ble_host/l2cap_if.c create mode 100644 src/lib/ble_host/l2cap_task.c create mode 100644 src/lib/ble_host/l2cap_util.c create mode 100644 src/lib/ble_host/linkdb.c create mode 100644 src/lib/ble_host/sm_intpairing.c create mode 100644 src/lib/ble_host/sm_mgr.c create mode 100644 src/lib/ble_host/sm_pairing.c create mode 100644 src/lib/ble_host/sm_rsppairing.c create mode 100644 src/lib/ble_host/sm_task.c create mode 100644 src/lib/ble_host/smp.c create mode 100644 src/lib/ble_host_multi5.lib create mode 100644 src/lib/phy_font.lib create mode 100644 src/lib/rf.lib create mode 100644 src/lib/rf/patch.c create mode 100644 src/lib/rf_mst.lib create mode 100644 src/lib/rflib.h create mode 100644 src/lib/sec/aes.c create mode 100644 src/lib/sec/aes.h create mode 100644 src/lib/sec/phy_sec_ext.c create mode 100644 src/lib/ui_font.h create mode 100644 src/misc/bb_rom_sym_m0.gcc create mode 100644 src/misc/bb_rom_sym_m0.txt create mode 100644 src/misc/generate_gccsymfile.py create mode 100644 src/misc/jump_function.h create mode 100644 src/misc/jump_table.c create mode 100644 src/misc/rom_sym_def.h diff --git a/README.md b/README.md index e79d194..5bd0ffa 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ python3 rdwr_phy6222.py -p COM11 -b 1000000 -r rc 0x11000000 0x80000 ff_thb2.bin ## ВоÑÑтановление оригинальной прошивки. -1. ВзÑть Ñохраненный файл r11000000-00080000.bin оригинальной прошивки. +1. ВзÑть Ñохраненный файл ff_thb2.bin оригинальной прошивки. 2. Соединить GND, TX, RX, RTS–RESET, VCC (+3.3B). 3. ЗапуÑтить: ``` diff --git a/src/TestTHB2/RTE/Device/ARMCM0/phy6202.ld b/src/TestTHB2/RTE/Device/ARMCM0/phy6202.ld new file mode 100644 index 0000000..974d505 --- /dev/null +++ b/src/TestTHB2/RTE/Device/ARMCM0/phy6202.ld @@ -0,0 +1,208 @@ +/* Linker script to configure memory regions. */ +MEMORY +{ + /* In mirror mode, flash content is copied to RAM and progrm execute in RAM */ + FLASH (rx) : ORIGIN = 0x1FFF4000, LENGTH = 64K /*Mirror mode : flash is copied to RAM for execution*/ + RAM (rwx) : ORIGIN = 0x20004000, LENGTH = 48K + + JUMP_TABLE (rwx) : ORIGIN = 0x1FFF0800, LENGTH = 1K + GLOBAL_CONFIG (rwx) : ORIGIN = 0x1FFF0C00, LENGTH = 1K + +} + + +/* Linker script to place sections and symbol values. Should be used together + * with other linker script that defines memory regions FLASH and RAM. + * It references following symbols, which must be defined in code: + * Reset_Handler : Entry of reset handler + * + * It defines following symbols, which code can use without definition: + * __exidx_start + * __exidx_end + * __copy_table_start__ + * __copy_table_end__ + * __zero_table_start__ + * __zero_table_end__ + * __etext + * __data_start__ + * __preinit_array_start + * __preinit_array_end + * __init_array_start + * __init_array_end + * __fini_array_start + * __fini_array_end + * __data_end__ + * __bss_start__ + * __bss_end__ + * __end__ + * end + * __HeapLimit + * __StackLimit + * __StackTop + * __stack + */ +ENTRY(Reset_Handler) + +SECTIONS +{ + /* Store jump table between ROM/lib and code at a fixed address */ + .jump_table_mem_area : + { + KEEP(*(.jump_table_mem_area)) + } > JUMP_TABLE + + /* Store global config at a fixed address */ + .global_config_area : + { + KEEP(*(.global_config_area)) + } > GLOBAL_CONFIG + + + .text : + { + KEEP(*(.vectors)) + *(.text*) + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.rodata*) + + KEEP(*(.eh_frame*)) + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* To copy multiple ROM to RAM sections, + * uncomment .copy.table section and, + * define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */ + /* + .copy.table : + { + . = ALIGN(4); + __copy_table_start__ = .; + LONG (__etext) + LONG (__data_start__) + LONG (__data_end__ - __data_start__) + LONG (__etext2) + LONG (__data2_start__) + LONG (__data2_end__ - __data2_start__) + __copy_table_end__ = .; + } > FLASH + */ + + /* To clear multiple BSS sections, + * uncomment .zero.table section and, + * define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */ + /* + .zero.table : + { + . = ALIGN(4); + __zero_table_start__ = .; + LONG (__bss_start__) + LONG (__bss_end__ - __bss_start__) + LONG (__bss2_start__) + LONG (__bss2_end__ - __bss2_start__) + __zero_table_end__ = .; + } > FLASH + */ + + /* Location counter can end up 2byte aligned with narrow Thumb code but + __etext is assumed by startup code to be the LMA of a section in RAM + which must be 4byte aligned */ + __etext = ALIGN (4); + + .data : AT (__etext) + { + __data_start__ = .; + *(vtable) + *(.data*) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + KEEP(*(.jcr*)) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + + } > RAM + + .bss : + { + . = ALIGN(4); + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + .heap (COPY): + { + __end__ = .; + PROVIDE(end = .); + *(.heap*) + __HeapLimit = .; + } > RAM + + /* .stack_dummy section doesn't contain any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + *(.stack*) + } > RAM + + /* Set stack top to end of RAM, and stack limit move down by + * size of stack_dummy section */ + __initial_sp = ORIGIN(RAM) + LENGTH(RAM); + __StackTop = ORIGIN(RAM) + LENGTH(RAM); + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") +} \ No newline at end of file diff --git a/src/TestTHB2/RTE/Device/ARMCM0/startup_ARMCM0.c b/src/TestTHB2/RTE/Device/ARMCM0/startup_ARMCM0.c new file mode 100644 index 0000000..0990b8b --- /dev/null +++ b/src/TestTHB2/RTE/Device/ARMCM0/startup_ARMCM0.c @@ -0,0 +1,309 @@ +/**************************************************************************/ /** + * @file startup_ARMCM0.c + * @brief CMSIS Core Device Startup File for + * ARMCM0 Device + * @version V1.1.0 + * @date 23. January 2019 + ******************************************************************************/ +/* + * Copyright (c) 2009-2019 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 + * + * 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. + */ + +/* +//-------- <<< Use Configuration Wizard in Context Menu >>> ------------------ +*/ + +#include "ARMCM0.h" + +/*---------------------------------------------------------------------------- + Linker generated Symbols + *----------------------------------------------------------------------------*/ +extern uint32_t __etext; +extern uint32_t __data_start__; +extern uint32_t __data_end__; +extern uint32_t __bss_start__; +extern uint32_t __bss_end__; +extern uint32_t __StackTop; + +#define __STARTUP_CLEAR_BSS + +/*---------------------------------------------------------------------------- + Exception / Interrupt Handler Function Prototype + *----------------------------------------------------------------------------*/ +typedef void (*pFunc)(void); +extern const uint32_t *const jump_table_base[256]; +extern uint32_t global_config[256]; + +/*---------------------------------------------------------------------------- + External References + *----------------------------------------------------------------------------*/ +extern void _start(void) __attribute__((noreturn)); /* PreeMain (C library entry point) */ +// extern const uint32_t *const jump_table_base[256]; +// extern uint32_t global_config[256]; + +/*---------------------------------------------------------------------------- + Internal References + *----------------------------------------------------------------------------*/ +void Default_Handler(void) __attribute__((noreturn)); +void Reset_Handler(void) __attribute__((noreturn)); + +/*---------------------------------------------------------------------------- + User Initial Stack & Heap + *----------------------------------------------------------------------------*/ +// Stack Configuration +// Stack Size (in Bytes) <0x0-0xFFFFFFFF:8> +// +#define __STACK_SIZE 0x00000400 +static uint8_t stack[__STACK_SIZE] __attribute__((aligned(8), used, section(".stack"))); + +// Heap Configuration +// Heap Size (in Bytes) <0x0-0xFFFFFFFF:8> +// +#define __HEAP_SIZE 0x00000C00 +#if __HEAP_SIZE > 0 +static uint8_t heap[__HEAP_SIZE] __attribute__((aligned(8), used, section(".heap"))); +#endif + +/*---------------------------------------------------------------------------- + Exception / Interrupt Handler + *----------------------------------------------------------------------------*/ +/* Exceptions */ +void NMI_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void HardFault_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void SVC_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void PendSV_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void SysTick_Handler(void) __attribute__((weak, alias("Default_Handler"))); + +void WDT_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void RTC_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void TIM0_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void TIM2_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void MCIA_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void MCIB_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void UART0_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void UART1_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void UART2_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void UART3_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void UART4_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void AACI_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void CLCD_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void ENET_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void USBDC_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void USBHC_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void CHLCD_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void FLEXRAY_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void CAN_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void LIN_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void I2C_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void CPU_CLCD_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); +void SPI_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); + +/*---------------------------------------------------------------------------- + Exception / Interrupt Vector table + *----------------------------------------------------------------------------*/ +extern const pFunc __Vectors[48]; +const pFunc __Vectors[48] __attribute__((used, section(".vectors"))) = { + (pFunc)(&__StackTop), /* Initial Stack Pointer */ + Reset_Handler, /* Reset Handler */ + NMI_Handler, /* -14 NMI Handler */ + HardFault_Handler, /* -13 Hard Fault Handler */ + 0, /* Reserved */ + 0, /* Reserved */ + 0, /* Reserved */ + 0, /* Reserved */ + 0, /* Reserved */ + 0, /* Reserved */ + 0, /* Reserved */ + SVC_Handler, /* -5 SVCall Handler */ + 0, /* Reserved */ + 0, /* Reserved */ + PendSV_Handler, /* -2 PendSV Handler */ + SysTick_Handler, /* -1 SysTick Handler */ + + /* Interrupts */ + WDT_IRQHandler, /* 0 Interrupt 0 */ + RTC_IRQHandler, /* 1 Interrupt 1 */ + TIM0_IRQHandler, /* 2 Interrupt 2 */ + TIM2_IRQHandler, /* 3 Interrupt 3 */ + MCIA_IRQHandler, /* 4 Interrupt 4 */ + MCIB_IRQHandler, /* 5 Interrupt 5 */ + UART0_IRQHandler, /* 6 Interrupt 6 */ + UART1_IRQHandler, /* 7 Interrupt 7 */ + UART2_IRQHandler, /* 8 Interrupt 8 */ + UART3_IRQHandler, /* 9 Interrupt 9 */ + UART4_IRQHandler, /* 10 Interrupt 10 */ + AACI_IRQHandler, /* 10 Interrupt 10 */ + CLCD_IRQHandler, + ENET_IRQHandler, + USBDC_IRQHandler, + USBHC_IRQHandler, + CHLCD_IRQHandler, + FLEXRAY_IRQHandler, + CAN_IRQHandler, + LIN_IRQHandler, + I2C_IRQHandler, + CPU_CLCD_IRQHandler, + SPI_IRQHandler, +}; + +/*---------------------------------------------------------------------------- + Reset Handler called on controller reset + *----------------------------------------------------------------------------*/ +void Reset_Handler(void) +{ + uint32_t *pSrc, *pDest; + uint32_t *pTable __attribute__((unused)); + + SystemInit(); /* CMSIS System Initialization */ + +/* Firstly it copies data from read only memory to RAM. + * There are two schemes to copy. One can copy more than one sections. + * Another can copy only one section. The former scheme needs more + * instructions and read-only data to implement than the latter. + * Macro __STARTUP_COPY_MULTIPLE is used to choose between two schemes. + */ + +#ifdef __STARTUP_COPY_MULTIPLE + /* Multiple sections scheme. + * + * Between symbol address __copy_table_start__ and __copy_table_end__, + * there are array of triplets, each of which specify: + * offset 0: LMA of start of a section to copy from + * offset 4: VMA of start of a section to copy to + * offset 8: size of the section to copy. Must be multiply of 4 + * + * All addresses must be aligned to 4 bytes boundary. + */ + pTable = &__copy_table_start__; + + for (; pTable < &__copy_table_end__; pTable = pTable + 3) + { + pSrc = (uint32_t *)*(pTable + 0); + pDest = (uint32_t *)*(pTable + 1); + for (; pDest < (uint32_t *)(*(pTable + 1) + *(pTable + 2));) + { + *pDest++ = *pSrc++; + } + } +#else + /* Single section scheme. + * + * The ranges of copy from/to are specified by following symbols + * __etext: LMA of start of the section to copy from. Usually end of text + * __data_start__: VMA of start of the section to copy to + * __data_end__: VMA of end of the section to copy to + * + * All addresses must be aligned to 4 bytes boundary. + */ + pSrc = &__etext; + pDest = &__data_start__; + + for (; pDest < &__data_end__;) + { + *pDest++ = *pSrc++; + } +#endif /*__STARTUP_COPY_MULTIPLE */ + +/* This part of work usually is done in C library startup code. + * Otherwise, define this macro to enable it in this startup. + * + * There are two schemes too. + * One can clear multiple BSS sections. Another can only clear one section. + * The former is more size expensive than the latter. + * + * Define macro __STARTUP_CLEAR_BSS_MULTIPLE to choose the former. + * Otherwise define macro __STARTUP_CLEAR_BSS to choose the later. + */ +#ifdef __STARTUP_CLEAR_BSS_MULTIPLE + /* Multiple sections scheme. + * + * Between symbol address __copy_table_start__ and __copy_table_end__, + * there are array of tuples specifying: + * offset 0: Start of a BSS section + * offset 4: Size of this BSS section. Must be multiply of 4 + */ + pTable = &__zero_table_start__; + + for (; pTable < &__zero_table_end__; pTable = pTable + 2) + { + pDest = (uint32_t *)*(pTable + 0); + for (; pDest < (uint32_t *)(*(pTable + 0) + *(pTable + 1));) + { + *pDest++ = 0; + } + } +#elif defined(__STARTUP_CLEAR_BSS) + /* Single BSS section scheme. + * + * The BSS section is specified by following symbols + * __bss_start__: start of the BSS section. + * __bss_end__: end of the BSS section. + * + * Both addresses must be aligned to 4 bytes boundary. + */ + pDest = &__bss_start__; + + for (; pDest < &__bss_end__;) + { + *pDest++ = 0UL; + } +#endif /* __STARTUP_CLEAR_BSS_MULTIPLE || __STARTUP_CLEAR_BSS */ + + /* Tested OK */ + // while (1) + // { + // hal_gpio_toggle(GPIO_P14); + // } + + // Avoid optimizating out the jump_table and global_config + // The following lines crash + // volatile uint32_t *t1 = jump_table_base[0]; + // volatile uint32_t t2 = global_config[0]; + + _start(); /* Enter PreeMain (C library entry point) */ +} + +/*---------------------------------------------------------------------------- + Default Handler for Exceptions / Interrupts + *----------------------------------------------------------------------------*/ +void Default_Handler(void) +{ +// BM_SET(REG_FMUX_EN_FUC(GPIO_P14), Bit_DISABLE); //set bit +// BM_SET(reg_gpio_ioe_porta, OEN); +// while (1) +// { +// //Toggle GPIO 2/3 PWM +// BM_SET(reg_gpio_swporta_dr, GPIO_P14); +// BM_SET(reg_gpio_swporta_dr, GPIO_P14); +// BM_CLR(reg_gpio_swporta_dr, GPIO_P14); +// } +} + +/*---------------------------------------------------------------------------- + _exit implementation for libc + *----------------------------------------------------------------------------*/ +void _exit(int status) +{ + (void)status; + while (1) + ; +} + +// ROM lib expect __initial_sp symbol to be defined +// Either add the following line +// const pFunc __initial_sp = (pFunc)(&__StackTop); +// or provide __initial_sp in the linker diff --git a/src/TestTHB2/RTE/Device/ARMCM0/startup_ARMCM0.s b/src/TestTHB2/RTE/Device/ARMCM0/startup_ARMCM0.s new file mode 100644 index 0000000..8a40716 --- /dev/null +++ b/src/TestTHB2/RTE/Device/ARMCM0/startup_ARMCM0.s @@ -0,0 +1,121 @@ +;/**************************************************************************//** +; * @file startup_ARMCM0.s +; * @brief CMSIS Core Device Startup File for +; * ARMCM0 Device Series +; * @version V5.00 +; * @date 02. March 2016 +; ******************************************************************************/ +;/* +; * Copyright (c) 2009-2016 ARM Limited. All rights reserved. +; * +; * SPDX-License-Identifier: Apache-2.0 +; * +; * 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. +; */ + +;/* +;//-------- <<< Use Configuration Wizard in Context Menu >>> ------------------ +;*/ + + +; Stack Configuration +; Stack Size (in Bytes) <0x0-0xFFFFFFFF:8> +; + +Stack_Size EQU 0x00000400 + + AREA STACK, NOINIT, READWRITE, ALIGN=3 +Stack_Mem SPACE Stack_Size +__initial_sp + + +; Heap Configuration +; Heap Size (in Bytes) <0x0-0xFFFFFFFF:8> +; + +Heap_Size EQU 0x00000200 + + AREA HEAP, NOINIT, READWRITE, ALIGN=3 +__heap_base +Heap_Mem SPACE Heap_Size +__heap_limit + + + PRESERVE8 + THUMB + + +; Vector Table Mapped to Address 0 at Reset + + AREA RESET, DATA, READONLY + EXPORT __Vectors + EXPORT __Vectors_End + EXPORT __Vectors_Size + +__Vectors DCD __initial_sp ; Top of Stack + DCD Reset_Handler ; Reset Handler +__Vectors_End + +__Vectors_Size EQU __Vectors_End - __Vectors + + AREA |.text|, CODE, READONLY + + +; Reset Handler + +Reset_Handler PROC + EXPORT Reset_Handler [WEAK] + IMPORT SystemInit + IMPORT __main + LDR R0, =SystemInit + BLX R0 + LDR R0, =__main + BX R0 + ENDP + + +Default_Handler PROC + B . + ENDP + + + ALIGN + + +; User Initial Stack & Heap + + IF :DEF:__MICROLIB + + EXPORT __initial_sp + EXPORT __heap_base + EXPORT __heap_limit + + ELSE + + IMPORT __use_two_region_memory + EXPORT __user_initial_stackheap + +__user_initial_stackheap PROC + LDR R0, = Heap_Mem + LDR R1, =(Stack_Mem + Stack_Size) + LDR R2, = (Heap_Mem + Heap_Size) + LDR R3, = Stack_Mem + BX LR + ENDP + + ALIGN + + ENDIF + + + END diff --git a/src/TestTHB2/RTE/Device/ARMCM0/system_ARMCM0.c b/src/TestTHB2/RTE/Device/ARMCM0/system_ARMCM0.c new file mode 100644 index 0000000..66fd60f --- /dev/null +++ b/src/TestTHB2/RTE/Device/ARMCM0/system_ARMCM0.c @@ -0,0 +1,60 @@ +/**************************************************************************//** + @file system_ARMCM0.c + @brief CMSIS Device System Source File for + ARMCM0 Device Series + @version V2.00 + @date 18. August 2015 + ******************************************************************************/ +/* Copyright (c) 2011 - 2015 ARM LIMITED + + 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 ARM 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 COPYRIGHT HOLDERS AND 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 "ARMCM0.h" + +/* ---------------------------------------------------------------------------- + Define clocks + ----------------------------------------------------------------------------*/ +#define XTAL ( 5000000U) /* Oscillator frequency */ + +#define SYSTEM_CLOCK (5 * XTAL) + + +/* ---------------------------------------------------------------------------- + System Core Clock Variable + ----------------------------------------------------------------------------*/ +uint32_t SystemCoreClock = SYSTEM_CLOCK; /* System Core Clock Frequency */ + + +void SystemCoreClockUpdate (void) +{ + SystemCoreClock = SYSTEM_CLOCK; +} + +void SystemInit (void) +{ + SystemCoreClock = SYSTEM_CLOCK; +} diff --git a/src/TestTHB2/RTE/_Target_1/RTE_Components.h b/src/TestTHB2/RTE/_Target_1/RTE_Components.h new file mode 100644 index 0000000..ad87cc1 --- /dev/null +++ b/src/TestTHB2/RTE/_Target_1/RTE_Components.h @@ -0,0 +1,21 @@ + +/* + * Auto generated Run-Time-Environment Configuration File + * *** Do not modify ! *** + * + * Project: 'TestTHB2' + * Target: 'Target 1' + */ + +#ifndef RTE_COMPONENTS_H +#define RTE_COMPONENTS_H + + +/* + * Define the Device Header File: + */ +#define CMSIS_device_header "ARMCM0.h" + + + +#endif /* RTE_COMPONENTS_H */ diff --git a/src/TestTHB2/TestTHB2.uvprojx b/src/TestTHB2/TestTHB2.uvprojx new file mode 100644 index 0000000..70fc116 --- /dev/null +++ b/src/TestTHB2/TestTHB2.uvprojx @@ -0,0 +1,1043 @@ + + + + 2.1 + +
### uVision Project, (C) Keil Software
+ + + + Target 1 + 0x4 + ARM-ADS + 5060960::V5.06 update 7 (build 960)::.\ARMCC + 0 + + + ARMCM0 + ARM + ARM.CMSIS.5.8.0 + http://www.keil.com/pack/ + IRAM(0x20000000,0x20000) IROM(0x00000000,0x40000) CPUTYPE("Cortex-M0") CLOCK(12000000) ESEL ELITTLE + + + UL2CM3(-S0 -C0 -P0 -FD20000000 -FC1000 -FN1 -FF0NEW_DEVICE -FS00 -FL040000 -FP0($$Device:ARMCM0$Device\ARM\Flash\NEW_DEVICE.FLM)) + 0 + $$Device:ARMCM0$Device\ARM\ARMCM0\Include\ARMCM0.h + + + + + + + + + + $$Device:ARMCM0$Device\ARM\SVD\ARMCM0.svd + 0 + 0 + + + + + + + 0 + 0 + 0 + 0 + 1 + + .\Objects\ + TestTHB2 + 1 + 0 + 1 + 1 + 1 + .\Listings\ + 1 + 0 + 0 + + 0 + 0 + + + 0 + 0 + 0 + 0 + + + 0 + 0 + + + 0 + 0 + 0 + 0 + + + 1 + 1 + fromelf.exe .\Objects\TestTHB2.axf --i32combined --output .\bin\TestTHB2.hex + fromelf -c -a -d -e -v -o TestTHB2.asm ./Objects/TestTHB2.axf + 0 + 0 + 0 + 0 + + 0 + + + + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 3 + + + 1 + + + SARMCM3.DLL + + DARMCM1.DLL + -pCM0 + SARMCM3.DLL + + TARMCM1.DLL + -pCM0 + + + + 1 + 0 + 0 + 0 + 16 + + + + + 1 + 1 + 0 + 1 + 1 + 4096 + + 1 + BIN\UL2CM3.DLL + "" () + .\ram.ini + + + + 0 + + + + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 1 + 1 + 0 + 1 + 1 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 0 + "Cortex-M0" + + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 8 + 1 + 1 + 0 + 0 + 3 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x20000000 + 0x20000 + + + 1 + 0x0 + 0x40000 + + + 0 + 0x0 + 0x0 + + + 1 + 0x0 + 0x0 + + + 1 + 0x0 + 0x0 + + + 1 + 0x0 + 0x0 + + + 1 + 0x20000000 + 0x400 + + + 1 + 0x1fff8000 + 0x1f40 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x1fff6000 + 0x2000 + + + 0 + 0x0 + 0x0 + + + + + + 1 + 4 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 1 + 0 + 0 + 1 + 1 + 1 + 1 + 0 + 0 + 0 + + -DADV_NCONN_CFG=0x01 -DADV_CONN_CFG=0x02 -DSCAN_CFG=0x04 -DINIT_CFG=0x08 -DBROADCASTER_CFG=0x01 -DOBSERVER_CFG=0x02 -DPERIPHERAL_CFG=0x04 -DCENTRAL_CFG=0x08 + DEBUG_INFO=2 CFG_CP OSAL_CBTIMER_NUM_TASKS=1 MTU_SIZE=247 HOST_CONFIG=4 HCI_TL_NONE=1 ENABLE_LOG_ROM_=0 _BUILD_FOR_DTM_=0 DBG_ROM_MAIN=0 APP_CFG=0 OSALMEM_METRICS=0 PHY_MCU_TYPE=MCU_BUMBEE_M0 CFG_SLEEP_MODE=PWR_MODE_SLEEP DEF_GAPBOND_MGR_ENABLE=0 USE_FS=0 MAX_NUM_LL_CONN=1 + + ..\components\inc;..\components\ble\controller;..\components\osal\include;..\components\common;..\components\ble\include;..\components\ble\hci;..\components\ble\host;..\components\Profiles\ota_app;..\components\Profiles\DevInfo;..\components\Profiles\SimpleProfile;..\components\Profiles\Roles;.\source;..\components\libraries\crc16;..\components\driver\watchdog;..\components\driver\clock;..\components\arch\cm0;..\components\driver\pwrmgr;..\components\driver\uart;..\components\driver\gpio;..\components\driver\timer;..\misc;..\components\driver\log;..\components\libraries\cliface;..\components\driver\key;..\components\driver\pwm;..\components\driver\flash;..\components\libraries\fs;..\components\driver\led_light;..\components\driver\i2c;..\components\Profiles\Batt;..\components\driver\adc + + + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 4 + + + + + + + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + .\scatter_load.sct + + + ..\misc\bb_rom_sym_m0.txt --keep=jump_table_base --keep=global_config + + + + + + + + arch + + + main.c + 1 + .\main.c + + + + + driver + + + uart.c + 1 + ..\components\driver\uart\uart.c + + + clock.c + 1 + ..\components\driver\clock\clock.c + + + gpio.c + 1 + ..\components\driver\gpio\gpio.c + + + timer.c + 1 + ..\components\driver\timer\timer.c + + + watchdog.c + 1 + ..\components\driver\watchdog\watchdog.c + + + pwrmgr.c + 1 + ..\components\driver\pwrmgr\pwrmgr.c + + + my_printf.c + 1 + ..\components\driver\log\my_printf.c + + + key.c + 1 + ..\components\driver\key\key.c + + + 2 + 0 + 0 + 0 + 0 + 0 + 2 + 2 + 2 + 2 + 11 + + + 1 + + + + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 0 + 0 + 2 + 2 + 2 + 2 + 2 + + + + + + + + + + + + pwm.c + 1 + ..\components\driver\pwm\pwm.c + + + 2 + 0 + 0 + 0 + 0 + 0 + 2 + 2 + 2 + 2 + 11 + + + 1 + + + + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 0 + 0 + 2 + 2 + 2 + 2 + 2 + + + + + + + + + + + + osal_snv.c + 1 + ..\components\osal\snv\osal_snv.c + + + flash.c + 1 + ..\components\driver\flash\flash.c + + + led_light.c + 1 + ..\components\driver\led_light\led_light.c + + + 2 + 0 + 0 + 0 + 0 + 0 + 2 + 2 + 2 + 2 + 11 + + + 1 + + + + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 0 + 0 + 2 + 2 + 2 + 2 + 2 + + + + + + + + + + + + fs.c + 1 + ..\components\libraries\fs\fs.c + + + fs.h + 5 + ..\components\libraries\fs\fs.h + + + i2c.c + 1 + ..\components\driver\i2c\i2c.c + + + 2 + 0 + 0 + 0 + 0 + 0 + 2 + 2 + 2 + 2 + 11 + + + 1 + + + + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 0 + 0 + 2 + 2 + 2 + 2 + 2 + + + + + + + + + + + + + + profile + + + gap.c + 1 + ..\components\profiles\Roles\gap.c + + + gapbondmgr.c + 1 + ..\components\profiles\Roles\gapbondmgr.c + + + 2 + 0 + 0 + 0 + 0 + 1 + 2 + 2 + 2 + 2 + 11 + + + 1 + + + + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 0 + 0 + 2 + 2 + 2 + 2 + 2 + + + + + + + + + + + + gapgattserver.c + 1 + ..\components\profiles\Roles\gapgattserver.c + + + peripheral.c + 1 + ..\components\profiles\Roles\peripheral.c + + + gattservapp.c + 1 + ..\components\profiles\GATT\gattservapp.c + + + ota_app_service.c + 1 + ..\components\profiles\ota_app\ota_app_service.c + + + sbpProfile_ota.c + 1 + .\source\sbpProfile_ota.c + + + 2 + 0 + 0 + 0 + 0 + 0 + 2 + 2 + 2 + 2 + 11 + + + 1 + + + + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 0 + 0 + 2 + 2 + 2 + 2 + 2 + + + + + + + + + + + + battservice.c + 1 + ..\components\profiles\Batt\battservice.c + + + devinfoservice.c + 1 + ..\components\profiles\DevInfo\devinfoservice.c + + + + + jump + + + jump_table.c + 1 + ..\misc\jump_table.c + + + + + lib + + + rf.lib + 4 + ..\lib\rf.lib + + + ble_host.lib + 4 + ..\lib\ble_host.lib + + + + + TestTHB2 + + + OSAL_SimpleBLEPeripheral.c + 1 + .\source\OSAL_SimpleBLEPeripheral.c + + + SimpleBLEPeripheral_Main.c + 1 + .\source\SimpleBLEPeripheral_Main.c + + + thb2_main.c + 1 + .\source\thb2_main.c + + + bthome_beacon.c + 1 + .\source\bthome_beacon.c + + + sensors.c + 1 + .\source\sensors.c + + + battery.c + 1 + .\source\battery.c + + + thservice.c + 1 + .\source\thservice.c + + + + + ::CMSIS + + + ::Device + + + 0 + 0 + 0 + 0 + 0 + 1 + 2 + 2 + 2 + 2 + 11 + + + 1 + + + + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 0 + 0 + 2 + 2 + 2 + 2 + 2 + + + + + + + + + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + RTE\Device\ARMCM0\startup_ARMCM0.s + + + + + + + + RTE\Device\ARMCM0\system_ARMCM0.c + + + + + + + + RTE\Device\ARMCM4\startup_ARMCM4.s + + + + + + RTE\Device\ARMCM4\system_ARMCM4.c + + + + + + RTE\Device\ARMCM4_FP\startup_ARMCM4.s + + + + + + RTE\Device\ARMCM4_FP\system_ARMCM4.c + + + + + + + + + + + <Project Info> + 0 + 1 + + + + +
diff --git a/src/TestTHB2/main.c b/src/TestTHB2/main.c new file mode 100644 index 0000000..4329af3 --- /dev/null +++ b/src/TestTHB2/main.c @@ -0,0 +1,264 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +#include "bus_dev.h" +#include "gpio.h" +#include "clock.h" +#include "timer.h" +#include "jump_function.h" +#include "pwrmgr.h" +#include "mcu.h" +#include "gpio.h" +#include "log.h" +#include "rf_phy_driver.h" +#include "flash.h" +#include "version.h" +#include "watchdog.h" +#include "fs.h" +#include "adc.h" +#define DEFAULT_UART_BAUD 115200 + + +/********************************************************************* + LOCAL FUNCTION PROTOTYPES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +extern void init_config(void); +extern int app_main(void); +extern void hal_rom_boot_init(void); +/********************************************************************* + CONNECTION CONTEXT RELATE DEFINITION +*/ + +#define BLE_MAX_ALLOW_CONNECTION 1 +#define BLE_MAX_ALLOW_PKT_PER_EVENT_TX 3 +#define BLE_MAX_ALLOW_PKT_PER_EVENT_RX 3 +#define BLE_PKT_VERSION BLE_PKT_VERSION_5_1 // BLE_PKT_VERSION_4_0 + + +/* BLE_MAX_ALLOW_PER_CONNECTION + { + ... + struct ll_pkt_desc *tx_conn_desc[MAX_LL_BUF_LEN]; // new Tx data buffer + struct ll_pkt_desc *rx_conn_desc[MAX_LL_BUF_LEN]; + + struct ll_pkt_desc *tx_not_ack_pkt; + struct ll_pkt_desc *tx_ntrm_pkts[MAX_LL_BUF_LEN]; + ... + } + tx_conn_desc[] + tx_ntrm_pkts[] --> BLE_MAX_ALLOW_PKT_PER_EVENT_TX * BLE_PKT_BUF_SIZE*2 + rx_conn_desc[] --> BLE_MAX_ALLOW_PKT_PER_EVENT_RX * BLE_PKT_BUF_SIZE + tx_not_ack_pkt --> 1*BLE_PKT_BUF_SIZE + +*/ + +#define BLE_PKT_BUF_SIZE (((BLE_PKT_VERSION == BLE_PKT_VERSION_5_1) ? 1 : 0) * BLE_PKT51_LEN \ + + ((BLE_PKT_VERSION == BLE_PKT_VERSION_4_0) ? 1 : 0) * BLE_PKT40_LEN \ + + (sizeof(struct ll_pkt_desc) - 2)) + +#define BLE_MAX_ALLOW_PER_CONNECTION ( (BLE_MAX_ALLOW_PKT_PER_EVENT_TX * BLE_PKT_BUF_SIZE*2) \ + +(BLE_MAX_ALLOW_PKT_PER_EVENT_RX * BLE_PKT_BUF_SIZE) \ + + BLE_PKT_BUF_SIZE ) + +#define BLE_CONN_BUF_SIZE (BLE_MAX_ALLOW_CONNECTION * BLE_MAX_ALLOW_PER_CONNECTION) + + +ALIGN4_U8 g_pConnectionBuffer[BLE_CONN_BUF_SIZE]; +llConnState_t pConnContext[BLE_MAX_ALLOW_CONNECTION]; + +/********************************************************************* + CTE IQ SAMPLE BUF config +*/ +//#define BLE_SUPPORT_CTE_IQ_SAMPLE TRUE +#ifdef BLE_SUPPORT_CTE_IQ_SAMPLE + uint16 g_llCteSampleI[LL_CTE_MAX_SUPP_LEN * LL_CTE_SUPP_LEN_UNIT]; + uint16 g_llCteSampleQ[LL_CTE_MAX_SUPP_LEN * LL_CTE_SUPP_LEN_UNIT]; +#endif + + +/********************************************************************* + OSAL LARGE HEAP CONFIG +*/ +#define LARGE_HEAP_SIZE (4*1024) +ALIGN4_U8 g_largeHeap[LARGE_HEAP_SIZE]; + +/********************************************************************* + GLOBAL VARIABLES +*/ +volatile uint8 g_clk32K_config; +volatile sysclk_t g_spif_clk_config; + + +/********************************************************************* + EXTERNAL VARIABLES +*/ +extern uint32_t __initial_sp; + + +static void hal_low_power_io_init(void) +{ + //========= disable all gpio pullup/down to preserve juice + const ioinit_cfg_t ioInit[]= + { +#if(SDK_VER_CHIP == __DEF_CHIP_QFN32__) + {GPIO_P00, GPIO_PULL_DOWN }, + {GPIO_P01, GPIO_PULL_DOWN }, + {GPIO_P02, GPIO_PULL_DOWN }, + {GPIO_P03, GPIO_PULL_DOWN }, + {GPIO_P07, GPIO_PULL_UP }, // KEY + {GPIO_P09, GPIO_PULL_UP }, // TX + {GPIO_P10, GPIO_PULL_UP }, // RX + {GPIO_P11, GPIO_FLOATING }, // ADC_VBAT + {GPIO_P14, GPIO_PULL_DOWN }, + {GPIO_P15, GPIO_PULL_DOWN }, + {GPIO_P16, GPIO_PULL_DOWN }, + {GPIO_P17, GPIO_PULL_DOWN }, + {GPIO_P18, GPIO_FLOATING }, // I2C_SDA + {GPIO_P20, GPIO_FLOATING }, // I2C_SCL + {GPIO_P23, GPIO_PULL_DOWN }, + {GPIO_P24, GPIO_PULL_DOWN }, + {GPIO_P25, GPIO_PULL_DOWN }, + {GPIO_P26, GPIO_FLOATING }, // LED + {GPIO_P31, GPIO_PULL_DOWN }, + {GPIO_P32, GPIO_PULL_DOWN }, + {GPIO_P33, GPIO_PULL_DOWN }, + {GPIO_P34, GPIO_PULL_DOWN } +#else + {GPIO_P02, GPIO_FLOATING }, + {GPIO_P03, GPIO_FLOATING }, + {GPIO_P07, GPIO_FLOATING }, + {GPIO_P09, GPIO_FLOATING }, + {GPIO_P10, GPIO_FLOATING }, + {GPIO_P11, GPIO_FLOATING }, + {GPIO_P14, GPIO_FLOATING }, + {GPIO_P15, GPIO_FLOATING }, + {GPIO_P18, GPIO_FLOATING }, + {GPIO_P20, GPIO_FLOATING }, + {GPIO_P34, GPIO_FLOATING }, + +#endif + }; + + for(uint8_t i=0; iintr_mask = 0; // MASK coresponding channel + for (i = 0; i < (MAX_ADC_SAMPLE_SIZE-2); i++) + { + adc_sum += (uint16_t)(read_reg(ADC_CH_BASE + ((ADC_CH1N_P11+1) * 0x80) + ((i+2) * 4)) & 0xfff); + } + AP_ADCC->intr_clear = 0x1FF; + // stop_adc_batt + AP_AON->PMCTL2_1 = 0x00; + NVIC_DisableIRQ((IRQn_Type)ADCC_IRQn); +// JUMP_FUNCTION(ADCC_IRQ_HANDLER) = 0; +// AP_ADCC->intr_clear = 0x1FF; + AP_PCRM->ANA_CTL &= ~BIT(3); + if(g_system_clk != SYS_CLK_DBL_32M) + { + AP_PCRM->CLKHF_CTL1 &= ~BIT(13); + } + hal_gpio_cfg_analog_io(ADC_PIN,Bit_DISABLE); + hal_gpio_pin_init(ADC_PIN,GPIO_INPUT); // ie=0, oen=1 set to imput + hal_gpio_pull_set(ADC_PIN,GPIO_FLOATING); + AP_PCRM->ANA_CTL &= ~BIT(0); // Power down analog LDO + hal_clk_reset(MOD_ADCC); + hal_clk_gate_disable(MOD_ADCC); + hal_pwrmgr_unlock(MOD_ADCC); + + // 3280/3764 = 0.8714 + // 30*3764 = 112920 + // 112920 * 1904 = 214999680 + // 214999680 >> 16 = 3280 + LOG("ADC_measure = %d\n", adc_sum); + measured_data.battery_mv = (adc_sum * 1904)>> 16; + if(measured_data.battery_mv < 3000) + if (measured_data.battery_mv > 2000) + measured_data.battery = (measured_data.battery_mv - 2000)/10; + else + measured_data.battery = 0; + else + measured_data.battery = 100; + extern uint8 gapRole_AdvEnabled; + if(!gapRole_AdvEnabled) + osal_set_event(simpleBLEPeripheral_TaskID, BATT_VALUE_EVT); +} + +//static void adc_batt_wakeup(void) +//{ +// NVIC_SetPriority((IRQn_Type)ADCC_IRQn, IRQ_PRIO_HAL); +//} + +void hal_adc_init(void) +{ + hal_pwrmgr_register(MOD_ADCC, NULL, NULL); +} + +void init_adc_batt(void) { + AP_AON->PMCTL2_1 = 0x00; + AP_PCRM->ANA_CTL &= ~BIT(0); + AP_PCRM->ANA_CTL &= ~BIT(3); + hal_clk_gate_disable(MOD_ADCC); + hal_clk_reset(MOD_ADCC); + hal_clk_gate_enable(MOD_ADCC); + //CLK_1P28M_ENABLE; + AP_PCRM->CLKSEL |= BIT(6); + //ENABLE_XTAL_OUTPUT; //enable xtal 16M output,generate the 32M dll clock + AP_PCRM->CLKHF_CTL0 |= BIT(18); + //ENABLE_DLL; //enable DLL + AP_PCRM->CLKHF_CTL1 |= BIT(7); + //ADC_DBLE_CLOCK_DISABLE; //disable double 32M clock,we are now use 32M clock,should enable bit<13>, diable bit<21> + AP_PCRM->CLKHF_CTL1 &= ~BIT(21);//check + //subWriteReg(0x4000F044,21,20,3); + //ADC_CLOCK_ENABLE; //adc clock enbale,always use clk_32M + AP_PCRM->CLKHF_CTL1 |= BIT(13); + //subWriteReg(0x4000f07c,4,4,1); //set adc mode,1:mannual,0:auto mode +// AP_PCRM->ADC_CTL4 |= BIT(4); // mannual mode + AP_PCRM->ADC_CTL4 &= ~BIT(4); //enable auto mode + AP_PCRM->ADC_CTL4 |= BIT(0); + AP_AON->PMCTL2_1 = BIT((ADC_CHL - MIN_ADC_CH)+8); + AP_PCRM->ADC_CTL0 &= ~BIT(20); + AP_PCRM->ADC_CTL0 &= ~BIT(4); + AP_PCRM->ADC_CTL1 &= ~BIT(20); + AP_PCRM->ADC_CTL1 &= ~BIT(4); + AP_PCRM->ADC_CTL2 &= ~BIT(20); + AP_PCRM->ADC_CTL2 &= ~BIT(4); + AP_PCRM->ADC_CTL3 &= ~BIT(20); + AP_PCRM->ADC_CTL3 &= ~BIT(4); + AP_PCRM->ANA_CTL &= ~BIT(23);//disable micbias + hal_gpio_pull_set(ADC_PIN,GPIO_FLOATING); + hal_gpio_ds_control(ADC_PIN, Bit_ENABLE); + hal_gpio_cfg_analog_io(ADC_PIN, Bit_ENABLE); +} + +void batt_start_measure(void) +{ + LOG("batt_meassured\n"); + //Event handler is called immediately after conversion is finished. + // init_adc_batt + AP_AON->PMCTL2_1 = 0x00; + AP_PCRM->ANA_CTL &= ~BIT(0); + AP_PCRM->ANA_CTL &= ~BIT(3); + hal_clk_gate_disable(MOD_ADCC); + hal_clk_reset(MOD_ADCC); + hal_clk_gate_enable(MOD_ADCC); + //CLK_1P28M_ENABLE; + AP_PCRM->CLKSEL |= BIT(6); + //ENABLE_XTAL_OUTPUT; //enable xtal 16M output,generate the 32M dll clock + AP_PCRM->CLKHF_CTL0 |= BIT(18); + //ENABLE_DLL; //enable DLL + AP_PCRM->CLKHF_CTL1 |= BIT(7); + //ADC_DBLE_CLOCK_DISABLE; //disable double 32M clock,we are now use 32M clock,should enable bit<13>, diable bit<21> + AP_PCRM->CLKHF_CTL1 &= ~BIT(21);//check + //subWriteReg(0x4000F044,21,20,3); + //ADC_CLOCK_ENABLE; //adc clock enbale,always use clk_32M + AP_PCRM->CLKHF_CTL1 |= BIT(13); + //subWriteReg(0x4000f07c,4,4,1); //set adc mode,1:mannual,0:auto mode +// AP_PCRM->ADC_CTL4 |= BIT(4); // mannual mode + AP_PCRM->ADC_CTL4 &= ~BIT(4); //enable auto mode + AP_PCRM->ADC_CTL4 |= BIT(0); + AP_AON->PMCTL2_1 = BIT((ADC_CHL - MIN_ADC_CH)+8); + AP_PCRM->ADC_CTL0 &= ~BIT(20); + AP_PCRM->ADC_CTL0 &= ~BIT(4); + AP_PCRM->ADC_CTL1 &= ~BIT(20); + AP_PCRM->ADC_CTL1 &= ~BIT(4); + AP_PCRM->ADC_CTL2 &= ~BIT(20); + AP_PCRM->ADC_CTL2 &= ~BIT(4); + AP_PCRM->ADC_CTL3 &= ~BIT(20); + AP_PCRM->ADC_CTL3 &= ~BIT(4); + AP_PCRM->ANA_CTL &= ~BIT(23);//disable micbias + hal_gpio_pull_set(ADC_PIN,GPIO_FLOATING); + hal_gpio_ds_control(ADC_PIN, Bit_ENABLE); + hal_gpio_cfg_analog_io(ADC_PIN, Bit_ENABLE); + // start_adc_bat + hal_pwrmgr_lock(MOD_ADCC); + JUMP_FUNCTION(ADCC_IRQ_HANDLER) = (uint32_t)&hal_ADC_IRQHandler; + + AP_PCRM->ADC_CTL1 |= BIT(20); + AP_PCRM->ANA_CTL |= BIT(3);//ENABLE_ADC; + AP_PCRM->ANA_CTL |= BIT(0);//new + + NVIC_SetPriority((IRQn_Type)ADCC_IRQn, IRQ_PRIO_HAL); + NVIC_EnableIRQ((IRQn_Type)ADCC_IRQn); //ADC_IRQ_ENABLE; + AP_ADCC->intr_mask = BIT(ADC_CHL + 1); //ENABLE_ADC_INT; +} + + diff --git a/src/TestTHB2/source/battery.h b/src/TestTHB2/source/battery.h new file mode 100644 index 0000000..727f1fb --- /dev/null +++ b/src/TestTHB2/source/battery.h @@ -0,0 +1,54 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + + +/************************************************************** + * + * Module Name: battery + * File name: battery.h + * Brief description: + * battery module + * Author: Eagle.Lao + * Revision:V0.01 + +****************************************************************/ + +#ifndef _BATTERY_HEAD_FILE +#define _BATTERY_HEAD_FILE + +#define BATT_TIMER_MEASURE_INTERVAL 3*60*1000 // 3 minute interval + +void batt_start_measure(void); + +#endif + + diff --git a/src/TestTHB2/source/bthome_beacon.c b/src/TestTHB2/source/bthome_beacon.c new file mode 100644 index 0000000..137b251 --- /dev/null +++ b/src/TestTHB2/source/bthome_beacon.c @@ -0,0 +1,47 @@ +/* + * bthome_beacon.c + * + * Created on: 17.10.23 + * Author: pvvx + */ +#include "rom_sym_def.h" +#include "types.h" +#include "bcomdef.h" +#include "gapbondmgr.h" +#include "sensor.h" +#include "bthome_beacon.h" + +//adv_buf_t adv_buf; + +void bthome_data_beacon(padv_bthome_ns1_t p) { + // padv_bthome_ns1_t p = (padv_bthome_ns1_t)&adv_buf.data; + p->flag[0] = 0x02; // size + p->flag[1] = GAP_ADTYPE_FLAGS; // type + /* Flags: + bit0: LE Limited Discoverable Mode + bit1: LE General Discoverable Mode + bit2: BR/EDR Not Supported + bit3: Simultaneous LE and BR/EDR to Same Device Capable (Controller) + bit4: Simultaneous LE and BR/EDR to Same Device Capable (Host) + bit5..7: Reserved + */ + p->flag[2] = GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED | GAP_ADTYPE_FLAGS_GENERAL; // Flags + p->head.type = GAP_ADTYPE_SERVICE_DATA; // 16-bit UUID + p->head.UUID = ADV_BTHOME_UUID16; + p->info = BtHomeID_Info; + p->p_id = BtHomeID_PacketId; + p->pid = (uint8)measured_data.count; + p->data.b_id = BtHomeID_battery; + p->data.battery_level = measured_data.battery; + p->data.t_id = BtHomeID_temperature; + p->data.temperature = measured_data.temp; // x0.01 C + p->data.h_id = BtHomeID_humidity; + p->data.humidity = measured_data.humi; // x0.01 % + p->data.v_id = BtHomeID_voltage; + p->data.battery_mv = measured_data.battery_mv; // x mV + p->head.size = sizeof(adv_bthome_ns1_t) - sizeof(p->head.size) - sizeof(p->flag); +} + + + + diff --git a/src/TestTHB2/source/bthome_beacon.h b/src/TestTHB2/source/bthome_beacon.h new file mode 100644 index 0000000..b003c64 --- /dev/null +++ b/src/TestTHB2/source/bthome_beacon.h @@ -0,0 +1,151 @@ +/* + * bthome_beacon.h + * + * Created on: 17.10.23 + * Author: pvvx + */ + +#ifndef BTHOME_BEACON_H_ +#define BTHOME_BEACON_H_ + +//#include "stack/ble/ble_8258/ble_common.h" + +#define ADV_BTHOME_UUID16 0xFCD2 // 16-bit UUID Service 0xFCD2 BTHOME + +#define BtHomeID_Info 0x40 +#define BtHomeID_Info_Encrypt 0x41 + + +// https://github.com/custom-components/ble_monitor/issues/548 +typedef enum { + BtHomeID_PacketId = 0, //0x00, uint8 + BtHomeID_battery = 0x01, //0x01, uint8, % + BtHomeID_temperature = 0x02, //0x02, sint16, 0.01 °C + BtHomeID_humidity = 0x03, //0x03, uint16, 0.01 % + BtHomeID_pressure = 0x04, //0x04, uint24, 0.01 hPa + BtHomeID_illuminance = 0x05, //0x05, uint24, 0.01 lux + BtHomeID_weight = 0x06, //0x06, uint16, 0.01 kg + BtHomeID_weight_lb = 0x07, //0x07, uint16, 0.01 lb + BtHomeID_dewpoint = 0x08, //0x08, sint16, 0.01 °C + BtHomeID_count8 = 0x09, //0x09, uint8 + BtHomeID_energy24 = 0x0a, //0x0A, uint24, 0.001 kWh + BtHomeID_power24 = 0x0b, //0x0B, uint24, 0.01 W + BtHomeID_voltage = 0x0c, //0x0C, uint16, 0.001 V + BtHomeID_pm2x5 = 0x0d, //0x0D, uint16, kg/m3 + BtHomeID_pm10 = 0x0e, //0x0E, uint16, kg/m3 + BtHomeID_boolean = 0x0f, //0x0F, uint8, generic boolean + BtHomeID_switch = 0x10, //0x10, uint8, power on/off + BtHomeID_opened = 0x11, //0x11, uint8, opening =0 Closed, = 1 Open + BtHomeID_co2 = 0x12, //0x12, uint16 + BtHomeID_tvoc = 0x13, //0x13, uint16 + BtHomeID_moisture16 = 0x14, //0x14, uint16, 0.01 + BtHomeID_low_battery = 0x15, //0x15, uint8, =1 low + BtHomeID_chg_battery = 0x16, //0x16, uint8, battery charging + BtHomeID_carbon_monoxide = 0x17,//0x17, uint8, carbon monoxide + BtHomeID_cold = 0x18, //0x18, uint8 + BtHomeID_connectivity = 0x19, //0x19, uint8 + BtHomeID_door = 0x1a, //0x1a, uint8, =0 Closed, =1 Open + BtHomeID_garage_door = 0x1b, //0x1b, uint8, =0 Closed, =1 Open + BtHomeID_gas = 0x1c, //0x1c, uint8, =1 Detected + BtHomeID_heat = 0x1d, //0x1d, uint8, =1 Hot + BtHomeID_light = 0x1e, //0x1e, uint8, =1 Light detected + BtHomeID_lock = 0x1f, //0x1f, uint8, =1 Unlocked + BtHomeID_moisture_b = 0x20, //0x20, uint8, =0 Dry, =1 Wet + BtHomeID_motion = 0x21, //0x21, uint8, =0 Clear, =1 Detected + BtHomeID_moving = 0x22, //0x22, uint8, =1 Moving + BtHomeID_occupancy = 0x23, //0x23, uint8, =1 Detected + BtHomeID_plug = 0x24, //0x24, uint8, =0 Unplugged, =1 Plugged in + BtHomeID_presence = 0x25, //0x25, uint8, =0 Away, =1 Home + BtHomeID_problem = 0x26, //0x26, uint8, =0 Ok, =1 Problem + BtHomeID_running = 0x27, //0x27, uint8, =0 Not Running, =1 Running + BtHomeID_safety = 0x28, //0x28, uint8, =0 Unsafe, =1 Safe + BtHomeID_smoke = 0x29, //0x29, uint8, =0 Clear, =1 Detected + BtHomeID_sound = 0x2a, //0x2a, uint8, =0 Clear, =1 Detected + BtHomeID_tamper = 0x2b, //0x2b, uint8, =0 Off, =1 On + BtHomeID_vibration = 0x2c, //0x2c, uint8, =0 Clear, =1 Detected + BtHomeID_window = 0x2d, //0x2d, uint8, =0 Closed, =1 Open + BtHomeID_humidity8 = 0x2e, //0x2e, uint8 + BtHomeID_moisture8 = 0x2f, //0x2f, uint8 + BtHomeID_0x30 = 0x30, //0x30, uint8 + BtHomeID_0x31 = 0x31, //0x31, uint8 + BtHomeID_0x32 = 0x32, //0x32, uint8 + BtHomeID_0x33 = 0x33, //0x33, uint8 + BtHomeID_0x34 = 0x34, //0x34, uint8 + BtHomeID_0x35 = 0x35, //0x35, uint8 + BtHomeID_0x36 = 0x36, //0x36, uint8 + BtHomeID_0x37 = 0x37, //0x37, uint8 + BtHomeID_0x38 = 0x38, //0x38, uint8 + BtHomeID_0x39 = 0x39, //0x39, uint8 + BtHomeID_button = 0x3a, //0x3a, uint8, =1 press, =2 double_press ... https://bthome.io/format/ + BtHomeID_0x3b = 0x3b, //0x3b, uint8 + BtHomeID_dimmer = 0x3c, //0x3c, uint16 ?, =1 rotate left 3 steps, ... https://bthome.io/format/ + BtHomeID_count16 = 0x3d, //0x3d, uint16 + BtHomeID_count32 = 0x3e, //0x3e, uint32 + BtHomeID_rotation = 0x3f, //0x3f, sint16, 0.1 + BtHomeID_distance_mm = 0x40, //0x40, uint16, mm + BtHomeID_distance_m = 0x41, //0x41, uint16, m, 0.1 + BtHomeID_duration = 0x42, //0x42, uint24, 0.01 + BtHomeID_current = 0x43, //0x43, uint16, 0.001 + BtHomeID_speed = 0x44, //0x44, uint16, 0.01 + BtHomeID_temperature_01 = 0x45, //0x45, sint16, 0.1 + BtHomeID_UV_index = 0x46, //0x46, uint8, 0.1 + BtHomeID_volume16_01 = 0x47, //0x47, uint16, 0.1 + BtHomeID_volume16 = 0x48, //0x48, uint16, 1 + BtHomeID_Flow_Rate = 0x49, //0x49, uint16, 0.001 + BtHomeID_voltage_01 = 0x4a, //0x4a, uint16, 0.1 + BtHomeID_gas24 = 0x4b, //0x4b, uint24, 0.001 + BtHomeID_gas32 = 0x4c, //0x4c, uint32, 0.001 + BtHomeID_energy32 = 0x4d, //0x4d, uint32, 0.001 + BtHomeID_volume32 = 0x4e, //0x4e, uint32, 0.001 + BtHomeID_water32 = 0x4f, //0x4f, uint32, 0.001 + BtHomeID_timestamp = 0x50, //0x50, uint48 + BtHomeID_acceleration = 0x51, //0x51, uint16, 0.001 + BtHomeID_gyroscope = 0x52, //0x52, uint16, 0.001 + BtHomeID_text = 0x53, //0x53, size uint8, uint8[] + BtHomeID_raw = 0x54 //0x54, size uint8, uint8[] +} BtHomeIDs_e; + +typedef struct __attribute__((packed)) _adv_head_bth_t { + uint8 size; // = + uint8 type; // = 0x16, 16-bit UUID + uint16 UUID; // = 0xFCD2, GATT Service BTHome +} adv_head_bth_t, * padv_head_bth_t; + +typedef struct __attribute__((packed)) _adv_bthome_data1_t { + uint8 b_id; // = BtHomeID_battery + uint8 battery_level; // 0..100 % + uint8 t_id; // = BtHomeID_temperature + int16 temperature; // x 0.01 degree + uint8 h_id; // = BtHomeID_humidity + uint16 humidity; // x 0.01 % + uint8 v_id; // = BtHomeID_voltage + uint16 battery_mv; // x 0.001 V +} adv_bthome_data1_t, * padv_bthome_data1_t; + + +#define ADV_BUFFER_SIZE (31-3) + +// BTHOME data1, no security +typedef struct __attribute__((packed)) _adv_bthome_ns1_t { + uint8 flag[3]; // Advertise type flags + adv_head_bth_t head; + uint8 info; // = 0x40 BtHomeID_Info + uint8 p_id; // = BtHomeID_PacketId + uint8 pid; // PacketId (measurement count) + adv_bthome_data1_t data; +} adv_bthome_ns1_t, * padv_bthome_ns1_t; + +typedef struct _adv_buf_t { + uint32 send_count; // count & id advertise, = beacon_nonce.cnt32 +// uint16 old_measured_count; // old measured_data.count +// uint16 adv_restore_count; + adv_bthome_ns1_t data; +} adv_buf_t; + +//extern adv_buf_t adv_buf; + +//void bls_set_advertise_prepare(void *p); +//int app_advertise_prepare_handler(rf_packet_adv_t * p); +void bthome_data_beacon(padv_bthome_ns1_t p); + +#endif /* BTHOME_BEACON_H_ */ diff --git a/src/TestTHB2/source/halPeripheral.c b/src/TestTHB2/source/halPeripheral.c new file mode 100644 index 0000000..2f43c28 --- /dev/null +++ b/src/TestTHB2/source/halPeripheral.c @@ -0,0 +1,245 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: gpio_demo.c + Revised: $Date $ + Revision: $Revision $ + + +**************************************************************************************************/ + +/********************************************************************* + INCLUDES +*/ +#include "rom_sym_def.h" +#include "OSAL.h" +#include "halPeripheral.h" +#include "log.h" + +#include "gpio.h" +#include "clock.h" + +#include "pwrmgr.h" +#include "error.h" +#include "global_config.h" +#include "cliface.h" +#include "key.h" +#include "led_light.h" +#include "halPeripheral.h" + + +uint8 Hal_TaskID; + +uint8_t cmdstr[64]; +uint8_t cmdlen; + +extern key_contex_t key_state; + +uint16_t cli_demo_help(uint32_t argc, uint8_t* argv[]); +uint16_t cli_demo_light_ctrl(uint32_t argc, uint8_t* argv[]); + +const CLI_COMMAND cli_cmd_list[] = +{ + /* Help */ + { "help", "Help on this CLI Demo Menu", cli_demo_help }, + + /* Light control */ + { "light", "This is CLI light control", cli_demo_light_ctrl }, +}; + +static void ProcessUartData(uart_Evt_t* evt) +{ + if(evt->len) + { + osal_memcpy((cmdstr + cmdlen), evt->data, evt->len); + cmdlen += evt->len; + osal_set_event( Hal_TaskID, KEY_DEMO_UART_RX_EVT ); + } +} + +static void key_press_evt(uint8_t i,key_evt_t key_evt) +{ + LOG("\nkey index:%d gpio:%d ",i,key_state.key[i].pin); + + switch(key_evt) + { + case HAL_KEY_EVT_PRESS: + LOG("key(press down)\n"); + #ifdef HAL_KEY_SUPPORT_LONG_PRESS + osal_start_timerEx(key_state.task_id,KEY_DEMO_LONG_PRESS_EVT,HAL_KEY_LONG_PRESS_TIME); + #endif + break; + + case HAL_KEY_EVT_RELEASE: + LOG("key(press release)\n"); + break; + #ifdef HAL_KEY_SUPPORT_LONG_PRESS + + case HAL_KEY_EVT_LONG_RELEASE: + hal_pwrmgr_unlock(MOD_USR1); + LOG("key(long press release)\n"); + break; + #endif + + default: + LOG("unexpect\n"); + break; + } +} + +void peripheral_uart_init(void) +{ + uart_Cfg_t cfg = + { + .tx_pin = P9, + .rx_pin = P10, + .rts_pin = GPIO_DUMMY, + .cts_pin = GPIO_DUMMY, + .baudrate = 115200, + .use_fifo = TRUE, + .hw_fwctrl = FALSE, + .use_tx_buf = FALSE, + .parity = FALSE, + .evt_handler = ProcessUartData, + }; + hal_uart_init(cfg,UART0);//uart init +} + +void HalPeripheral_Init(uint8 task_id) +{ + uint8_t i; + Hal_TaskID = task_id; + hal_uart_deinit(UART0); + peripheral_uart_init(); + light_init(); + light_blink_evt_cfg(Hal_TaskID,LIGHT_PRCESS_EVT); + key_state.key[0].pin = GPIO_P11; + + for(i = 0; i < HAL_KEY_NUM; ++i) + { + key_state.key[i].state = HAL_STATE_KEY_IDLE; + key_state.key[i].idle_level = HAL_HIGH_IDLE; + } + + key_state.task_id = Hal_TaskID; + key_state.key_callbank = key_press_evt; + key_init(); +} + +uint16 HalPeripheral_ProcessEvent( uint8 task_id, uint16 events ) +{ + if(task_id != Hal_TaskID) + { + return 0; + } + + if( events & KEY_DEMO_UART_RX_EVT) + { + if ('\r' == cmdstr[cmdlen - 1]) + { + cmdstr[cmdlen - 1] = '\0'; + LOG("%s", cmdstr); + CLI_process_line + ( + cmdstr, + cmdlen, + (CLI_COMMAND*) cli_cmd_list, + (sizeof (cli_cmd_list)/sizeof(CLI_COMMAND)) + ); + cmdlen = 0; + } + + return (events ^ KEY_DEMO_UART_RX_EVT); + } + + if(events & LIGHT_PRCESS_EVT) + { + light_blink_porcess_evt(); + return (events ^ LIGHT_PRCESS_EVT); + } + + if( events & HAL_KEY_EVENT) //do not modify,key will use it + { + LOG("evt\n"); + + for (uint8 i = 0; i < HAL_KEY_NUM; ++i) + { + if ((key_state.temp[i].in_enable == TRUE)|| + (key_state.key[i].state == HAL_STATE_KEY_RELEASE_DEBOUNCE)) + { + gpio_key_timer_handler(i); + } + } + + return (events ^ HAL_KEY_EVENT); + } + + #ifdef HAL_KEY_SUPPORT_LONG_PRESS + + if( events & KEY_DEMO_LONG_PRESS_EVT) + { + for (int i = 0; i < HAL_KEY_NUM; ++i) + { + if(key_state.key[i].state == HAL_KEY_EVT_PRESS) + { + LOG("key:%d gpio:%d ",i,key_state.key[i].pin); + LOG("key(long press down)"); + osal_start_timerEx(key_state.task_id,KEY_DEMO_LONG_PRESS_EVT,HAL_KEY_LONG_PRESS_TIME);//2s + //user app code long press down process + } + } + + return (events ^ KEY_DEMO_LONG_PRESS_EVT); + } + + #endif + // Discard unknown events + return 0; +} + +uint16_t cli_demo_help(uint32_t argc, uint8_t* argv[]) +{ + uint32_t index; + LOG("\r\nCLI Demo\r\n"); + + /* Print all the available commands */ + for (index = 0; index < (sizeof (cli_cmd_list)/sizeof(CLI_COMMAND)); index++) + { + LOG(" %s: %s\n", + cli_cmd_list[index].cmd, + cli_cmd_list[index].desc); + } + + return 0; +} + +uint16_t cli_demo_light_ctrl(uint32_t argc, uint8_t* argv[]) +{ + uint8_t mode; + LOG("\r\nLight Demo\r\n"); + + if(argc == 1) + { + mode = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + + if(LIGHT_COLOR_NUM < mode) + { + LOG("Invalid Parament:0x%04X. Returning.\n", mode); + return 0xffff; + } + + light_color_quickSet((light_color_t)mode); + } + else + { + LOG("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return 0xffff; + } + + mode = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + return 0; +} +/********************************************************************* +*********************************************************************/ diff --git a/src/TestTHB2/source/halPeripheral.h b/src/TestTHB2/source/halPeripheral.h new file mode 100644 index 0000000..72535e4 --- /dev/null +++ b/src/TestTHB2/source/halPeripheral.h @@ -0,0 +1,42 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: gpio_demo.h + Revised: $Date $ + Revision: $Revision $ + + +**************************************************************************************************/ + +#ifndef __HAL_PERIPHERAL_H__ +#define __HAL_PERIPHERAL_H__ + +#include "types.h" +#include "key.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define START_DEVICE_EVT 0x0001 +#define KEY_DEMO_UART_RX_EVT 0x0002 +#define LIGHT_PRCESS_EVT 0x0004 + + + +/********************************************************************* + FUNCTIONS +*/ +uint16 HalPeripheral_ProcessEvent( uint8 task_id, uint16 events ); +void HalPeripheral_Init(uint8 task_id); +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* HEARTRATE_H */ diff --git a/src/TestTHB2/source/sbpProfile_ota.c b/src/TestTHB2/source/sbpProfile_ota.c new file mode 100644 index 0000000..d21f59b --- /dev/null +++ b/src/TestTHB2/source/sbpProfile_ota.c @@ -0,0 +1,459 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: sbpProfile_ota.c + Revised: + Revision: + + Description: This file contains the Simple GATT profile sample GATT service + profile for use with the BLE sample application. + + +**************************************************************************************************/ + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "linkdb.h" +#include "att.h" +#include "gatt.h" +#include "gatt_uuid.h" +#include "gattservapp.h" +#include "gapbondmgr.h" +//#include "log.h" +#include "sbpProfile_ota.h" +#include "simpleBLEPeripheral.h" + +/********************************************************************* + * MACROS + */ + +/********************************************************************* + * CONSTANTS + */ + +#define SERVAPP_NUM_ATTR_SUPPORTED 8 + +/********************************************************************* + * TYPEDEFS + */ + +/********************************************************************* + * GLOBAL VARIABLES + */ +// Simple GATT Profile Service UUID: 0xFFF0 +CONST uint8 simpleProfileServUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(SIMPLEPROFILE_SERV_UUID), HI_UINT16(SIMPLEPROFILE_SERV_UUID) +}; + +// Characteristic 1 UUID: 0xFFF3 +CONST uint8 simpleProfilechar1UUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(SIMPLEPROFILE_CHAR1_UUID), HI_UINT16(SIMPLEPROFILE_CHAR1_UUID) +}; + +// Characteristic 2 UUID: 0xFFF4 +CONST uint8 simpleProfilechar2UUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(SIMPLEPROFILE_CHAR2_UUID), HI_UINT16(SIMPLEPROFILE_CHAR2_UUID) +}; + +/********************************************************************* + * EXTERNAL VARIABLES + */ + +/********************************************************************* + * EXTERNAL FUNCTIONS + */ + +/********************************************************************* + * LOCAL VARIABLES + */ + +static simpleProfileCBs_t *simpleProfile_AppCBs = NULL; +//static uint8 ReadNotify_Len = 0; + +/********************************************************************* + * Profile Attributes - variables + */ + +// Simple Profile Service attribute +static CONST gattAttrType_t simpleProfileService = { ATT_BT_UUID_SIZE, simpleProfileServUUID }; + + +// Simple Profile Characteristic 1 Properties +static uint8 simpleProfileChar1Props = GATT_PROP_WRITE | GATT_PROP_WRITE_NO_RSP; +static uint8 simpleProfileChar1[BLE_ATT_CMD_LED]= {0,}; // Characteristic 1 Value +static uint8 simpleProfileChar1UserDesp[] = "Commond\0"; // Simple Profile Characteristic 1 User Description + + +// Simple Profile Characteristic 2 Properties +static uint8 simpleProfileChar2Props = GATT_PROP_READ |GATT_PROP_NOTIFY; +static uint8 simpleProfileChar2[BLE_ATT_CMD_LED]= {0,}; // Characteristic 2 Value +static uint8 simpleProfileChar2UserDesp[] = "Response\0"; // Simple Profile Characteristic 2 User Description +static gattCharCfg_t simpleProfileChar2Config[GATT_MAX_NUM_CONN]; // + +/********************************************************************* + * Profile Attributes - Table + */ + +static gattAttribute_t simpleProfileAttrTbl[SERVAPP_NUM_ATTR_SUPPORTED] = +{ + /* type */ /* permissions */ /* handle */ /* pValue */ + // Simple Profile Service + {{ ATT_BT_UUID_SIZE, primaryServiceUUID }, GATT_PERMIT_READ, 0, (uint8 *)&simpleProfileService}, + + // Characteristic 1 Declaration + {{ ATT_BT_UUID_SIZE, characterUUID }, GATT_PERMIT_READ, 0, &simpleProfileChar1Props}, + // Characteristic Value 1 + {{ ATT_BT_UUID_SIZE, simpleProfilechar1UUID }, GATT_PERMIT_READ | GATT_PERMIT_WRITE, 0, &simpleProfileChar1[0]}, + // Characteristic 1 User Description + {{ ATT_BT_UUID_SIZE, charUserDescUUID }, GATT_PERMIT_READ, 0, simpleProfileChar1UserDesp}, + + // Characteristic 2 Declaration + {{ ATT_BT_UUID_SIZE, characterUUID }, GATT_PERMIT_READ, 0, &simpleProfileChar2Props}, + // Characteristic Value 2 + {{ ATT_BT_UUID_SIZE, simpleProfilechar2UUID }, GATT_PERMIT_READ | GATT_PERMIT_WRITE, 0, &simpleProfileChar2[0]}, + // Characteristic 2 configuration + {{ ATT_BT_UUID_SIZE, clientCharCfgUUID }, GATT_PERMIT_READ | GATT_PERMIT_WRITE, 0, (uint8 *)simpleProfileChar2Config}, + // Characteristic 2 User Description + {{ ATT_BT_UUID_SIZE, charUserDescUUID }, GATT_PERMIT_READ, 0, simpleProfileChar2UserDesp}, +}; + + +/********************************************************************* + * LOCAL FUNCTIONS + */ +static bStatus_t simpleProfile_ReadAttrCB( uint16 connHandle, gattAttribute_t *pAttr,uint8 *pValue, uint16 *pLen, uint16 offset, uint8 maxLen ); +static bStatus_t simpleProfile_WriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr,uint8 *pValue, uint16 len, uint16 offset ); +static void simpleProfile_HandleConnStatusCB( uint16 connHandle, uint8 changeType ); +/********************************************************************* + * PROFILE CALLBACKS + */ +// Simple Profile Service Callbacks +CONST gattServiceCBs_t simpleProfileCBs = +{ + simpleProfile_ReadAttrCB, // Read callback function pointer + simpleProfile_WriteAttrCB, // Write callback function pointer + NULL // Authorization callback function pointer +}; + +/********************************************************************* + * PUBLIC FUNCTIONS + */ + +/********************************************************************* + * @fn SimpleProfile_AddService + * + * @brief Initializes the Simple Profile service by registering + * GATT attributes with the GATT server. + * + * @param services - services to add. This is a bit map and can + * contain more than one service. + * + * @return Success or Failure + */ +bStatus_t SimpleProfile_AddService( uint32 services ) +{ + uint8 status = SUCCESS; + + // Initialize Client Characteristic Configuration attributes + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, simpleProfileChar2Config ); + + // Register with Link DB to receive link status change callback + VOID linkDB_Register( simpleProfile_HandleConnStatusCB ); + + if ( services & SIMPLEPROFILE_SERVICE ) + { + // Register GATT attribute list and CBs with GATT Server App + status = GATTServApp_RegisterService( simpleProfileAttrTbl, + GATT_NUM_ATTRS( simpleProfileAttrTbl ), + &simpleProfileCBs ); + } + + return ( status ); +} + + +/********************************************************************* + * @fn SimpleProfile_RegisterAppCBs + * + * @brief Registers the application callback function. Only call + * this function once. + * + * @param callbacks - pointer to application callbacks. + * + * @return SUCCESS or bleAlreadyInRequestedMode + */ +bStatus_t SimpleProfile_RegisterAppCBs( simpleProfileCBs_t *appCallbacks ) +{ + if ( appCallbacks ){ + simpleProfile_AppCBs = appCallbacks; + return ( SUCCESS ); + }else{ + return ( bleAlreadyInRequestedMode ); + } +} + + +/********************************************************************* + * @fn SimpleProfile_SetParameter + * + * @brief Set a Simple Profile parameter. + * + * @param param - Profile parameter ID + * @param len - length of data to right + * @param value - pointer to data to write. This is dependent on + * the parameter ID and WILL be cast to the appropriate + * data type (example: data type of uint16 will be cast to + * uint16 pointer). + * + * @return bStatus_t + */ +bStatus_t SimpleProfile_SetParameter( uint8 param, uint8 len, void *value ) +{ + bStatus_t ret = SUCCESS; + switch ( param ) + { + case SIMPLEPROFILE_CHAR1: + if ( len <= BLE_ATT_CMD_LED ){ + osal_memcpy(simpleProfileChar1, value, len); + }else{ + ret = bleInvalidRange; + } + break; + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + * @fn SimpleProfile_GetParameter + * + * @brief Get a Simple Profile parameter. + * + * @param param - Profile parameter ID + * @param value - pointer to data to put. This is dependent on + * the parameter ID and WILL be cast to the appropriate + * data type (example: data type of uint16 will be cast to + * uint16 pointer). + * + * @return bStatus_t + */ +bStatus_t SimpleProfile_GetParameter( uint8 param, void *value ) +{ + bStatus_t ret = SUCCESS; + switch ( param ) + { + // case SIMPLEPROFILE_CHAR1: + // VOID osal_memcpy( value, simpleProfileChar1, BLE_ATT_CMD_LED); + // break; + + case SIMPLEPROFILE_CHAR2: + VOID osal_memcpy( value, simpleProfileChar2, BLE_ATT_CMD_LED ); + break; + + default: + ret = INVALIDPARAMETER; + break; + } + return ( ret ); +} + +/********************************************************************* + * @fn simpleProfile_ReadAttrCB + * + * @brief Read an attribute. + * + * @param connHandle - connection message was received on + * @param pAttr - pointer to attribute + * @param pValue - pointer to data to be read + * @param pLen - length of data to be read + * @param offset - offset of the first octet to be read + * @param maxLen - maximum length of data to be read + * + * @return Success or Failure + */ +static bStatus_t simpleProfile_ReadAttrCB( uint16 connHandle, gattAttribute_t *pAttr, + uint8 *pValue, uint16 *pLen, uint16 offset, uint8 maxLen ) +{ + bStatus_t status = SUCCESS; + + // If attribute permissions require authorization to read, return error + if ( gattPermitAuthorRead( pAttr->permissions ) ) + { + // Insufficient authorization + return ( ATT_ERR_INSUFFICIENT_AUTHOR ); + } + + // Make sure it's not a blob operation (no attributes in the profile are long) + if ( offset > 0 ) + { + return ( ATT_ERR_ATTR_NOT_LONG ); + } + + if ( pAttr->type.len == ATT_BT_UUID_SIZE ) + { + // 16-bit UUID + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + switch ( uuid ) + { + // No need for "GATT_SERVICE_UUID" or "GATT_CLIENT_CHAR_CFG_UUID" cases; + // gattserverapp handles those reads + case SIMPLEPROFILE_CHAR2_UUID: + *pLen = BLE_ATT_CMD_LED; + VOID osal_memcpy( pValue, pAttr->pValue, *pLen ); + LOG("Read_UUID2:\n"); + break; + default: + // Should never get here! (characteristics 3 and 4 do not have read permissions) + *pLen = 0; + status = ATT_ERR_ATTR_NOT_FOUND; + break; + } + }else{ + // 128-bit UUID + *pLen = 0; + status = ATT_ERR_INVALID_HANDLE; + } + return ( status ); +} + +/********************************************************************* + * @fn simpleProfile_WriteAttrCB + * + * @brief Validate attribute data prior to a write operation + * + * @param connHandle - connection message was received on + * @param pAttr - pointer to attribute + * @param pValue - pointer to data to be written + * @param len - length of data + * @param offset - offset of the first octet to be written + * + * @return Success or Failure + */ + // TODO: test this function +static bStatus_t simpleProfile_WriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr, + uint8 *pValue, uint16 len, uint16 offset ) +{ + bStatus_t status = SUCCESS; + uint8 notifyApp = 0xFF; + + // If attribute permissions require authorization to write, return error + if ( gattPermitAuthorWrite( pAttr->permissions ) ) + { + // Insufficient authorization + return ( ATT_ERR_INSUFFICIENT_AUTHOR ); + } + + if ( pAttr->type.len == ATT_BT_UUID_SIZE ) + { + // 16-bit UUID + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + switch ( uuid ) + { + case SIMPLEPROFILE_CHAR1_UUID: + //Validate the value + // Make sure it's not a blob oper + if ( offset == 0 ){ + if ( len > BLE_ATT_CMD_LED){ + status = ATT_ERR_INVALID_VALUE_SIZE; + } + }else{ + status = ATT_ERR_ATTR_NOT_LONG; + } + //Write the value + if ( status == SUCCESS ){ + uint8 *pCurValue = (uint8 *)pAttr->pValue; + VOID osal_memcpy(pCurValue, pValue, len ); + LOG("receive data = 0x "); + LOG_DUMP_BYTE(pCurValue, len); + // DO NOT deal data in call back!!!Copy data and start an event. + osal_set_event(simpleBLEPeripheral_TaskID, SBP_DEALDATA); + notifyApp = SIMPLEPROFILE_CHAR1; + } + break; + + case GATT_CLIENT_CHAR_CFG_UUID: + LOG("Enable/Disable Notity\n"); + status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len, + offset, GATT_CLIENT_CFG_NOTIFY ); + break; + + default: + // Should never get here! (characteristics 2 and 4 do not have write permissions) + status = ATT_ERR_ATTR_NOT_FOUND; + break; + } + }else{ + // 128-bit UUID + status = ATT_ERR_INVALID_HANDLE; + } + // If a charactersitic value changed then callback function to notify application of change + if ( (notifyApp != 0xFF ) && simpleProfile_AppCBs && simpleProfile_AppCBs->pfnSimpleProfileChange ){ + simpleProfile_AppCBs->pfnSimpleProfileChange( notifyApp ); + } + return ( status ); +} + +/********************************************************************* + * @fn simpleProfile_HandleConnStatusCB + * + * @brief Simple Profile link status change handler function. + * + * @param connHandle - connection handle + * @param changeType - type of change + * + * @return none + */ +static void simpleProfile_HandleConnStatusCB( uint16 connHandle, uint8 changeType ) +{ + // Make sure this is not loopback connection + if ( connHandle != LOOPBACK_CONNHANDLE ){ + // Reset Client Char Config if connection has dropped + if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED )||( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) &&( !linkDB_Up( connHandle ) ) ) ){ + GATTServApp_InitCharCfg( connHandle, simpleProfileChar2Config ); + } + } +} + +bStatus_t simpleProfile_Notify( uint8 param, uint8 len, void *value ) +{ + bStatus_t ret = SUCCESS; + uint16 notfEnable; + + switch ( param ) + { + case SIMPLEPROFILE_CHAR2: + notfEnable = GATTServApp_ReadCharCfg( 0, simpleProfileChar2Config ); + + // If notifications enabled + if ( notfEnable & GATT_CLIENT_CFG_NOTIFY ){ + VOID osal_memcpy( simpleProfileChar2, value, len ); +// ReadNotify_Len = len; + ret = GATTServApp_ProcessCharCfg( simpleProfileChar2Config, simpleProfileChar2, FALSE, + simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ), + INVALID_TASK_ID ); + }else{ + ret = bleNotReady; + } + break; + + default: + ret = INVALIDPARAMETER; + break; + } + return ( ret ); +} + + +/********************************************************************* +*********************************************************************/ diff --git a/src/TestTHB2/source/sbpProfile_ota.h b/src/TestTHB2/source/sbpProfile_ota.h new file mode 100644 index 0000000..009ae78 --- /dev/null +++ b/src/TestTHB2/source/sbpProfile_ota.h @@ -0,0 +1,135 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: sbpProfile_ota.h + Revised: + Revision: + + Description: This file contains the Simple GATT profile definitions and + prototypes. + + **************************************************************************************************/ + +#ifndef SBPPROFILE_OTA_H +#define SBPPROFILE_OTA_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + * INCLUDES + */ + +/********************************************************************* + * CONSTANTS + */ + +// Profile Parameters +#define SIMPLEPROFILE_CHAR1 0 // RW uint8 - Profile Characteristic 1 value +#define SIMPLEPROFILE_CHAR2 1 // RW uint8 - Profile Characteristic 2 value +//#define SIMPLEPROFILE_CHAR3 2 // RW uint8 - Profile Characteristic 3 value +//#define SIMPLEPROFILE_CHAR4 3 // RW uint8 - Profile Characteristic 4 value +//#define SIMPLEPROFILE_CHAR5 4 // RW uint8 - Profile Characteristic 4 value +//#define SIMPLEPROFILE_CHAR6 5 // RW uint8 - Profile Characteristic 4 value +//#define SIMPLEPROFILE_CHAR7 6 // RW uint8 - Profile Characteristic 4 value + +// Simple Profile Service UUID +#define SIMPLEPROFILE_SERV_UUID 0xFFF0 + +// Key Pressed UUID +#define SIMPLEPROFILE_CHAR1_UUID 0xFFF3 +#define SIMPLEPROFILE_CHAR2_UUID 0xFFF4 +//#define SIMPLEPROFILE_CHAR3_UUID 0xFFF3 +//#define SIMPLEPROFILE_CHAR4_UUID 0xFFF4 +//#define SIMPLEPROFILE_CHAR5_UUID 0xFFF5 +//#define SIMPLEPROFILE_CHAR6_UUID 0xFFF6 +//#define SIMPLEPROFILE_CHAR7_UUID 0xFFF7 + +// Simple Keys Profile Services bit fields +#define SIMPLEPROFILE_SERVICE 0x00000001 + +// Length of Characteristic 5 in bytes +#define LC_RGBLIGHT_READTIME_LEN 9 +#define BLE_ATT_CMD_LED 20 +#define IBEACON_ATT_LONG_PKT 251 //230//160 +/********************************************************************* + * TYPEDEFS + */ + +/********************************************************************* + * MACROS + */ + +/********************************************************************* + * Profile Callbacks + */ + +// Callback when a characteristic value has changed +typedef void (*simpleProfileChange_t)( uint8 paramID ); + +typedef struct +{ + simpleProfileChange_t pfnSimpleProfileChange; // Called when characteristic value changes +} simpleProfileCBs_t; + + + +/********************************************************************* + * API FUNCTIONS + */ + + +/* + * SimpleProfile_AddService- Initializes the Simple GATT Profile service by registering + * GATT attributes with the GATT server. + * + * @param services - services to add. This is a bit map and can + * contain more than one service. + */ + +extern bStatus_t SimpleProfile_AddService( uint32 services ); + +/* + * SimpleProfile_RegisterAppCBs - Registers the application callback function. + * Only call this function once. + * + * appCallbacks - pointer to application callbacks. + */ +extern bStatus_t SimpleProfile_RegisterAppCBs( simpleProfileCBs_t *appCallbacks ); + +/* + * SimpleProfile_SetParameter - Set a Simple GATT Profile parameter. + * + * param - Profile parameter ID + * len - length of data to right + * value - pointer to data to write. This is dependent on + * the parameter ID and WILL be cast to the appropriate + * data type (example: data type of uint16 will be cast to + * uint16 pointer). + */ +extern bStatus_t SimpleProfile_SetParameter( uint8 param, uint8 len, void *value ); + +/* + * SimpleProfile_GetParameter - Get a Simple GATT Profile parameter. + * + * param - Profile parameter ID + * value - pointer to data to write. This is dependent on + * the parameter ID and WILL be cast to the appropriate + * data type (example: data type of uint16 will be cast to + * uint16 pointer). + */ +extern bStatus_t SimpleProfile_GetParameter( uint8 param, void *value ); + +extern bStatus_t simpleProfile_Notify( uint8 param, uint8 len, void *value ); +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* SIMPLEGATTPROFILE_H */ diff --git a/src/TestTHB2/source/sensor.h b/src/TestTHB2/source/sensor.h new file mode 100644 index 0000000..082c27c --- /dev/null +++ b/src/TestTHB2/source/sensor.h @@ -0,0 +1,70 @@ + +#ifndef _SENSORS_H_ +#define _SENSORS_H_ + +#include + + +// Timing +#define SENSOR_POWER_TIMEOUT_ms 5 +#define SENSOR_RESET_TIMEOUT_ms 5 +#define SENSOR_MEASURING_TIMEOUT_ms 7 + +// I2C addres +#define CHT8310_I2C_ADDR0 0x40 +#define CHT8310_I2C_ADDR1 0x44 +#define CHT8310_I2C_ADDR2 0x48 +#define CHT8310_I2C_ADDR3 0x4C + +// Registers +#define CHT8310_REG_TMP 0x00 +#define CHT8310_REG_HMD 0x01 +#define CHT8310_REG_STA 0x02 +#define CHT8310_REG_CFG 0x03 +#define CHT8310_REG_CRT 0x04 +#define CHT8310_REG_TLL 0x05 +#define CHT8310_REG_TLM 0x06 +#define CHT8310_REG_HLL 0x07 +#define CHT8310_REG_HLM 0x08 +#define CHT8310_REG_OST 0x0f +#define CHT8310_REG_RST 0xfc +#define CHT8310_REG_ID 0xfe + +// Status register mask +#define CHT8310_STA_BUSY 0x8000 +#define CHT8310_STA_THI 0x4000 +#define CHT8310_STA_TLO 0x2000 +#define CHT8310_STA_HHI 0x1000 +#define CHT8310_STA_HLO 0x0800 + +// Config register mask +#define CHT8310_CFG_MASK 0x8000 +#define CHT8310_CFG_SD 0x4000 +#define CHT8310_CFG_ALTH 0x2000 +#define CHT8310_CFG_EM 0x1000 +#define CHT8310_CFG_EHT 0x0100 +#define CHT8310_CFG_TME 0x0080 +#define CHT8310_CFG_POL 0x0020 +#define CHT8310_CFG_ALT 0x0018 +#define CHT8310_CFG_CONSEC_FQ 0x0006 +#define CHT8310_CFG_ATM 0x0001 + + +typedef struct _measured_data_t { + uint16_t count; + int16_t temp; // x 0.01 C + int16_t humi; // x 0.01 % + uint16_t battery_mv; // mV + uint8_t battery; // 0..100 % +} measured_data_t; + +extern measured_data_t measured_data; + +void init_sensor(void); +int read_sensor(void); + +//void init_i2c(void); +//void deinit_i2c(void); + + +#endif // _SENSORS_H_ diff --git a/src/TestTHB2/source/sensors.c b/src/TestTHB2/source/sensors.c new file mode 100644 index 0000000..8f61f1b --- /dev/null +++ b/src/TestTHB2/source/sensors.c @@ -0,0 +1,174 @@ + +#include "types.h" +#include "gpio.h" +#include "rom_sym_def.h" +#include "i2c.h" +#include "sensor.h" + +/* Tuya: + * I2C0 SCL P24 + * I2C0 SDA P23 + + SCL P20 + SDA P18 + KEY P07 + VBAT P10 +*/ +#define I2C_SDA P18 +#define I2C_SCL P20 + +measured_data_t measured_data; + +void init_i2c(void) { + hal_gpio_fmux_set(I2C_SCL, FMUX_IIC0_SCL); + hal_gpio_fmux_set(I2C_SDA, FMUX_IIC0_SDA); + + //hal_i2c_init(I2C_0, I2C_CLOCK_400K); + + int pclk = clk_get_pclk(); + + AP_I2C_TypeDef* pi2cdev = AP_I2C0; + hal_clk_gate_enable(MOD_I2C0); + pi2cdev->IC_ENABLE = 0; + pi2cdev->IC_CON = 0x61; + pi2cdev->IC_CON = ((pi2cdev->IC_CON) & 0xfffffff9)|(0x02 << 1); + if(pclk == 16000000) + { + pi2cdev->IC_FS_SCL_HCNT = 10; + pi2cdev->IC_FS_SCL_LCNT = 17; + } + else if(pclk == 32000000) + { + pi2cdev->IC_FS_SCL_HCNT = 30; + pi2cdev->IC_FS_SCL_LCNT = 35; + } + else if(pclk == 48000000) + { + pi2cdev->IC_FS_SCL_HCNT = 48; + pi2cdev->IC_FS_SCL_LCNT = 54; + } + else if(pclk == 64000000) + { + pi2cdev->IC_FS_SCL_HCNT = 67; + pi2cdev->IC_FS_SCL_LCNT = 75; + } + else if(pclk == 96000000) + { + pi2cdev->IC_FS_SCL_HCNT = 105; + pi2cdev->IC_FS_SCL_LCNT = 113; + } + pi2cdev->IC_TAR = I2C_MASTER_ADDR_DEF; + pi2cdev->IC_INTR_MASK = 0; + pi2cdev->IC_RX_TL = 0x0; + pi2cdev->IC_TX_TL = 0x1; + pi2cdev->IC_ENABLE = 1; +} + +void deinit_i2c(void) { + AP_I2C_TypeDef * pi2cdev = AP_I2C0; + pi2cdev->IC_ENABLE = 0; + hal_clk_gate_disable(MOD_I2C0); + hal_gpio_pin_init(I2C_SCL, IE); + hal_gpio_pin_init(I2C_SDA, IE); +} + +extern volatile uint32 osal_sys_tick; + +/* size max = 7 ! */ +int read_i2c_bytes(uint8 addr, uint8 reg, uint8 * data, uint8 size) { + int i = size; + AP_I2C_TypeDef * pi2cdev = AP_I2C0; + pi2cdev->IC_ENABLE = 0; + pi2cdev->IC_TAR = addr; + HAL_ENTER_CRITICAL_SECTION(); + pi2cdev->IC_ENABLE = 1; + pi2cdev->IC_DATA_CMD = reg; + //while(!(pi2cdev->IC_RAW_INTR_STAT & 0x10)); + while(i--) + pi2cdev->IC_DATA_CMD = 0x100; + HAL_EXIT_CRITICAL_SECTION(); + uint32 to = osal_sys_tick; + i = size; + while(i) { + if(pi2cdev->IC_STATUS & 0x08) { // fifo not empty + *data = pi2cdev->IC_DATA_CMD & 0xff; + data++; + i--; + } + if(osal_sys_tick - to > 10) + return 1; + } + return 0; +} + +int send_i2c_byte(uint8 addr, uint8 data) { + AP_I2C_TypeDef * pi2cdev = AP_I2C0; + pi2cdev->IC_ENABLE = 0; + pi2cdev->IC_TAR = addr; + HAL_ENTER_CRITICAL_SECTION(); + pi2cdev->IC_ENABLE = 1; + pi2cdev->IC_DATA_CMD = data; + // while(!(pi2cdev->IC_RAW_INTR_STAT & 0x10)); + HAL_EXIT_CRITICAL_SECTION(); + uint32 to = osal_sys_tick; + while(1) { + if(pi2cdev->IC_RAW_INTR_STAT & 0x200)// check tx empty + break; + if(osal_sys_tick - to > 10) + return 1; + } + return 0; +} + +int send_i2c_wreg(uint8 addr, uint8 reg, uint16 data) { + AP_I2C_TypeDef * pi2cdev = AP_I2C0; + pi2cdev->IC_ENABLE = 0; + pi2cdev->IC_TAR = addr; + HAL_ENTER_CRITICAL_SECTION(); + pi2cdev->IC_ENABLE = 1; + pi2cdev->IC_DATA_CMD = reg; + while(!(pi2cdev->IC_RAW_INTR_STAT & 0x10)); + pi2cdev->IC_DATA_CMD = (data >> 8) & 0xff; + while(!(pi2cdev->IC_RAW_INTR_STAT & 0x10)); + pi2cdev->IC_DATA_CMD = data & 0xff; + HAL_EXIT_CRITICAL_SECTION(); + uint32 to = osal_sys_tick; + while(1) { + if(pi2cdev->IC_RAW_INTR_STAT & 0x200)// check tx empty + break; + if(osal_sys_tick - to > 10) + return 1; + } + return 0; +} + +__ATTR_SECTION_XIP__ void init_sensor(void) { + init_i2c(); + send_i2c_byte(0, 0x06); // Reset command using the general call address + WaitMs(3); + send_i2c_wreg(CHT8310_I2C_ADDR0, CHT8310_REG_CRT, 0x0300); // Set conversion ratio 5 sec + deinit_i2c(); +} + +int read_sensor(void) { + int32 _r32; + int16 _r16; + uint8 reg_data[4]; + init_i2c(); + _r32 = read_i2c_bytes(CHT8310_I2C_ADDR0, CHT8310_REG_TMP, reg_data, 2); + //? WaitUs(100); + _r32 |= read_i2c_bytes(CHT8310_I2C_ADDR0, CHT8310_REG_HMD, ®_data[2], 2); + deinit_i2c(); + if (!_r32) { + _r16 = (reg_data[0] << 8) | reg_data[1]; + measured_data.temp = (int32)(_r16 * 25606) >> 16; // x 0.01 C + _r32 = ((reg_data[2] << 8) | reg_data[3]) & 0x7fff; + measured_data.humi = (uint32)(_r32 * 20000) >> 16; // x 0.01 % + if (measured_data.humi > 9999) + measured_data.humi = 9999; + measured_data.count++; + return 0; + } + init_sensor(); + return 1; +} diff --git a/src/TestTHB2/source/simpleBLEPeripheral.h b/src/TestTHB2/source/simpleBLEPeripheral.h new file mode 100644 index 0000000..c360a27 --- /dev/null +++ b/src/TestTHB2/source/simpleBLEPeripheral.h @@ -0,0 +1,95 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: simpleBLEperipheral.h + Revised: + Revision: + + Description: This file contains the Simple BLE Peripheral sample application + definitions and prototypes. + + +**************************************************************************************************/ + +#ifndef SIMPLEBLEPERIPHERAL_H +#define SIMPLEBLEPERIPHERAL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + * INCLUDES + */ + +/********************************************************************* + * CONSTANTS + */ +// Minimum connection interval (units of 1.25ms, 80=100ms) if automatic parameter update request is enabled +#define DEFAULT_DESIRED_MIN_CONN_INTERVAL 24 // 12 -> 15 ms +// Maximum connection interval (units of 1.25ms, 800=1000ms) if automatic parameter update request is enabled +#define DEFAULT_DESIRED_MAX_CONN_INTERVAL 24 // 30 ms +// Slave latency to use if automatic parameter update request is enabled +#define DEFAULT_DESIRED_SLAVE_LATENCY 29 +// Supervision timeout value (units of 10ms, 1000=10s) if automatic parameter update request is enabled +#define DEFAULT_DESIRED_CONN_TIMEOUT 400 // 4s + +#define DEF_ADV_INERVAL 8000 // = 5 sec, actual time = advInt * 625us +#define DEF_ADV_INERVAL_MS ((DEF_ADV_INERVAL*625)/1000) // 5000 ms +#define DEF_CON_ADV_INERVAL 2500 // 1.5625 sec +#define DEF_CON_ADV_INERVAL_MS ((DEF_CON_ADV_INERVAL*625)/1000) // 1562 ms +// How often to perform periodic event +#define SBP_PERIODIC_EVT_PERIOD 5000 + +#define DEVINFO_SYSTEM_ID_LEN 8 +#define DEVINFO_SYSTEM_ID 0 + +#define DEFAULT_DISCOVERABLE_MODE GAP_ADTYPE_FLAGS_GENERAL + +// Whether to enable automatic parameter update request when a connection is formed +#define DEFAULT_ENABLE_UPDATE_REQUEST TRUE +// Connection Pause Peripheral time value (in seconds) +#define DEFAULT_CONN_PAUSE_PERIPHERAL 2 + +// Simple BLE Peripheral Task Events +#define SBP_START_DEVICE_EVT 0x0001 +#define SBP_RESET_ADV_EVT 0x0002 +#define SBP_DEALDATA 0x0004 +#define TIMER_BATT_EVT 0x0008 //for battery detect +#define BATT_VALUE_EVT 0x0010 //event for battery voltage value update +#define ADV_BROADCAST_EVT 0x0020 + +/********************************************************************* + * MACROS + */ +#define MAC_DATA_LEN 6 + +#define GPIO_KEY P7 +#define GPIO_LED P26 + +extern uint8 simpleBLEPeripheral_TaskID; +/********************************************************************* + * FUNCTIONS + */ + +/* + * Task Initialization for the BLE Application + */ +extern void SimpleBLEPeripheral_Init( uint8 task_id ); + +/* + * Task Event Processor for the BLE Application + */ +extern uint16 SimpleBLEPeripheral_ProcessEvent( uint8 task_id, uint16 events ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* SIMPLEBLEPERIPHERAL_H */ diff --git a/src/TestTHB2/source/thb2_main.c b/src/TestTHB2/source/thb2_main.c new file mode 100644 index 0000000..9ef38d5 --- /dev/null +++ b/src/TestTHB2/source/thb2_main.c @@ -0,0 +1,641 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: simpleBLEPeripheral.c + Revised: + Revision: + + Description: This file contains the Simple BLE Peripheral sample application + + +**************************************************************************************************/ +/********************************************************************* + * INCLUDES + */ +#include "bcomdef.h" +#include "rf_phy_driver.h" +#include "global_config.h" +#include "OSAL.h" +#include "OSAL_PwrMgr.h" +#include "gatt.h" +#include "hci.h" +#include "gapgattserver.h" +#include "gattservapp.h" +#include "devinfoservice.h" +#include "sbpProfile_ota.h" +#include "ota_app_service.h" +#include "peripheral.h" +#include "gapbondmgr.h" +#include "pwrmgr.h" +#include "gpio.h" +#include "simpleBLEPeripheral.h" +#include "ll.h" +#include "ll_hw_drv.h" +#include "ll_def.h" +#include "hci_tl.h" +#include "flash.h" +#include "fs.h" +#include "battservice.h" +#include "thservice.h" +#include "bthome_beacon.h" +#include "sensor.h" +#include "battery.h" +/********************************************************************* + * MACROS + */ +//#define LOG(...) +/********************************************************************* + * CONSTANTS + */ + +#define INVALID_CONNHANDLE 0xFFFF +// Default passcode +#define DEFAULT_PASSCODE 0 //19655 +// Length of bd addr as a string +#define B_ADDR_STR_LEN 15 +#define RESOLVING_LIST_ENTRY_NUM 10 +// Offset of advertData&scanRspData +#define RSP_OFFSET_MAC 4 + +/********************************************************************* + * build define + */ + +/********************************************************************* + * TYPEDEFS + */ + +/********************************************************************* + * GLOBAL VARIABLES + */ +perStatsByChan_t g_perStatsByChanTest; + +/********************************************************************* + * EXTERNAL VARIABLES + */ +volatile uint8_t g_current_advType = LL_ADV_CONNECTABLE_UNDIRECTED_EVT; + + +/********************************************************************* + * EXTERNAL FUNCTIONS + */ + + +/********************************************************************* + * LOCAL VARIABLES + */ +uint8 simpleBLEPeripheral_TaskID; // Task ID for internal task/event processing + +static gaprole_States_t gapProfileState = GAPROLE_INIT; + + +/** Advertisement payload */ +static const uint8 advertData[] = +{ + 0x02, // length of this data + GAP_ADTYPE_FLAGS, + GAP_ADTYPE_FLAGS_GENERAL | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED +}; + +// GAP GATT Attributes +static uint8 attDeviceName[] = "THB2-000000"; // GAP_DEVICE_NAME_LEN + +// GAP - SCAN RSP data (max size = 31 bytes) +static uint8 scanRspData[GAP_DEVICE_NAME_LEN + 2]; + + +/********************************************************************* + * LOCAL FUNCTIONS + */ +static void simpleBLEPeripheral_ProcessOSALMsg( osal_event_hdr_t *pMsg ); +static void peripheralStateNotificationCB( gaprole_States_t newState ); +//static void simpleProfileChangeCB( uint8 paramID ); +static void peripheralStateReadRssiCB( int8 rssi ); + +const char* hex_ascii = { "0123456789ABCDEF" }; +uint8_t * str_bin2hex(uint8_t *d, uint8_t *s, int len) { + while(len--) { + *d++ = hex_ascii[(*s >> 4) & 0xf]; + *d++ = hex_ascii[(*s++ >> 0) & 0xf]; + } + return d; +} + +static void set_mac(void) +{ + extern uint8 ownPublicAddr[LL_DEVICE_ADDR_LEN]; + uint8 * p = &attDeviceName[5]; +#if 0 // =0 - test! + uint16 len; + if(hal_fs_item_read(0xACAD, ownPublicAddr, LL_DEVICE_ADDR_LEN, &len) != PPlus_SUCCESS) { + LL_Rand(ownPublicAddr,3); + ownPublicAddr[3] = 0x8d; + ownPublicAddr[4] = 0x1f; + ownPublicAddr[5] = 0x38; + hal_fs_item_write(0xACAD, ownPublicAddr, LL_DEVICE_ADDR_LEN); + } +#else + ownPublicAddr[0] = 0x56; + ownPublicAddr[1] = 0x34; + ownPublicAddr[2] = 0x12; + ownPublicAddr[3] = 0x34; + ownPublicAddr[4] = 0x12; + ownPublicAddr[5] = 0x25; +#endif + + p = str_bin2hex(p, &ownPublicAddr[2], 1); + p = str_bin2hex(p, &ownPublicAddr[1], 1); + str_bin2hex(p, &ownPublicAddr[0], 1); + scanRspData[0] = sizeof(attDeviceName) + 1; + scanRspData[1] = GAP_ADTYPE_LOCAL_NAME_COMPLETE; + osal_memcpy(&scanRspData[2], attDeviceName, sizeof(attDeviceName)); +} + + +uint8 adv_count; +uint8 adv_con_count; +extern uint8 gapRole_AdvEnabled; +extern uint8 gapRole_AdvertData[B_MAX_ADV_LEN]; +extern uint8 gapRole_AdvDirectAddr[B_ADDR_LEN]; +extern uint8 gapRole_AdvEventType; +extern uint8 gapRole_AdvDirectType; +extern uint8 gapRole_AdvChanMap; +extern uint8 gapRole_AdvFilterPolicy; +extern uint8 gapRole_TaskID; +extern gaprole_States_t gapRole_state; + +// Set new advertising interval +static void set_adv_interval(uint16 advInt) +{ + GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MIN, advInt ); + GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MAX, advInt ); + GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MIN, advInt ); + GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MAX, advInt ); + GAP_EndDiscoverable( gapRole_TaskID ); + gapRole_state = GAPROLE_WAITING_AFTER_TIMEOUT; +/* + LL_SetAdvParam(advInt, advInt, // actual time = advInt * 625us + LL_ADV_CONNECTABLE_UNDIRECTED_EVT, + gapRole_AdvEventType, + gapRole_AdvDirectType, + gapRole_AdvDirectAddr, + gapRole_AdvChanMap, + gapRole_AdvFilterPolicy ); */ + // Turn advertising back on. + osal_set_event( gapRole_TaskID, START_ADVERTISING_EVT ); +} + +static void adv_measure(void) { + if(gapRole_AdvEnabled) { + if(++adv_count & 1) { + read_sensor(); + bthome_data_beacon((padv_bthome_ns1_t) gapRole_AdvertData); + LL_SetAdvData(sizeof(adv_bthome_ns1_t), gapRole_AdvertData); + if(adv_con_count) { + if(--adv_con_count == 0) { + set_adv_interval(DEF_ADV_INERVAL); + } + } + } + else if(adv_count >= BATT_TIMER_MEASURE_INTERVAL/DEF_ADV_INERVAL_MS) // = 60 + { + adv_count = 0; + batt_start_measure(); + } + } +} + +static void posedge_int_wakeup_cb(GPIO_Pin_e pin,IO_Wakeup_Pol_e type) +{ + if(type == POSEDGE) + { + adv_con_count = 30000/DEF_CON_ADV_INERVAL_MS; // 60 sec + LOG("int or wakeup(pos):gpio:%d type:%d\n",pin,type); + hal_gpio_write(GPIO_LED,1); + if(gapRole_AdvEnabled) { + set_adv_interval(DEF_CON_ADV_INERVAL); // actual time = advInt * 625us + } + } + else + { + LOG("error\n"); + } +} +static void negedge_int_wakeup_cb(GPIO_Pin_e pin,IO_Wakeup_Pol_e type) +{ + if(type == NEGEDGE) + { + LOG("int or wakeup(neg):gpio:%d type:%d\n",pin,type); + hal_gpio_write(GPIO_LED,0); + } + else + { + LOG("error\n"); + } +} +static void init_led_key(void) +{ + //hal_gpio_pin_init(GPIO_KEY, GPIO_INPUT); + hal_gpioin_register(GPIO_KEY, posedge_int_wakeup_cb, negedge_int_wakeup_cb); + hal_gpioretention_register(GPIO_LED);//enable this pin retention + //hal_gpioretention_unregister(pin);//disable this pin retention + hal_gpio_write(GPIO_LED,1); +} + +/********************************************************************* + * PROFILE CALLBACKS + */ + +// GAP Role Callbacks +static gapRolesCBs_t simpleBLEPeripheral_PeripheralCBs = +{ + peripheralStateNotificationCB, // Profile State Change Callbacks + peripheralStateReadRssiCB // When a valid RSSI is read from controller (not used by application) +}; +#if (DEF_GAPBOND_MGR_ENABLE==1) +// GAP Bond Manager Callbacks, add 2017-11-15 +static gapBondCBs_t simpleBLEPeripheral_BondMgrCBs = +{ + NULL, // Passcode callback (not used by application) + NULL // Pairing / Bonding state Callback (not used by application) +}; +#endif +// Simple GATT Profile Callbacks +//static +#if 0 +simpleProfileCBs_t simpleBLEPeripheral_SimpleProfileCBs = +{ + simpleProfileChangeCB // Charactersitic value change callback +}; +#endif +/********************************************************************* + * PUBLIC FUNCTIONS + */ +/********************************************************************* + * @fn SimpleBLEPeripheral_Init + * + * @brief Initialization function for the Simple BLE Peripheral App Task. + * This is called during initialization and should contain + * any application specific initialization (ie. hardware + * initialization/setup, table initialization, power up + * notificaiton ... ). + * + * @param task_id - the ID assigned by OSAL. This ID should be + * used to send messages and set timers. + * + * @return none + */ +void SimpleBLEPeripheral_Init( uint8 task_id ) +{ + simpleBLEPeripheral_TaskID = task_id; + + init_led_key(); + + init_sensor(); + + // Setup the GAP + VOID GAP_SetParamValue( TGAP_CONN_PAUSE_PERIPHERAL, DEFAULT_CONN_PAUSE_PERIPHERAL ); + + // Setup the GAP Peripheral Role Profile + { + // device starts advertising upon initialization + uint8 initial_advertising_enable = FALSE; + + uint8 enable_update_request = DEFAULT_ENABLE_UPDATE_REQUEST; + uint8 advChnMap = GAP_ADVCHAN_37 | GAP_ADVCHAN_38 | GAP_ADVCHAN_39; + + // By setting this to zero, the device will go into the waiting state after + // being discoverable for 30.72 second, and will not being advertising again + // until the enabler is set back to TRUE + uint16 gapRole_AdvertOffTime = 0; + + extern gapPeriConnectParams_t periConnParameters; + uint8 peerPublicAddr[] = { + 0x01, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06 + }; + set_mac(); + uint8 advType = LL_ADV_CONNECTABLE_UNDIRECTED_EVT; + GAPRole_SetParameter( GAPROLE_ADV_EVENT_TYPE, sizeof( uint8 ), &advType ); + GAPRole_SetParameter( GAPROLE_ADV_DIRECT_ADDR, sizeof(peerPublicAddr), peerPublicAddr); + // set adv channel map + GAPRole_SetParameter( GAPROLE_ADV_CHANNEL_MAP, sizeof( uint8 ), &advChnMap); + // Set the GAP Role Parameters + GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &initial_advertising_enable ); + GAPRole_SetParameter( GAPROLE_ADVERT_OFF_TIME, sizeof( uint16 ), &gapRole_AdvertOffTime ); + GAPRole_SetParameter( GAPROLE_ADVERT_DATA, sizeof(advertData), (void *)advertData); // advertData + GAPRole_SetParameter( GAPROLE_SCAN_RSP_DATA, scanRspData[0] + 1, scanRspData ); + GAPRole_SetParameter( GAPROLE_PARAM_UPDATE_ENABLE, sizeof( uint8 ), &enable_update_request); + GAPRole_SetParameter( GAPROLE_MIN_CONN_INTERVAL, sizeof( uint16 ), &periConnParameters.intervalMin); + GAPRole_SetParameter( GAPROLE_MAX_CONN_INTERVAL, sizeof( uint16 ), &periConnParameters.intervalMax ); + GAPRole_SetParameter( GAPROLE_SLAVE_LATENCY, sizeof( uint16 ), &periConnParameters.latency ); + GAPRole_SetParameter( GAPROLE_TIMEOUT_MULTIPLIER, sizeof( uint16 ), &periConnParameters.timeout ); + } + + // Set the GAP Characteristics + GGS_SetParameter( GGS_DEVICE_NAME_ATT, sizeof(attDeviceName), (void *)attDeviceName ); // GAP_DEVICE_NAME_LEN, attDeviceName ); + + // Set advertising interval + { + uint16 advInt = DEF_ADV_INERVAL; // actual time = advInt * 625us + GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MIN, advInt ); + GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MAX, advInt ); + GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MIN, advInt ); + GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MAX, advInt ); + } + HCI_PPLUS_AdvEventDoneNoticeCmd(simpleBLEPeripheral_TaskID, ADV_BROADCAST_EVT); +#if (DEF_GAPBOND_MGR_ENABLE==1) + // Setup the GAP Bond Manager, add 2017-11-15 + { + uint32 passkey = DEFAULT_PASSCODE; + uint8 pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ; + uint8 mitm = TRUE; + uint8 ioCap = GAPBOND_IO_CAP_NO_INPUT_NO_OUTPUT; + uint8 bonding = TRUE; + GAPBondMgr_SetParameter( GAPBOND_DEFAULT_PASSCODE, sizeof ( uint32 ), &passkey ); + GAPBondMgr_SetParameter( GAPBOND_PAIRING_MODE, sizeof ( uint8 ), &pairMode ); + GAPBondMgr_SetParameter( GAPBOND_MITM_PROTECTION, sizeof ( uint8 ), &mitm ); + GAPBondMgr_SetParameter( GAPBOND_IO_CAPABILITIES, sizeof ( uint8 ), &ioCap ); + GAPBondMgr_SetParameter( GAPBOND_BONDING_ENABLED, sizeof ( uint8 ), &bonding ); + } +#endif + // Initialize GATT attributes + GGS_AddService( GATT_ALL_SERVICES ); // GAP + GATTServApp_AddService( GATT_ALL_SERVICES ); // GATT attributes + DevInfo_AddService(); // Device Information Service + //SimpleProfile_AddService( GATT_ALL_SERVICES ); // Simple GATT Profile + Batt_AddService(); + //Batt_Register(NULL); + TH_AddService(); + + uint8 OTA_Passward_AscII[8] = {'1','2','3','4','5','6','7','8'}; + ota_app_AddService_UseKey(8, OTA_Passward_AscII); + ota_app_AddService(); + +#if (1) + llInitFeatureSet2MPHY(TRUE); + llInitFeatureSetDLE(TRUE); +#else + llInitFeatureSet2MPHY(FALSE); + llInitFeatureSetDLE(FALSE); +#endif + +#ifdef MTU_SIZE + ATT_SetMTUSizeMax(MTU_SIZE); +#else + ATT_SetMTUSizeMax(23); +#endif + // Setup a delayed profile startup + osal_set_event( simpleBLEPeripheral_TaskID, SBP_START_DEVICE_EVT ); + // for receive HCI complete message + GAP_RegisterForHCIMsgs(simpleBLEPeripheral_TaskID); + LL_PLUS_PerStats_Init(&g_perStatsByChanTest); + + batt_start_measure(); + + LOG("=====SimpleBLEPeripheral_Init Done=======\n"); +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_ProcessEvent + * + * @brief Simple BLE Peripheral Application Task event processor. This function + * is called to process all events for the task. Events + * include timers, messages and any other user defined events. + * + * @param task_id - The OSAL assigned task ID. + * @param events - events to process. This is a bit map and can + * contain more than one event. + * + * @return events not processed + */ +uint16 SimpleBLEPeripheral_ProcessEvent( uint8 task_id, uint16 events ) +{ + VOID task_id; // OSAL required parameter that isn't used in this function + if ( events & ADV_BROADCAST_EVT) + { + adv_measure(); + LOG("advN%u\n", adv_count); + // return unprocessed events + return (events ^ ADV_BROADCAST_EVT); + } + + if ( events & SYS_EVENT_MSG ) + { + uint8 *pMsg; + + if ( (pMsg = osal_msg_receive( simpleBLEPeripheral_TaskID )) != NULL ) + { + simpleBLEPeripheral_ProcessOSALMsg( (osal_event_hdr_t *)pMsg ); + + // Release the OSAL message + VOID osal_msg_deallocate( pMsg ); + } + + // return unprocessed events + return (events ^ SYS_EVENT_MSG); + } + + // enable adv + if ( events & SBP_RESET_ADV_EVT ) + { + LOG("SBP_RESET_ADV_EVT\n"); + adv_count = 0; + + //adv_con_count = 1; + // set_adv_interval(DEF_ADV_INERVAL); // actual time = advInt * 625us + uint8 initial_advertising_enable = TRUE; + GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &initial_advertising_enable ); + return ( events ^ SBP_RESET_ADV_EVT ); + } + if( events & TIMER_BATT_EVT) + { + LOG("TIMER_EVT\n"); + read_sensor(); + // TH Notify + TH_NotifyLevel(); + if(++adv_count >= 6) { // 60 sec + adv_count = 0; + batt_start_measure(); + } + // return unprocessed events + return ( events ^ TIMER_BATT_EVT); + } + if( events & BATT_VALUE_EVT) + { + LOG("Vbat: %d mV, %d %%\n", measured_data.battery_mv, measured_data.battery); + // Batt Notify + if(!gapRole_AdvEnabled) { + BattNotifyLevel(); + } + // return unprocessed events + return ( events ^ BATT_VALUE_EVT); + } + if ( events & SBP_START_DEVICE_EVT ) + { + // Start the Device + VOID GAPRole_StartDevice( &simpleBLEPeripheral_PeripheralCBs ); +#if (DEF_GAPBOND_MGR_ENABLE==1) + // Start Bond Manager, 2017-11-15 + VOID GAPBondMgr_Register( &simpleBLEPeripheral_BondMgrCBs ); +#endif + HCI_LE_ReadResolvingListSizeCmd(); + // return unprocessed events + return ( events ^ SBP_START_DEVICE_EVT ); + } + + if(events & SBP_DEALDATA) + { + LOG("\ndeal app datas in events!!!\n"); + // return unprocessed events + return(events ^ SBP_DEALDATA); + } + // Discard unknown events + return 0; +} + +/********************************************************************* + * @fn simpleBLEPeripheral_ProcessOSALMsg + * + * @brief Process an incoming task message. + * + * @param pMsg - message to process + * + * @return none + */ +static void simpleBLEPeripheral_ProcessOSALMsg( osal_event_hdr_t *pMsg ) +{ +#if DEBUG_INFO + hciEvt_CmdComplete_t *pHciMsg; +#endif + switch ( pMsg->event ){ + case HCI_GAP_EVENT_EVENT:{ + switch( pMsg->status ){ + + case HCI_COMMAND_COMPLETE_EVENT_CODE: +#if DEBUG_INFO + pHciMsg = (hciEvt_CmdComplete_t *)pMsg; + LOG("==> HCI_COMMAND_COMPLETE_EVENT_CODE: %x\n", pHciMsg->cmdOpcode); + //safeToDealloc = gapProcessHCICmdCompleteEvt( (hciEvt_CmdComplete_t *)pMsg ); +#endif + break; + + default: + //safeToDealloc = FALSE; // Send to app + break; + } + } + } +} +/********************************************************************* + * @fn peripheralStateReadRssiCB + * + * @brief Notification from the profile of a state change. + * + * @param newState - new state + * + * @return none + */ +static void peripheralStateReadRssiCB( int8 rssi ) +{ +} + +/********************************************************************* + * @fn peripheralStateNotificationCB + * + * @brief Notification from the profile of a state change. + * + * @param newState - new state + * + * @return none + */ + static void peripheralStateNotificationCB( gaprole_States_t newState ) +{ + switch ( newState ) + { + case GAPROLE_STARTED: + { + // set_mac(); + LOG("Gaprole_start\n"); + osal_set_event(simpleBLEPeripheral_TaskID, SBP_RESET_ADV_EVT); + } + break; + + case GAPROLE_ADVERTISING: + { + LOG("Gaprole_adversting\n"); + osal_stop_timerEx(simpleBLEPeripheral_TaskID, TIMER_BATT_EVT); + adv_count = 0; + //bthome_data_beacon((padv_bthome_ns1_t) gapRole_AdvertData); + //LL_SetAdvData(sizeof(adv_bthome_ns1_t), gapRole_AdvertData); + } + break; + + case GAPROLE_CONNECTED: + adv_con_count = 0; + osal_start_reload_timer(simpleBLEPeripheral_TaskID, TIMER_BATT_EVT, 2*DEF_ADV_INERVAL_MS); + HCI_PPLUS_ConnEventDoneNoticeCmd(simpleBLEPeripheral_TaskID, NULL); + LOG("Gaprole_Connected\n"); + break; + + case GAPROLE_CONNECTED_ADV: + + break; + + case GAPROLE_WAITING: + LOG("Gaprole_Disconnection\n"); + adv_con_count = 1; + osal_stop_timerEx(simpleBLEPeripheral_TaskID, TIMER_BATT_EVT); + break; + + case GAPROLE_WAITING_AFTER_TIMEOUT: + LOG("Gaprole_waitting_after_timerout\n"); + break; + + case GAPROLE_ERROR: + LOG("Gaprole error!\n"); + break; + + default: + break; + } + gapProfileState = newState; + LOG("[GAP ROLE %d]\n",newState); + + VOID gapProfileState; +} + +#if 0 +/********************************************************************* + * @fn simpleProfileChangeCB + * + * @brief Callback from SimpleBLEProfile indicating a value change + * + * @param paramID - parameter ID of the value that was changed. + * + * @return none + */ +static void simpleProfileChangeCB( uint8 paramID ) +{ + + switch( paramID ) + { + case SIMPLEPROFILE_CHAR1: + + break; + + default: + // not process other attribute change + break; + } +} +#endif + +/********************************************************************* +*********************************************************************/ diff --git a/src/TestTHB2/source/thservice.c b/src/TestTHB2/source/thservice.c new file mode 100644 index 0000000..416cb49 --- /dev/null +++ b/src/TestTHB2/source/thservice.c @@ -0,0 +1,391 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "types.h" +#include "OSAL.h" +#include "linkdb.h" +#include "att.h" +#include "gatt.h" +#include "gatt_uuid.h" +#include "gatt_profile_uuid.h" +#include "gattservapp.h" +#include "peripheral.h" +#include "hiddev.h" + +#include "thservice.h" +#include "sensor.h" +/********************************************************************* + MACROS +*/ +/********************************************************************* + CONSTANTS +*/ + +#define TEMP_LEVEL_VALUE_IDX 2 // Position of temp level in attribute array +#define TEMP_LEVEL_VALUE_CCCD_IDX 3 // Position of temp level CCCD in attribute array +#define HUMI_LEVEL_VALUE_IDX 5 // Position of humi level in attribute array +#define HUMI_LEVEL_VALUE_CCCD_IDX 6 // Position of humi level CCCD in attribute array + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ +// Battery service +CONST uint8 temphumServUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(ENV_SENSING_SERV_UUID), HI_UINT16(ENV_SENSING_SERV_UUID) +}; + +// Temperatyre level characteristic +CONST uint8 tempLevelUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(TEMPERATYRE_UUID), HI_UINT16(TEMPERATYRE_UUID) +}; + +// Humidity level characteristic +CONST uint8 humiLevelUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(HUMIDITY_UUID), HI_UINT16(HUMIDITY_UUID) +}; + + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +// Application callback +static thServiceCB_t thServiceCB; + +/********************************************************************* + Profile Attributes - variables +*/ + +// TH Service attribute +static CONST gattAttrType_t thService = { ATT_BT_UUID_SIZE, temphumServUUID }; + +// TH level characteristic +static uint8 thProps = GATT_PROP_READ | GATT_PROP_NOTIFY; + +static gattCharCfg_t tempLevelClientCharCfg[GATT_MAX_NUM_CONN]; +static gattCharCfg_t humiLevelClientCharCfg[GATT_MAX_NUM_CONN]; + + +/********************************************************************* + Profile Attributes - Table +*/ + +static gattAttribute_t thAttrTbl[] = +{ + // 0 TH Service + { + { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */ + GATT_PERMIT_READ, /* permissions */ + 0, /* handle */ + (uint8*)& thService /* pValue */ + }, + + // 1 Temp Level Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &thProps + }, + + // 2 Temp Level Value + { + { ATT_BT_UUID_SIZE, tempLevelUUID }, + GATT_PERMIT_READ, + 0, + (uint8_t*)&measured_data.temp + }, + + // 3 Temp Level Client Characteristic Configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8*)& tempLevelClientCharCfg + }, + + // 4 Humi Level Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &thProps + }, + + // 5 Humi Level Value + { + { ATT_BT_UUID_SIZE, humiLevelUUID }, + GATT_PERMIT_READ, + 0, + (uint8_t*)&measured_data.humi + }, + + // 6 Humi Level Client Characteristic Configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8*)& humiLevelClientCharCfg + }, + +}; + + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static uint8 thReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ); +static bStatus_t thWriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ); +static void thNotifyCB( linkDBItem_t* pLinkItem ); + +/********************************************************************* + PROFILE CALLBACKS +*/ +// TH Service Callbacks +CONST gattServiceCBs_t thCBs = +{ + thReadAttrCB, // Read callback function pointer + thWriteAttrCB, // Write callback function pointer + NULL // Authorization callback function pointer +}; + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/********************************************************************* + @fn TH_AddService + + @brief Initializes the Battery Service by registering + GATT attributes with the GATT server. + + @return Success or Failure +*/ +bStatus_t TH_AddService( void ) +{ + uint8 status = SUCCESS; + // Initialize Client Characteristic Configuration attributes + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, tempLevelClientCharCfg ); + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, humiLevelClientCharCfg ); + // Register GATT attribute list and CBs with GATT Server App + status = GATTServApp_RegisterService( thAttrTbl, + GATT_NUM_ATTRS( thAttrTbl ), + &thCBs ); + return ( status ); +} + +/********************************************************************* + @fn Batt_Register + + @brief Register a callback function with the Battery Service. + + @param pfnServiceCB - Callback function. + + @return None. +*/ +extern void TH_Register( thServiceCB_t pfnServiceCB ) +{ + thServiceCB = pfnServiceCB; +} + +/********************************************************************* + @fn thReadAttrCB + + @brief Read an attribute. + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be read + @param pLen - length of data to be read + @param offset - offset of the first octet to be read + @param maxLen - maximum length of data to be read + + @return Success or Failure +*/ +static uint8 thReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ) +{ + bStatus_t status = SUCCESS; + + // Make sure it's not a blob operation (no attributes in the profile are long) + if ( offset > 0 ) + { + return ( ATT_ERR_ATTR_NOT_LONG ); + } + + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1] ); + + // Measure temp level if reading level + if ( uuid == TEMPERATYRE_UUID ) + { + *pLen = 2; + pValue[0] = measured_data.temp; + pValue[1] = measured_data.temp >> 8; + } + // Measure humi level if reading level + else if ( uuid == HUMIDITY_UUID) + { + *pLen = 2; + pValue[0] = measured_data.humi; + pValue[1] = measured_data.humi >> 8; + } + else + { + status = ATT_ERR_ATTR_NOT_FOUND; + } + return ( status ); +} + +/********************************************************************* + @fn thWriteAttrCB + + @brief Validate attribute data prior to a write operation + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be written + @param len - length of data + @param offset - offset of the first octet to be written + + @return Success or Failure +*/ +static bStatus_t thWriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ) +{ + bStatus_t status = SUCCESS; + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + switch ( uuid ) + { + case GATT_CLIENT_CHAR_CFG_UUID: + status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len, + offset, GATT_CLIENT_CFG_NOTIFY ); + + if ( status == SUCCESS ) + { + uint16 charCfg = BUILD_UINT16( pValue[0], pValue[1] ); + + if ( thServiceCB ) + { + (*thServiceCB)( (charCfg == GATT_CFG_NO_OPERATION) ? + TEMP_LEVEL_NOTI_DISABLED : + TEMP_LEVEL_NOTI_ENABLED); + } + } + + break; + + default: + status = ATT_ERR_ATTR_NOT_FOUND; + break; + } + + return ( status ); +} + +/********************************************************************* + @fn thNotifyCB + + @brief Send a notification of the level state characteristic. + + @param connHandle - linkDB item + + @return None. +*/ +static void thNotifyCB( linkDBItem_t* pLinkItem ) +{ + attHandleValueNoti_t noti; + + if ( pLinkItem->stateFlags & LINK_CONNECTED ) + { + if ( GATTServApp_ReadCharCfg( pLinkItem->connectionHandle, + tempLevelClientCharCfg ) + & GATT_CLIENT_CFG_NOTIFY ) + { + noti.handle = thAttrTbl[TEMP_LEVEL_VALUE_IDX].handle; + noti.len = 2; + noti.value[0] = measured_data.temp; + noti.value[1] = measured_data.temp >> 8; + GATT_Notification( pLinkItem->connectionHandle, ¬i, FALSE ); + } + + if ( GATTServApp_ReadCharCfg( pLinkItem->connectionHandle, + humiLevelClientCharCfg ) + & GATT_CLIENT_CFG_NOTIFY ) + { + noti.handle = thAttrTbl[HUMI_LEVEL_VALUE_IDX].handle; + noti.len = 2; + noti.value[0] = measured_data.humi; + noti.value[1] = measured_data.humi >> 8; + GATT_Notification( pLinkItem->connectionHandle, ¬i, FALSE ); + } + } +} + +/********************************************************************* + @fn thNotifyLevelState + + @brief Send a notification of the battery level state + characteristic if a connection is established. + + @return None. +*/ +void TH_NotifyLevel(void) +{ + // Execute linkDB callback to send notification + linkDB_PerformFunc( thNotifyCB ); +} + +/********************************************************************* + @fn TH_HandleConnStatusCB + + @brief TH Service link status change handler function. + + @param connHandle - connection handle + @param changeType - type of change + + @return none +*/ +void TH_HandleConnStatusCB( uint16 connHandle, uint8 changeType ) +{ + // Make sure this is not loopback connection + if ( connHandle != LOOPBACK_CONNHANDLE ) + { + // Reset Client Char Config if connection has dropped + if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) || + ( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && + ( !linkDB_Up( connHandle ) ) ) ) + { + GATTServApp_InitCharCfg( connHandle, tempLevelClientCharCfg ); + GATTServApp_InitCharCfg( connHandle, humiLevelClientCharCfg ); + } + } +} + + +/********************************************************************* +*********************************************************************/ diff --git a/src/TestTHB2/source/thservice.h b/src/TestTHB2/source/thservice.h new file mode 100644 index 0000000..29276ed --- /dev/null +++ b/src/TestTHB2/source/thservice.h @@ -0,0 +1,115 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#ifndef _THSERVICE_H_ +#define _THSERVICE_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + CONSTANTS +*/ +#define ENV_SENSING_SERV_UUID 0x181A +#define TEMPERATYRE_UUID 0x2A6E +#define HUMIDITY_UUID 0x2A6F + + +// Battery Service Get/Set Parameters +#define BATT_PARAM_LEVEL 0 +#define BATT_PARAM_CRITICAL_LEVEL 1 +#define BATT_PARAM_SERVICE_HANDLE 2 +#define BATT_PARAM_BATT_LEVEL_IN_REPORT 3 + +// Callback events +#define TEMP_LEVEL_NOTI_ENABLED 1 +#define TEMP_LEVEL_NOTI_DISABLED 2 + + +/********************************************************************* + TYPEDEFS +*/ + +// TH Service callback function +typedef void (*thServiceCB_t)(uint8 event); + +// TH measure HW setup function +typedef void (*thServiceSetupCB_t)(void); + +// TH measure percentage calculation function +typedef uint8 (*thServiceCalcCB_t)(uint16 adcVal); + +// TH measure HW teardown function +typedef void (*thServiceTeardownCB_t)(void); + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + Profile Callbacks +*/ + + +/********************************************************************* + API FUNCTIONS +*/ + +/********************************************************************* + @fn Batt_AddService + + @brief Initializes the Battery service by registering + GATT attributes with the GATT server. + + @return Success or Failure +*/ +extern bStatus_t TH_AddService( void ); + +/********************************************************************* + @fn Batt_Register + + @brief Register a callback function with the Battery Service. + + @param pfnServiceCB - Callback function. + + @return None. +*/ +extern void TH_Register( thServiceCB_t pfnServiceCB ); + +/********************************************************************* + @fn Batt_HandleConnStatusCB + + @brief Battery Service link status change handler function. + + @param connHandle - connection handle + @param changeType - type of change + + @return none +*/ +void TH_HandleConnStatusCB( uint16 connHandle, uint8 changeType ); + +/********************************************************************* + @fn thNotifyLevelState + + @brief Send a notification of the battery level state + characteristic if a connection is established. + + @return None. +*/ +void TH_NotifyLevel(void); +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* _THSERVICE_H_ */ diff --git a/src/components/arch/cm0/core_bumbee_m0.h b/src/components/arch/cm0/core_bumbee_m0.h new file mode 100644 index 0000000..70babad --- /dev/null +++ b/src/components/arch/cm0/core_bumbee_m0.h @@ -0,0 +1,88 @@ + +#ifndef PHY_BUMBEE_M0_H +#define PHY_BUMBEE_M0_H + +#ifdef __cplusplus +extern "C" { +#endif + + + + + +/* ================================================================================ */ +/* ================ Processor and Core Peripheral Section ================ */ +/* ================================================================================ */ + +/* ------- Start of section using anonymous unions and disabling warnings ------- */ +#if defined (__CC_ARM) + #pragma push + #pragma anon_unions +#elif defined (__ICCARM__) + #pragma language=extended +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wc11-extensions" + #pragma clang diagnostic ignored "-Wreserved-id-macro" +#elif defined (__GNUC__) + /* anonymous unions are enabled by default */ +#elif defined (__TMS470__) + /* anonymous unions are enabled by default */ +#elif defined (__TASKING__) + #pragma warning 586 +#elif defined (__CSMC__) + /* anonymous unions are enabled by default */ +#else + #warning Not supported compiler type +#endif + + +/* -------- Configuration of the Cortex-M0 Processor and Core Peripherals ------- */ +//#define __CM0_REV 0x0000U /* Core revision r0p0 */ +//#define __MPU_PRESENT 0U /* MPU present or not */ +//#define __VTOR_PRESENT 0U /* no VTOR present*/ +#define __NVIC_PRIO_BITS 2U /* Number of Bits used for Priority Levels */ +//#define __Vendor_SysTickConfig 0U /* Set to 1 if different SysTick Config is used */ + +#include "core_cm0.h" /* Processor and core peripherals */ +#include "system_ARMCM0.h" /* System Header */ + +#define NVIC_GetPendingIRQs() (NVIC->ISPR[0U]) +#define NVIC_ClearPendingIRQs(icpr) (NVIC->ICPR[0U] = (unsigned int)icpr) +#define NVIC_SetPendingIRQs(ispr) (NVIC->ISPR[0U] = (unsigned int)ispr) + +#define NVIC_GetEnableIRQs() (NVIC->ISER[0U]) +#define NVIC_DisableIRQs(irqs) (NVIC->ICER[0U] = (unsigned int)irqs) +#define NVIC_EnableIRQs(iser) (NVIC->ISER[0U] = (unsigned int)iser) + +#define NVIC_ClearWakeupIRQ(irqn) +#define NVIC_SetWakeupIRQ(irqn) + + +/* -------- End of section using anonymous unions and disabling warnings -------- */ +#if defined (__CC_ARM) + #pragma pop +#elif defined (__ICCARM__) + /* leave anonymous unions enabled */ +#elif (__ARMCC_VERSION >= 6010050) + #pragma clang diagnostic pop +#elif defined (__GNUC__) + /* anonymous unions are enabled by default */ +#elif defined (__TMS470__) + /* anonymous unions are enabled by default */ +#elif defined (__TASKING__) + #pragma warning restore +#elif defined (__CSMC__) + /* anonymous unions are enabled by default */ +#else + #warning Not supported compiler type +#endif + + + + +#ifdef __cplusplus +} +#endif + +#endif /* PHY_BUMBEE_M0 */ diff --git a/src/components/ble/controller/ll.h b/src/components/ble/controller/ll.h new file mode 100644 index 0000000..77758a3 --- /dev/null +++ b/src/components/ble/controller/ll.h @@ -0,0 +1,3452 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +/******************************************************************************* + Filename: ll.h + Revised: + Revision: + + Description: This file contains the Link Layer (LL) API for the Bluetooth + Low Energy (BLE) Controller. It provides the defines, types, + and functions for all supported Bluetooth Low Energy (BLE) + commands. + + This API is based on the Bluetooth Core Specification, + V4.0.0, Vol. 6. + + +*******************************************************************************/ + +#ifndef LL_H +#define LL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* + * INCLUDES + */ +#include "bcomdef.h" +#include "timer.h" +#include "ll_def.h" +/******************************************************************************* + * MACROS + */ + +// check if connection parameter ranges for CI (min/max), SL, and LSTO are valid +#define LL_INVALID_CONN_TIME_PARAM( ciMin, ciMax, sl, lsto ) \ + (((ciMin) < LL_CONN_INTERVAL_MIN) || \ + ((ciMin) > LL_CONN_INTERVAL_MAX) || \ + ((ciMax) < LL_CONN_INTERVAL_MIN) || \ + ((ciMax) > LL_CONN_INTERVAL_MAX) || \ + ((ciMax) < (ciMin)) || \ + ((sl) > LL_SLAVE_LATENCY_MAX) || \ + ((lsto) < LL_CONN_TIMEOUT_MIN) || \ + ((lsto) > LL_CONN_TIMEOUT_MAX)) + +// check if the CI/SL/LSTO combination is valid +// based on: LSTO > (1 + Slave Latency) * (Connection Interval * 2) +// Note: The CI * 2 requirement based on ESR05 V1.0, Erratum 3904. +// Note: LSTO time is normalized to units of 1.25ms (i.e. 10ms = 8 * 1.25ms). +#define LL_INVALID_CONN_TIME_PARAM_COMBO( ci, sl, lsto ) \ + ((uint32)((lsto)*8) <= ((uint32)(1+(sl)) * (uint32)((ci)*2))) + +#define LL_TIME_DELTA(T1, T2) ((T2 >= T1) ? (T2 - T1) : (BASE_TIME_UNITS - T1 + T2)) + + +/******************************************************************************* + * CONSTANTS + */ + +/* +** LL API Status Codes +** +** Note: These status values map directly to the HCI Error Codes. +** Per the Bluetooth Core Specification, V4.0.0, Vol. 2, Part D. +*/ +#define LL_STATUS_SUCCESS 0x00 // Success +#define LL_STATUS_ERROR_UNKNOWN_CONN_HANDLE 0x02 // Unknown Connection Identifier +#define LL_STATUS_ERROR_INACTIVE_CONNECTION 0x02 // Unknown Connection Identifier for now; may be needed for multiple connections +#define LL_STATUS_ERROR_AUTH_FAILURE 0x05 // Authentication Failure +#define LL_STATUS_ERROR_PIN_OR_KEY_MISSING 0x06 // Pin or Key Missing +#define LL_STATUS_ERROR_OUT_OF_CONN_RESOURCES 0x07 // Memory Capacity Exceeded +#define LL_STATUS_ERROR_OUT_OF_TX_MEM 0x07 // Memory Capacity Exceeded +#define LL_STATUS_ERROR_OUT_OF_RX_MEM 0x07 // Memory Capacity Exceeded +#define LL_STATUS_ERROR_OUT_OF_HEAP 0x07 // Memory Capacity Exceeded +#define LL_STATUS_ERROR_WL_TABLE_FULL 0x07 // Memory Capacity Exceeded +#define LL_STATUS_ERROR_RL_TABLE_FULL 0x07 // Memory Capacity Exceeded +#define LL_STATUS_ERROR_PAL_TABLE_FULL 0x07 // Memory Capacity Exceeded +#define LL_STATUS_ERROR_TX_DATA_QUEUE_FULL 0x07 // Memory Capacity Exceeded +#define LL_STATUS_ERROR_TX_DATA_QUEUE_EMPTY 0x07 // Memory Capacity Exceeded +#define LL_STATUS_ERROR_CONNECTION_TIMEOUT 0x08 // Connection Timeout +#define LL_STATUS_ERROR_CONNECTION_LIMIT_EXCEEDED 0x09 // Connection Limit Exceeded +#define LL_STATUS_ERROR_COMMAND_DISALLOWED 0x0C // Command Disallowed +#define LL_STATUS_ERROR_DUE_TO_LIMITED_RESOURCES 0x0D // Command Rejected Due To Limited Resources +#define LL_STATUS_ERROR_DUE_TO_DELAYED_RESOURCES 0x0D // Command Delayed Due To Limited Resources +#define LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED 0x11 // Unsupported Feature or Parameter Value +#define LL_STATUS_ERROR_UNEXPECTED_PARAMETER 0x12 // Invalid HCI Command Parameters +#define LL_STATUS_ERROR_ILLEGAL_PARAM_COMBINATION 0x12 // Invalid HCI Command Parameters +#define LL_STATUS_ERROR_BAD_PARAMETER 0x12 // Invalid HCI Command Parameters or 0x30: Parameter Out of Mandatory Range? +#define LL_STATUS_ERROR_UNKNOWN_ADV_EVT_TYPE 0x12 // Invalid HCI Command Parameters or 0x30: Parameter Out of Mandatory Range? +#define LL_STATUS_ERROR_PEER_TERM 0x13 // Remote User Terminated Connection +#define LL_STATUS_ERROR_PEER_DEVICE_TERM_LOW_RESOURCES 0x14 // Remote Device Terminated Connection Due To Low Resources +#define LL_STATUS_ERROR_PEER_DEVICE_TERM_POWER_OFF 0x15 // Remote Device Terminated Connection Due To Power Off +#define LL_STATUS_ERROR_HOST_TERM 0x16 // Connection Terminated By Local Host +#define LL_STATUS_ERROR_UNSUPPORTED_REMOTE_FEATURE 0x1A // Unsupported Remote Feature + +// 2020-01-23 add error Code +#define LL_STATUS_ERROR_INVALID_LMP_LL_PARAMETER 0x1E + +#define LL_STATUS_ERROR_WL_ENTRY_NOT_FOUND 0x1F // Unspecified Error +#define LL_STATUS_ERROR_WL_TABLE_EMPTY 0x1F // Unspecified Error +#define LL_STATUS_ERROR_RL_ENTRY_NOT_FOUND 0x1F // Unspecified Error +#define LL_STATUS_ERROR_RL_TABLE_EMPTY 0x1F // Unspecified Error +#define LL_STATUS_ERROR_RNG_FAILURE 0x1F // Unspecified Error +#define LL_STATUS_ERROR_DISCONNECT_IMMEDIATE 0x1F // Unspecified Error +#define LL_STATUS_ERROR_DATA_PACKET_QUEUED 0x1F // Unspecified Error + +// 2020-01-23 add error Code +#define LL_STATUS_ERROR_UNSUPPORT_LMP_LL_PARAMETER 0x20 + +#define LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE 0x21 // Role Change Not Allowed +#define LL_STATUS_ERROR_LL_TIMEOUT 0x22 // Link Layer Response Timeout +#define LL_STATUS_ERROR_LL_TIMEOUT_HOST 0x22 // Link Layer Response Timeout +#define LL_STATUS_ERROR_LL_TIMEOUT_PEER 0x22 // Link Layer Response Timeout +#define LL_STATUS_ERROR_LL_PROCEDURE_COLLISION 0x23 // Link Layer Procedure collision + + +#define LL_STATUS_ERROR_INSTANT_PASSED 0x28 // Instant Passed +#define LL_STATUS_ERROR_INSTANT_PASSED_HOST 0x28 // Instant Passed +#define LL_STATUS_ERROR_INSTANT_PASSED_PEER 0x28 // Instant Passed +#define LL_STATUS_ERROR_KEY_PAIRING_NOT_SUPPORTED 0x29 // Pairing With Unit Key Not Supported +#define LL_STATUS_ERROR_DIFF_TRANSACTION_COLLISION 0x2A // Link Layer collision in same procedure + + +#define LL_STATUS_ERROR_NO_ADV_CHAN_FOUND 0x30 // Parameter Out Of Mandatory Range +#define LL_STATUS_ERROR_PARAM_OUT_OF_RANGE 0x30 // Parameter Out Of Mandatory Range +#define LL_STATUS_ERROR_UPDATE_CTRL_PROC_PENDING 0x3A // Controller Busy +#define LL_STATUS_ERROR_CTRL_PROC_ALREADY_ACTIVE 0x3A // Controller Busy +#define LL_STATUS_ERROR_VER_INFO_REQ_ALREADY_PENDING 0x3A // Controller Busy +#define LL_STATUS_ERROR_UNACCEPTABLE_CONN_INTERVAL 0x3B // Unacceptable Connection Interval +#define LL_STATUS_ERROR_DIRECTED_ADV_TIMEOUT 0x3C // Directed Advertising Timeout +#define LL_STATUS_ERROR_CONN_TERM_DUE_TO_MIC_FAILURE 0x3D // Connection Terminated Due To MIC Failure +#define LL_STATUS_ERROR_CONN_FAILED_TO_BE_ESTABLISHED 0x3E // Connection Failed To Be Established +#define LL_STATUS_ERROR_SYNC_FAILED_TO_BE_ESTABLISHED 0x3E // Connection Failed To Be Established +#define LL_STATUS_ERROR_CONN_TIMING_FAILURE 0x3F // MAC Connection Failed +#define LL_STATUS_ERROR_COARSE_CLK_ADJ_REJECT 0x40 // Coarse Clock Adjustment Rejected but Will Try to Adjust Using Clock Dragging +#define LL_STATUS_ERROR_TYPE0_SUBMAP_NOT_DEF 0x41 // Type0 Submap Not Defined +#define LL_STATUS_ERROR_UNKNOWN_ADV_ID 0x42 // Unknown Advertising Identifier +#define LL_STATUS_ERROR_LIMIT_REACHED 0x43 // Limit Reached +#define LL_STATUS_ERROR_OP_CANCEL_BY_HOST 0x44 // Operation Cancelled by Host +#define LL_STATUS_ERROR_PACKET_TOO_LONG 0x45 // Packet Too Long + +// Internal +#define LL_STATUS_DISABLE_LATENCY_INACTIVE_CONN 0x81 +#define LL_STATUS_DISABLE_LATENCY_DISABLED 0x82 +#define LL_STATUS_DISABLE_LATENCY_PENDING 0x83 +#define LL_STATUS_DISABLE_LATENCY_MISS_EVT 0x84 + +#define LL_STATUS_DISABLE_LATENCY_FAIL 0x8F +#define LL_STATUS_WARNING_WAITING_LLIRQ 0xFE // only used internally, so value doesn't matter + +#define LL_STATUS_WARNING_TX_DISABLED 0xFF // only used internally, so value doesn't matter +#define LL_STATUS_WARNING_FLAG_UNCHANGED 0xFF // only used internally, so value doesn't matter + +// Encryption Key Request Reason Codes +#define LL_ENC_KEY_REQ_ACCEPTED LL_STATUS_SUCCESS +#define LL_ENC_KEY_REQ_REJECTED LL_STATUS_ERROR_PIN_OR_KEY_MISSING +#define LL_ENC_KEY_REQ_UNSUPPORTED_FEATURE LL_STATUS_ERROR_UNSUPPORTED_REMOTE_FEATURE + +// Disconnect Reason Codes +#define LL_SUPERVISION_TIMEOUT_TERM LL_STATUS_ERROR_CONNECTION_TIMEOUT +#define LL_PEER_REQUESTED_TERM LL_STATUS_ERROR_PEER_TERM +#define LL_PEER_REQUESTED_LOW_RESOURCES_TERM LL_STATUS_ERROR_PEER_DEVICE_TERM_LOW_RESOURCES +#define LL_PEER_REQUESTED_POWER_OFF_TERM LL_STATUS_ERROR_PEER_DEVICE_TERM_POWER_OFF +#define LL_HOST_REQUESTED_TERM LL_STATUS_ERROR_HOST_TERM +#define LL_CTRL_PKT_TIMEOUT_TERM LL_STATUS_ERROR_LL_TIMEOUT +#define LL_CTRL_PKT_TIMEOUT_HOST_TERM LL_STATUS_ERROR_LL_TIMEOUT_HOST +#define LL_CTRL_PKT_TIMEOUT_PEER_TERM LL_STATUS_ERROR_LL_TIMEOUT_PEER +#define LL_CTRL_PKT_INSTANT_PASSED_TERM LL_STATUS_ERROR_INSTANT_PASSED +#define LL_CTRL_PKT_INSTANT_PASSED_HOST_TERM LL_STATUS_ERROR_INSTANT_PASSED_HOST +#define LL_CTRL_PKT_INSTANT_PASSED_PEER_TERM LL_STATUS_ERROR_INSTANT_PASSED_PEER +#define LL_UNACCEPTABLE_CONN_INTERVAL_TERM LL_STATUS_ERROR_UNACCEPTABLE_CONN_INTERVAL +#define LL_MIC_FAILURE_TERM LL_STATUS_ERROR_CONN_TERM_DUE_TO_MIC_FAILURE +#define LL_CONN_ESTABLISHMENT_FAILED_TERM LL_STATUS_ERROR_CONN_FAILED_TO_BE_ESTABLISHED + +// Disconnect API Parameter +#define LL_DISCONNECT_AUTH_FAILURE LL_STATUS_ERROR_AUTH_FAILURE +#define LL_DISCONNECT_REMOTE_USER_TERM LL_STATUS_ERROR_PEER_TERM +#define LL_DISCONNECT_REMOTE_DEV_LOW_RESOURCES LL_STATUS_ERROR_PEER_DEVICE_TERM_LOW_RESOURCES +#define LL_DISCONNECT_REMOTE_DEV_POWER_OFF LL_STATUS_ERROR_PEER_DEVICE_TERM_POWER_OFF +#define LL_DISCONNECT_UNSUPPORTED_REMOTE_FEATURE LL_STATUS_ERROR_UNSUPPORTED_REMOTE_FEATURE +#define LL_DISCONNECT_KEY_PAIRING_NOT_SUPPORTED LL_STATUS_ERROR_KEY_PAIRING_NOT_SUPPORTED +#define LL_DISCONNECT_UNACCEPTABLE_CONN_INTERVAL LL_STATUS_ERROR_UNACCEPTABLE_CONN_INTERVAL + + +// LL Advertiser Events +#define LL_ADV_CONNECTABLE_UNDIRECTED_EVT 0 +#define LL_ADV_CONNECTABLE_HDC_DIRECTED_EVT 1 // High Duty Cycle +#define LL_ADV_SCANNABLE_UNDIRECTED_EVT 2 +#define LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT 3 +#define LL_ADV_CONNECTABLE_LDC_DIRECTED_EVT 4 // Low Duty Cycle + +// LL Address Type +#define LL_DEV_ADDR_TYPE_PUBLIC 0 +#define LL_DEV_ADDR_TYPE_RANDOM 1 +#define LL_DEV_ADDR_TYPE_RPA_PUBLIC 2 // Controller generates Resolvable Private Address based on the local IRK from resolving list. If resolving list contains no matching entry, use public address +#define LL_DEV_ADDR_TYPE_RPA_RANDOM 3 // Controller generates Resolvable Private Address based on the local IRK from resolving list. If resolving list contains no matching entry, use random address from LE_Set_Random_Address. + + + +// Advertiser White List Policy +#define LL_ADV_WL_POLICY_ANY_REQ 0 // any scan request or connect request +#define LL_ADV_WL_POLICY_WL_SCAN_REQ 1 // any connect request, white list scan request +#define LL_ADV_WL_POLICY_WL_CONNECT_REQ 2 // any scan request, white list connect request +#define LL_ADV_WL_POLICY_WL_ALL_REQ 3 // white list scan request and connect request + +// Scanner White List Policy +#define LL_SCAN_WL_POLICY_ANY_ADV_PKTS 0 +#define LL_SCAN_WL_POLICY_USE_WHITE_LIST 1 +#define LL_SCAN_WL_POLICY_BLE42_1 2 +#define LL_SCAN_WL_POLICY_BLE42_2 3 + + +// Initiator White List Policy +#define LL_INIT_WL_POLICY_USE_PEER_ADDR 0 +#define LL_INIT_WL_POLICY_USE_WHITE_LIST 1 + +// Black List Control +#define LL_SET_BLACKLIST_DISABLE 0 +#define LL_SET_BLACKLIST_ENABLE 1 + +// Advertiser Commands +#define LL_ADV_MODE_OFF 0 +#define LL_ADV_MODE_ON 1 +#define LL_ADV_MODE_RESERVED 2 + +// LL Scan Commands +#define LL_SCAN_STOP 0 +#define LL_SCAN_START 1 + +// LL Scan Filtering +#define LL_FILTER_REPORTS_DISABLE 0 +#define LL_FILTER_REPORTS_ENABLE 1 + +// LL Scan Types +#define LL_SCAN_PASSIVE 0 +#define LL_SCAN_ACTIVE 1 + +// LL Tx Power Types +#define LL_READ_CURRENT_TX_POWER_LEVEL 0 +#define LL_READ_MAX_TX_POWER_LEVEL 1 + +// Data Fragmentation Flag +#define LL_DATA_FIRST_PKT_HOST_TO_CTRL 0 +#define LL_DATA_CONTINUATION_PKT 1 +#define LL_DATA_FIRST_PKT_CTRL_TO_HOST 2 + +// Connection Complete Role +#define LL_LINK_CONNECT_COMPLETE_MASTER 0 +#define LL_LINK_CONNECT_COMPLETE_SLAVE 1 + +// Encryption Related +#define LL_ENCRYPTION_OFF 0 +#define LL_ENCRYPTION_ON 1 + +// Feature Set Related +#define LL_MAX_FEATURE_SET_SIZE 8 // in bytes +// +#define LL_FEATURE_RFU 0 // all bits in a byte +#define LL_FEATURE_ENCRYPTION 1 // byte 0, bit 0 +#define LL_FEATURE_EXT_REJECT_IND 4 // byte 0, bit 0 +#define LL_FEATURE_DATA_LENGTH_EXTENSION 0x20 // byte 0, bit 0 + +#define LL_FEATURE_2M_PHY 0x01 // byte 1, bit 0 +#define LL_FEATURE_CODED_PHY 0x08 // byte 1, bit 3 + +#define LL_FEATURE_CSA2 0x40 // byte 1, bit 6 + +// 2020-01-15 add +// CODE PHY feature +#define LL_FEATURE_CODE_PHY_IDX 1 // byte 1 +#define LL_FEATURE_CODE_PHY 0x08 +// extended advertisingCTE feature +#define LL_FEATURE_EXT_ADV_IDX 1 +#define LL_FEATURE_EXT_ADV 0x10 +// periodic advertising +#define LL_FEATURE_PRD_ADV_IDX 1 +#define LL_FEATURE_PRD_ADV 0x20 +// Channel selection Algorithm #2 +#define LL_FEATURE_CSA2_IDX 1 +#define LL_FEATURE_CSA2 0x40 + +// CTE FEATURE +#define LL_CTE_FEATURE_IDX 2 +#define LL_CONN_CTE_REQ 0x02 +#define LL_CONN_CTE_RSP 0x04 +#define LL_CONNLESS_CTE_TRANSMITER 0x08 +#define LL_CONNLESS_CTE_RECEIVER 0x10 +#define LL_AOD_SUPPORT 0x20 +#define LL_AOA_SUPPORT 0x40 + + +// Receive Flow Control +#define LL_DISABLE_RX_FLOW_CONTROL 0 +#define LL_ENABLE_RX_FLOW_CONTROL 1 + +// Direct Test Mode +#define LL_DIRECT_TEST_NUM_RF_CHANS 40 // PHY_NUM_RF_CHANS +#define LL_DIRECT_TEST_MAX_PAYLOAD_LEN 37 +// +#define LL_DIRECT_TEST_PAYLOAD_PRBS9 0 +#define LL_DIRECT_TEST_PAYLOAD_0x0F 1 +#define LL_DIRECT_TEST_PAYLOAD_0x55 2 +#define LL_DIRECT_TEST_PAYLOAD_PRBS15 3 +#define LL_DIRECT_TEST_PAYLOAD_0xFF 4 +#define LL_DIRECT_TEST_PAYLOAD_0x00 5 +#define LL_DIRECT_TEST_PAYLOAD_0xF0 6 +#define LL_DIRECT_TEST_PAYLOAD_0xAA 7 +#define LL_DIRECT_TEST_PAYLOAD_UNDEFINED 0xFF +// +#define LL_DIRECT_TEST_MODE_TX 0 +#define LL_DIRECT_TEST_MODE_RX 1 +// +#define LL_RF_RSSI_UNDEFINED PHY_RSSI_VALUE_INVALID + +// Vendor Specific +#define LL_EXT_RX_GAIN_STD 0 +#define LL_EXT_RX_GAIN_HIGH 1 +// +#define LL_EXT_TX_POWER_MINUS_23_DBM 0 +#define LL_EXT_TX_POWER_MINUS_6_DBM 1 +#define LL_EXT_TX_POWER_0_DBM 2 +#define LL_EXT_TX_POWER_4_DBM 3 + + +// +#define LL_EXT_DISABLE_ONE_PKT_PER_EVT 0 +#define LL_EXT_ENABLE_ONE_PKT_PER_EVT 1 +// +#define LL_EXT_DISABLE_CLK_DIVIDE_ON_HALT 0 +#define LL_EXT_ENABLE_CLK_DIVIDE_ON_HALT 1 +// +#define LL_EXT_NV_NOT_IN_USE 0 +#define LL_EXT_NV_IN_USE 1 +// +#define LL_EXT_DISABLE_FAST_TX_RESP_TIME 0 +#define LL_EXT_ENABLE_FAST_TX_RESP_TIME 1 +// +#define LL_EXT_DISABLE_SL_OVERRIDE 0 +#define LL_EXT_ENABLE_SL_OVERRIDE 1 +// +#define LL_EXT_TX_MODULATED_CARRIER 0 +#define LL_EXT_TX_UNMODULATED_CARRIER 1 +// +#define LL_EXT_SET_FREQ_TUNE_DOWN 0 +#define LL_EXT_SET_FREQ_TUNE_UP 1 + +// +#define LL_EXT_PER_RESET 0 +#define LL_EXT_PER_READ 1 +// +#define LL_EXT_HALT_DURING_RF_DISABLE 0 +#define LL_EXT_HALT_DURING_RF_ENABLE 1 +// +#define LL_EXT_SET_USER_REVISION 0 +#define LL_EXT_READ_BUILD_REVISION 1 +// +#define LL_EXT_RESET_SYSTEM_DELAY 100 // in ms +#define LL_EXT_RESET_SYSTEM_HARD 0 +#define LL_EXT_RESET_SYSTEM_SOFT 1 +// +#define LL_EXT_DISABLE_OVERLAPPED_PROCESSING 0 +#define LL_EXT_ENABLE_OVERLAPPED_PROCESSING 1 +// +#define LL_EXT_DISABLE_NUM_COMPL_PKTS_ON_EVENT 0 +#define LL_EXT_ENABLE_NUM_COMPL_PKTS_ON_EVENT 1 + + +/* +** Event Parameters +*/ + +// Advertising Report Data +#define LL_ADV_RPT_ADV_IND LL_ADV_CONNECTABLE_UNDIRECTED_EVT +#define LL_ADV_RPT_ADV_DIRECT_IND LL_ADV_CONNECTABLE_HDC_DIRECTED_EVT +#define LL_ADV_RPT_ADV_SCANNABLE_IND LL_ADV_SCANNABLE_UNDIRECTED_EVT +#define LL_ADV_RPT_ADV_NONCONN_IND LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT +#define LL_ADV_RPT_SCAN_RSP (LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT + 1) +#define LL_ADV_RPT_INVALID 0xFF +// +#define LL_RSSI_NOT_AVAILABLE 127 + +// Sleep Clock Accuracy (SCA) +#define LL_SCA_500_PPM 0 +#define LL_SCA_250_PPM 1 +#define LL_SCA_150_PPM 2 +#define LL_SCA_100_PPM 3 +#define LL_SCA_75_PPM 4 +#define LL_SCA_50_PPM 5 +#define LL_SCA_30_PPM 6 +#define LL_SCA_20_PPM 7 + + +// Default SCA +//#define LL_SCA_MASTER_DEFAULT 5 // 50ppm (ordinal value) +#define LL_SCA_MASTER_DEFAULT 0 // 500ppm (ordinal value) +#define LL_SCA_SLAVE_DEFAULT 500 // 500ppm + +// LL Advertiser Channels +#define LL_ADV_CHAN_37 1 +#define LL_ADV_CHAN_38 2 +#define LL_ADV_CHAN_39 4 +#define LL_ADV_CHAN_ALL (LL_ADV_CHAN_37 | LL_ADV_CHAN_38 | LL_ADV_CHAN_39) +#define LL_ADV_CHAN_MAP_DEFAULT LL_ADV_CHAN_ALL + +#define LL_ADV_CHAN_FIRST 37 +#define LL_ADV_CHAN_LAST 39 + +// max future number of events for an update to parameters or data channel +#define LL_MAX_UPDATE_COUNT_RANGE 32767 + +// Extended Header Flags +#define LE_EXT_HDR_ADVA_PRESENT_BITMASK 0x01 +#define LE_EXT_HDR_TARGETA_PRESENT_BITMASK 0x02 +#define LE_EXT_HDR_CTE_INFO_PRESENT_BITMASK 0x04 +#define LE_EXT_HDR_ADI_PRESENT_BITMASK 0x08 +#define LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK 0x10 +#define LE_EXT_HDR_SYNC_INFO_PRESENT_BITMASK 0x20 +#define LE_EXT_HDR_TX_PWR_PRESENT_BITMASK 0x40 +#define LE_EXT_HDR_RFU_PRESENT_BITMASK 0x80 + + + +// extended advertisement Macros +#define LE_ADV_PROP_CONN_BITMASK 0x00000001 +#define LE_ADV_PROP_SCAN_BITMASK 0x00000002 +#define LE_ADV_PROP_DIRECT_BITMASK 0x00000004 +#define LE_ADV_PROP_HI_DC_CONN_BITMASK 0x00000008 +#define LE_ADV_PROP_LEGACY_BITMASK 0x00000010 +#define LE_ADV_PROP_ANON_BITMASK 0x00000020 // applicable to extended adv only +#define LE_ADV_PROP_TX_POWER_BITMASK 0x00000040 // applicable to extended adv & periodic adv + +/* TODO: update according to spec + 0x00 Intermediate fragment of fragmented extended advertising data +0x01 First fragment of fragmented extended advertising data +0x02 Last fragment of fragmented extended advertising data +0x03 Complete extended advertising data +0x04 Unchanged data (just update the Advertising DID) */ + +#define BLE_EXT_ADV_OP_INTERM_FRAG 0x00 +#define BLE_EXT_ADV_OP_FIRST_FRAG 0x01 +#define BLE_EXT_ADV_OP_LAST_FRAG 0x02 +#define BLE_EXT_ADV_OP_COMPLETE_DATA 0x03 +#define BLE_EXT_ADV_OP_UNCHANGED_DATA 0x04 + +#define BLE_EXT_ADV_FRAG_ENABLED 0x00 +#define BLE_EXT_ADV_FRAG_DISABLED 0x01 + +#define LL_EXT_ADV_MODE_NOCONN_NOSC 0 +#define LL_EXT_ADV_MODE_AUX_CONN_RSP 0 +#define LL_EXT_ADV_MODE_CONN 1 +#define LL_EXT_ADV_MODE_SC 2 +#define LL_EXT_ADV_MODE_RFU 3 + +// AuxPtr +// channel Idx(6bits) | CA(1bit) | offset Unit(1 bit) | Aux offset(13bits) | Aux PHY +#define LL_AUX_PTR_CHN_IDX_SHIFT 0 +#define LL_AUX_PTR_CA_SHIFT 6 +#define LL_AUX_PTR_OFFSET_UNIT_SHIFT 7 +#define LL_AUX_PTR_AUX_OFFSET_SHIFT 8 +#define LL_AUX_PTR_AUX_PHY_SHIFT 21 + +#define LL_AUX_PTR_CHN_IDX_MASK 0x3F +#define LL_AUX_PTR_CA_MASK 0x1 +#define LL_AUX_PTR_OFFSET_UNIT_MASK 0x1 +#define LL_AUX_PTR_AUX_OFFSET_MASK 0x1FFF +#define LL_AUX_PTR_AUX_PHY_MASK 0x7 + + +// for Periodic scanner +#define LL_PERIODIC_ADV_CREATE_SYNC_USING_ADV_LIST_BITMASK 0x00000001 +#define LL_PERIODIC_ADV_CREATE_SYNC_INIT_RPT_DISABLE_BITMASK 0x00000002 + +/* +** Miscellaneous +*/ +#define BLE_PKT40_LEN 42 +#define BLE_PKT51_LEN 262 + +#define BLE_PKT_VERSION_4_0 0 +#define BLE_PKT_VERSION_5_1 1 + + +//====== add after BBB ROM code release +#define LL_EXT_ADV_PROP_ADV_IND 0x13 //0b00010011 +#define LL_EXT_ADV_PROP_ADV_LDC_ADV 0x15 //0b00010101 +#define LL_EXT_ADV_PROP_ADV_HDC_ADV 0x1d //0b00011101 +#define LL_EXT_ADV_PROP_ADV_SCAN_IND 0x12 //0b00010010 +#define LL_EXT_ADV_PROP_ADV_NOCONN_IND 0x10 //0b00010000 + +#define LL_CHN_SEL_ALGORITHM_1 0 +#define LL_CHN_SEL_ALGORITHM_2 1 + + +/******************************************************************************* + * TYPEDEFS + */ + + + +/******************************************************************************* + * LOCAL VARIABLES + */ + +/******************************************************************************* + * GLOBAL VARIABLES + */ +/******************************************************************************* + * LL OSAL Functions + */ + +/******************************************************************************* + * @fn LL_Init + * + * @brief This is the Link Layer task initialization called by OSAL. It + * must be called once when the software system is started and + * before any other function in the LL API is called. + * + * input parameters + * + * @param taskId - Task identifier assigned by OSAL. + * + * output parameters + * + * @param None. + * + * @return None. + */ +extern void LL_Init( uint8 taskId ); + + +/******************************************************************************* + * @fn LL_ProcessEvent + * + * @brief This is the Link Layer process event handler called by OSAL. + * + * input parameters + * + * @param taskId - Task identifier assigned by OSAL. + * events - Event flags to be processed by this task. + * + * output parameters + * + * @param None. + * + * @return Unprocessed event flags. + */ +extern uint16 LL_ProcessEvent( uint8 task_id, uint16 events ); + + +/******************************************************************************* + * LL API for HCI + */ + +/******************************************************************************* + * @fn LL_TX_bm_alloc API + * + * @brief This API is used to allocate memory using buffer management. + * + * Note: This function should never be called by the application. + * It is only used by HCI and L2CAP_bm_alloc. + * + * input parameters + * + * @param size - Number of bytes to allocate from the heap. + * + * output parameters + * + * @param None. + * + * @return Pointer to buffer, or NULL. + */ +extern void *LL_TX_bm_alloc( uint16 size ); + + +/******************************************************************************* + * @fn LL_RX_bm_alloc API + * + * @brief This API is used to allocate memory using buffer management. + * + * Note: This function should never be called by the application. + * It is only used by HCI and L2CAP_bm_alloc. + * + * input parameters + * + * @param size - Number of bytes to allocate from the heap. + * + * output parameters + * + * @param None. + * + * @return Pointer to buffer, or NULL. + */ +extern void *LL_RX_bm_alloc( uint16 size ); + + +/******************************************************************************* + * @fn LL_Reset API + * + * @brief This function is used by the HCI to reset and initialize the + * LL Controller. + * + * input parameters + * + * @param None. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS + */ +extern llStatus_t LL_Reset( void ); + + +/******************************************************************************* + * @fn LL_ReadBDADDR API + * + * @brief This API is called by the HCI to read the controller's + * own public device address. + * + * Note: The device's address is stored in NV memory. + * + * input parameters + * + * @param None. + * + * output parameters + * + * @param bdAddr - A pointer to a buffer to hold this device's address. + * + * @return LL_STATUS_SUCCESS + */ +extern llStatus_t LL_ReadBDADDR( uint8 *bdAddr ); + + +/******************************************************************************* + * + * @fn LL_SetRandomAddress API + * + * @brief This function is used to save this device's random address. It + * is provided by the Host for devices that are unable to store a + * IEEE assigned public address in NV memory. + * + * input parameters + * + * @param devAddr - Pointer to a random address (LSO..MSO). + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS + * + */ +extern llStatus_t LL_SetRandomAddress( uint8 *devAddr ); + +/******************************************************************************* + * @fn LL_ClearWhiteList API + * + * @brief This API is called by the HCI to clear the White List. + * + * Note: If Scanning is enabled using filtering, and the white + * list policy is "Any", then this command will be + * disallowed. + * + * input parameters + * + * @param None. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS + */ +extern llStatus_t LL_ClearWhiteList( void ); + + +/******************************************************************************* + * @fn LL_AddWhiteListDevice API + * + * @brief This API is called by the HCI to add a device address and its + * type to the White List. + * + * input parameters + * + * @param devAddr - Pointer to a 6 byte device address. + * @param addrType - Public or Random device address. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + * LL_STATUS_ERROR_WL_TABLE_FULL + */ +extern llStatus_t LL_AddWhiteListDevice( uint8 *devAddr, + uint8 addrType ); + +/******************************************************************************* + * @fn LL_RemoveWhiteListDevice API + * + * @brief This API is called by the HCI to remove a device address and + * it's type from the White List. + * + * input parameters + * + * @param devAddr - Pointer to a 6 byte device address. + * @param addrType - Public or Random device address. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + * LL_STATUS_ERROR_WL_TABLE_EMPTY, + * LL_STATUS_ERROR_WL_ENTRY_NOT_FOUND + */ +extern llStatus_t LL_RemoveWhiteListDevice( uint8 *devAddr, + uint8 addrType ); + + +/******************************************************************************* + * @fn LL_ReadWlSize API + * + * @brief This API is called by the HCI to get the total number of white + * list entries that can be stored in the Controller. + * + * input parameters + * + * @param None. + * + * output parameters + * + * @param *numEntries - Total number of available White List entries. + * + * @return LL_STATUS_SUCCESS + */ +extern llStatus_t LL_ReadWlSize( uint8 *numEntries ); + + +/******************************************************************************* + * @fn LL_NumEmptyWlEntries API + * + * @brief This API is called by the HCI to get the number of White List + * entries that are empty. + * + * input parameters + * + * @param None. + * + * output parameters + * + * @param *numEmptyEntries - number of empty entries in the White List. + * + * @return LL_STATUS_SUCCESS + */ +extern llStatus_t LL_NumEmptyWlEntries( uint8 *numEmptyEntries ); + + +/******************************************************************************* + * @fn LL_Encrypt API + * + * @brief This API is called by the HCI to request the LL to encrypt the + * data in the command using the key given in the command. + * + * Note: The parameters are byte ordered MSO to LSO. + * + * input parameters + * + * @param *key - A 128 bit key to be used to calculate the + * session key. + * @param *plaintextData - A 128 bit block that is to be encrypted. + * + * output parameters + * + * @param *encryptedData - A 128 bit block that is encrypted. + * + * @param None. + * + * @return LL_STATUS_SUCCESS + */ +extern llStatus_t LL_Encrypt( uint8 *key, + uint8 *plaintextData, + uint8 *encryptedData ); + + +/******************************************************************************* + * @fn LL_Rand API + * + * @brief This API is called by the HCI to request the LL Controller to + * provide a data block with random content. + * + * Note: If the radio is in use, then this operation has to be + * delayed until the radio finishes. + * + * input parameters + * + * @param *randData - Pointer to buffer to place a random block of data. + * @param dataLen - The length of the random data block, from 1-255. + * + * output parameters + * + * @param *randData - Pointer to buffer containing a block of true random + * data. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_DUE_TO_LIMITED_RESOURCES, + * LL_STATUS_ERROR_COMMAND_DISALLOWED, + * LL_STATUS_ERROR_BAD_PARAMETER, LL_STATUS_ERROR_RNG_FAILURE + */ +extern llStatus_t LL_Rand( uint8 *randData, + uint8 dataLen ); + + +/******************************************************************************* + * @fn LL_ReadSupportedStates API + * + * @brief This function is used to provide the HCI with the Link Layer + * supported states and supported state/role combinations. + * + * input parameters + * + * @param None. + * + * output parameters + * + * @param *states - Eight byte Bit map of supported states/combos. + * + * @return LL_STATUS_SUCCESS + */ +extern llStatus_t LL_ReadSupportedStates( uint8 *states ); + + +/******************************************************************************* + * @fn LL_ReadLocalSupportedFeatures API + * + * @brief This API is called by the HCI to read the controller's + * Features Set. The Controller indicates which features it + * supports. + * + * input parameters + * + * @param featureSet - A pointer to the Feature Set where each bit: + * 0: Feature not supported. + * 1: Feature supported by controller. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS + */ +extern llStatus_t LL_ReadLocalSupportedFeatures( uint8 *featureSet ); + + +/******************************************************************************* + * @fn LL_ReadLocalVersionInfo API + * + * @brief This API is called by the HCI to read the controller's + * Version information. + * + * input parameters + * + * @param None. + * + * output parameters + * + * @param verNum - Version of the Bluetooth Controller specification. + * @param comId - Company identifier of the manufacturer of the + * Bluetooth Controller. + * @param subverNum - A unique value for each implementation or revision + * of an implementation of the Bluetooth Controller. + * + * @return LL_STATUS_SUCCESS + */ +extern llStatus_t LL_ReadLocalVersionInfo( uint8 *verNum, + uint16 *comId, + uint16 *subverNum ); + + +/******************************************************************************* + * @fn LL_CtrlToHostFlowControl API + * + * @brief This function is used to indicate if the LL enable/disable + * receive FIFO processing. This function provides support for + * Controller to Host flow control. + * + * input parameters + * + * @param mode: LL_ENABLE_RX_FLOW_CONTROL, LL_DISABLE_RX_FLOW_CONTROL + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS + */ +extern llStatus_t LL_CtrlToHostFlowControl( uint8 mode ); + +/******************************************************************************* + * @fn LL_ReadRemoteVersionInfo API + * + * @brief This API is called by the HCI to read the peer controller's + * Version Information. If the peer's Version Information has + * already been received by its request for our Version + * Information, then this data is already cached and can be + * directly returned to the Host. If the peer's Version Information + * is not already cached, then it will be requested from the peer, + * and when received, returned to the Host via the + * LL_ReadRemoteVersionInfoCback callback. + * + * Note: Only one Version Indication is allowed for a connection. + * + * input parameters + * + * @param None. + * + * output parameters + * + * @param connId - The LL connection ID on which to send this data. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_VER_IND_ALREADY_SENT + */ +extern llStatus_t LL_ReadRemoteVersionInfo( uint16 connId ); + +/******************************************************************************* + * @fn LL_ReadTxPowerLevel + * + * @brief This function is used to read a connection's current transmit + * power level or the maximum transmit power level. + * + * input parameters + * + * @param connId - The LL connection handle. + * @param type - LL_READ_CURRENT_TX_POWER_LEVEL or + * LL_READ_MAX_TX_POWER_LEVEL + * @param *txPower - A signed value from -30..+20, in dBm. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + * LL_STATUS_ERROR_PARAM_OUT_OF_RANGE, + * LL_STATUS_ERROR_INACTIVE_CONNECTION + */ +llStatus_t LL_ReadTxPowerLevel( uint8 connId, + uint8 type, + int8 *txPower ); + +// A1 ROM metal change add +/******************************************************************************* + * @fn LL_SetTxPowerLevel + * + * @brief This function is used to set transmit power level + * + * input parameters + * + * @param txPower - The transmit power level to be set + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + * LL_STATUS_ERROR_INACTIVE_CONNECTION + */ +llStatus_t LL_SetTxPowerLevel( int8 txPower ); + +/******************************************************************************* + * @fn LL_ReadChanMap API + * + * @brief This API is called by the HCI to read the channel map that the + * LL controller is using for the LL connection. + * + * input parameters + * + * @param connId - The LL connection handle. + * + * output parameters + * + * @param chanMap - A five byte array containing one bit per data channel + * where a 1 means the channel is "used" and a 0 means + * the channel is "unused". + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + * LL_STATUS_ERROR_INACTIVE_CONNECTION + */ +extern llStatus_t LL_ReadChanMap( uint8 connId, + uint8 *chanMap ); + + + +/******************************************************************************* + * @fn LL_ReadRssi API + * + * @brief This API is called by the HCI to request RSSI. If there is an + * active connection for the given connection ID, then the RSSI of + * the last received data packet in the LL will be returned. If a + * receiver Modem Test is running, then the RF RSSI for the last + * received data will be returned. If no valid RSSI value is + * available, then LL_RSSI_NOT_AVAILABLE will be returned. + * + * input parameters + * + * @param connId - The LL connection ID on which to read last RSSI. + * + * output parameters + * + * @param *lastRssi - The last data RSSI received. + * Range: -127dBm..+20dBm, 127=Not Available. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + * LL_STATUS_ERROR_INACTIVE_CONNECTION + */ +extern llStatus_t LL_ReadRssi( uint16 connId, + int8 *lastRssi ); +extern llStatus_t LL_ReadFoff( uint16 connId, + uint16 *foff ); +extern llStatus_t LL_ReadCarrSens( uint16 connId, + uint8 *carrSense ); + +/******************************************************************************* + * @fn LL_Disconnect API + * + * @brief This API is called by the HCI to terminate a LL connection. + * + * input parameters + * + * @param connId - The LL connection ID on which to send this data. + * @param reason - The reason for the Host connection termination. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + * LL_STATUS_ERROR_INACTIVE_CONNECTION + * LL_STATUS_ERROR_CTRL_PROC_ALREADY_ACTIVE + */ +extern llStatus_t LL_Disconnect( uint16 connId, + uint8 reason ); + +/******************************************************************************* + * @fn LL_TxData API + * + * @brief This API is called by the HCI to transmit a buffer of data on a + * given LL connection. If fragmentation is supported, the HCI must + * also indicate whether this is the first Host packet, or a + * continuation Host packet. When fragmentation is not supported, + * then a start packet should always specified. If the device is in + * a connection as a Master and the current connection ID is the + * connection for this data, or is in a connection as a Slave, then + * the data is written to the TX FIFO (even if the radio is + * curerntly active). If this is a Slave connection, and Fast TX is + * enabled and Slave Latency is being used, then the amount of time + * to the next event is checked. If there's at least a connection + * interval plus some overhead, then the next event is re-aligned + * to the next event boundary. Otherwise, in all cases, the buffer + * pointer will be retained for transmission, and the callback + * event LL_TxDataCompleteCback will be generated to the HCI when + * the buffer pointer is no longer needed by the LL. + * + * Note: If the return status is LL_STATUS_ERROR_OUT_OF_TX_MEM, + * then the HCI must not release the buffer until it receives + * the LL_TxDataCompleteCback callback, which indicates the + * LL has copied the transmit buffer. + * + * Note: The HCI should not call this routine if a buffer is still + * pending from a previous call. This is fatal! + * + * Note: If the connection should be terminated within the LL + * before the Host knows, attempts by the HCI to send more + * data (after receiving a LL_TxDataCompleteCback) will + * fail (LL_STATUS_ERROR_INACTIVE_CONNECTION). + * + * input parameters + * + * @param connId - The LL connection ID on which to send this data. + * @param *pBuf - A pointer to the data buffer to transmit. + * @param pktLen - The number of bytes to transmit on this connection. + * @param fragFlag - LL_DATA_FIRST_PKT_HOST_TO_CTRL: + * Indicates buffer is the start of a + * Host-to-Controller packet. + * LL_DATA_CONTINUATION_PKT: + * Indicates buffer is a continuation of a + * Host-to-Controller packet. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + * LL_STATUS_ERROR_INACTIVE_CONNECTION, + * LL_STATUS_ERROR_OUT_OF_TX_MEM, + * LL_STATUS_ERROR_UNEXPECTED_PARAMETER + */ +extern llStatus_t LL_TxData( uint16 connId, + uint8 *pBuf, + uint8 pktLen, + uint8 fragFlag ); + + +/******************************************************************************* + * @fn LL_DirectTestTxTest API + * + * @brief This function is used to initiate a BLE PHY level Transmit Test + * in Direct Test Mode where the DUT generates test reference + * packets at fixed intervals. This test will make use of the + * nanoRisc Raw Data Transmit and Receive task. + * + * Note: The BLE device is to transmit at maximum power. + * Note: A LL reset should be issued when done using DTM! + * + * input parameters + * + * @param txFreq - Tx RF frequency k=0..39, where F=2402+(k*2MHz). + * @param payloadLen - Number of bytes (0..37)in payload for each packet. + * @param payloadType - The type of pattern to transmit. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + * LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE + */ +extern llStatus_t LL_DirectTestTxTest( uint8 txFreq, + uint8 payloadLen, + uint8 payloadType ); + + +/******************************************************************************* + * @fn LL_DirectTestRxTest API + * + * @brief This function is used to initiate a BLE PHY level Receive Test + * in Direct Test Mode where the DUT receives test reference + * packets at fixed intervals. This test will make use of the + * nanoRisc Raw Data Transmit and Receive task. The received + * packets are verified based on the CRC, and metrics are kept. + * + * Note: A LL reset should be issued when done using DTM! + * + * input parameters + * + * @param rxFreq - Rx RF frequency k=0..39, where F=2402+(k*2MHz). + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + * LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE + */ +extern llStatus_t LL_DirectTestRxTest( uint8 rxFreq ); + + +/******************************************************************************* + * @fn LL_DirectTestEnd API + * + * @brief This function is used to end the Direct Test Transmit or Direct + * Test Receive tests executing in Direct Test mode. When the raw + * task is ended, the LL_DirectTestEndDoneCback callback is called. + * If a Direct Test mode operation is not currently active, an + * error is returned. + * + * Note: A LL reset is issued upon completion! + * + * input parameters + * + * @param None. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE + */ +extern llStatus_t LL_DirectTestEnd( void ); + + +/******************************************************************************* + * @fn LL_SetAdvParam API + * + * @brief This API is called by the HCI to set the Advertiser's + * parameters. + * + * input parameters + * @param advIntervalMin - The minimum Adv interval. + * @param advIntervalMax - The maximum Adv interval. + * @param advEvtType - The type of advertisment event. + * @param ownAddrType - The Adv's address type of public or random. + * @param directAddrType - Only used for directed advertising. + * @param *directAddr - Only used for directed advertising (NULL otherwise). + * @param advChanMap - A byte containing 1 bit per advertising + * channel. A bit set to 1 means the channel is + * used. The bit positions define the advertising + * channels as follows: + * Bit 0: 37, Bit 1: 38, Bit 2: 39. + * @param advWlPolicy - The Adv white list filter policy. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + * LL_STATUS_ERROR_NO_ADV_CHAN_FOUND + */ +extern llStatus_t LL_SetAdvParam( uint16 advIntervalMin, + uint16 advIntervalMax, + uint8 advEvtType, + uint8 ownAddrType, + uint8 directAddrType, + uint8 *directAddr, + uint8 advChanMap, + uint8 advWlPolicy ); + +/******************************************************************************* + * @fn LL_SetAdvData API + * + * @brief This API is called by the HCI to set the Advertiser's data. + * + * Note: If the Advertiser is restarted without intervening calls + * to this routine to make updates, then the previously + * defined data will be reused. + * + * Note: If the data happens to be changed while advertising, then + * the new data will be sent on the next advertising event. + * + * input parameters + * + * @param advDataLen - The number of scan response bytes: 0..31. + * @param advData - Pointer to the advertiser data, or NULL. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER + */ +extern llStatus_t LL_SetAdvData( uint8 advDataLen, + uint8 *advData ); + +/******************************************************************************* + * @fn LL_SetScanRspData API + * + * @brief This API is called by the HCI to set the Advertiser's Scan + * Response data. + * + * Note: If the Advertiser is restarted without intervening calls + * to this routine to make updates, then the previously + * defined data will be reused. + * + * input parameters + * + * @param scanRspLen - The number of scan response bytes: 0..31. + * @param *scanRspData - Pointer to the scan response data. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER + */ +extern llStatus_t LL_SetScanRspData( uint8 scanRspLen, + uint8 *scanRspData ); + +/******************************************************************************* + * @fn LL_SetAdvControl API + * + * @brief This API is called by the HCI to request the Controller to start + * or stop advertising. + * + * input parameters + * + * @param advMode - LL_ADV_MODE_ON or LL_ADV_MODE_OFF. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_UNEXPECTED_PARAMETER, + * LL_STATUS_ERROR_BAD_PARAMETER, + * LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE, + * LL_STATUS_ERROR_COMMAND_DISALLOWED + */ +extern llStatus_t LL_SetAdvControl( uint8 advMode ); + +/******************************************************************************* + * @fn LL_ReadAdvChanTxPower + * + * @brief This function is used to read the transmit power level used + * for BLE advertising channel packets. Currently, only two + * settings are possible, a standard setting of 0 dBm, and a + * maximum setting of 4 dBm. + * + * input parameters + * + * @param *txPower - A non-null pointer. + * + * output parameters + * + * @param *txPower - A signed value from -20..+10, in dBm. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_PARAM_OUT_OF_RANGE + */ +extern llStatus_t LL_ReadAdvChanTxPower( int8 *txPower ); + +/******************************************************************************* + * @fn LL_SetScanParam API + * + * @brief This API is called by the HCI to set the Scanner's parameters. + * + * input parameters + * + * @param scanType - Passive or Active scan type. + * @param scanInterval - Time between scan events. + * @param scanWindow - Duration of a scan. When the same as the scan + * interval, then scan continuously. + * @param ownAddrType - Address type (Public or Random) to use in the + * SCAN_REQ packet. + * @param advWlPolicy - Either allow all Adv packets, or only those that + * are in the white list. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER + */ +extern llStatus_t LL_SetScanParam( uint8 scanType, + uint16 scanInterval, + uint16 scanWindow, + uint8 ownAddrType, + uint8 advWlPolicy ); + +/******************************************************************************* + * @fn LL_SetScanControl API + * + * @brief This API is called by the HCI to start or stop the Scanner. It + * also specifies whether the LL will filter duplicate advertising + * reports to the Host, or generate a report for each packet + * received. + * + * input parameters + * + * @param scanMode - LL_SCAN_START or LL_SCAN_STOP. + * @param filterReports - LL_FILTER_REPORTS_DISABLE or + * LL_FILTER_REPORTS_ENABLE + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + * LL_STATUS_ERROR_UNEXPECTED_PARAMETER, + * LL_STATUS_ERROR_OUT_OF_TX_MEM, + * LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE + */ +extern llStatus_t LL_SetScanControl( uint8 scanMode, + uint8 filterReports ); + +/******************************************************************************* + * @fn LL_EncLtkReply API + * + * @brief This API is called by the HCI to provide the controller with + * the Long Term Key (LTK) for encryption. This command is + * actually a reply to the link layer's LL_EncLtkReqCback, which + * provided the random number and encryption diversifier received + * from the Master during an encryption setup. + * + * Note: The key parameter is byte ordered LSO to MSO. + * + * input parameters + * + * @param connId - The LL connection ID on which to send this data. + * @param *key - A 128 bit key to be used to calculate the session key. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS + */ +extern llStatus_t LL_EncLtkReply( uint16 connId, + uint8 *key ); + +/******************************************************************************* + * @fn LL_EncLtkNegReply API + * + * @brief This API is called by the HCI to indicate to the controller + * that the Long Term Key (LTK) for encryption can not be provided. + * This command is actually a reply to the link layer's + * LL_EncLtkReqCback, which provided the random number and + * encryption diversifier received from the Master during an + * encryption setup. How the LL responds to the negative reply + * depends on whether this is part of a start encryption or a + * re-start encryption after a pause. For the former, an + * encryption request rejection is sent to the peer device. For + * the latter, the connection is terminated. + * + * input parameters + * + * @param connId - The LL connection ID on which to send this data. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS + */ +extern llStatus_t LL_EncLtkNegReply( uint16 connId ); + +/******************************************************************************* + * @fn LL_CreateConn API + * + * @brief This API is called by the HCI to create a connection. + * + * input parameters + * + * @param scanInterval - The scan interval. + * @param scanWindow - The scan window. + * @param initWlPolicy - Filter Adv address directly or using WL. + * @param peerAddrType - Peer address is Public or Random. + * @param *peerAddr - The Adv address, or NULL for WL policy. + * @param ownAddrType - This device's address is Public or Random. + * @param connIntervalMin - Defines minimum connection interval value. + * @param connIntervalMax - Defines maximum connection interval value. + * @param connLatency - The connection's Slave Latency. + * @param connTimeout - The connection's Supervision Timeout. + * @param minLength - Info parameter about min length of connection. + * @param maxLength - Info parameter about max length of connection. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE, + * LL_STATUS_ERROR_ILLEGAL_PARAM_COMBINATION, + * LL_STATUS_ERROR_BAD_PARAMETER + */ +extern llStatus_t LL_CreateConn( uint16 scanInterval, + uint16 scanWindow, + uint8 initWlPolicy, + uint8 peerAddrType, + uint8 *peerAddr, + uint8 ownAddrType, + uint16 connIntervalMin, + uint16 connIntervalMax, + uint16 connLatency, + uint16 connTimeout, + uint16 minLength, + uint16 maxLength ); + +/******************************************************************************* + * @fn LL_CreateConnCancel API + * + * @brief This API is called by the HCI to cancel a previously given LL + * connection creation command that is still pending. This command + * should only be used after the LL_CreateConn command as been + * issued, but before the LL_ConnComplete callback. + * + * input parameters + * + * @param None. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_COMMAND_DISALLOWED + */ +extern llStatus_t LL_CreateConnCancel( void ); + +/******************************************************************************* + * @fn LL_ConnActive + * + * @brief This API is called by the HCI to check if a connection + * given by the connection handle is active. + * + * input parameters + * + * @param connId - Connection handle. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + * LL_STATUS_ERROR_INACTIVE_CONNECTION + */ +extern llStatus_t LL_ConnActive( uint16 connId ); + +/******************************************************************************* + * @fn LL_ConnUpdate API + * + * @brief This API is called by the HCI to update the connection + * parameters by initiating a connection update control procedure. + * + * input parameters + * + * @param connId - The connection ID on which to send this data. + * @param connIntervalMin - Defines minimum connection interval value. + * @param connIntervalMax - Defines maximum connection interval value. + * @param connLatency - The connection's Slave Latency. + * @param connTimeout - The connection's Supervision Timeout. + * @param minLength - Info parameter about min length of connection. + * @param maxLength - Info parameter about max length of connection. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + * LL_STATUS_ERROR_INACTIVE_CONNECTION + * LL_STATUS_ERROR_CTRL_PROC_ALREADY_ACTIVE, + * LL_STATUS_ERROR_ILLEGAL_PARAM_COMBINATION + */ +extern llStatus_t LL_ConnUpdate( uint16 connId, + uint16 connIntervalMin, + uint16 connIntervalMax, + uint16 connLatency, + uint16 connTimeout, + uint16 minLength, + uint16 maxLength ); + +/******************************************************************************* + * @fn LL_ChanMapUpdate API + * + * @brief This API is called by the HCI to update the Host data channels + * initiating an Update Data Channel control procedure. + * + * Note: While it isn't specified, it is assumed that the Host + * expects an update channel map on all active connections. + * + * Note: This LL currently only supports one connection. + * + * input parameters + * + * @param chanMap - A five byte array containing one bit per data channel + * where a 1 means the channel is "used". + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + * LL_STATUS_ERROR_ILLEGAL_PARAM_COMBINATION + */ +extern llStatus_t LL_ChanMapUpdate( uint8 *chanMap ); + +/******************************************************************************* + * @fn LL_StartEncrypt API + * + * @brief This API is called by the Master HCI to setup encryption and to + * update encryption keys in the LL connection. If the connection + * is already in encryption mode, then this command will first + * pause the encryption before subsequently running the encryption + * setup. + * + * Note: The parameters are byte ordered LSO to MSO. + * + * input parameters + * + * @param connId - The LL connection ID on which to send this data. + * @param *rand - Random vector used in device identification. + * @param *eDiv - Encrypted diversifier. + * @param *key - A 128 bit key to be used to calculate the session key. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED + */ +extern llStatus_t LL_StartEncrypt( uint16 connId, + uint8 *rand, + uint8 *eDiv, + uint8 *ltk ); + +/******************************************************************************* + * @fn LL_ReadRemoteUsedFeatures API + * + * @brief This API is called by the Master HCI to initiate a feature + * setup control process. + * + * input parameters + * + * @param connId - The LL connection ID on which to send this data. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS + */ +extern llStatus_t LL_ReadRemoteUsedFeatures( uint16 connId ); + + +/* +** Vendor Specific Command API +*/ + +/******************************************************************************* + * @fn LL_EXT_SetRxGain Vendor Specific API + * + * @brief This function is used to to set the RF RX gain. + * + * input parameters + * + * @param rxGain - LL_EXT_RX_GAIN_STD, LL_EXT_RX_GAIN_HIGH + * + * output parameters + * + * @param cmdComplete - Boolean to indicate the command is still pending. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER + */ +extern llStatus_t LL_EXT_SetRxGain( uint8 rxGain, + uint8 *cmdComplete ); + + +/******************************************************************************* + * @fn LL_EXT_SetTxPower Vendor Specific API + * + * @brief This function is used to to set the RF TX power. + * + * input parameters + * + * @param txPower - LL_EXT_TX_POWER_0_DBM, LL_EXT_TX_POWER_4_DBM + * + * output parameters + * + * @param cmdComplete - Boolean to indicate the command is still pending. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER + */ +extern llStatus_t LL_EXT_SetTxPower( uint8 txPower, + uint8 *cmdComplete ); + + + +/******************************************************************************* + * @fn LL_EXT_OnePacketPerEvent Vendor Specific API + * + * @brief This function is used to enable or disable allowing only one + * packet per event. + * + * input parameters + * + * @param control - LL_EXT_ENABLE_ONE_PKT_PER_EVT, + * LL_EXT_DISABLE_ONE_PKT_PER_EVT + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER + */ +extern llStatus_t LL_EXT_OnePacketPerEvent( uint8 control ); + + + +/******************************************************************************* + * @fn LL_EXT_ClkDivOnHalt Vendor Specific API + * + * @brief This function is used to enable or disable dividing down the + * system clock while halted. + * + * Note: This command is disallowed if haltDuringRf is not defined. + * + * input parameters + * + * @param control - LL_EXT_ENABLE_CLK_DIVIDE_ON_HALT, + * LL_EXT_DISABLE_CLK_DIVIDE_ON_HALT + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_COMMAND_DISALLOWED + */ +extern llStatus_t LL_EXT_ClkDivOnHalt( uint8 control ); + + +/******************************************************************************* + * @fn LL_EXT_DeclareNvUsage Vendor Specific API + * + * @brief This HCI Extension API is used to indicate to the Controller + * whether or not the Host will be using the NV memory during BLE + * operations. + * + * input parameters + * + * @param mode - HCI_EXT_NV_IN_USE, HCI_EXT_NV_NOT_IN_USE + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + * LL_STATUS_ERROR_COMMAND_DISALLOWED + */ +extern llStatus_t LL_EXT_DeclareNvUsage( uint8 mode ); + + +/******************************************************************************* + * @fn LL_EXT_Decrypt API + * + * @brief This API is called by the HCI to request the LL to decrypt the + * data in the command using the key given in the command. + * + * Note: The parameters are byte ordered MSO to LSO. + * + * input parameters + * + * @param *key - A 128 bit key to be used to calculate the + * session key. + * @param *encryptedData - A 128 bit block that is encrypted. + * + * output parameters + * + * @param *plaintextData - A 128 bit block that is to be encrypted. + * + * @param None. + * + * @return LL_STATUS_SUCCESS + */ +extern llStatus_t LL_EXT_Decrypt( uint8 *key, + uint8 *encryptedData, + uint8 *plaintextData ); + + +/******************************************************************************* + * @fn LL_EXT_SetLocalSupportedFeatures API + * + * @brief This API is called by the HCI to indicate to the Controller + * which features can or can not be used. + * + * Note: Not all features indicated by the Host to the Controller + * are valid. If invalid, they shall be ignored. + * + * input parameters + * + * @param featureSet - A pointer to the Feature Set where each bit: + * 0: Feature shall not be used. + * 1: Feature can be used. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS + */ +extern llStatus_t LL_EXT_SetLocalSupportedFeatures( uint8 *featureSet ); + + +/******************************************************************************* + * @fn LL_EXT_SetFastTxResponseTime API + * + * @brief This API is used to enable or disable the fast TX response + * time feature. This can be helpful when a short connection + * interval is used in combination with slave latency. In such + * a scenario, the response time for sending the TX data packet + * can effectively shorten or eliminate slave latency, thereby + * increasing power consumption. By disabling, this feature + * trades fast response time for less power consumption. + * + * input parameters + * + * @param control - LL_EXT_ENABLE_FAST_TX_RESP_TIME, + * LL_EXT_DISABLE_FAST_TX_RESP_TIME + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_COMMAND_DISALLOWED, + * LL_STATUS_ERROR_BAD_PARAMETER + */ +extern llStatus_t LL_EXT_SetFastTxResponseTime( uint8 control ); + +/******************************************************************************* + * @fn LL_EXT_SetSlaveLatencyOverride API + * + * @brief This API is used to enable or disable the suspention of slave + * latency. This can be helpful when the Slave application knows + * it will soon receive something that needs to be handled without + * delay. + * + * input parameters + * + * @param control - LL_EXT_DISABLE_SL_OVERRIDE, + * LL_EXT_ENABLE_SL_OVERRIDE + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_COMMAND_DISALLOWED, + * LL_STATUS_ERROR_BAD_PARAMETER + */ +extern llStatus_t LL_EXT_SetSlaveLatencyOverride( uint8 control ); + +/******************************************************************************* + * @fn LL_EXT_ModemTestTx + * + * @brief This API is used start a continuous transmitter modem test, + * using either a modulated or unmodulated carrier wave tone, at + * the frequency that corresponds to the specified RF channel. Use + * LL_EXT_EndModemTest command to end the test. + * + * Note: A LL reset will be issued by LL_EXT_EndModemTest! + * Note: The BLE device will transmit at maximum power. + * Note: This API can be used to verify this device meets Japan's + * TELEC regulations. + * + * input parameters + * + * @param cwMode - LL_EXT_TX_MODULATED_CARRIER, + * LL_EXT_TX_UNMODULATED_CARRIER + * txFreq - Transmit RF channel k=0..39, where BLE F=2402+(k*2MHz). + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + * LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE + */ +extern llStatus_t LL_EXT_ModemTestTx( uint8 cwMode, + uint8 txFreq ); + + +/******************************************************************************* + * @fn LL_EXT_ModemHopTestTx + * + * @brief This API is used to start a continuous transmitter direct test + * mode test using a modulated carrier wave and transmitting a + * 37 byte packet of Pseudo-Random 9-bit data. A packet is + * transmitted on a different frequency (linearly stepping through + * all RF channels 0..39) every 625us. Use LL_EXT_EndModemTest + * command to end the test. + * + * Note: A LL reset will be issued by LL_EXT_EndModemTest! + * Note: The BLE device will transmit at maximum power. + * Note: This API can be used to verify this device meets Japan's + * TELEC regulations. + * + * input parameters + * + * @param None. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE + */ +extern llStatus_t LL_EXT_ModemHopTestTx( void ); + + +/******************************************************************************* + * @fn LL_EXT_ModemTestRx + * + * @brief This API is used to start a continuous receiver modem test + * using a modulated carrier wave tone, at the frequency that + * corresponds to the specific RF channel. Any received data is + * discarded. Receiver gain may be adjusted using the + * LL_EXT_SetRxGain command. RSSI may be read during this test by + * using the LL_ReadRssi command. Use LL_EXT_EndModemTest command + * to end the test. + * + * Note: A LL reset will be issued by LL_EXT_EndModemTest! + * Note: The BLE device will transmit at maximum power. + * + * input parameters + * + * @param rxFreq - Receiver RF channel k=0..39, where BLE F=2402+(k*2MHz). + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + * LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE + */ +extern llStatus_t LL_EXT_ModemTestRx( uint8 rxFreq ); + + +/******************************************************************************* + * @fn LL_EXT_EndModemTest + * + * @brief This API is used to shutdown a modem test. A complete link + * layer reset will take place. + * + * input parameters + * + * @param None. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE + */ +extern llStatus_t LL_EXT_EndModemTest( void ); + + +/******************************************************************************* + * @fn LL_EXT_SetBDADDR + * + * @brief This API is used to set this device's BLE address (BDADDR). + * + * Note: This command is only allowed when the device's state is + * Standby. + * + * input parameters + * + * @param bdAddr - A pointer to a buffer to hold this device's address. + * An invalid address (i.e. all FF's) will restore this + * device's address to the address set at initialization. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + * LL_STATUS_ERROR_COMMAND_DISALLOWED + */ +extern llStatus_t LL_EXT_SetBDADDR( uint8 *bdAddr ); + + +/******************************************************************************* + * @fn LL_EXT_SetSCA + * + * @brief This API is used to set this device's Sleep Clock Accuracy. + * + * Note: For a slave device, this value is directly used, but only + * if power management is enabled. For a master device, this + * value is converted into one of eight ordinal values + * representing a SCA range, as specified in Table 2.2, + * Vol. 6, Part B, Section 2.3.3.1 of the Core specification. + * + * Note: This command is only allowed when the device is not in a + * connection. + * + * Note: The device's SCA value remains unaffected by a HCI_Reset. + * + * input parameters + * + * @param scaInPPM - This device's SCA in PPM from 0..500. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + * LL_STATUS_ERROR_COMMAND_DISALLOWED + */ +extern llStatus_t LL_EXT_SetSCA( uint16 scaInPPM ); + + +/******************************************************************************* + * @fn LL_EXT_SetFreqTune + * + * @brief This API is used to set the Frequncy Tuning up or down. If the + * current setting is already at the max/min value, then no + * update is performed. + * + * Note: This is a Production Test Mode only command! + * + * input parameters + * + * @param step - LL_EXT_SET_FREQ_TUNE_UP or LL_EXT_SET_FREQ_TUNE_DOWN + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER + */ +extern llStatus_t LL_EXT_SetFreqTune( uint8 step ); + + +/******************************************************************************* + * @fn LL_EXT_SaveFreqTune + * + * @brief This API is used to save the current Frequency Tuning value to + * flash memory. It is restored on reboot or wake from sleep. + * + * Note: This is a Production Test Mode only command! + * + * input parameters + * + * @param None. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_COMMAND_DISALLOWED + */ +extern llStatus_t LL_EXT_SaveFreqTune( void ); + + +/******************************************************************************* + * @fn LL_EXT_SetMaxDtmTxPower Vendor Specific API + * + * @brief This function is used to set the max RF TX power to be used + * when using Direct Test Mode. + * + * input parameters + * + * @param txPower - LL_EXT_TX_POWER_MINUS_23_DBM, + * LL_EXT_TX_POWER_MINUS_6_DBM, + * LL_EXT_TX_POWER_0_DBM, + * LL_EXT_TX_POWER_4_DBM + * + * output parameters + * + * @param cmdComplete - Boolean to indicate the command is still pending. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER + */ +extern llStatus_t LL_EXT_SetMaxDtmTxPower( uint8 txPower ); + + + +/******************************************************************************* + * @fn LL_EXT_DisconnectImmed Vendor Specific API + * + * @brief This function is used to disconnect the connection immediately. + * + * Note: The connection (if valid) is immediately terminated + * without notifying the remote device. The Host is still + * notified. + * + * input parameters + * + * @param connId - The LL connection ID on which to send this data. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_INACTIVE_CONNECTION + */ +extern llStatus_t LL_EXT_DisconnectImmed( uint16 connId ); + +/******************************************************************************* + * @fn LL_EXT_PacketErrorRate Vendor Specific API + * + * @brief This function is used to Reset or Read the Packet Error Rate + * counters for a connection. When Reset, the counters are cleared; + * when Read, the total number of packets received, the number of + * packets received with a CRC error, the number of events, and the + * number of missed events are returned via a callback. + * + * Note: The counters are only 16 bits. At the shortest connection + * interval, this provides a bit over 8 minutes of data. + * + * input parameters + * + * @param connId - The LL connection ID on which to send this data. + * @param command - LL_EXT_PER_RESET, LL_EXT_PER_READ + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_INACTIVE_CONNECTION + */ +extern llStatus_t LL_EXT_PacketErrorRate( uint16 connId, uint8 command ); + +/******************************************************************************* + * @fn LL_EXT_PERbyChan Vendor Specific API + * + * @brief This API is called by the HCI to start or end Packet Error Rate + * by Channel counter accumulation for a connection. If the + * pointer is not NULL, it is assumed there is sufficient memory + * for the PER data, per the type perByChan_t. If NULL, then + * the operation is considered disabled. + * + * Note: It is the user's responsibility to make sure there is + * sufficient memory for the data, and that the counters + * are cleared prior to first use. + * + * Note: The counters are only 16 bits. At the shortest connection + * interval, this provides a bit over 8 minutes of data. + * + * input parameters + * + * @param connId - The LL connection ID on which to send this data. + * @param perByChan - Pointer to PER by Channel data, or NULL. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_INACTIVE_CONNECTION + */ +extern llStatus_t LL_EXT_PERbyChan( uint16 connId, perByChan_t *perByChan ); + + + +/******************************************************************************* + * @fn LL_EXT_HaltDuringRf Vendor Specfic API + * + * @brief This function is used to enable or disable halting the + * CPU during RF. The system defaults to enabled. + * + * input parameters + * + * @param mode - LL_EXT_HALT_DURING_RF_ENABLE, + * LL_EXT_HALT_DURING_RF_DISABLE + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_COMMAND_DISALLOWED, + * LL_STATUS_ERROR_BAD_PARAMETER + */ +extern llStatus_t LL_EXT_HaltDuringRf( uint8 mode ); + +/******************************************************************************* + * @fn LL_EXT_AdvEventNotice Vendor Specific API + * + * @brief This API is called to enable or disable a notification to the + * specified task using the specified task event whenever a Adv + * event ends. A non-zero taskEvent value is taken to be "enable", + * while a zero valued taskEvent is taken to be "disable". + * + * input parameters + * + * @param taskID - User's task ID. + * @param taskEvent - User's task event. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER + */ +extern llStatus_t LL_EXT_AdvEventNotice( uint8 taskID, uint16 taskEvent ); + +/******************************************************************************* + * @fn LL_EXT_ConnEventNotice Vendor Specific API + * + * @brief This API is called to enable or disable a notification to the + * specified task using the specified task event whenever a + * Connection event ends. A non-zero taskEvent value is taken to + * be "enable", while a zero valued taskEvent is taken to be + * "disable". + * + * Note: Currently, only a Slave connection is supported. + * + * input parameters + * + * @param taskID - User's task ID. + * @param taskEvent - User's task event. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_INACTIVE_CONNECTION, + * LL_STATUS_ERROR_BAD_PARAMETER + */ +extern llStatus_t LL_EXT_ConnEventNotice( uint8 taskID, uint16 taskEvent ); + + + +/******************************************************************************* + * @fn LL_EXT_BuildRevision Vendor Specific API + * + * @brief This API is used to to set a user revision number or read the + * build revision number. + * + * input parameters + * + * @param mode - LL_EXT_SET_USER_REVISION | + * LL_EXT_READ_BUILD_REVISION + * @param userRevNum - A 16 bit value the user can set as their own + * revision number + * + * output parameters + * + * @param buildRev - Pointer to returned build revision, if any. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER + */ +extern llStatus_t LL_EXT_BuildRevision( uint8 mode, uint16 userRevNum, uint8 *buildRev ); + + +/******************************************************************************* + * @fn LL_EXT_DelaySleep Vendor Specific API + * + * @brief This API is used to to set the sleep delay. + * + * input parameters + * + * @param delay - 0 .. 1000, in milliseconds. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER + */ +extern llStatus_t LL_EXT_DelaySleep( uint16 delay ); + + +/******************************************************************************* + * @fn LL_EXT_ResetSystem Vendor Specific API + * + * @brief This API is used to to issue a soft or hard system reset. + * + * input parameters + * + * @param mode - LL_EXT_RESET_SYSTEM_HARD | LL_EXT_RESET_SYSTEM_SOFT + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER + */ +extern llStatus_t LL_EXT_ResetSystem( uint8 mode ); + + +/******************************************************************************* + * @fn LL_EXT_OverlappedProcessing Vendor Specific API + * + * @brief This API is used to enable or disable overlapped processing. + * + * input parameters + * + * @param mode - LL_EXT_ENABLE_OVERLAPPED_PROCESSING | + * LL_EXT_DISABLE_OVERLAPPED_PROCESSING + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_ERROR_CODE_INVALID_HCI_CMD_PARAMS + */ +extern llStatus_t LL_EXT_OverlappedProcessing( uint8 mode ); + +/******************************************************************************* + * @fn LL_EXT_NumComplPktsLimit Vendor Specific API + * + * @brief This API is used to set the minimum number of + * completed packets which must be met before a Number of + * Completed Packets event is returned. If the limit is not + * reach by the end of the connection event, then a Number of + * Completed Packets event will be returned (if non-zero) based + * on the flushOnEvt flag. + * + * input parameters + * + * @param limit - From 1 to LL_MAX_NUM_DATA_BUFFERS. + * @param flushOnEvt - LL_EXT_DISABLE_NUM_COMPL_PKTS_ON_EVENT | + * LL_EXT_ENABLE_NUM_COMPL_PKTS_ON_EVENT + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS, LL_ERROR_CODE_INVALID_HCI_CMD_PARAMS + */ +extern llStatus_t LL_EXT_NumComplPktsLimit( uint8 limit, + uint8 flushOnEvt ); + + +/* +** LL Callbacks to HCI +*/ + +/******************************************************************************* + * @fn LL_ConnectionCompleteCback Callback + * + * @brief This Callback is used by the LL to indicate to the Host that + * a new connection has been created. For the Slave, this means + * a CONNECT_REQ message was received from an Initiator. For the + * Master, this means a CONNECT_REQ message was sent in response + * to a directed or undirected message addressed to the Initiator. + * + * input parameters + * + * @param reasonCode - LL_STATUS_SUCCESS or ? + * @param connId - The LL connection ID for new connection. + * @param role - LL_LINK_CONNECT_COMPLETE_MASTER or + * LL_LINK_CONNECT_COMPLETE_SLAVE. + * @param peerAddrType - Peer address type (public or random). + * @param peerAddr - Peer address. + * @param connInterval - Connection interval. + * @param slaveLatency - The connection's Slave Latency. + * @param connTimeout - The connection's Supervision Timeout. + * @param clockAccuracy - The sleep clock accurracy of the Master. Only + * valid on the Slave. Set to 0x00 for the Master. + * + * output parameters + * + * @param None. + * + * @return None. + */ +extern void LL_ConnectionCompleteCback( uint8 reasonCode, + uint16 connId, + uint8 role, + uint8 peerAddrType, + uint8 *peerAddr, + uint16 connInterval, + uint16 slaveLatency, + uint16 connTimeout, + uint8 clockAccuracy ); + +/******************************************************************************* + * @fn LL_DisconnectCback Callback + * + * @brief This Callback is used by the LL to indicate to the Host that + * the connection has been terminated. The cause is given by the + * reason code. + * + * input parameters + * + * @param connId - The LL connection ID. + * @param reason - The reason the connection was terminated. + * + * output parameters + * + * @param None. + * + * @return None. + */ +extern void LL_DisconnectCback( uint16 connId, + uint8 reason ); + +/******************************************************************************* + * @fn LL_ConnParamUpdateCback Callback + * + * @brief This Callback is used by the LL to indicate to the Host that + * the update parameters control procedure has completed. It is + * always made to the Master's Host when the update request has + * been sent. It is only made to the Slave's Host when the update + * results in a change to the connection interval, and/or the + * connection latency, and/or the connection timeout. + * + * input parameters + * + * @param connId - The LL connection ID. + * @param connInterval - Connection interval. + * @param connLatency - The connection's Slave Latency. + * @param connTimeout - The connection's Supervision Timeout. + * + * output parameters + * + * @param None. + * + * @return None. + */ +extern void LL_ConnParamUpdateCback( uint16 connId, + uint16 connInterval, + uint16 connLatency, + uint16 connTimeout ); + +/******************************************************************************* + * @fn LL_ReadRemoteVersionInfoCback Callback + * + * @brief This Callback is used by the LL to indicate to the Host the + * requested peer's Version information. + * + * input parameters + * + * @param status - Status of callback. + * @param connId - The LL connection ID. + * @param verNum - Version of the Bluetooth Controller specification. + * @param comId - Company identifier of the manufacturer of the + * Bluetooth Controller. + * @param subverNum - A unique value for each implementation or revision + * of an implementation of the Bluetooth Controller. + * + * output parameters + * + * @param None. + * + * @return None. + */ +extern void LL_ReadRemoteVersionInfoCback( uint8 status, + uint16 connId, + uint8 verNum, + uint16 comId, + uint16 subverNum ); + +/******************************************************************************* + * @fn LL_EncChangeCback Callback + * + * @brief This Callback is used by the LL to indicate to the Host that + * an encryption change has taken place. This results when + * the host performs a LL_StartEncrypt when encryption is not + * already enabled. + * + * Note: If the key request was rejected, then encryption will + * remain off. + * + * input parameters + * + * @param connId - The LL connection ID for new connection. + * @param reason - LL_ENC_KEY_REQ_ACCEPTED or LL_ENC_KEY_REQ_REJECTED. + * @param encEnab - LL_ENCRYPTION_OFF or LL_ENCRYPTION_ON. + * + * output parameters + * + * @param None. + * + * @return None. + */ +extern void LL_EncChangeCback( uint16 connId, + uint8 reason, + uint8 encEnab ); + +/******************************************************************************* + * @fn LL_EncKeyRefreshCback Callback + * + * @brief This Callback is used by the LL to indicate to the Host that + * an encryption key change has taken place. This results when + * the host performs a LL_StartEncrypt when encryption is already + * enabled. + * + * input parameters + * + * @param connId - The LL connection ID for new connection. + * @param reason - LL_ENC_KEY_REQ_ACCEPTED. + * + * output parameters + * + * @param None. + * + * @return None. + */ +extern void LL_EncKeyRefreshCback( uint16 connId, + uint8 reason ); + +/******************************************************************************* + * @fn LL_AdvReportCback Callback + * + * @brief This Callback is used by the LL to provide information about + * advertisers from which an advertising packet was received. + * + * input parameters + * + * @param eventType - Type of advertisement packet received by Scanner + * or Initiator, and scan response for Initiator. + * @param advAddrType - Advertiser address type (public or random). + * @param advAddr - Advertiser address. + * @param dataLen - Size in bytes of advertisement packet. + * @param data - Advertisement data. + * @param rssi - RSSI value (-127..20dBm), or not available + * + * output parameters + * + * @param None. + * + * @return None. + */ +extern void LL_AdvReportCback( uint8 eventType, + uint8 advAddrType, + uint8 *advAddr, + uint8 dataLen, + uint8 *data, + int8 rssi ); + +void LL_AdvSetTerminatedCback(uint8 status, + uint8 adv_handle, + uint16 connHandle, + uint8 Num_Completed_Extended_Advertising_Events); + +extern void LL_ExtAdvReportCback( uint8 advEvt, + uint8 advAddrType, + uint8 *advAddr, + uint8 primaryPHY, + uint8 secondaryPHY, + uint8 advertisingSID, + uint8 txPower, + int8 rssi, + uint16 periodicAdvertisingInterval, + uint8 directAddrType, + uint8 *directAddr, + uint8 dataLen, + uint8 *rptData); + +void LL_PrdAdvReportCback(uint16 syncHandle, + uint8 txPower, + uint8 rssi, + uint8 cteType, + uint8 dataStatus, + uint8 dataLength, + uint8 *data + ); + +void LL_PrdAdvSyncEstablishedCback(uint8 status, + uint16 syncHandle, + uint8 advertisingSID, + uint8 advertiserAddressType, + uint8 *advertiserAddress, + uint8 advertiserPHY, + uint16 periodicAdvertisingInterval, + uint8 advertiserClockAccuracy + ); + +void LL_PrdAdvSyncLostCback(uint16 syncHandle); + +void LL_ChannelSelectionAlgorithmCback(uint16 connHandle, + uint8 chnSel + ); + +void LL_EnhConnectionCompleteCback( uint8 reasonCode, + uint16 connHandle, + uint8 role, + uint8 peerAddrType, + uint8 *peerAddr, + uint8 *localRpaAddr, + uint8 *peerRpaAddr, + uint16 connInterval, + uint16 slaveLatency, + uint16 connTimeout, + uint8 clockAccuracy ); + +/****************************************************************************** + * fn: LL_ConnectionlessIQReportCback + * + * brief: 1ã€usd by the controller to report IQ Information from the CTE of the + * received advertising packet + * 2ã€report IQ Information from the CTE of a received Test Mode packet + * + * date:2020-01-14 + * + * input parameters: + * syncHandle : Identifying the periodic advertising train + * chan_idx : the index of the channel on which the packet has received + * rssi : rssi of the packet , units 0.1 dBm + * rssi_antID : Antenna ID + * cte_type : AOA/AOD CTE Type, AOD with 1us or 2us slots + * slot_duration : switching and sampling slots with 1us or 2us + * packet_status : indicates whether the received packet had a valid CRC + * and if not , whether the controller has determined the + * position and size of the CTE + * PE_Cnt : the value of paEventCounter + * sampCnt : total number of sample pairs + * ISample : the list of the I Sample of the report packets + * QSample : the list of the Q Sample of the report packets + * + * + * output parameters: + * + * Note: Controller shall not generate this event for packets that have a bad CRC + * + * return hciStatus_t + * + ******************************************************************************/ + void LL_ConnectionlessIQReportCback( uint16 syncHandle, + uint8 chan_idx, + int16 rssi, + uint8 rssi_antID, + uint8 cte_type, + uint8 slot_duration, + uint8 packet_status, + uint16 PE_Cnt, + uint8 sampCnt, + uint16 *ISample, + uint16 *QSample); + + +/***************************************************************************************** + * fn: LL_ConnectionIQReportCback + * + * date:2020-01-14 + * + * brief: used by the controller to report the IQ samples from the CTE of a received packet. + * + * input parameters: + * connHandle : identifies the connections that corresponds to the reported information + * rx_PHY : receiver PHY for the connection 1M or 2M + * data_chan_idx: the index of data channel on which the data physical channel PDU has received + * rssi : rssi of the packet , units 0.1 dBm + * rssi_antID : id of the antenna on which the RSSI is measured + * cte_type : AOA/AOD CTE Type, AOD with 1us or 2us slots + * slot_duration: switching and sampling slots with 1us or 2us + * packet_status: indicates whether the received packet had a valid CRC + * and if not , whether the controller has determined the + * position and size of the CTE + * connEventCounter:the value of connection event counter + * sampCnt : total number of sample pairs + * ISample : the list of the I Sample of the report packets + * QSample : the list of the Q Sample of the report packets + * + * + * output parameters: + * + * + * return hciStatus_t + * + *****************************************************************************************/ +void LL_ConnectionIQReportCback( uint16 connHandle, + uint8 rx_PHY, + uint8 data_chan_idx, + int16 rssi, + uint8 rssi_antID, + uint8 cte_type, + uint8 slot_duration, + uint8 packet_status, + uint16 connEventCounter, + uint8 sampCnt, + uint16 *ISample, + uint16 *QSample); + + +/***************************************************************************************** + * fn: LL_CTE_Report_FailedCback + * + * date:2020-01-14 + * + * brief: used by the controller to report an issue following a request to a peer device + * to reply with a packet containing an LL_CTE_RSP PDU and a CTE + * + * + * input parameters: + * status : received LL_CTE_RSP PDU status + * connHandle : connection handle + * + * output parameters: + * + * + * return hciStatus_t + * + *****************************************************************************************/ +void LL_CTE_Report_FailedCback( uint8 status,uint16 connHandle); + +/******************************************************************************* + * @fn LL_ReadRemoteUsedFeaturesCompleteCback Callback + * + * @brief This Callback is used by the LL to indicate to the Host that + * the Read Remote Feature Support command as completed. + * + * input parameters + * + * @param status - SUCCESS or control procedure timeout. + * @param connId - The LL connection ID for new connection. + * @param featureSet - A pointer to the Feature Set. + * + * output parameters + * + * @param None. + * + * @return None. + */ +extern void LL_ReadRemoteUsedFeaturesCompleteCback( uint8 status, + uint16 connId, + uint8 *featureSet ); + + + +/******************************************************************************* + * @fn LL_EncLtkReqCback Callback + * + * @brief This Callback is used by the LL to provide to the Host the + * Master's random number and encryption diversifier, and to + * request the Host's Long Term Key (LTK). + * + * input parameters + * + * @param connId - The LL connection ID for new connection. + * @param randNum - Random vector used in device identification. + * @param encDiv - Encrypted diversifier. + * + * output parameters + * + * @param None. + * + * @return None. + */ +extern void LL_EncLtkReqCback( uint16 connId, + uint8 *randNum, + uint8 *encDiv ); + + +/******************************************************************************* + * @fn LL_DirectTestEndDone Callback + * + * @brief This Callback is used by the LL to notify the HCI that the + * Direct Test End command has completed. + * + * + * input parameters + * + * @param numPackets - The number of packets received. Zero for transmit. + * @param mode - LL_DIRECT_TEST_MODE_TX or LL_DIRECT_TEST_MODE_RX. + * + * output parameters + * + * @param None. + * + * @return LL_STATUS_SUCCESS + */ +extern void LL_DirectTestEndDoneCback( uint16 numPackets, + uint8 mode ); + +/******************************************************************************* + * @fn LL_DataLengthChange Callback + * + * + */ + +extern void LL_DataLengthChangeCback(uint16 connHandle, + uint16 MaxTxOctets, + uint16 MaxTxTime, + uint16 MaxRxOctets, + uint16 MaxRxTime); + + +/******************************************************************************* + * @fn LL_TxDataCompleteCback Callback + * + * @brief This Callback is used by the LL to indicate to the HCI that + * the HCI's buffer is free for its own use again. + * + * input parameters + * + * @param connId - The LL connection ID on which to send this data. + * @param *pBuf - A pointer to the data buffer to transmit, or NULL. + * + * output parameters + * + * @param None. + * + * @return None. + ******************************************************************************/ +extern void LL_TxDataCompleteCback( uint16 connId, + uint8 *pBuf ); + +/******************************************************************************* + * @fn LL_RxDataCompleteCback Callback + * + * @brief This Callback is used by the LL to indicate to the HCI that + * data has been received and placed in the buffer provided by + * the HCI. + * + * input parameters + * + * @param connId - The LL connection ID on which data was received. + * @param *pBuf - A pointer to the receive data buffer provided by + * the HCI. + * @param len - The number of bytes received on this connection. + * @param fragFlag - LL_DATA_FIRST_PKT indicates buffer is the start of + * a Host packet. + * LL_DATA_CONTINUATION_PKT: Indicates buffer is a + * continuation of a Host packet. + * @param rssi - The RSSI of this received packet as a signed byte. + * Range: -127dBm..+20dBm, 127=Not Available. + * + * output parameters + * + * @param **pBuf - A double pointer updated to the next receive data + * buffer, or NULL if no next buffer is available. + * + * @return None. + */ +extern void LL_RxDataCompleteCback( uint16 connId, + uint8 *ppBuf, + uint8 len, + uint8 fragFlag, + int8 rssi ); + + + +/******************************************************************************* + * @fn LL_RandCback API + * + * @brief This Callback is used by the LL to notify the HCI that the true + * random number command has been completed. + * + * Note: The length is always given by B_RANDOM_NUM_SIZE. + * + * input parameters + * + * @param *randData - Pointer to buffer to place a random block of data. + * + * output parameters + * + * @param None. + * + * @return None. + */ +extern void LL_RandCback( uint8 *randData ); + + +/******************************************************************************* + * @fn LL_EXT_SetRxGainCback Callback + * + * @brief This Callback is used by the LL to notify the HCI that the set + * RX gain command has been completed. + * + * input parameters + * + * @param None. + * + * output parameters + * + * @param None. + * + * @return None. + */ +extern void LL_EXT_SetRxGainCback( void ); + + +/******************************************************************************* + * @fn LL_EXT_SetTxPowerCback Callback + * + * @brief This Callback is used by the LL to notify the HCI that the set + * TX power command has been completed. + * + * input parameters + * + * @param None. + * + * output parameters + * + * @param None. + * + * @return None. + */ +extern void LL_EXT_SetTxPowerCback( void ); + + +/******************************************************************************* + * @fn LL_EXT_PacketErrorRateCback Callback + * + * @brief This Callback is used by the LL to notify the HCI that the + * Packet Error Rate Read command has been completed. + * + * Note: The counters are only 16 bits. At the shortest connection + * interval, this provides a bit over 8 minutes of data. + * + * input parameters + * + * @param numPkts - Number of Packets received. + * @param numCrcErr - Number of Packets received with a CRC error. + * @param numEvents - Number of Connection Events. + * @param numPkts - Number of Missed Connection Events. + * + * output parameters + * + * @param None. + * + * @return None. + */ +extern void LL_EXT_PacketErrorRateCback( uint16 numPkts, + uint16 numCrcErr, + uint16 numEvents, + uint16 numMissedEvts ); + + +/******************************************************************************* + * @fn LL_EXT_ExtendRfRangeCback Callback + * + * @brief This Callback is used by the LL to notify the HCI that the + * Extend Rf Range command has been completed. + * + * input parameters + * + * @param None. + * + * output parameters + * + * @param None. + * + * @return None. + */ +//extern void LL_EXT_ExtendRfRangeCback( void ); + +/******************************************************************************* + * @fn LL_PLUS_PerStats_Init + * + * @brief Used to init linklayer per stats + * + * input parameters + * + * @param None. + * + * output parameters + * + * @param None. + * + * @return None. + */ +extern void LL_PLUS_PerStats_Init(perStatsByChan_t* p_per); +/******************************************************************************* + * @fn LL_PLUS_PerStatsReset + * + * @brief Used to reset linklayer per stats + * + * input parameters + * + * @param None. + * + * output parameters + * + * @param None. + * + * @return None. + */ +extern void LL_PLUS_PerStatsReset(void); + + +/******************************************************************************* + * @fn LL_PLUS_PerStasReadByChn + * + * @brief read per stats by data channel id + * + * input parameters + * + * @param None. + * + * output parameters + * + * @param None. + * + * @return None. + */ +extern void LL_PLUS_PerStasReadByChn(uint8 chnId,perStats_t * perStats); + +extern LL_PLUS_AdvDataFilterCB_t LL_PLUS_AdvDataFilterCBack; +extern void LL_PLUS_SetAdvDataFilterCB(LL_PLUS_AdvDataFilterCB_t AdvDataFilterCBack); +extern uint8_t* LL_PLUS_GetAdvDataExtendData(void); +extern void LL_PLUS_SetScanRequestData(uint8 dLen,uint8* pData); + + +extern LL_PLUS_ScanRequestFilterCB_t LL_PLUS_ScanRequestFilterCBack; +extern void LL_PLUS_SetScanRequestFilterCB(LL_PLUS_ScanRequestFilterCB_t ScanRequestFilterCBack); +extern uint8 LL_PLUS_GetScanRequestExtendData(uint8* pData); +extern void LL_PLUS_GetScanerAddr(uint8* pData); +extern void LL_PLUS_SetScanRsqData(uint8 dLen,uint8* pData); + +extern void LL_PLUS_SetScanRsqDataByIndex(uint8 dIdx,uint8 data); + + + +//DLE +extern llStatus_t LL_SetDataLengh( uint16 connId,uint16 TxOctets,uint16 TxTime ); +//extern uint8 LL_PLUS_GetLocalPduDataLength(ll_pdu_length_ctrl_t* pduLen); +extern llStatus_t LL_WriteSuggestedDefaultDataLength(uint16 TxOctets,uint16 TxTime); +extern void LL_DataLengthChangeCback( uint16 connHandle, + uint16 MaxTxOctets, + uint16 MaxTxTime, + uint16 MaxRxOctets, + uint16 MaxRxTime); + + + +//PHY UPDATE + +extern llStatus_t LL_SetDefaultPhyMode( uint16 connId,uint8 allPhy,uint8 txPhy, uint8 rxPhy); +extern llStatus_t LL_SetPhyMode( uint16 connId,uint8 allPhy,uint8 txPhy, uint8 rxPhy,uint16 phyOptions); + + +extern llStatus_t LL_PhyUpdate( uint16 connId ); +extern void LL_PhyUpdateCompleteCback( uint16 connHandle, + uint8 status, + uint8 txPhy, + uint8 rxPhy); + +// Resolving list +extern llStatus_t LL_AddResolvingListLDevice( uint8 addrType, + uint8 *devAddr, + uint8 *peerIrk, + uint8 *localIrk); +extern llStatus_t LL_RemoveResolvingListDevice( uint8 *devAddr, + uint8 addrType ); + +extern llStatus_t LL_ClearResolvingList( void ); + +extern llStatus_t LL_ReadPeerResolvableAddress( uint8 *peerRpa ); + +extern llStatus_t LL_ReadLocalResolvableAddress( uint8 *localRpa ); + +extern llStatus_t LL_ReadResolvingListSize( uint8 *numEntries ); + +extern llStatus_t LL_SetAddressResolutionEnable( uint8 enable ); + + +extern llStatus_t LL_SetResolvablePrivateAddressTimeout( uint16 rpaTimeout ); + +extern llStatus_t LL_PLUS_DisableSlaveLatency(uint8 connId); + +extern llStatus_t LL_PLUS_EnableSlaveLatency(uint8 connId); + +// extended advertisement +llStatus_t LL_InitExtendedAdv( extAdvInfo_t *extAdvInfo, + uint8 extAdvNumber, + uint16 advSetMaxLen); +llStatus_t LL_SetExtAdvSetRandomAddress( uint8 adv_handle, + uint8* random_address); +llStatus_t LL_SetExtAdvParam( uint8 adv_handle, + uint16 adv_event_properties, + uint32 primary_advertising_interval_Min, // 3 octets + uint32 primary_advertising_interval_Max, // 3 octets + uint8 primary_advertising_channel_map, + uint8 own_address_type, + uint8 peer_address_type, + uint8 *peer_address, + uint8 advertising_filter_policy, + int8 advertising_tx_power, + uint8 primary_advertising_PHY, + uint8 secondary_advertising_max_skip, + uint8 secondary_advertising_PHY, + uint8 advertising_SID, + uint8 scan_request_notification_enable, + int8 *selectTxPwr); +llStatus_t LL_SetExtAdvData( uint8 adv_handle, + uint8 operation, + uint8 fragment_preference, + uint8 advertising_data_length, + uint8 *advertising_data); +llStatus_t LL_SetExtScanRspData( uint8 adv_handle, + uint8 operation, + uint8 fragment_preference, + uint8 scan_rsp_data_length, + uint8 *scan_rsp_data); +llStatus_t LL_SetExtAdvEnable(uint8 enable, + uint8 number_of_sets, + uint8 *advertising_handle, + uint16 *duration, + uint8 *max_extended_advertising_events); +llStatus_t LL_ReadMaximumAdvDataLength( uint16 *length ); +llStatus_t LL_ReadNumberOfSupportAdvSet( uint8 *number ); +llStatus_t LL_RemoveAdvSet( uint8 adv_handle); +llStatus_t LL_ClearAdvSets(void); + +llStatus_t LL_SetExtendedScanParameters(uint8 own_address_type, + uint8 scanning_filter_policy, + uint8 scanning_PHYs, + uint8 *scan_type, + uint16 *scan_interval, + uint16 *scan_window); +llStatus_t LL_SetExtendedScanEnable(uint8 enable, + uint8 filter_duplicates, + uint16 duration, + uint16 period); +llStatus_t LL_ExtendedCreateConnection(uint8 initiator_filter_policy, + uint8 own_address_type, + uint8 peer_address_type, + uint8* peer_address, + uint8 initiating_PHYs, + uint16 *scan_interval, + uint16 *scan_window, + uint16 *conn_interval_min, + uint16 *conn_interval_max, + uint16 *conn_latency, + uint16 *supervision_timeout, + uint16 *minimum_CE_length, + uint16 *maximum_CE_length); + + +// extended adv +void llSetupAdvExtIndPDU(extAdvInfo_t *pAdvInfo, periodicAdvInfo_t *pPrdAdv); + +void llSetupAuxAdvIndPDU(extAdvInfo_t *pAdvInfo, periodicAdvInfo_t *pPrdAdv); + +void llSetupAuxChainIndPDU(extAdvInfo_t *pAdvInfo, periodicAdvInfo_t *pPrdAdv); + +void llSetupAuxSyncIndPDU(extAdvInfo_t *pAdvInfo, periodicAdvInfo_t *pPrdAdv); + +void llSetupAuxConnectReqPDU(void); + +void llSetupAuxConnectRspPDU(extAdvInfo_t *pAdvInfo); + +void llSetupAuxScanRspPDU(extAdvInfo_t *pAdvInfo); + +uint8 ll_isLegacyAdv(extAdvInfo_t *pExtAdv); + +/******************************************************************************* + * @fn LL_InitConnectContext + * + * @brief This function initialize the LL connection-orient context + * + * input parameters + * + * @param pConnContext - connection-orient context, the memory is allocated by application + * maxConnNum - the size of connect-orient context + * maxPktPerEventTx/Rx - number of packets transmit/receive per connection event + * + * output parameters + * + * @param None. + * + * @return None. + */ +llStatus_t LL_InitConnectContext(llConnState_t *pConnContext, + uint8 *pConnBuffer, + uint8 maxConnNum, + uint8 maxPktPerEventTx, + uint8 maxPktPerEventRx, + uint8 blePktVersion); + +// extended scan +llStatus_t LL_InitExtendedScan(uint8 *scanDataBuffer, + uint16 scanDataBufferLength); + +llStatus_t LL_InitPeriodicAdv(extAdvInfo_t *extAdvInfo, + periodicAdvInfo_t *periodicAdvInfo, + uint8 periodicAdvSetNumber, + uint16 advSetMaxLen); + + +// Periodic Adv +llStatus_t LL_SetPeriodicAdvParameter(uint8 adv_handle, + uint16 interval_min, + uint16 interval_max, + uint16 adv_event_properties); + + +llStatus_t LL_SetPeriodicAdvData(uint8 adv_handle, + uint8 operation, + uint8 advertising_data_length, + uint8 *advertising_data); + + + +llStatus_t LL_SetPeriodicAdvEnable(uint8 enable, + uint8 advertising_handle); + + +// periodic scan +llStatus_t LL_PeriodicAdvertisingCreateSync(uint8 options, + uint8 advertising_SID, + uint8 advertiser_Address_Type, + uint8 *advertiser_Address, + uint16 skip, + uint16 sync_Timeout, + uint8 sync_CTE_Type); + +llStatus_t LL_PeriodicAdvertisingCreateSyncCancel(void); + +llStatus_t LL_PeriodicAdvertisingTerminateSync( uint16 sync_handle); + +// Periodic advertiser list +extern llStatus_t LL_AddDevToPeriodicAdvList(uint8 addrType, + uint8 *devAddr, + uint8 sid); +extern llStatus_t LL_RemovePeriodicAdvListDevice(uint8 addrType, + uint8 *devAddr, + uint8 sid); + +extern llStatus_t LL_ClearPeriodicAdvList( void ); + +extern llStatus_t LL_ReadPeriodicAdvListSize( uint8 *numEntries ); + + +/***************************************************************************************** + * fn: LL_ConnectionlessCTE_TransmitParamCmd + * + * date:2020-01-15 + * + * brief: set CTE Parameters in any periodic advertising + * 1ã€CTE Type + * 2ã€CTE Length + * 3ã€CTE antenna switching pattern + * + * input parameters: + * advertising handle : Identify advertising set 0x0-0xEF + * CTE_Length : CTE Length in 8us 0x2-0x14 + * CTE_Type : 0:AOA CTE , 1:AoD CTE with 1us,2:AoD CTE with 2us, + * CTE_Count : how many CTE packet in each PA event 0x1-0x10 + * Switch_Pattern_LEN : number of Antenna IDs in the pattern + * : AOD CTE, AOA shall be ignored + * : 0x2-0x4B + * Antenna_IDs[i] : List of Antenna IDs in the pattern + * : AOD CTE, AOA shall be ignored + * + * output parameters: + * Status :LL_STATUS_SUCCESS or other error codes + * + * + * return LL_STATUS_SUCCESS or other error codes + * + *****************************************************************************************/ +llStatus_t LL_ConnectionlessCTE_TransmitParam( uint8 advertising_handle, + uint8 len, + uint8 type, + uint8 count, + uint8 Pattern_LEN, + uint8 *AnaIDs); + + +/***************************************************************************************** + * fn: LL_ConnectionlessCTE_TransmitEnable + * + * date:2020-01-16 + * + * brief: Controller enable or disable CTE in PA + * + * input parameters: + * advertising handle : Identify advertising set in which CTE is enable or disable + * : 0x0-0xEF + * enable : 0 : disable , 1: enable + * + * + * output parameters: + * Status :LL_STATUS_SUCCESS or other error codes + * + * + * return LL_STATUS_SUCCESS or other error codes + * + *****************************************************************************************/ +llStatus_t LL_ConnectionlessCTE_TransmitEnable( uint8 advertising_handle, + uint8 enable); + + +/***************************************************************************************** + * fn: LL_ConnectionlessIQ_SampleEnable + * + * date:2020-01-17 + * + * brief: Controller enable or disable capturing IQ Samples from the CTE of PA pcakets + * + * input parameters: + * sync_handle : periodic advertising handle + * Range:0x0 - 0x0EFF + * slot_Duration : switching and sampling slot 0x1:1us,0x2:2us,Other:RFU + * enable : 0x0:IQ Sampling disable, 0x1:IQ Sampling enable + * MaxSampledCTEs : max number of CTE in each PA event that the controller + * should collect and report + * Range : 0x0-0x10 + * 0x0 : sample and report all available CTE + * pattern_len : number of Antenna IDs in the pattern + * Range:0x2 - 0x4B + * AnaIDs : list of Antenna IDs in the pattern + * + * + * output parameters: + * status : LL_STATUS_SUCCESS or other error codes + * sync_handle : Periodic advertising handle + * + * + * return LL_STATUS_SUCCESS or other error codes + * + + *****************************************************************************************/ +llStatus_t LL_ConnectionlessIQ_SampleEnable( uint16 sync_handle, + uint8 enable, + uint8 slot_Duration, + uint8 MaxSampledCTEs, + uint8 pattern_len, + uint8 *AnaIDs); + + +/***************************************************************************************** + * fn: LL_Set_ConnectionCTE_ReceiveParam + * + * date:2020-01-19 + * + * brief: enable or disable sampling received CTE fields on the connection + * set antenna switching pattern + * set switching and sampling slot durations + * + * input parameters: + * connHandle : connection handle Range 0x0 - 0x0EFF + * enable : sampling enable 0:disable , 1:enable + * slot_Duration : switching and sampling slot 0:1us, 1: 2us + * pattern_len : the number of Antenna IDs in the pattern + * Range: 0x2-0x4B + * AnaIDs : list of Antenna IDs in the pattern + * + * + * output parameters: + * Status : LL_STATUS_SUCCESS or other error codes + * connHandle : Connection Handle + * + * + * return llStatus_t + + * + *****************************************************************************************/ +llStatus_t LL_Set_ConnectionCTE_ReceiveParam( uint16 connHandle, + uint8 enable, + uint8 slot_Duration, + uint8 pattern_len, + uint8 *AnaIDs); + + +/***************************************************************************************** + * fn: LL_Connection_CTE_Request_Enable + * + * date:2020-01-19 + * + * brief: request Controller to start or stop initiating the CTE request + * procedure on connection + * + * input parameters: + * connHandle : connection Handle + * Range:0x0 - 0x0EFF + * enable : Enable or disable CTE request for the connection + * 0:disable,1:enable + * Interval : define whether the CTE request procedure is initiated + * only once or periodically. + * Range:0x0 - 0xFFFF + * 0x0 : Initiate the CTE request procedure once + * 0x1 - 0xFFFF : Requested interval for initiating the CTE + * procedure in number of connection events + * Range: + * len : minimum length of the CTE in 8us units + * Range: 0x2 - 0x14 + * type : indicate the type of CTE that the controller shall + * request from the remote device + * 0x0:AOA CTE + * 0x1:AOD CTE with 1us + * 0x2:AOD CTE with 2us + * + * + * output parameters: + * Status : 0x0 : command succeed , 0x1 - 0xff : other error code + * connHandle : connection handle + * + * + * return llStatus_t + + * + *****************************************************************************************/ +llStatus_t LL_Connection_CTE_Request_Enable( uint16 connHandle, + uint8 enable, + uint16 Interval, + uint8 len, + uint8 type); + + + +/***************************************************************************************** + * fn: LL_Set_ConnectionCTE_TransmitParam + * + * date:2000-01-19 + * + * brief: used to set the antenna switching pattern and permitted CTE type + * + * input parameters: + * connHandle : connection Handle, Range: 0x0 - 0x0EFF + * type : bit set for CTE type , bit 0 : AOA CTE response, + * bit 1 : AOD CTE response with 1us slots + * bit 2 : AOD CTE response with 2us slots + * pattern_len : the number of Antenna IDs in the pattern + * AnaIDs : list of Antenna IDs in the pattern + * + * + * output parameters: + * Status : 0 : success, other error code + * ConnHandle : connection handle + * + * + * return llStatus_t + * + + *****************************************************************************************/ +llStatus_t LL_Set_ConnectionCTE_TransmitParam( uint16 connHandle, + uint8 type, + uint8 pattern_len, + uint8 *AnaIDs); + + +/***************************************************************************************** + * fn: LL_Connection_CTE_Response_Enable + * + * date:2020-01-19 + * + * brief: request the controller to respond to LL_CTE_REQ with LL_CTE_RSP on the + * specified connection + * + * input parameters: + * connHandle : connection Handle + * Range:0x0 - 0x0EFF + * enable : enable or disable CTE response for the connection + * + * + * output parameters: + * status : 0x0 : command succeed , 0x1 - 0xff : other error code + * connHandle : connection handle + * + * + * + * return llStatus_t + * + + *****************************************************************************************/ +llStatus_t LL_Connection_CTE_Response_Enable( uint16 connHandle,uint8 enable); + + +/***************************************************************************************** + * fn: HCI_LE_READ_Anatenna_InfoCmd + * + * date:2020-01-19 + * + * brief: Host read the switching rates, the sampling reate, the number of antennae, + * and the maxumum length of a transmitted CTE supported by the controller + * + * input parameters: + * None + * + * + * output parameters: + * status : 0x0 : command succeed , 0x1 - 0xff : other error code + * switch_sample_rate : bit number indicate supported switching and sampling rate + * bit 0 : 1us switching AOD transmission + * bit 1 : 1us sampling AOD reception + * bit 2 : 1us switching and sampling AOA reception + * Antenna_len : number of Antennae supported by the controller + * MAX_Pattern_len : MAX length of antenna switching pattern spooorted by the controller + * MAX_CTE_LEN : MAX length or a transmitted CTE supported in 8us units + * + * + * return llStatus_t + * + + *****************************************************************************************/ +llStatus_t LL_READ_Anatenna_Info( uint8 *param ); + + +// RF path compensation configuration +llStatus_t LL_Read_Rf_Path_Compensation(uint8 *param); + +llStatus_t LL_Write_Rf_Path_Compensation( int16 tx_compensation, int16 rx_compensation); + +llStatus_t LL_Set_Privacy_Mode(uint8 peerIdType, + uint8 *peerIdAddr, + uint8 privacyMode); + +llStatus_t LL_Read_Transmit_Power( uint8 *param); + +void LL_EXT_Init_IQ_pBuff(uint16 *ibuf,uint16 *qbuf); + + +#ifdef __cplusplus +} +#endif + +#endif /* LL_H */ + + diff --git a/src/components/ble/controller/ll_buf.h b/src/components/ble/controller/ll_buf.h new file mode 100644 index 0000000..8a763a0 --- /dev/null +++ b/src/components/ble/controller/ll_buf.h @@ -0,0 +1,110 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#ifndef _LL_BUF_H_ +#define _LL_BUF_H_ +#include + +#define MAX_ADV_BUF 1 // buffer advertisement packet +#define TYP_CONN_BUF_LEN 4 // typical packet number per connection event +#define MAX_LL_BUF_LEN 8 // maximum LL buffer for Rx/Tx packet + + +//#define LL_CTRL_PDU_LEN 29 //V4.0/4.2: 2octets header + 27 octets payload +//#define LL_ADV_PDU_LEN 39 //V4.0/4.2: 2octets header + 37 octets payload +//#define LL_DATA_PDU_LEN 33 //V4.0 : 2octets header + 31 octets payload + +// for Rx FIFO, HW will pack zero bytes to align 4bytes boarder +// BLE 4.0, PDU length < 39, 3Bytes CRC will also be read. +// note that PDU head is write in "rxheader/txheader" field, the buffer need (39 + 3 - 2) = 40 bytes, +// add 2 bytes to align 4 bytes edge +//#define BLE_PACKET_BUF_LEN 42 +//257+3-2=256 +// BLE5.0, PDU length: maximum 257 octets, 3 octets CRC, 2 octets PDU head is write in "rxheader/txheader" field +//#define BLE_PACKET_BUF_LEN 258 //(257+3-2) + +// BLE 5.1, PDU length: 2-258 octets, 3 octets CRC, 2 octets PDU head is write in "rxheader/txheader" field +// length should align to word edge, so + 3 octet +#define BLE_PACKET_BUF_LEN 262 //(258+3-2) + 3 + + +#define RX_BUF_LEN BLE_PACKET_BUF_LEN +#define TX_BUF_LEN BLE_PACKET_BUF_LEN +#define TX_CTRL_BUF_LEN 34 //(27+4+3) + +#define LL_PDU_LENGTH_SUPPORTED_MAX_TX_OCTECTS 251 +#define LL_PDU_LENGTH_SUPPORTED_MAX_RX_OCTECTS 251 +#define LL_PDU_LENGTH_SUPPORTED_MAX_TX_TIME 2120 +#define LL_PDU_LENGTH_SUPPORTED_MAX_RX_TIME 2120 + +#define LL_PDU_LENGTH_INITIAL_MAX_TX_OCTECTS 27 +#define LL_PDU_LENGTH_INITIAL_MAX_RX_OCTECTS 27 +#define LL_PDU_LENGTH_INITIAL_MAX_TX_TIME 328 +#define LL_PDU_LENGTH_INITIAL_MAX_RX_TIME 328 + +// BBB update +struct ll_pkt_desc +{ + uint32_t valid; // mean a valid data received from ble + uint16_t header; + uint8_t data[2]; +}; + + +struct buf_rx_desc +{ + uint32_t valid; // mean a valid data received from ble + /// rx header + uint16_t rxheader; + uint8_t data[RX_BUF_LEN ]; // for v4.2 BLE, set to 256 +}; + +struct buf_tx_desc +{ + uint32_t valid; // means a valid data to wait for send to ble + //uint32_t sent; // means tha data has been sent before + /// tx header + uint16_t txheader; + /// data + uint8_t data[TX_BUF_LEN]; +}; + +typedef struct +{ + uint16_t header; + //uint8_t data[TX_BUF_LEN]; + uint8_t data[TX_CTRL_BUF_LEN]; +} __attribute__((aligned(4))) ctrl_packet_buf; + +typedef struct +{ +#if 0 + struct buf_tx_desc tx_conn_desc[MAX_LL_BUF_LEN]; // new Tx data buffer + struct buf_rx_desc rx_conn_desc[MAX_LL_BUF_LEN]; + + struct buf_tx_desc tx_not_ack_pkt; + struct buf_tx_desc tx_ntrm_pkts[MAX_LL_BUF_LEN]; +#endif + struct ll_pkt_desc *tx_conn_desc[MAX_LL_BUF_LEN]; // new Tx data buffer + struct ll_pkt_desc *rx_conn_desc[MAX_LL_BUF_LEN]; + + struct ll_pkt_desc *tx_not_ack_pkt; + struct ll_pkt_desc *tx_ntrm_pkts[MAX_LL_BUF_LEN]; + + + uint8_t ntrm_cnt; // number of packets not transmit + + uint8_t tx_write; + uint8_t tx_read; + uint8_t tx_loop; // flag for write ptr & read ptr work in the same virtual buffer bank + + uint8_t rx_write; + uint8_t rx_read; + uint8_t rx_loop; // flag for write ptr & read ptr work in the same virtual buffer bank +} llLinkBuf_t; + + + +#endif diff --git a/src/components/ble/controller/ll_common.h b/src/components/ble/controller/ll_common.h new file mode 100644 index 0000000..ec8edb1 --- /dev/null +++ b/src/components/ble/controller/ll_common.h @@ -0,0 +1,345 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#ifndef _LL_H_ +#define _LL_H_ + +#include "types.h" +#include "mcu.h" +#include "ll.h" +#include "ll_def.h" + +#define LL_DATA_PDU( pktHdr ) ((pktHdr) != LL_DATA_PDU_HDR_LLID_CONTROL_PKT) +#define LL_CTRL_PDU( pktHdr ) ((pktHdr) == LL_DATA_PDU_HDR_LLID_CONTROL_PKT) +#define LL_INVALID_LLID( pktHdr ) ((pktHdr) == LL_DATA_PDU_HDR_LLID_RESERVED) + + +void LL_IRQHandler(void); + +void move_to_slave_function(void); + +void LL_slave_conn_event(void); + +void LL_master_conn_event(void); + +void LL_set_default_conn_params(llConnState_t *connPtr); + +//void ll_setMem(uint8_t *buf, uint8_t v, int n); + +//void ll_cpyMem(uint8_t *dst, uint8_t *src, int n); + +void LL_evt_schedule(void); + +llStatus_t llSetupAdv( void ); + +void llConvertLstoToEvent( llConnState_t *connPtr, + connParam_t *connParams ); + +void llSlaveEvt_TaskEndOk( void ); + +// for master process +void llMasterEvt_TaskEndOk( void ); + +// Connection Management +extern llConnState_t *llAllocConnId( void ); +extern void llReleaseConnId( llConnState_t *connPtr ); +extern void llReleaseAllConnId( void ); +extern uint16 llGetMinCI( uint16 connInterval ); +extern uint8 llGetNextConn( void ); +extern void llConnCleanup( llConnState_t *connPtr ); +extern void llConnTerminate( llConnState_t *connPtr, uint8 reason ); +extern uint8 llPendingUpdateParam( void ); +extern void llInitFeatureSet( void ); +extern uint32 llGenerateValidAccessAddr( void ); +extern uint32 llGenerateCRC( void ); +extern uint8 llEventInRange( uint16 curEvent, uint16 nextEvent, uint16 updateEvent ); +extern uint16 llEventDelta( uint16 eventA, uint16 eventB ); +extern void llConvertLstoToEvent( llConnState_t *connPtr, connParam_t *connParams ); +extern void llConvertCtrlProcTimeoutToEvent( llConnState_t *connPtr ); + +// Task Setup +extern llStatus_t llSetupAdv( void ); +extern void llSetupDirectedAdvEvt( void ); +extern void llSetupUndirectedAdvEvt( void ); +extern void llSetupNonConnectableAdvEvt( void ); +extern void llSetupScannableAdvEvt( void ); +extern void llSetupScan( uint8 chan ); +extern void llSetupScanInit( void ); +extern void llSetupInit( uint8 connId ); +extern void llSetupConn( void ); +// A2 added +extern uint8 llSetupSecNonConnectableAdvEvt( void ); +// A2 multi-connection +extern uint8 llSetupSecConnectableAdvEvt( void ); +extern uint8 llSetupSecScannableAdvEvt( void ); + + +extern void llSetupSecScan( uint8 chan ); +extern uint32 llCalcMaxScanTime(void); +extern uint8 llSecAdvAllow(void); +// A2 multi-connection +extern uint8 llSetupSecAdvEvt( void ); + +extern void llSetupSecInit( uint8 chan ); +extern uint8_t ll_get_next_active_conn(uint8_t current_conn_id); +extern uint32 ll_get_next_timer(uint8 current_conn_id); + +extern void ll_scheduler(uint32 time); + +extern void ll_addTask(uint8 connId, uint32 time); +extern void ll_deleteTask(uint8 connId); + +// extended adv scheduler functions +void ll_adv_scheduler(void); + +void ll_add_adv_task(extAdvInfo_t *pExtAdv); + +void ll_delete_adv_task(uint8 index); + +uint8 llSetupExtAdvEvent(extAdvInfo_t *pAdvInfo); + +// periodic adv functions +void ll_add_adv_task_periodic(periodicAdvInfo_t *pPrdAdv, extAdvInfo_t *pExtAdv); + +void ll_add_adv_task_periodic(periodicAdvInfo_t *pPrdAdv, extAdvInfo_t *pExtAdv); + +void ll_delete_adv_task_periodic(uint8 index); + +uint8 llSetupPrdAdvEvent(periodicAdvInfo_t *pPrdAdv, extAdvInfo_t *pExtAdv); + +void ll_adv_scheduler_periodic(void); + + +// extended scan functions +extern void llSetupExtScan( uint8 chan ); + +extern void llSetupExtInit(void); + +extern void llSetupPrdScan( void ); + +extern uint16 llAllocateSyncHandle(void); + +extern uint8 llDeleteSyncHandle(uint16 sync_handle); + + + +// Data Management +extern uint8 llEnqueueDataQ( llDataQ_t *pDataQ, txData_t *pTxData ); +extern uint8 llEnqueueHeadDataQ( llDataQ_t *pDataQ, txData_t *pTxData ); +extern txData_t *llDequeueDataQ( llDataQ_t *pDataQ ); +extern uint8 llDataQEmpty( llDataQ_t *pDataQ ); +extern uint8 llWriteTxData ( llConnState_t *connPtr, uint8 pktHdr, uint8 pktLen, uint8 *pBuf ); +extern uint8 *llMemCopySrc( uint8 *pDst, uint8 *pSrc, uint8 len ); +extern uint8 *llMemCopyDst( uint8 *pDst, uint8 *pSrc, uint8 len ); +extern void llProcessMasterControlPacket( llConnState_t *connPtr, uint8 *pBuf ); +extern void llProcessSlaveControlPacket( llConnState_t *connPtr, uint8 *pBuf ); +extern void llProcessTxData( llConnState_t *connPtr, uint8 context ); +extern uint8 llProcessRxData( void ); + +// Control Procedure Setup +extern uint8 llSetupUpdateParamReq( llConnState_t *connPtr ); // M +extern uint8 llSetupUpdateChanReq( llConnState_t *connPtr ); // M +extern uint8 llSetupEncReq( llConnState_t *connPtr ); // M +extern uint8 llSetupEncRsp( llConnState_t *connPtr ); // S +extern uint8 llSetupStartEncReq( llConnState_t *connPtr ); // S +extern uint8 llSetupStartEncRsp( llConnState_t *connPtr ); // M, S +extern uint8 llSetupPauseEncReq( llConnState_t *connPtr ); // M +extern uint8 llSetupPauseEncRsp( llConnState_t *connPtr ); // S +extern uint8 llSetupRejectInd( llConnState_t *connPtr ,uint8 errCode); // S +extern uint8 llSetupFeatureSetReq( llConnState_t *connPtr ); // M, S +extern uint8 llSetupFeatureSetRsp( llConnState_t *connPtr ); // M, S +extern uint8 llSetupVersionIndReq( llConnState_t *connPtr ); // M +extern uint8 llSetupTermInd( llConnState_t *connPtr ); // M, S +extern uint8 llSetupUnknownRsp( llConnState_t *connPtr ); // M, S + +extern uint8 llSetupDataLenghtReq( llConnState_t *connPtr );//M,S +extern uint8 llSetupDataLenghtRsp( llConnState_t *connPtr );//M,S +extern uint8 llSetupPhyReq( llConnState_t *connPtr ); //M,S +extern uint8 llSetupPhyRsp( llConnState_t *connPtr ); //M,S +extern uint8 llSetupPhyUpdateInd( llConnState_t *connPtr );//M +extern uint8 llSetupRejectExtInd( llConnState_t *connPtr ,uint8 errCode); + +// Control Procedure Management +extern void llEnqueueCtrlPkt( llConnState_t *connPtr, uint8 ctrlType ); +extern void llDequeueCtrlPkt( llConnState_t *connPtr ); +extern void llReplaceCtrlPkt( llConnState_t *connPtr, uint8 ctrlType ); + + +// Data Channel Management +extern void llProcessChanMap( llConnState_t *connPtr, uint8 *chanMap ); +extern uint8 llGetNextDataChan( llConnState_t *connPtr, uint16 numEvents ); +extern void llSetNextDataChan( llConnState_t *connPtr ); +extern uint8 llAtLeastTwoChans( uint8 *chanMap ); + +//2020-01-20 add for LL CTE +extern uint8 llSetupCTEReq( llConnState_t *connPtr ); +extern uint8 llSetupCTERsp( llConnState_t *connPtr ); + + + +uint8_t llTimeCompare(int base_time, int fine_time); +uint32_t calculateTimeDelta(int base_time, int fine_time); + +void llSetNextDataChan( llConnState_t *connPtr ); + +// White List Related +extern llStatus_t llCheckWhiteListUsage( void ); + +// function add by HZF +void llResetConnId( uint8 connId ); +void llResetRfCounters(void); +extern void llInitFeatureSet( void ); + + +extern uint16 llCalcScaFactor( uint8 masterSCA ); + + +extern void llCalcTimerDrift( uint32 connInterval, + uint16 slaveLatency, + uint8 sleepClkAccuracy, + uint32 *timerDrift ); + + +// add by HZF +uint8 llGetNextAdvChn(uint8 cur_chn); + +// Tx loop buffer process +void update_tx_write_ptr(llConnState_t *connPtr); + +void update_tx_read_ptr(llConnState_t *connPtr); + +uint8_t getTxBufferSize(llConnState_t *connPtr); +uint8_t getTxBufferFree(llConnState_t *connPtr); + +uint8_t get_tx_read_ptr(llConnState_t *connPtr); + +uint8_t get_tx_write_ptr(llConnState_t *connPtr); + +// Rx loop buffer process +void update_rx_write_ptr(llConnState_t *connPtr); + +void update_rx_read_ptr(llConnState_t *connPtr); + +uint8_t getRxBufferSize(llConnState_t *connPtr); +uint8_t getRxBufferFree(llConnState_t *connPtr); + +uint8_t get_rx_read_ptr(llConnState_t *connPtr); + +uint8_t get_rx_write_ptr(llConnState_t *connPtr); + +// reset buffer +void reset_conn_buf(uint8 index); + +void ll_schedule_next_event(int time); + +uint16 ll_generateTxBuffer(int txFifo_vacancy, uint16 *pSave_ptr); + +void ll_read_rxfifo(void); +void ll_hw_read_tfifo_rtlp(void); +int ll_hw_read_tfifo_packet(uint8 *pkt); + +// function in ll_slaveEndCause.c +uint8 llSetupNextSlaveEvent( void ); +uint8 llProcessSlaveControlProcedures( llConnState_t *connPtr ); +uint8 llCheckForLstoDuringSL( llConnState_t *connPtr ); + +// function in ll_hwItf.c +void ll_hw_process_RTO(uint32 ack_num); +void ll_debug_output(uint32 state); + +void llAdjSlaveLatencyValue( llConnState_t *connPtr ); + +//function for DLE add by ZQ +void llPduLengthManagmentReset(void); +void llTrxNumAdaptiveConfig(void); +void llPduLengthUpdate(uint16 connHandle); +//uint8 LL_PLUS_GetLocalPduDataLength(ll_pdu_length_ctrl_t * pduLen); + +//function for PHY UPDATE add by ZQ +void llPhyModeCtrlReset(void); +void llPhyModeCtrlUpdateNotify(llConnState_t *connPtr, uint8 status); +//llStatus_t LL_PLUS_GetLocalPhyMode(ll_phy_ctrl_t * phyCtrl); +void llSetNextPhyMode( llConnState_t *connPtr ); +extern void llInitFeatureSetDLE(uint8 enable); +extern void llInitFeatureSet2MPHY(uint8 enable); +extern void llInitFeatureSetCodedPHY(uint8 enable); + +// function for whitelist +extern uint8 ll_isAddrInWhiteList(uint8 addrType, uint8 *addr); + +// function for resolving list +uint8 ll_readLocalIRK(uint8 **localIrk, uint8 *peerAddr, uint8 peerAddrType); +uint8 ll_readPeerIRK(uint8 **peerIrk, uint8 *peerAddr, uint8 peerAddrType); +uint8_t ll_getRPAListEntry(uint8 *peerAddr); + +uint8_t ll_isIrkAllZero(uint8 *irk); + +uint8_t ll_CalcRandomAddr( uint8 *pIRK, uint8 *pNewAddr ); +uint8_t ll_ResolveRandomAddrs(uint8 *pIRK, uint8 *pAddr); + +uint16 ll_generateExtAdvDid(uint16 old); + +// extended advertiser process +uint8 LL_extAdvTimerExpProcess(void); + +uint8 LL_prdAdvTimerExpProcess(void); + +uint8 LL_prdScanTimerExpProcess(void); + +uint8 ll_isFirstAdvChn(uint8 chnMap, uint8 chan); + +uint8 ll_getFirstAdvChn(uint8 chnMap); + +void ll_ext_adv_schedule_next_event(int time); + +void ll_prd_adv_schedule_next_event(int time); + +void ll_ext_scan_schedule_next_event(int time); + +void ll_ext_init_schedule_next_event(int time); + +void ll_prd_scan_schedule_next_event(int time); + + +uint8 ll_allocAuxAdvTimeSlot(uint8 index); + +void ll_updateAuxAdvTimeSlot(uint8 index); + +void ll_updateExtAdvRemainderTime(uint32 time); + + +uint8 ll_allocAuxAdvTimeSlot_prd(uint8 index); + +void LL_extScanTimerExpProcess(void); + +void LL_extInitTimerExpProcess(void); + +void ll_parseExtHeader(uint8 *payload, uint16 length); + +uint8 llGetNextAuxAdvChn(uint8 current); + + +/****************************************************************************** + * fn: llGetNextDataChanCSA2 + * + * brief: 2020-01-07 add for CSA 2 + * + * input parameters: counter : event counter( PA Counter or connection counter) + * chan_id : current data or periodic advertising channel Identifier, + * calculate from Access Address + * chan_map: PA or connection channel map + * cMap_tab: current chan map table that is in use for connection or PA event + * chanCnt : used channel count + * + * output parameters: None + * + * + * return uint8 : next channel index + * + ******************************************************************************/ +uint8 llGetNextDataChanCSA2(uint16_t counter ,uint16_t chan_id,uint8 *chan_map,uint8 *cMap_tab,uint8 chanCnt); + +#endif + diff --git a/src/components/ble/controller/ll_debug.h b/src/components/ble/controller/ll_debug.h new file mode 100644 index 0000000..afe1b27 --- /dev/null +++ b/src/components/ble/controller/ll_debug.h @@ -0,0 +1,74 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +/** + **************************************************************************************** + * + * @file ll_debug.h + * + * @brief This file defines the status used for debug + * + * + * $Rev: $ + * + **************************************************************************************** + */ + + +#ifndef _LL_DEBUG_H_ +#define _LL_DEBUG_H_ + +#define DEBUG_ENTER_SYSTEM_SLEEP 0 +#define DEBUG_ENTER_MCU_SLEEP 1 +#define DEBUG_WAKEUP 2 + +#define DEBUG_ISR_EXIT 3 +#define DEBUG_ISR_ENTRY 4 + +#define DEBUG_LL_HW_STX 5 +#define DEBUG_LL_HW_SRX 6 + +#define DEBUG_LL_HW_TRX 7 +#define DEBUG_LL_HW_RTX 8 +#define DEBUG_LL_HW_TRLP 9 +#define DEBUG_LL_HW_TRLP_EMPT 10 +#define DEBUG_LL_HW_RTLP 11 +#define DEBUG_LL_HW_RTLP_1ST 12 +#define DEBUG_LL_HW_RTLP_EMPT 13 + +#define DEBUG_LL_HW_SET_STX 14 +#define DEBUG_LL_HW_SET_SRX 15 + +#define DEBUG_LL_HW_SET_TRX 16 +#define DEBUG_LL_HW_SET_RTX 17 +#define DEBUG_LL_HW_SET_TRLP 18 +#define DEBUG_LL_HW_SET_TRLP_EMPT 19 +#define DEBUG_LL_HW_SET_RTLP 20 +#define DEBUG_LL_HW_SET_RTLP_1ST 21 +#define DEBUG_LL_HW_SET_RTLP_EMPT 22 + +#define DEBUG_LL_STATE_IDLE 30 +#define DEBUG_LL_STATE_ADV_UNDIRECTED 31 +#define DEBUG_LL_STATE_ADV_DIRECTED 32 +#define DEBUG_LL_STATE_ADV_SCAN 33 +#define DEBUG_LL_STATE_ADV_NONCONN 34 +#define DEBUG_LL_STATE_SCAN 35 +#define DEBUG_LL_STATE_INIT 36 +#define DEBUG_LL_STATE_CONN_SLAVE 37 +#define DEBUG_LL_STATE_CONN_MASTER 38 +#define DEBUG_LL_STATE_DIRECT_TEST_MODE_TX 39 +#define DEBUG_LL_STATE_DIRECT_TEST_MODE_RX 40 +#define DEBUG_LL_STATE_MODEM_TEST_TX 41 +#define DEBUG_LL_STATE_MODEM_TEST_RX 42 +#define DEBUG_LL_STATE_MODEM_TEST_TX_FREQ_HOPPING 43 + +#define DEBUG_LL_SEND_ADV 44 + +#define DEBUG_LL_TIMER_EXPIRY_ENTRY 50 +#define DEBUG_LL_TIMER_EXPIRY_EXIT 51 + + + +#endif // _LL_DEBUG_H_ diff --git a/src/components/ble/controller/ll_def.h b/src/components/ble/controller/ll_def.h new file mode 100644 index 0000000..c5aed55 --- /dev/null +++ b/src/components/ble/controller/ll_def.h @@ -0,0 +1,1569 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#ifndef LL_DEF_H_ +#define LL_DEF_H_ + +#include "types.h" +#include "comdef.h" +#include "bcomdef.h" +#include "ll_buf.h" + +#if (MAX_NUM_LL_CONN_ROM_LIMT > 1) +#define MULTI_ROLE +#endif + +#define MAX_NUM_LL_PRD_ADV_SYNC 2 // for periodic adv listener + +#define LL_INVALID_CONNECTION_ID 0xFF + + +#define LL_PKT_PREAMBLE_LEN 1 +#define LL_PKT_SYNCH_LEN 4 +#define LL_PKT_LLID_LEN 1 +#define LL_PKT_HDR_LEN 2 +#define LL_PKT_MIC_LEN 4 +#define LL_PKT_CRC_LEN 3 + +#define LL_DATA_PDU_HDR_LLID_RESERVED 0 +#define LL_DATA_PDU_HDR_LLID_DATA_PKT_NEXT 1 +#define LL_DATA_PDU_HDR_LLID_DATA_PKT_FIRST 2 +#define LL_DATA_PDU_HDR_LLID_CONTROL_PKT 3 + + +///adv header shift and mask +#define PDU_TYPE_SHIFT 0 +#define PDU_TYPE_MASK 0xf +#define CHSEL_SHIFT 5 +#define CHSEL_MASK 0x20 +#define TX_ADD_SHIFT 6 +#define TX_ADD_MASK 0x40 +#define RX_ADD_SHIFT 7 +#define RX_ADD_MASK 0x80 +#define LENGTH_SHIFT 8 +#define LENGTH_MASK 0xFf00 + +// macro for bit operations +#define SET_BITS(p,f,l,m) p=(f<>l + +// Receive Flow Control +#define LL_RX_FLOW_CONTROL_DISABLED 0 +#define LL_RX_FLOW_CONTROL_ENABLED 1 + +//LL packet type +#define ADV_IND 0 //Connectable Undirected Event +#define ADV_DIRECT_IND 1 //Connectable Directed Event +#define ADV_NONCONN_IND 2 //Non-connectable Undirected Event +#define ADV_SCAN_REQ 3 +#define ADV_AUX_SCAN_REQ 3 +#define ADV_SCAN_RSP 4 +#define ADV_CONN_REQ 5 +#define ADV_AUX_CONN_REQ 5 +#define ADV_SCAN_IND 6 //Scannable Undirected Event +#define ADV_EXT_TYPE 7 +#define ADV_AUX_CONN_RSP 8 + +// LL state defines +#define LL_STATE_IDLE 0x00 +#define LL_STATE_ADV_UNDIRECTED 0x01 +#define LL_STATE_ADV_DIRECTED 0x02 +#define LL_STATE_ADV_SCAN 0x03 +#define LL_STATE_ADV_NONCONN 0x04 +#define LL_STATE_SCAN 0x05 +#define LL_STATE_INIT 0x06 +#define LL_STATE_CONN_SLAVE 0x07 +#define LL_STATE_CONN_MASTER 0x08 +#define LL_STATE_DIRECT_TEST_MODE_TX 0x09 +#define LL_STATE_DIRECT_TEST_MODE_RX 0x0A +#define LL_STATE_MODEM_TEST_TX 0x0B +#define LL_STATE_MODEM_TEST_RX 0x0C +#define LL_STATE_MODEM_TEST_TX_FREQ_HOPPING 0x0D + +#define LL_STATE_ADV_EXT 0x0E +#define LL_STATE_ADV_PERIODIC 0x0F + +/* +** LL Buffers Supported +*/ +#define LL_MAX_NUM_DATA_BUFFERS 12 +#define LL_MAX_NUM_CMD_BUFFERS 1 + +/* +** LL API Parameters +*/ + +// LL Parameter Limits +#define LL_ADV_CONN_INTERVAL_MIN 32 // 20ms in 625us +#define LL_ADV_CONN_INTERVAL_MAX 16384 // 10.24s in 625us +#define LL_ADV_NONCONN_INTERVAL_MIN 160 // 100ms in 625us +#define LL_ADV_NONCONN_INTERVAL_MAX 16384 // 10.24s in 625us +// temporary macro define : align to version 5.1 non-conn intv 20ms +// affect function LL_SetAdvControl +#define LL_ADV_V51_NONCONN_INTERVAL_MIN 32 +#define LL_ADV_DELAY_MIN 0 // in ms +#define LL_ADV_DELAY_MAX 10 // in ms +#define LL_SCAN_INTERVAL_MIN 4 // 2.5ms in 625us +#define LL_SCAN_INTERVAL_MAX 16384 // 10.24s in 625us +#define LL_SCAN_WINDOW_MIN 4 // 2.5ms in 625us +#define LL_SCAN_WINDOW_MAX 16384 // 10.24s in 625us +#define LL_CONN_INTERVAL_MIN 6 // 7.5ms in 1.25ms +#define LL_CONN_INTERVAL_MAX 3200 // 4s in 1.25ms +#define LL_CONN_TIMEOUT_MIN 10 // 100ms in 10ms +#define LL_CONN_TIMEOUT_MAX 3200 // 32s in 10ms +#define LL_SLAVE_LATENCY_MIN 0 +#define LL_SLAVE_LATENCY_MAX 499 +#define LL_HOP_LENGTH_MIN 5 +#define LL_HOP_LENGTH_MAX 16 +#define LL_INSTANT_NUMBER_MIN 6 + +#define LL_ADV_INTERVAL_DEFAULT 160 // 100ms in 625us ticks +#define LL_SCAN_INTERVAL_DEFAULT 640 // 400ms in 625us ticks +// LL Advertiser Channels +#define LL_ADV_CHAN_37 1 +#define LL_ADV_CHAN_38 2 +#define LL_ADV_CHAN_39 4 +#define LL_ADV_CHAN_ALL (LL_ADV_CHAN_37 | LL_ADV_CHAN_38 | LL_ADV_CHAN_39) + +#define LL_MAX_NUM_DATA_CHAN 37 // 0 - 36 + +// Advertiser Synchronization Word +#define ADV_SYNCH_WORD 0x8E89BED6 // Adv channel sync +#define ADV_CRC_INIT_VALUE 0x00555555 // not needed; handled by NR hardware automatically + +// Packet Lengths +#define LL_DEVICE_ADDR_LEN 6 +#define LL_MAX_ADV_DATA_LEN 31 +#define LL_MAX_ADV_PAYLOAD_LEN (LL_DEVICE_ADDR_LEN + LL_MAX_ADV_DATA_LEN) +#define LL_MAX_SCAN_DATA_LEN 31 +#define LL_MAX_SCAN_PAYLOAD_LEN (LL_DEVICE_ADDR_LEN + LL_MAX_SCAN_DATA_LEN) +#define LL_MAX_LINK_DATA_LEN 27 // ZQ 20181030 for DLE feature + //replaced by g_llPduLen.local.MaxTxOctets + +// =============== add in A2 for simultaneous slave and adv/scan +#define LL_SEC_STATE_IDLE 0x00 +#define LL_SEC_STATE_SCAN 0x01 +#define LL_SEC_STATE_ADV 0x02 +#define LL_SEC_STATE_SCAN_PENDING 0x03 +#define LL_SEC_STATE_ADV_PENDING 0x04 +#define LL_SEC_STATE_IDLE_PENDING 0x05 +#define LL_SEC_STATE_INIT 0x06 +#define LL_SEC_STATE_INIT_PENDING 0x07 + +// ============= for multi-role +#define LL_ROLE_SLAVE 0x01 +#define LL_ROLE_MASTER 0x02 +#define LL_ROLE_INVALID 0xFF + +#define LL_INVALID_TIME 0xFFFFFFFF + +#define LL_TASK_MASTER_DURATION 3000 +#define LL_TASK_SLAVE_DURATION 2700 + + +enum +{ + LL_SCH_PRIO_LOW = 0, + LL_SCH_PRIO_MED, + LL_SCH_PRIO_HIGH, + LL_SCH_PRIO_IMMED, + LL_SCH_PRIO_LAST +}; + + +// ===== A2 End + +// 2020-01-15 CTE Macro define +#define LL_CTE_MAX_ANTENNA_LEN 8 +#define LL_CTE_MAX_ANT_ID (LL_CTE_MAX_ANTENNA_LEN - 1) +#define LL_CTE_MAX_PATTERN_LEN 16 +#define LL_CTE_MIN_SUPP_LEN 0x2 +#define LL_CTE_MAX_SUPP_LEN 0x14 // CTE MAX Support length in 8us units( MAX 160us) +#define LL_CTE_SUPP_LEN_UNIT 0x08 +#define LL_CTE_MAX_PA_INTV_CNT 0x10 +#define LL_CTE_MAX_IQ_SAMP_CNT 0x10 +#define LL_CTE_ENABLE 0x1 +#define LL_CTE_DISABLE 0x0 +#define LL_IQ_SAMP_ENABLE 0x1 +#define LL_IQ_SAMP_DISABLE 0x0 +#define LL_CONN_IQSAMP_ENABLE 0x1 +#define LL_CONN_IQSAMP_DISENABLE 0x0 +#define LL_CONN_IQTX_ENABLE 0x1 +#define LL_CONN_IQTX_DISENABLE 0x0 +#define LL_CONN_CTE_REQ_ENABLE 0x1 +#define LL_CONN_CTE_REQ_DISENABLE 0x0 +#define LL_CONN_CTE_RSP_ENABLE 0x1 +#define LL_CONN_CTE_RSP_DISENABLE 0x0 +#define LL_IQ_SW_SAMP_1US 0x1 +#define LL_IQ_SW_SAMP_2US 0x2 +#define LL_CONTROLLER_SUPP_1US_AOD_TX 0x1 +#define LL_CONTROLLER_SUPP_1US_AOD_SAMP 0x2 +#define LL_CONTROLLER_SUPP_1US_AOA_TX_SAMP 0x4 + +// 2020-01-20 add for Extended advertising +#define LL_SECOND_ADV_PHY_1M 0x1 +#define LL_SECOND_ADV_PHY_2M 0x2 +#define LL_SECOND_ADV_PHY_CODE 0x3 +#define LL_PHY_1M 0x1 +#define LL_PHY_2M 0x2 +#define LL_PHY_CODE 0x3 + + +//LL connecction control type +#define LL_CONNECTION_UPDATE_REQ 0 +#define LL_CHANNEL_MAP_REQ 1 +#define LL_TERMINATE_IND 2 +#define LL_ENC_REQ 3 +#define LL_ENC_RSP 4 +#define LL_START_ENC_REQ 5 +#define LL_START_ENC_RSP 6 +#define LL_UNKNOWN_RSP 7 +#define LL_FEATURE_REQ 8 +#define LL_FEATURE_RSP 9 +#define LL_PAUSE_ENC_REQ 10 +#define LL_PAUSE_ENC_RSP 11 +#define LL_VERSION_IND 12 +#define LL_REJECT_IND 13 +#define LL_SLAVE_FEATURE_REQ 14 +#define LL_CONNECTION_PARAM_REQ 15 +#define LL_CONNECTION_PARAM_RSP 16 +#define LL_REJECT_IND_EXT 17 +#define LL_PING_REQ 18 +#define LL_PING_RSP 19 +#define LL_LENGTH_REQ 20 +#define LL_LENGTH_RSP 21 +#define LL_PHY_REQ 22 +#define LL_PHY_RSP 23 +#define LL_PHY_UPDATE_IND 24 + + +#define LL_CONNECT_REQ_PAYLOAD_LEN 18 +#define LL_CONN_UPDATE_REQ_PAYLOAD_LEN 12 +#define LL_CHAN_MAP_REQ_PAYLOAD_LEN 8 +#define LL_TERM_IND_PAYLOAD_LEN 2 +#define LL_ENC_REQ_PAYLOAD_LEN 23 +#define LL_ENC_RSP_PAYLOAD_LEN 13 +#define LL_START_ENC_REQ_PAYLOAD_LEN 1 +#define LL_START_ENC_RSP_PAYLOAD_LEN 1 +#define LL_PAUSE_ENC_REQ_PAYLOAD_LEN 1 +#define LL_PAUSE_ENC_RSP_PAYLOAD_LEN 1 +#define LL_REJECT_IND_PAYLOAD_LEN 2 +#define LL_REJECT_EXT_IND_PAYLOAD_LEN 3 +#define LL_FEATURE_REQ_PAYLOAD_LEN 9 +#define LL_FEATURE_RSP_PAYLOAD_LEN 9 +#define LL_VERSION_IND_PAYLOAD_LEN 6 +#define LL_UNKNOWN_RSP_PAYLOAD_LEN 2 +#define LL_LENGTH_REQ_PAYLOAD_LEN 9 +#define LL_LENGTH_RSP_PAYLOAD_LEN 9 +#define LL_PHY_REQ_PAYLOAD_LEN 3 +#define LL_PHY_RSP_PAYLOAD_LEN 3 +#define LL_PHY_UPDATE_IND_PAYLOAD_LEN 5 + +// 2020-01-20 add for CTE +#define LL_CTE_REQ_LEN 2 +#define LL_CTE_RSP_LEN 1 + +#define LL_MAX_NUM_CTRL_PROC_PKTS 4 +#define LL_CTRL_UNDEFINED_PKT 0xFF + +// LL Events +#define LL_EVT_POST_PROCESS_NR 0x0001 +#define LL_EVT_DIRECTED_ADV_FAILED 0x0002 +#define LL_EVT_SLAVE_CONN_CREATED 0x0004 +#define LL_EVT_NEXT_INTERVAL 0x0008 +#define LL_EVT_MASTER_CONN_CANCELLED 0x0010 +#define LL_EVT_TASK_TIMER_FENCE_EXPIRED 0x0020 +#define LL_EVT_SLAVE_CONN_CREATED_BAD_PARAM 0x0040 +#define LL_EVT_START_32KHZ_XOSC_DELAY 0x0080 +#define LL_EVT_32KHZ_XOSC_DELAY 0x0100 +#define LL_EVT_RESET_SYSTEM_HARD 0x0200 +#define LL_EVT_RESET_SYSTEM_SOFT 0x0400 + +#define LL_EVT_MASTER_CONN_CREATED 0x0800 +#define LL_EVT_SECONDARY_SCAN 0x1000 +#define LL_EVT_SECONDARY_ADV 0x2000 +#define LL_EVT_SECONDARY_INIT 0x4000 +#define LL_EVT_RPA_TIMEOUT 0x8000 + + + +#define LL_ADV_NONCONN_STATE 0x00 +#define LL_ADV_DISCOV_STATE 0x01 +#define LL_ADV_UNDIRECT_STATE 0x02 +#define LL_ADV_HDC_DIRECT_STATE 0x03 +#define LL_SCAN_PASSIVE_STATE 0x04 +#define LL_SCAN_ACTIVE_STATE 0x05 +#define LL_INIT_STATE 0x06 // connection state in master role also supported +#define LL_SLAVE_STATE 0x07 +// +#define LL_ADV_NONCONN_SCAN_PASSIVE_STATE 0x10 +#define LL_ADV_DISCOV_SCAN_PASSIVE_STATE 0x11 +#define LL_ADV_UNDIRECT_SCAN_PASSIVE_STATE 0x12 +#define LL_ADV_HDC_DIRECT_SCAN_PASSIVE_STATE 0x13 +#define LL_ADV_NONCONN_SCAN_ACTIVE_STATE 0x14 +#define LL_ADV_DISCOV_SCAN_ACTIVE_STATE 0x15 +#define LL_ADV_UNDIRECT_SCAN_ACTIVE_STATE 0x16 +#define LL_ADV_HDC_DIRECT_SCAN_ACTIVE_STATE 0x17 +// +#define LL_ADV_NONCONN_INIT_STATE 0x20 +#define LL_ADV_DISCOV_INIT_STATE 0x21 +#define LL_ADV_NONCONN_MASTER_STATE 0x22 +#define LL_ADV_DISCOV_MASTER_STATE 0x23 +#define LL_ADV_NONCONN_SLAVE_STATE 0x24 +#define LL_ADV_DISCOV_SLAVE_STATE 0x25 +#define LL_SCAN_PASSIVE_INIT_STATE 0x26 +#define LL_SCAN_ACTIVE_INIT_STATE 0x27 +// +#define LL_SCAN_PASSIVE_MASTER_STATE 0x30 +#define LL_SCAN_ACTIVE_MASTER_STATE 0x31 +#define LL_SCAN_PASSIVE_SLAVE_STATE 0x32 +#define LL_SCAN_ACTIVE_SLAVE_STATE 0x33 +#define LL_INIT_MASTER_STATE 0x34 // master role and master role combination also supported +// +#define LL_ADV_LDC_DIRECT_STATE 0x35 +#define LL_ADV_LDC_DIRECT_SCAN_PASSIVE_STATE 0x36 +#define LL_ADV_LDC_DIRECT_SCAN_ACTIVE_STATE 0x37 + +#define HCI_RX_PKT_HDR_SIZE 5 +#define LL_NUM_BYTES_FOR_CHAN_MAP 5 //(LL_MAX_NUM_ADV_CHAN+LL_MAX_NUM_DATA_CHAN)/sizeof(uint8) + +#define LL_CTRL_PROC_STATUS_SUCCESS 0 +#define LL_CTRL_PROC_STATUS_TERMINATE 1 + +// A2 multi-connection +#define LL_PROC_LINK_KEEP 0 +#define LL_PROC_LINK_TERMINATE 1 + +#define LL_TX_DATA_CONTEXT_POST_PROCESSING 2 + +#define LL_TX_DATA_CONTEXT_SEND_DATA 0 + +#define LL_LINK_SETUP_TIMEOUT 5 // 6 connection intervals (i.e. 0..5) + +// Setup Next Slave Procedure Actions +#define LL_SETUP_NEXT_LINK_STATUS_SUCCESS 0 +#define LL_SETUP_NEXT_LINK_STATUS_TERMINATE 1 + + +// Data PDU Control Packet Types +#define LL_CTRL_CONNECTION_UPDATE_REQ 0 // M +#define LL_CTRL_CHANNEL_MAP_REQ 1 // M +#define LL_CTRL_TERMINATE_IND 2 // M, S +#define LL_CTRL_ENC_REQ 3 // M +#define LL_CTRL_ENC_RSP 4 // , S +#define LL_CTRL_START_ENC_REQ 5 // , S +#define LL_CTRL_START_ENC_RSP 6 // M, S +#define LL_CTRL_UNKNOWN_RSP 7 // M, S +#define LL_CTRL_FEATURE_REQ 8 // M +#define LL_CTRL_FEATURE_RSP 9 // , S , also could be M in ver4.2 ... HZF +#define LL_CTRL_PAUSE_ENC_REQ 10 // M +#define LL_CTRL_PAUSE_ENC_RSP 11 // , S +#define LL_CTRL_VERSION_IND 12 // M, S +#define LL_CTRL_REJECT_IND 13 // , S + +// BLE 4.2 +#define LL_CTRL_SLAVE_FEATURE_REQ 14 +#define LL_CTRL_CONNECTION_PARAM_REQ 15 +#define LL_CTRL_CONNECTION_PARAM_RSP 16 +#define LL_CTRL_REJECT_EXT_IND 17 +#define LL_CTRL_PING_REQ 18 +#define LL_CTRL_PING_RSP 19 +#define LL_CTRL_LENGTH_REQ 20 +#define LL_CTRL_LENGTH_RSP 21 +// BLE 5.0 +#define LL_CTRL_PHY_REQ 22 +#define LL_CTRL_PHY_RSP 23 +#define LL_CTRL_PHY_UPDATE_IND 24 +#define LL_CTRL_MIN_USED_CHANNELS_IND 25 + +// TODO 2020-02-07 change , default: 26 +#define LL_CTRL_TERMINATE_RX_WAIT_FOR_TX_ACK 0xFE //26 // M (internal to LL only) + +// 2020-01-19 add for CTE +#define LL_CTRL_CTE_REQ 0x1A +#define LL_CTRL_CTE_RSP 0x1B + +// control procedure timeout in coarse timer ticks +#define LL_MAX_CTRL_PROC_TIMEOUT 64000 // 40s + +// Encryption Related +#define LL_ENC_RAND_LEN 8 +#define LL_ENC_EDIV_LEN 2 +#define LL_ENC_LTK_LEN 16 +#define LL_ENC_IRK_LEN 16 + +#define LL_ENC_IV_M_LEN 4 +#define LL_ENC_IV_S_LEN 4 +#define LL_ENC_IV_LINK_LEN 4 +#define LL_ENC_IV_LEN (LL_ENC_IV_M_LEN + LL_ENC_IV_S_LEN) +#define LL_ENC_SKD_M_LEN 8 +#define LL_ENC_SKD_S_LEN 8 +#define LL_ENC_SKD_LINK_LEN 8 +#define LL_ENC_SKD_LEN (LL_ENC_SKD_M_LEN + LL_ENC_SKD_S_LEN) +#define LL_ENC_SK_LEN 16 +#define LL_ENC_NONCE_LEN 13 +#define LL_END_NONCE_IV_OFFSET 5 +#define LL_ENC_MIC_LEN LL_PKT_MIC_LEN +// +#define LL_ENC_IV_M_OFFSET LL_ENC_IV_S_LEN +#define LL_ENC_IV_S_OFFSET 0 +#define LL_ENC_SKD_M_OFFSET LL_ENC_SKD_S_LEN +#define LL_ENC_SKD_S_OFFSET 0 +// +#define LL_ENC_BLOCK_LEN 16 +#define LL_ENC_CCM_BLOCK_LEN LL_ENC_BLOCK_LEN +#define LL_ENC_BLOCK_B0_FLAGS 0x49 +#define LL_ENC_BLOCK_A0_FLAGS 0x01 + +// Resolving Private Address list +#define LEN_24BIT 3 // Number of bytes in a 24 bit number +#define PRAND_SIZE LEN_24BIT // PRAND size in the Private Resolvable Address calculation + +// Address header bits +#define RANDOM_ADDR_HDR 0xC0 // Used for LL RANDOM Address +#define STATIC_ADDR_HDR 0xC0 // Host Static Address, same as RANDOM address +#define PRIVATE_RESOLVE_ADDR_HDR 0x40 + + +// Extended advertiser setting +#define LL_MAX_ADVERTISER_SET_LENGTH 0x672 // spec range: 0x1F ~ 0x672 +#define LL_INVALID_ADV_SET_HANDLE 0xFF + + +//////////////////// for scan +// Scanner Advertisment Channels +#define LL_SCAN_ADV_CHAN_37 37 +#define LL_SCAN_ADV_CHAN_38 38 +#define LL_SCAN_ADV_CHAN_39 39 + + +// add by HZF for whitelist +#define LL_WHITELIST_ENTRY_NUM 8 + +// BBB ROM code: resolving list size +#define LL_RESOLVINGLIST_ENTRY_NUM 8 + +// Periodic advertiser list size +#define LL_PRD_ADV_ENTRY_NUM 8 + + +struct bd_addr{ + uint8_t addr[6]; +}; + + +typedef struct +{ + uint8_t peerAddrType; // peer device address type of public or random + uint8_t peerAddr[ 6 ]; // peer device address +} peerInfo_t; + +#define NETWORK_PRIVACY_MODE 0 +#define DEVICE_PRIVACY_MODE 1 +// BBB ROM code add +typedef struct +{ + uint8_t localIrk[16]; + uint8_t peerIrk[16]; + uint8_t peerAddrType; // peer device address type of public or random + uint8_t peerAddr[6]; // peer device address + + uint8_t privacyMode; // privacy mode, Network privacy mode or Device privacy mode + + // ==== add after BBB ROM code freeze + uint8_t localRpa[6]; // local resolvable address +} resolvingListInfo_t; + +// Periodic Advertiser list +typedef struct +{ + uint8_t addrType; // Advertising address type + uint8_t addr[6]; // Advertising address + uint8_t sid; // Advertising SID +} periodicAdvertiserListInfo_t; + +/// Advertising parameters +typedef struct +{ + uint8_t active; + + uint16_t advInterval; // the advertiser interval, based on advIntMin and advIntMax + /// Advertising type + uint16_t advMode; // flag to indicate if currently advertising + + uint8_t ownAddrType; // own device address type of public or random + uint8_t ownAddr[LL_DEVICE_ADDR_LEN]; // own device address + + uint8_t advChanMap; // saved Adv channel map; note, only lower three bits used + + uint8_t advEvtType; //connectable directed, undirected, discoverable, or non-connectable + + uint8_t wlPolicy; // white list policy for Adv + uint16_t scaValue; // Slave SCA in PPM + + uint8_t advDataLen; // advertiser data length + + // Scan Repsonse Parameters + uint8_t scanRspLen; // scan response data length + + // add by HZF + uint8 advNextChan; + + // multi-connection + uint8 connId; + +}advInfo_t; + +/// Extended Advertising parameters +typedef struct +{ +// uint8_t advHandle; // range: 0x00 - 0xEF + uint8_t advertisingSID; // range: 0x00 - 0x0F + + uint16_t advEventProperties; // adv event type + + uint32_t priAdvIntMin; // 3 octets, minimum primary adv interval + uint32_t priAdvgIntMax; // 3 octets, maximum primary adv interval + + uint8_t priAdvChnMap; + + uint8_t ownAddrType; // own device address type of public or random + uint8_t isOwnRandomAddressSet; // own random address type set flag. The address is set by HCI_LE_SET_ADVERTISING_SET_RANDOM_ADDRESS + uint8_t ownRandomAddress[LL_DEVICE_ADDR_LEN]; + + uint8_t peerAddrType; + uint8_t peerAddress[LL_DEVICE_ADDR_LEN]; + + uint8_t wlPolicy; // white list policy for Adv + + int8 advTxPower; + + uint8_t primaryAdvPHY; + uint8_t secondaryAdvPHY; + + uint8_t secondaryAdvMaxSkip; // the maximum number of advertising events that can be skipped before the AUX_ADV_IND can be sent + + uint8_t scanReqNotificationEnable; + +}extAdvParameter_t; + +/// data of Advertising set or scan response data +typedef struct +{ +// uint8_t advHandle; + uint8_t dataComplete; // all data of advert set received + uint8 fragmentPreference; + + uint16 advertisingDataLength; + uint8 *advertisingData; + + // LL generated + uint16 DIDInfo; // 12bits +}advSetData_t; + +/// extended adv parameters, include spec parameters & implemented-specific parameters +typedef struct +{ + uint8_t advHandle; + + extAdvParameter_t parameter; + advSetData_t data; // only for extended adv + uint16 scanRspMaxLength; // length of scan rsp data + uint8 *scanRspData; + + // ===================== advertisement enable info + uint32_t duration; // unit us, note spec parameter is 10ms unit + uint8_t maxExtAdvEvents; + + // ================= advertisement context parameters + uint8_t isPeriodic; // is the adv parameters for periodic adv + uint8_t active; // extended adv enable or not + uint32_t primary_advertising_interval; + + uint16_t adv_event_counter; // counter for extend adv event + uint32_t adv_event_duration; // duration of advertise + + int8 tx_power; // range -127 ~ 127 dBm, will be filled to field TxPower + + uint8_t sendingAuxAdvInd; + + // below parameters only applicable to extended adv, not for periodic adv + uint8_t currentChn; // current adv channel + + uint8_t auxChn; // 1st aux PDU channel No. + uint16_t currentAdvOffset; // current read ptr of adv data set, for fill AUX_XXX_IND PDUs +} extAdvInfo_t; + +typedef struct +{ + uint16 syncPacketOffset : 13; // 13bits + uint16 offsetUnit : 1; // 1 bit + uint16 offsetAdj : 1; // 1 bit + uint16 rfu : 1; // 1 bit +} syncInfoOffset_t; + +typedef struct +{ + uint8 chn_map : 5; // 5bits + uint8 sca : 3; // 3 bit +} chanMap4_t; + +typedef struct +{ + syncInfoOffset_t offset; + + uint16 interval; + + uint8 chn_map[4]; + chanMap4_t chn_map4; + + uint8 AA[4]; + uint8 crcInit[3]; + + uint16 event_counter; +} syncInfo_t; + +/// data of periodic Advertising set +typedef struct +{ + uint8 dataComplete; // all data of advert set received + + uint16 advertisingDataLength; + uint8 *advertisingData; +}periodicAdvSetData_t; + +// 2020-01-15 add for connection & connectionless parameter +typedef struct +{ + // common +// uint16 handle; // syncConnHandle for connectionless , connHandle for connection + uint8 enable; // + uint8 CTE_Length; // connectionless transmit CTE length or connection request and response CTE Length + uint8 CTE_Type; // AOA, ADO 1us , AOD 2us + uint8 CTE_Count; // number of CTE to transmit in each PA interval + // IQ Sample:max number of CTE to sample and report in each PA interval + uint8 CTE_Count_Idx; // record the number of times that the CTE send , max equal to CTE_Count + uint8 pattern_LEN; + uint8 AntID[LL_CTE_MAX_PATTERN_LEN]; + + uint8 slot_Duration; // switching and sampling slot 1us or 2us + + // connectionless transmit param +// uint8 advSet; // identify connectionless advertising set + // CTEInfo_t merge to periodicAdvInfo_t , advSet not used + + // connection CTE request & response enable command + uint16 CTE_Request_Intv; + +}CTEInfo_t; + + +// periodic adv: data + parameters + enable flag +// note that periodic adv also need extended adv parameters + enable +typedef struct +{ + uint8_t advHandle; + + periodicAdvSetData_t data; + + uint16 adv_interval_min; + uint16 adv_interval_max; + uint16_t adv_event_properties; // adv event type + + // ================= advertisement context parameters + uint8_t active; // extended adv enable or not + uint32_t adv_interval; + + uint8_t secondaryAdvPHY; // reserved, should we copy this setting from ext adv info? ext adv may be disabled while keep periodic adv alive + + uint8 chn_map[5]; // 37 bits + uint8_t chanMapTable[LL_MAX_NUM_DATA_CHAN]; + uint8_t numUsedChans; // count of the number of usable data channels + uint8 sca; // 3 bit + + uint32 AA; + uint32 crcInit; + + uint8_t tx_power; // not setting now, reserve for TxPwr field + + uint16_t periodic_adv_event_counter; // counter for periodic adv event + uint8 pa_current_chn; // current periodic adv channel + + uint8_t currentChn; // current adv channel + + uint16_t currentAdvOffset; // current read ptr of adv data set, for fill AUX_XXX_IND PDUs + + // 2020-01-15 CTE global variable + CTEInfo_t PrdCTEInfo; +} periodicAdvInfo_t; + +/////////////////////////////////////////////////////////// +// Scanner Event Parameters +typedef struct +{ +// taskInfo_t *llTask; // pointer to associated task block + uint8 ownAddrType; // own device address type of public or random + uint8 ownAddr[ LL_DEVICE_ADDR_LEN ]; // own device address + uint8 initPending; // flag to indicate if Scan needs to be initialized + uint8 scanMode; // flag to indicate if currently scanning + uint8 scanType; // passive or active scan + uint16 scanInterval; // the interval between scan events + uint16 scanWindow; // the duration of a scan event + uint8 wlPolicy; // white list policy for Scan + uint8 filterReports; // flag to indicate if duplicate Adv packet reports are to be filtered + uint16 scanBackoffUL; // backoff upper limit count + uint8 nextScanChan; // advertising channel to be used by scanner + uint8 numSuccess; // for adjusting backoff count by tracking successive successes + uint8 numFailure; // for adjusting backoff count by tracking successive failures + uint16 currentBackoff; // current back off count, uint16 because the upper limit is 256 +} scanInfo_t; + +/////////////////////////////////////////////////////////// +// Extended Scanner Parameters +#define LL_MAX_EXTENDED_SCAN_PHYS 2 +#define LL_MAX_EXTENDED_INIT_PHYS 3 +#define LL_SCAN_PHY_1M_BITMASK 0x01 +#define LL_CONN_PHY_2M_BITMASK 0x02 // only for init +#define LL_SCAN_PHY_CODED_BITMASK 0x04 +typedef struct +{ + uint8 enable; + uint8 ownAddrType; // own device address type of public or random + uint8 ownAddr[ LL_DEVICE_ADDR_LEN ]; // own device address + uint8 wlPolicy; // white list policy for Scan + + uint8 numOfScanPHY; + uint8 scanPHYs[LL_MAX_EXTENDED_SCAN_PHYS]; // scan PHYs + + uint8 scanType[LL_MAX_EXTENDED_SCAN_PHYS]; // passive or active scan + uint16 scanInterval[LL_MAX_EXTENDED_SCAN_PHYS]; // the interval between scan events + uint16 scanWindow[LL_MAX_EXTENDED_SCAN_PHYS]; // the duration of a scan event + + uint8 filterDuplicate; // Duplicate filtering setting + uint16 duration; // scan duration in a scan period + uint16 period; // scan period + + // scan context + uint8 current_index; // current scan parameter index, 0 or 1 + uint8 current_scan_PHY; + uint8 current_chn; + + // TODO: check below members are required or not + uint16 adv_data_offset; // offset of long adv data + uint16 adv_data_buf_len; // adv data buffer size + uint8 *adv_data; +} extScanInfo_t; + +typedef struct +{ + uint8 valid; + uint8 options; + uint8 advertising_SID; + uint8 advertiser_Address_Type; + uint8 advertiser_Address[LL_DEVICE_ADDR_LEN]; + uint16 skip; + uint16 sync_Timeout; + uint8 sync_CTE_Type; +} scannerSyncInfo_t; + +typedef struct +{ + uint8 header; + + uint8 advA[LL_DEVICE_ADDR_LEN]; + uint8 targetA[LL_DEVICE_ADDR_LEN]; + uint8 cteInfo; + uint16 adi; + + struct + { + uint8 chn_idx; + uint8 ca; + uint8 offset_unit; + uint16 aux_offset; + uint8 aux_phy; + } auxPtr; + + uint8 syncInfo[18]; + + uint8 txPower; +} extAdvHdr_t; + +/////////////////// Initiator Event Parameters +typedef struct +{ + uint8 ownAddrType; // own device address type of public or random + uint8 ownAddr[ LL_DEVICE_ADDR_LEN ]; // own device address + // + uint8 initPending; // flag to indicate if Scan needs to be initialized + uint8 scanMode; // flag to indicate if currently scanning + uint16 scanInterval; // the interval between scan events + uint16 scanWindow; // the duration of a scan event + uint8 nextScanChan; // advertising channel to be used by scanner + uint8 wlPolicy; // white list policy for Init + uint8 connId; // allocated connection ID + uint8 scaValue; // Master SCA as an ordinal value for PPM +} initInfo_t; + + +typedef struct +{ + uint8 ownAddrType; // own device address type of public or random + uint8 ownAddr[ LL_DEVICE_ADDR_LEN ]; // own device address + + uint8 wlPolicy; // white list policy for Init +// uint8 initPending; // flag to indicate if Scan needs to be initialized + uint8 scanMode; // flag to indicate if currently scanning + + uint8 numOfScanPHY; + uint8 initPHYs[LL_MAX_EXTENDED_SCAN_PHYS]; // scan PHYs + uint16 scanInterval[LL_MAX_EXTENDED_SCAN_PHYS]; // the interval between scan events + uint16 scanWindow[LL_MAX_EXTENDED_SCAN_PHYS]; // the duration of a scan event + + uint16 conn_interval_min[LL_MAX_EXTENDED_SCAN_PHYS]; + uint16 conn_interval_max[LL_MAX_EXTENDED_SCAN_PHYS]; + uint16 conn_latency[LL_MAX_EXTENDED_SCAN_PHYS]; + uint16 supervision_timeout[LL_MAX_EXTENDED_SCAN_PHYS]; + uint16 minimum_CE_length[LL_MAX_EXTENDED_SCAN_PHYS]; + uint16 maximum_CE_length[LL_MAX_EXTENDED_SCAN_PHYS]; + + // initiator parameters for 2Mbps PHY + uint8 is_2M_parameter_present; + uint16 conn_interval_min_2Mbps; + uint16 conn_interval_max_2Mbps; + uint16 conn_latency_2Mbps; + uint16 supervision_timeout_2Mbps; + uint16 minimum_CE_length_2Mbps; + uint16 maximum_CE_length_2Mbps; + + // scan context + uint8 current_index; // current scan parameter index, 0 or 1 + uint8 current_scan_PHY; + uint8 current_chn; + + uint8 connId; // allocated connection ID + uint8 scaValue; // Master SCA as an ordinal value for PPM +} extInitInfo_t; +///////////////////////////////////////////////////////////////// + +typedef struct +{ + uint8_t winSize; // window size + uint16_t winOffset; // window offset + uint16_t connInterval; // connection interval + uint16_t slaveLatency; // number of connection events the slave can ignore + uint16_t connTimeout; // supervision connection timeout +} connParam_t; + +typedef struct +{ + uint8_t verNum; // controller spec version + uint16_t comId; // company identifier + uint16_t subverNum; // implementation version +} verInfo_t; + +typedef struct +{ + uint8_t connId; // connection ID + uint8_t termIndRcvd; // indicates a TERMINATE_IND was received + uint8_t reason; // reason code to return to Host when connection finally ends +} termInfo_t; + +// TX Data +typedef struct txData_t +{ + struct txData_t *pNext; // pointer to next Tx data entry on queue +} txData_t; + +// Data Packet Queue +typedef struct +{ + txData_t *head; // pointer to head of queue + txData_t *tail; // pointer to tail of queue +} llDataQ_t; + + +// Version Information Exchange +typedef struct +{ + uint8_t peerInfoValid; // flag to indicate the peer's version information is valid + uint8_t hostRequest; // flag to indicate the host has requested the peer's version information + uint8_t verInfoSent; // flag to indicate this device's version information has been sent +} verExchange_t; + +// Feature Set Data +typedef struct +{ + uint8_t featureRspRcved; // flag to indicate the Feature Request has been responded to + uint8_t featureSet[ 8 ]; +} featureSet_t; + +// Channel Map +typedef struct +{ + uint8_t chanMap[ 5 ]; // bit map corresponding to the data channels 0..39 +} chanMap_t; + +// Control Procedure Information +typedef struct +{ + uint8_t ctrlPktActive; // flag that indicates a control packet is being processed + uint8_t ctrlPkts[ LL_MAX_NUM_CTRL_PROC_PKTS ]; // queue of control packets to be processed + uint8_t ctrlPktCount; // number of queued control packets + uint16_t ctrlTimeoutVal; // timeout in CI events for control procedure for this connection + uint16_t ctrlTimeout; // timeout counter in CI events for control procedure +} ctrlPktInfo_t; + +typedef struct +{ + uint16_t MaxTxOctets; + uint16_t MaxTxTime; + uint16_t MaxRxOctets; + uint16_t MaxRxTime; +}ll_pdu_length_ctrl_t; + +typedef struct +{ + ll_pdu_length_ctrl_t local; + ll_pdu_length_ctrl_t remote; + ll_pdu_length_ctrl_t suggested; // global setting + uint8_t isProcessingReq; + uint8_t isWatingRsp; + uint8_t isChanged; + uint8_t dummy[1]; +}llPduLenManagment_t; + +typedef struct +{ + uint8_t allPhy; + uint8_t txPhy; + uint8_t rxPhy; + uint8_t dummy[1]; +}ll_phy_ctrl_t; + +typedef struct +{ + uint8_t m2sPhy; + uint8_t s2mPhy; + uint16_t instant; +}ll_phy_update_ind_t; + +typedef struct +{ + ll_phy_ctrl_t def; + ll_phy_ctrl_t local; + ll_phy_ctrl_t req; + ll_phy_ctrl_t rsp; + uint16_t phyOptions; + uint8_t isChanged; + uint8_t isProcessingReq; + uint8_t isWatingRsp; + uint8_t status; + uint8_t dummy[2]; + +}llPhyModeManagment_t; + +// 2020-02-21 add for CTE req & rsp logic +typedef struct +{ + uint8_t isChanged; + uint8_t isProcessingReq; + uint8_t isWatingRsp; // wait other Ctrl command procedure + uint8_t errorCode; +}llCTEModeManagement_t; + +// for timer drift adjust +typedef struct +{ + uint32 coarse; // number of 625us ticks at SFD capture + uint16 fine; // number of 31.25ns ticks at SFD capture +} sysTime_t; + +// Encryption +typedef struct +{ + // Note: IV and SKD provide enough room for the full IV and SKD. When the + // Master and Slave values are provided, the result is one combined + // (concatenated) value. + uint8 IV[ LL_ENC_IV_LEN ]; // combined master and slave IV values concatenated + uint8 SKD [ LL_ENC_SKD_LEN ]; // combined master and slave SKD values concatenated + uint8 RAND[ LL_ENC_RAND_LEN ]; // random vector from Master + uint8 EDIV[ LL_ENC_EDIV_LEN ]; // encrypted diversifier from Master + uint8 nonce[ LL_ENC_NONCE_LEN ]; // current nonce with current IV value + uint8 SK[ LL_ENC_SK_LEN ]; // session key derived from LTK and SKD + uint8 LTK[ LL_ENC_LTK_LEN ]; // Long Term Key from Host + uint8 SKValid; // flag that indicates the Session Key is valid + uint8 LTKValid; // Long Term Key is valid + uint32 txPktCount; // used for nonce formation during encryption (Note: 39 bits!)?? + uint32 rxPktCount; // used for nonce formation during encryption (Note: 39 bits!)?? + uint8 encRestart; // flag to indicate if an encryption key change took place + uint8 encRejectErrCode; // error code for rejecting encryption request + // ALT: COULD USE ONE VARIABLE AND STATES FOR THESE FLAGS; IF SO, THE + // CONTROL PROCEDURE WOULD NEED TO BE REWORKED. + uint8 startEncRspRcved; // flag to indicate the Start Request has been responded to + uint8 pauseEncRspRcved; // flag to indicate the Pause Request has been responded to + uint8 encReqRcved; // flag to indicate an Enc Req was received in a Enc Pause procedure + + + uint8 startEncReqRcved; // flag to indicate the Start Request has been responded to + uint8 rejectIndRcved; // flag to indicate the Start Encryption needs to be aborted + +} encInfo_t; + +// Packet Error Rate Information - General +typedef struct +{ + uint16 numPkts; // total number of packets + uint16 numCrcErr; // total number of packets with CRC error + uint16 numEvents; // total number of connection events + uint16 numMissedEvts; // total number of missed connection events +} perInfo_t; + +typedef struct +{ + // adv channel statistics + int ll_send_undirect_adv_cnt; + int ll_send_nonconn_adv_cnt; + int ll_send_scan_adv_cnt; + int ll_send_hdc_dir_adv_cnt; + int ll_send_ldc_dir_adv_cnt; + + // adv in conn event + int ll_send_conn_adv_cnt; + int ll_conn_adv_pending_cnt; + + // scan in conn event + int ll_conn_scan_pending_cnt; + + // slave counter + int ll_recv_scan_req_cnt; + int ll_send_scan_rsp_cnt; + int ll_recv_conn_req_cnt; + int ll_send_conn_rsp_cnt; + + // whitelist + int ll_filter_scan_req_cnt; + int ll_filter_conn_req_cnt; + + // scan + int ll_recv_adv_pkt_cnt; + int ll_send_scan_req_cnt; + int ll_recv_scan_rsp_cnt; + + + // connection event counters + int ll_conn_succ_cnt; // LL accept connect, but not always sync succ + + int ll_link_lost_cnt; + int ll_link_estab_fail_cnt; + + // connection packet statistics +// int ll_recv_ctrl_pkt_cnt; +// int ll_recv_data_pkt_cnt; +// int ll_recv_invalid_pkt_cnt; +// +// int ll_recv_abnormal_cnt; +// +// int ll_send_data_pkt_cnt; +// +// int ll_conn_event_cnt; +// int ll_recv_crcerr_event_cnt; // CRC error detected in the connection event +// int ll_conn_event_timeout_cnt; // timeout connection event countt + + int ll_rx_peer_cnt; // scan/conn request counter, to consider whether we need it + + // LL <-> HCI packets statistics +// int ll_to_hci_pkt_cnt; +// int ll_hci_to_ll_pkt_cnt; +// +// int ll_hci_buffer_alloc_err_cnt; + + //ll_hw err cnt + int ll_evt_shc_err; + + //ll_hw err cnt + int ll_trigger_err; + int ll_rfifo_rst_err; + int ll_rfifo_rst_cnt; + int ll_rfifo_read_err; + + // reserve counter + int ll_tbd_cnt1; + int ll_tbd_cnt2; + int ll_tbd_cnt3; + int ll_tbd_cnt4; + int ll_tbd_cnt5; + int ll_tbd_cnt6; + int ll_tbd_cnt7; + int ll_tbd_cnt8; + +} llGlobalStatistics_t; + +// ======= multi-connection +typedef struct +{ + // connection packet statistics + uint32_t ll_recv_ctrl_pkt_cnt; + uint32_t ll_recv_data_pkt_cnt; + uint32_t ll_recv_invalid_pkt_cnt; + + uint32_t ll_recv_abnormal_cnt; + + uint32_t ll_send_data_pkt_cnt; + + uint32_t ll_conn_event_cnt; + uint32_t ll_recv_crcerr_event_cnt; // CRC error detected in the connection event + uint32_t ll_conn_event_timeout_cnt; // timeout connection event countt + + // LL <-> HCI packets statistics + uint32_t ll_to_hci_pkt_cnt; + uint32_t ll_hci_to_ll_pkt_cnt; + + uint32_t ll_hci_buffer_alloc_err_cnt; + + uint32_t ll_miss_master_evt_cnt; + uint32_t ll_miss_slave_evt_cnt; + + + // reserve counter + uint32_t ll_tbd_cnt1; + uint32_t ll_tbd_cnt2; + uint32_t ll_tbd_cnt3; + uint32_t ll_tbd_cnt4; + +} llLinkStatistics_t; + +typedef struct +{ + uint8_t chanMap[5]; + uint16_t chanMapUpdateEvent; // event count to indicate when to apply pending chan map update + uint8_t chanMapUpdated; +} preChanMapUpdate_t; + + +// Connection Data +typedef struct +{ + uint8_t rx_timeout; // ----- + uint8_t rx_crcok; // ----- + uint8_t allocConn; // flag to indicate if this connection is allocated + uint8_t active; // flag to indicate if this connection is active + uint8_t connId; // connection ID + uint8_t firstPacket; // flag to indicate when the first packet has been received. 0 means TURE, 1 means FALSE + + uint16_t currentEvent; // current event number + uint16_t nextEvent; // next active event number + uint16_t lastCurrentEvent; + uint16_t expirationEvent; // event at which the LSTO has expired + uint16_t expirationValue; // number of events to a LSTO expiration + + + uint16_t scaFactor; // SCA factor for timer drift calculation + uint32_t timerDrift; // saved timer drift adjustment to avoid recalc + uint32_t accuTimerDrift; // accumulate timer drift + // Connection Parameters + uint32_t lastTimeToNextEvt; // the time to next event from the previous connection event + uint8_t slaveLatencyAllowed; // flag to indicate slave latency is permitted + uint16_t slaveLatency; // current slave latency; 0 means inactive + uint8_t lastSlaveLatency; // last slave latency value used + uint16_t slaveLatencyValue; // current slave latency value (when enabled) + + uint32_t accessAddr; // saved synchronization word to be used by Slave + uint32_t initCRC; // connection CRC initialization value (24 bits) + + uint8_t sleepClkAccuracy; // peer's sleep clock accurracy; used by own device to determine timer drift + connParam_t curParam; + + // current connection parameters + // Channel Map + uint8_t nextChan; // the channel for the next active connection event + uint8_t currentChan; // the channel for the currently completed connection event + uint8_t lastCurrentChan; // the channel for the last currentChan for disable slavelatency usage + + uint8_t numUsedChans; // count of the number of usable data channels + // uint8_t hopLength; // used for finding next data channel at next connection event + uint8_t chanMapTable[LL_MAX_NUM_DATA_CHAN]; // current chan map table that is in use for this connection + + uint8_t chanMap[5]; + + chanMap_t chanMapUpdate; // slave chanMapUpdate for different connId + preChanMapUpdate_t preChanMapUpdate; // used for disable latency + uint8_t hop; + + // TX Related + uint8_t txDataEnabled; // flag that indicates whether data output is allowed + llDataQ_t txDataQ; // queue of Tx Data packets + // RX Related + uint8_t rxDataEnabled; // flag that indicates whether data input is allowed + uint8_t lastRssi; // last data packet RSSI received on this connection + + uint16_t foff; // A2 add, sync qualitiy indicator, estimated by rx BB + uint8_t carrSens; // A2 add, estimated freq offset by rx BB ,foff-512-->[-512 511]KHz + + // Control Packet Information + ctrlPktInfo_t ctrlPktInfo; // information for control procedure processing + // Parameter Update Control Procedure + uint8_t pendingParamUpdate; // flag to indicate connection parameter update is pending + uint16_t paramUpdateEvent; // event count to indicate when to apply pending param update + connParam_t paramUpdate; // update parameters + // Channel Map Update Control Procedure + uint8_t pendingChanUpdate; // flag to indicate connection channel map update is pending + uint16 chanMapUpdateEvent; // event count to indicate when to apply pending chan map update + // Encryption Data Control Procedure + uint8 encEnabled; // flag to indicate that encryption is enabled for this connection + encInfo_t encInfo; // structure that holds encryption related data + // Feature Set + featureSet_t featureSetInfo; // feature set for this connection + // Version Information + verExchange_t verExchange; // version information exchange + verInfo_t verInfo; // peer version information + // Termination Control Procedure + termInfo_t termInfo; // structure that holds connection termination data + // Unknnown Control Packet + uint8 unknownCtrlType; // value of unknown control type + // Packet Error Rate + perInfo_t perInfo; // PER + + uint8_t isCollision; + uint8_t rejectOpCode; + + ll_phy_update_ind_t phyUpdateInfo; // ll_phy update + // Parameter Update Control Procedure + uint8_t pendingPhyModeUpdate; // flag to indicate connection ll phy update is pending + uint16_t phyModeUpdateEvent; + + uint8_t sn_nesn; // use to save last sn/nesn in new IC + + // for new IC + uint8_t llMode; // for RTLP & TRLP loop, may need change the HW engine mode. + + // =============== A2 multi connection + uint8_t ctrlDataIsProcess ; // seding a control packet or not + uint8_t ctrlDataIsPending ; // control packet is pending to be sent +// uint8_t dummy[2]; // for 4-bytes align + + int anchor_point_base_time; // do we need it? + int anchor_point_fine_time; // do we need it? + + int next_event_base_time; // do we need it? + int next_event_fine_time; // do we need it? + + ctrl_packet_buf ctrlData; + llLinkBuf_t ll_buf; + + // DLE + llPduLenManagment_t llPduLen; + llPhyModeManagment_t llPhyModeCtrl; + + // add after BBB ROM release, PHY format + uint8_t llRfPhyPktFmt; + // add after BBB ROM release, channel selection algorithm + uint8_t channel_selection; + + llLinkStatistics_t pmCounter; + + // 2020-01-19 add for CTE + // llCTE_ReqFlag,llCTE_RspFlag only indicate CTE Request and Response enable or disable status + uint8 llCTE_ReqFlag; + uint8 llCTE_RspFlag; + // CTE REQ & RSP Control + llCTEModeManagement_t llCTEModeCtrl; + CTEInfo_t llConnCTE; + + // reserved variables + uint32 llTbd1; + uint32 llTbd2; + uint32 llTbd3; + uint32 llTbd4; +} llConnState_t; + +typedef struct +{ + uint8 rsc_idx; // connection ID, reserved for dynamic resource allocate + uint8 priority; + uint8 linkRole; // link role, slave(LL_ROLE_SLAVE) or master(LL_ROLE_MASTER) + + uint32 task_period; // schedule period, calculate from connection interval, in us. required??? + uint32 task_duration; // task duration + uint32 remainder; // remainder time + +// uint32 lastTimerValue; // last timer configure value + +} llScheduleInfo_t; + +// Per BLE LL Connection (max number is BLE_LL_MAX_NUM_LL_CONNS) +typedef struct +{ + uint8 numLLConns; // number of allocated connections + uint8 numLLMasterConns; // number of master, to check whether we need it + uint8 currentConn; // the LL connection currently in use + + llScheduleInfo_t scheduleInfo[MAX_NUM_LL_CONN_ROM_LIMT]; // scheduler information + + // ========== common link parameter for all master connection + uint16 connInterval; // connection interval + uint16 slaveLatency; // number of connection events the slave can ignore + uint16 connTimeout; // supervision connection timeout + + uint32 per_slot_time; // delta T per resource slot + + uint32 timerExpiryTick; // last LL timer expiry tick in 1s timer + uint32 current_timer; // LL timer initial load value + +} llConns_t; + +// for extended/periodic adv shceduler +typedef struct +{ +// uint8 advInfoIdx; // index in the adv parameters array +// uint8 advSetIdx; // index in the adv parameters array + uint8 adv_handler; + extAdvInfo_t *pAdvInfo; + +// uint8 eventType; // adv event type + +// uint32 task_period; // schedule period, calculate from connection interval, in us. required??? +// uint32 task_duration; // task duration + uint32 nextEventRemainder; // remainder time + uint32 auxPduRemainder; // remainder time + +} llAdvScheduleInfo_t; + +typedef struct +{ +// uint8 advInfoIdx; // index in the adv parameters array +// uint8 advSetIdx; // index in the adv parameters array + uint8 adv_handler; + periodicAdvInfo_t *pAdvInfo_prd; + extAdvInfo_t *pAdvInfo; + +// uint32 task_period; // schedule period, calculate from connection interval, in us. required??? +// uint32 task_duration; // task duration + uint32 nextEventRemainder; // primary channel PDU remainder time + uint32 auxPduRemainder; // auxilary channel PDU remainder time + +} llPeriodicAdvScheduleInfo_t; + +// periodic scanner context +typedef struct +{ + uint16 syncHandler; + uint8 valid; // the syncInfo is valid or not + uint8 syncEstOk; // sync the periodic adv event OK? + uint8 event1stFlag; // indicate LL is searching AUX_SYNC_IND PDU + + uint16 skip; + uint32 syncTimeout; // unit us, need *1250 when convert from HCI value + uint8 syncCteType; + +// syncInfoOffset_t offset; + + uint32 advInterval; // periodic adv event interval, unit us, need *1250 when convert from air interface PDU value + + uint8 chnMap[5]; + + uint8_t chanMapTable[LL_MAX_NUM_DATA_CHAN]; + uint8_t numUsedChans; // count of the number of usable data channels + + uint8 sca; + + uint8 accessAddress[4]; + uint16 channelIdentifier; + uint8 crcInit[3]; + + uint8 advPhy; + uint8 current_channel; // current scan channel, for AUX_CHAIN_IND, it may different with 1st PDU channel + uint8 currentEventChannel; // current periodic adv event 1st PDU channel + uint16 eventCounter; // periodic adv event counter + + uint16 syncLostTime; + + uint32 nextEventRemainder; // next periodic advertisement event remainder time + + // 2020-01-17 add for CTE Sampling + CTEInfo_t IQSampleInfo; +} llPeriodicScannerInfo_t; + +// ===== BBB ROM code added +typedef struct +{ + uint8 isTimer1RecoverRequired; + uint32 timer1Remainder; + +// uint8 isTimer2RecoverRequired; +// uint32 timer2Remainder; +// +// uint8 isTimer3RecoverRequired; +// uint32 timer3Remainder; + + uint8 isTimer4RecoverRequired; + uint32 timer4Remainder; +} llSleepContext; + +typedef uint8 llStatus_t; + +// Packet Error Rate Information By Channel +typedef struct +{ + uint16 numPkts[ LL_MAX_NUM_DATA_CHAN ]; + uint16 numCrcErr[ LL_MAX_NUM_DATA_CHAN ]; +} perByChan_t; + +typedef struct +{ + uint16 rxNumPkts[ LL_MAX_NUM_DATA_CHAN ]; + uint16 rxNumCrcErr[ LL_MAX_NUM_DATA_CHAN ]; + uint16 txNumRetry[ LL_MAX_NUM_DATA_CHAN ]; + uint16 TxNumAck[ LL_MAX_NUM_DATA_CHAN ]; + uint16 rxToCnt[ LL_MAX_NUM_DATA_CHAN ]; + uint16 connEvtCnt[ LL_MAX_NUM_DATA_CHAN ]; + + +} perStatsByChan_t; + +typedef struct +{ + uint16 rxNumPkts; + uint16 rxNumCrcErr; + uint16 txNumRetry; + uint16 TxNumAck; + uint16 rxToCnt; + uint16 connEvtCnt; + + +} perStats_t; + + +typedef enum{ + LE_1M_PHY= 0x01, + LE_2M_PHY= 0x02, + LE_CODED_PHY=0x04, + +}PhyModeCtrl_e; + +typedef uint8_t ( *LL_PLUS_AdvDataFilterCB_t )(void); + +typedef uint8_t ( *LL_PLUS_ScanRequestFilterCB_t )(void); + + +// Counters +typedef struct +{ + uint8 numTxDone; // TX pkts ACK'ed (auto-empty not counted) + uint8 numTxAck; // TX pkts ACK'ed (both auto-empty and TX FIFO packets) + uint8 numTxCtrlAck; // TX control pkts ACK'ed + uint8 numTxCtrl; // TX control pkts TX'ed + uint8 numTxRetrans; // retrans + auto-empty retrans + uint8 numTx; // trans (incl. auto-empty) + retrans (incl. auto-empty) + uint8 numRxOk; // non-empty correctly RX'ed and not ignored data and control pkts + uint8 numRxCtrl; // correctly RX'ed control pkts + uint8 numRxNotOk; // RX'ed with bad CRC + uint8 numRxIgnored; // correctly RX'ed, but ignored + uint8 numRxEmpty; // correctly RX'ed empty packets + uint8 numRxFifoFull; // correctly RX'ed but discarded due to full RX FIFO +} rfCounters_t; + + +// global variables +extern uint8_t LL_TaskID; +extern uint8_t llState; +extern peerInfo_t peerInfo; +extern advInfo_t adv_param; +extern scanInfo_t scanInfo; // scan data +extern initInfo_t initInfo; // Initiator info +extern extScanInfo_t extScanInfo; // extended Scanner info +extern extInitInfo_t extInitInfo; // extended Initiator info +extern chanMap_t chanMapUpdate; +extern featureSet_t deviceFeatureSet; +//extern preChanMapUpdate_t preChanMapUpdate[]; + +extern uint8 g_maxConnNum; +extern uint8 g_maxPktPerEventTx; +extern uint8 g_maxPktPerEventRx; +extern llConnState_t *conn_param; + +extern uint8 numComplPkts; +extern uint8 numComplPktsLimit; + +extern verInfo_t verInfo; + +extern rfCounters_t rfCounters; + +extern llConns_t g_ll_conn_ctx; + +extern llGlobalStatistics_t g_pmCounters; + +extern llPduLenManagment_t g_llPduLen; +//extern llPhyModeManagment_t g_llPhyModeCtrl; + +extern peerInfo_t g_llWhitelist[]; +// Resolving list +extern resolvingListInfo_t g_llResolvinglist[]; +extern uint8 g_llRlEnable; +extern uint8 g_llRlDeviceNum; // current device number in resolving list, should not exceed LL_RESOLVINGLIST_ENTRY_NUM +extern uint16 g_llRlTimeout; + +// extended advertiser +extern extAdvInfo_t *g_pExtendedAdvInfo; +extern periodicAdvInfo_t *g_pPeriodicAdvInfo; +extern uint8 g_extAdvNumber; // number of ext adv set +extern uint8 g_perioAdvNumber; // number of periodic adv set + +extern uint16 g_advSetMaximumLen; + +// extended adv scheduler context +extern llAdvScheduleInfo_t *g_pAdvSchInfo; +extern uint8 g_schExtAdvNum; // current schedule extended adv number +extern uint8 g_currentExtAdv; // current schedule extended adv index + +// ==== periodic adv scheduler context +extern llPeriodicAdvScheduleInfo_t *g_pAdvSchInfo_periodic; // periodic adv scheduler info +extern uint8 g_schExtAdvNum_periodic; // current scheduler periodic adv number +extern uint8 g_currentExtAdv_periodic; // current scheduler periodic adv index + +extern uint32 g_advPerSlotTick; // us +extern uint32 g_advSlotPeriodic; // us +extern uint32 g_currentAdvTimer; // us +extern uint32 g_timerExpiryTick; // us + +extern uint8 g_currentTimerTask; + +extern llSleepContext g_llSleepContext; + + +extern llPeriodicScannerInfo_t g_llPeriodAdvSyncInfo[]; +// =========== BBB ROM code +#define LL_TASK_EXTENDED_ADV 0x01 +#define LL_TASK_PERIODIC_ADV 0x02 + +#define LL_TASK_EXTENDED_SCAN 0x03 +#define LL_TASK_EXTENDED_INIT 0x04 +#define LL_TASK_PERIODIC_SCAN 0x05 +//#define LL_TASK_SLAVE_CONN 0x03 +//#define LL_TASK_MASTER_CONN 0x04 +#define LL_TASK_OTHERS 0x10 +#define LL_TASK_INVALID 0xFF +extern uint8 llTaskState; + +extern extAdvHdr_t ext_adv_hdr; + + // 2020-02-15 add for connectionless IQ Sample buffer +extern uint16 *g_pLLcteISample; +extern uint16 *g_pLLcteQSample; +#endif + + + + + + + + + + + + + + diff --git a/src/components/ble/controller/ll_enc.h b/src/components/ble/controller/ll_enc.h new file mode 100644 index 0000000..735141b --- /dev/null +++ b/src/components/ble/controller/ll_enc.h @@ -0,0 +1,97 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +/******************************************************************************* + Filename: ll_enc.h + Revised: + Revision: + + Description: This file contains the Link Layer (LL) types, contants, + API's etc. for the Bluetooth Low Energy (BLE) Controller + CCM encryption and decryption. + + This API is based on ULP BT LE D09R23. + + +*******************************************************************************/ + +#ifndef LL_ENC_H +#define LL_ENC_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* + * INCLUDES + */ +#include "bcomdef.h" +#include "ll_def.h" + +/******************************************************************************* + * MACROS + */ + +/******************************************************************************* + * CONSTANTS + */ + +#define LL_ENC_TX_DIRECTION_MASTER 1 +#define LL_ENC_TX_DIRECTION_SLAVE 0 +#define LL_ENC_RX_DIRECTION_MASTER 0 +#define LL_ENC_RX_DIRECTION_SLAVE 1 + +#define LL_ENC_DATA_BANK_MASK 0xFF7F + +#define LL_ENC_TRUE_RAND_BUF_SIZE ((LL_ENC_IV_LEN/2) + (LL_ENC_SKD_LEN/2)) + +// Generate Session Key using LTK for key and SKD for plaintext. +#define LL_ENC_GenerateSK LL_ENC_AES128_Encrypt + +/******************************************************************************* + * TYPEDEFS + */ + +/******************************************************************************* + * LOCAL VARIABLES + */ + +/******************************************************************************* + * GLOBAL VARIABLES + */ +extern uint8 dataPkt[2*LL_ENC_BLOCK_LEN]; +extern uint8 cachedTRNGdata[ LL_ENC_TRUE_RAND_BUF_SIZE ]; + +/******************************************************************************* + * Functions + */ + +// Random Number Generation +extern uint8 LL_ENC_GeneratePseudoRandNum( void ); +extern uint8 LL_ENC_GenerateTrueRandNum( uint8 *buf, uint8 len ); + +// CCM Encryption +extern void LL_ENC_AES128_Encrypt( uint8 *key, uint8 *plaintext, uint8 *ciphertext ); +extern void LL_ENC_AES128_Decrypt( uint8 *key, uint8 *ciphertext, uint8 *plaintext ); +extern void LL_ENC_LoadEmptyIV( void ); +extern void LL_ENC_ReverseBytes( uint8 *buf, uint8 len ); +extern void LL_ENC_GenDeviceSKD( uint8 *SKD ); +extern void LL_ENC_GenDeviceIV( uint8 *IV ); +extern void LL_ENC_GenerateNonce( uint32 pktCnt, uint8 direction, uint8 *nonce ); +extern void LL_ENC_EncryptMsg( uint8 *nonce, uint8 pktLen, uint8 *pbuf, uint8 *mic ); +extern void LL_ENC_DecryptMsg( uint8 *nonce, uint8 pktLen, uint8 *pBuf, uint8 *mic ); +extern void LL_ENC_Encrypt( llConnState_t *connPtr, uint8 pktHdr, uint8 pktLen, uint8 *pBuf ); +extern uint8 LL_ENC_Decrypt( llConnState_t *connPtr, uint8 pktHdr, uint8 pktLen, uint8 *pBuf ); +extern void LL_ENC_sm_ah( uint8 *pK, uint8 *pR, uint8 *pAh ); +// + +extern void LL_ENC_MoveData( uint8 *pDst, uint8 *pSrc, uint16 len ); + +#ifdef __cplusplus +} +#endif + +#endif /* LL_ENC_H */ diff --git a/src/components/ble/controller/ll_hw_drv.h b/src/components/ble/controller/ll_hw_drv.h new file mode 100644 index 0000000..f6130a4 --- /dev/null +++ b/src/components/ble/controller/ll_hw_drv.h @@ -0,0 +1,217 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#ifndef _LL_HW_DRV_H_ +#define _LL_HW_DRV_H_ + +#include "types.h" +#include "ll_def.h" +#include "bus_dev.h" +#include "rf_phy_driver.h" + +// LL_HW_REGISTER_ADDRESS +#define BB_HW_BASE 0x40030000 //BB_HW Base address +#define LL_HW_BASE 0x40031000 //LL_HW Base address +#define LL_HW_TFIFO (LL_HW_BASE+0x400) +#define LL_HW_RFIFO (LL_HW_BASE+0xC00) + +#define LL_HW_WRT_EMPTY_PKT *(volatile uint32_t *)(LL_HW_TFIFO) = 0x00000001 + +//LL_HW_MODE +#define LL_HW_STX 0x0000 +#define LL_HW_SRX 0x0001 + +#define LL_HW_TRX 0x0010 +#define LL_HW_RTX 0x0012 + +#define LL_HW_TRLP 0x0020 +#define LL_HW_TRLP_EMPT 0x0022 + +#define LL_HW_RTLP 0x0030 +#define LL_HW_RTLP_1ST 0x0031 +#define LL_HW_RTLP_EMPT 0x0032 + +#define HCLK16M + +//#define LL_HW_CYCLES_PER_US CYCLES_PER_US +#ifdef HCLK16M +#define LL_HW_HCLK_PER_US 16 // +#define LL_HW_HCLK_PER_US_BITS 4 +#else +#define LL_HW_HCLK_PER_US 32 // +#define LL_HW_HCLK_PER_US_BITS 5 +#endif + +#define LL_HW_FIFO_MARGIN 70 // + + +// LL_HW_IRQ_STATUS +#define LIRQ_MD 0x0001 //bit00 +#define LIRQ_CERR 0x0002 //bit01 +#define LIRQ_RTO 0x0004 //bit02 +#define LIRQ_RFULL 0x0008 //bit03 +#define LIRQ_RHALF 0x0010 //bit04 +#define LIRQ_BIT5 0x0020 //bit05 +#define LIRQ_BIT6 0x0040 //bit06 +#define LIRQ_BIT7 0x0080 //bit07 +#define LIRQ_TD 0x0100 //bit08 +#define LIRQ_RD 0x0200 //bit09 +#define LIRQ_COK 0x0400 //bit10 +#define LIRQ_CERR2 0x0800 //bit11 +#define LIRQ_LTO 0x1000 //bit12 +#define LIRQ_NACK 0x2000 //bit13 +#define LIRQ_BIT14 0x4000 //bit14 +#define LIRQ_BIT15 0x8000 //bit15 + +#define LL_HW_IRQ_MASK 0x3FFF //total 14bit + +// LL_HW_RFIFO_CTRL +#define LL_HW_IGN_EMP 0x0001 //bit0 +#define LL_HW_IGN_CRC 0x0002 //bit1 +#define LL_HW_IGN_SSN 0x0004 //bit2 +#define LL_HW_IGN_ALL 0x0007 //bit2 +#define LL_HW_IGN_NONE 0x0000 + +// LL_MD_RX_INI +#define LL_HW_MD_RX_SET0 0x4000 //set md_rx ini=0 and md_rx_soft=0 +#define LL_HW_MD_RX_SET1 0x4440 //set md_rx ini=1 and md_rx_soft=1 + +//LL FIFO DEPTH CONFIG +#define LL_HW_FIFO_TX_2K_RX_2K 0x0200 //TX FIFO 512 Word +#define LL_HW_FIFO_TX_3K_RX_1K 0x0300 //TX FIFO 768 Word +#define LL_HW_FIFO_TX_1K_RX_3K 0x0100 //TX FIFO 256 Word + +//BB CRC Format Setting +#define LL_HW_CRC_BLE_FMT 0x02 +#define LL_HW_CRC_ZB_FMT 0x03 +#define LL_HW_CRC_16_FMT 0x04 +#define LL_HW_CRC_NULL 0x00 + + +//ANT SWITCH SLOT +#define LL_HW_ANT_WIN_1us 4 +#define LL_HW_ANT_SW_CTE_OFF 0x00 +#define LL_HW_ANT_SW_CTE_AUTO 0x01 +#define LL_HW_ANT_SW_TX_MANU 0x02 +#define LL_HW_ANT_SW_RX_MANU 0x04 + +//CTE Supplement Config +#define CTE_SUPP_AUTO 0xC0 +#define CTE_SUPP_LEN_SET 0x00 +#define CTE_SUPP_NULL 0x00 + +#define CONNLESS_CTE_TYPE_AOA 0x00 +#define CONNLESS_CTE_TYPE_AOD_1us 0x01 +#define CONNLESS_CTE_TYPE_AOD_2us 0x02 +#define CONN_CTE_TYPE_AOA 0x01 +#define CONN_CTE_TYPE_AOD_1us 0x02 +#define CONN_CTE_TYPE_AOD_2us 0x04 + + +// 2020-01-21 add for CONN CTE REQ TYPE +#define CTE_REQ_TYPE_AOA 0x00 +#define CTE_REQ_TYPE_AOD_1US 0x01 +#define CTE_REQ_TYPE_AOD_2US 0x02 + +#define BLE_HEAD_WITH_CTE(x) (((x & 0x20)==0x00) ? 0:1) + + + +void ll_hw_set_stx(void); +void ll_hw_set_srx(void); +void ll_hw_set_trx(void); +void ll_hw_set_rtx(void); +void ll_hw_set_trlp(uint8_t snNesn,uint8_t txPktNum,uint8_t rxPktNum,uint8_t mdRx); +void ll_hw_set_rtlp(uint8_t snNesn,uint8_t txPktNum,uint8_t rxPktNum,uint8_t mdRx,uint32_t rdCntIni); +void ll_hw_set_rtlp_1st(uint8_t snNesn,uint8_t txPktNum,uint8_t rxPktNum,uint8_t mdRx); +void ll_hw_config(uint8_t ll_mode,uint8_t snNesn,uint8_t txPktNum,uint8_t rxPktNum,uint8_t mdRx,uint32_t rdCntIni); + + + +void ll_hw_go(void); +void ll_hw_trigger(void); +void ll_hw_clr_irq(void); +void ll_hw_set_irq(uint32_t mask); +void ll_hw_set_empty_head(uint16_t txHeader); +void ll_hw_set_rx_timeout_1st(uint32_t rxTimeOut); +void ll_hw_set_rx_timeout(uint32_t rxTimeOut); +void ll_hw_set_tx_rx_release(uint16_t txTime,uint16_t rxTime); +void ll_hw_set_rx_tx_interval(uint32_t intvTime); +void ll_hw_set_tx_rx_interval(uint32_t intvTime); +void ll_hw_set_trx_settle(uint8_t tmBb,uint8_t tmAfe,uint8_t tmPll); +void ll_hw_set_loop_timeout(uint32_t loopTimeOut); +void ll_hw_set_loop_nack_num(uint8_t nAckNum); +void ll_hw_set_timing(uint8_t pktFmt); + +void ll_hw_set_tfifo_space(uint16 space); + +void ll_hw_set_ant_switch_mode(uint8_t mode); +void ll_hw_set_ant_switch_timing(uint8_t antWin,uint8_t antDly); +void ll_hw_set_ant_pattern(uint32_t ant1, uint32_t ant0); + +void ll_hw_set_cte_rxSupp(uint8_t rxSupp); +void ll_hw_set_cte_txSupp(uint8_t txSupp); +uint8_t ll_hw_get_iq_RawSample(uint16_t* p_iSample, uint16_t* p_qSample); + + +void ll_hw_rst_rfifo(void); +void ll_hw_rst_tfifo(void); + +void ll_hw_ign_rfifo(uint8_t ignCtrl); + +void ll_hw_get_tfifo_info(int* rdPtr,int* wrPtr,int* wrDepth); +void ll_hw_get_rfifo_info(int* rdPtr,int* wrPtr,int* rdDepth); +void ll_hw_get_rxPkt_stats(uint8_t *crcErrNum,uint8_t *rxTotalNum,uint8_t *rxPktNum); + +uint8_t ll_hw_read_rfifo(uint8_t* rxPkt, uint16_t* pktLen, uint32_t* pktFoot0, uint32_t* pktFoot1); +uint8_t ll_hw_read_rfifo_zb(uint8_t* rxPkt, uint16_t* pktLen, uint32_t* pktFoot0, uint32_t* pktFoot1); +uint8_t ll_hw_read_rfifo_pplus(uint8_t* rxPkt, uint16_t* pktLen, uint32_t* pktFoot0, uint32_t* pktFoot1); + +uint8_t ll_hw_write_tfifo(uint8_t* rxPkt, uint16_t pktLen); + +void ll_hw_set_crc_fmt(uint8_t txCrc,uint8_t rxCrc); +void ll_hw_set_pplus_pktfmt(uint8_t plen); + +uint8_t ll_hw_get_snNesn(void); +uint8_t ll_hw_get_txAck(void); +uint8_t ll_hw_get_nAck(void); +uint8_t ll_hw_get_rxPkt_num(void); +uint32_t ll_hw_get_anchor(void); +uint32_t ll_hw_get_irq_status(void); +uint8_t ll_hw_get_fsm_status(void); +uint8_t ll_hw_get_last_ack(void); +uint32_t ll_hw_get_loop_cycle(void); + +uint8_t ll_hw_get_rxPkt_Total_num(void); +uint8_t ll_hw_get_rxPkt_CrcErr_num(void); +uint8_t ll_hw_get_rxPkt_CrcOk_num(void); + +uint8_t ll_hw_get_iq_RawSample(uint16_t* p_iSample, uint16_t* p_qSample); + +uint8_t ll_hw_update_rtlp_mode(uint8_t llMode); +uint8_t ll_hw_update_trlp_mode(uint8_t llMode); +uint8_t ll_hw_update(uint8_t llMode,uint8_t *txAck,uint8_t *rxRec,uint8_t *snNesn); + + +void byte_to_bit(uint8_t byteIn,uint8_t* bitOut); +void bit_to_byte(uint8_t* bitIn,uint8_t * byteOut); +void zigbee_crc16_gen(uint8_t *dataIn,int length,uint8_t *seed,uint8_t *crcCode); + + +// copy from rf.h by Zeng jiaping +void set_tx_rx_mode(uint8_t mode); + +void set_channel(uint32_t channel); + +void set_access_address( uint32_t access); +void set_crc_seed(uint32_t seed); +void set_whiten_seed(uint32_t channel); + +void set_max_length(uint32_t length); + +void calculate_whiten_seed(void); + + +#endif diff --git a/src/components/ble/controller/ll_sleep.h b/src/components/ble/controller/ll_sleep.h new file mode 100644 index 0000000..5c324d1 --- /dev/null +++ b/src/components/ble/controller/ll_sleep.h @@ -0,0 +1,96 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#ifndef LL_SLEEP__H_ +#define LL_SLEEP__H_ + +#include "OSAL_PwrMgr.h" + +#include "ll_def.h" +#include "ll_common.h" + +/******************************************************************************* + MACROS +*/ + +// convert 625us units to 32kHz units without round: the ratio of 32 kHz ticks +// to 625 usec ticks is 32768/1600 = 20.48 or 512/25 +#define LL_SLEEP_625US_TO_32KHZ( us ) ((((uint32) (us)) * 512) / 25) + +// convert 31.25ns units to 32kHz units without round: the ratio of 31.25ns usec +// ticks to 32 kHz ticks is 32M/32768 = 976.5625 or 15625/16, but using 976 is +// close enough given the accuracy +#define LL_SLEEP_31_25NS_TO_32KHZ( ns ) (((uint32) (ns)) / 976) + + +// 32KHz timer: +// crystal: 32768Hz +// RC : 32768Hz Should be same as Xtal +// timer1 - 4 : 4MHz +#define TIMER_TO_32K_CRYSTAL 122 // 122.0703 +#define TIMER_TO_32K_RC 122 // 125 + +#define STD_RC32_8_CYCLE_16MHZ_CYCLE 3906 // standard 16Mhz cycles for 8 RC32KHz tick +#define STD_CRY32_8_CYCLE_16MHZ_CYCLE 3906 // standard 16Mhz cycles for 8 crystal 32KHz tick +#define ERR_THD_RC32_CYCLE 200 // error threshold for N+x rcosc tracking cycle + + +#define CRY32_8_CYCLE_16MHZ_CYCLE_MAX (3906 + 196) // tracking value range std +/- 5% +#define CRY32_8_CYCLE_16MHZ_CYCLE_MIN (3906 - 196) + +#define STD_RC32_16_CYCLE_16MHZ_CYCLE (7812) // standard 16Mhz cycles for 16 RC32KHz tick +#define STD_CRY32_16_CYCLE_16MHZ_CYCLE (7812) // standard 16Mhz cycles for 16 crystal 32KHz tick + + +#define CRY32_16_CYCLE_16MHZ_CYCLE_MAX (7812 + 391) // tracking value range std +/- 5% +#define CRY32_16_CYCLE_16MHZ_CYCLE_MIN (7812 - 391) + +#define SLEEP_MAGIC 0x032141B6 + + +/******************************************************************************* + TYPEDEFS +*/ +typedef enum +{ + MCU_SLEEP_MODE, + SYSTEM_SLEEP_MODE, + SYSTEM_OFF_MODE +} Sleep_Mode; + + + +/******************************************************************************* + Functions +*/ + +// is sleep allow +uint8 isSleepAllow(void); + +void enableSleep(void); + +void disableSleep(void); + +void setSleepMode(Sleep_Mode mode); + +Sleep_Mode getSleepMode(void); + +void enterSleepProcess(uint32 time); + +void wakeupProcess(void); + +void set_sleep_flag(int flag); + +unsigned int get_sleep_flag(void); + +void config_RTC(uint32 time); + +void enter_sleep_off_mode(Sleep_Mode mode); + +#endif // LL_SLEEP__H_ + + + + diff --git a/src/components/ble/controller/rf_phy_driver.h b/src/components/ble/controller/rf_phy_driver.h new file mode 100644 index 0000000..ecc717d --- /dev/null +++ b/src/components/ble/controller/rf_phy_driver.h @@ -0,0 +1,511 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file rf_phy_driver.h + @brief + @version 1.0 + @date 24. Aug. 2017 + @author Zhongqi Yang + + + +*******************************************************************************/ +#ifndef __RF_PHY_DRIVER_H_ +#define __RF_PHY_DRIVER_H_ + + + + +/******************************************************************************* + INCLUDES +*/ + + +#include "clock.h" +#include "ll_hw_drv.h" +#include "jump_function.h" +#include "version.h" + + +typedef enum _RF_PHY_CLK_SEL +{ + RF_PHY_CLK_SEL_16M_XTAL = 0, + RF_PHY_CLK_SEL_32M_DBL_B = 1, + RF_PHY_CLK_SEL_32M_DBL = 2, + RF_PHY_CLK_SEL_32M_DLL = 3 +} rfphy_clk_t; + +typedef enum _RX_ADC_CLK_SEL +{ + RX_ADC_CLK_SEL_16M_XTAL = 0, + RX_ADC_CLK_SEL_32M_DBL_B = 1, + RX_ADC_CLK_SEL_32M_DBL = 2, + RX_ADC_CLK_SEL_32M_DLL = 3 +} rxadc_clk_t; + + + + +/******************************************************************************* + Global Var +*/ +extern volatile uint8_t g_rfPhyTpCal0; //** two point calibraion result0 **// +extern volatile uint8_t g_rfPhyTpCal1; //** two point calibraion result1 **// +extern volatile uint8_t g_rfPhyTpCal0_2Mbps; //** two point calibraion result0 **// +extern volatile uint8_t g_rfPhyTpCal1_2Mbps; //** two point calibraion result1 **// +extern volatile uint8_t g_rfPhyTxPower; //** rf pa output power setting [0x00 0x1f] **// +extern volatile uint8_t g_rfPhyPktFmt; //** rf_phy pkt format config **// +extern volatile uint32 g_rfPhyRxDcIQ; //** rx dc offset cal result **// +extern volatile int8_t g_rfPhyFreqOffSet; + +extern volatile sysclk_t g_system_clk; +extern volatile rfphy_clk_t g_rfPhyClkSel; +extern volatile rxadc_clk_t g_rxAdcClkSel; + +extern volatile uint8_t g_rfPhyDtmCmd[]; +extern volatile uint8_t g_rfPhyDtmEvt[]; +extern volatile uint8_t g_dtmModeType ; +extern volatile uint8_t g_dtmCmd ; +extern volatile uint8_t g_dtmFreq ; +extern volatile uint8_t g_dtmLength ; +extern volatile uint8_t g_dtmExtLen ; +extern volatile uint16_t g_dtmPktIntv ; +extern volatile uint8_t g_dtmPKT ; +extern volatile uint8_t g_dtmCtrl ; +extern volatile uint8_t g_dtmPara ; +extern volatile uint8_t g_dtmEvt ; +extern volatile uint8_t g_dtmStatus ; +extern volatile uint16_t g_dtmPktCount ; +extern volatile uint16_t g_dtmRxCrcNum ; +extern volatile uint16_t g_dtmRxTONum ; +extern volatile uint16_t g_dtmRsp ; +extern volatile uint8_t g_dtmTxPower ;//RF_PHY_TX_POWER_EXTRA_MAX;//according to the rfdrv +extern volatile uint16_t g_dtmFoff ; +extern volatile uint8_t g_dtmRssi ; +extern volatile uint8_t g_dtmCarrSens ; +extern volatile uint8_t g_dtmTpCalEnable ; //default enable tpcal +extern volatile uint32_t g_dtmTick ; +extern volatile uint32_t g_dtmPerAutoIntv ; +extern volatile uint32_t g_dtmAccessCode ; + +extern volatile uint8_t g_rc32kCalRes ; +/******************************************************************************* + MACRO +*/ +#define RF_PHY_EXT_PREAMBLE_US (8) // ext ble preamble length + +#define PHY_REG_RD(x) *(volatile uint32_t *)(x) +#define PHY_REG_WT(x,y) *(volatile uint32_t *)(x) = (y) +#define RF_CHN_TO_FREQ(x) + +#define DCDC_REF_CLK_SETTING(x) subWriteReg(0x4000f014,25,25, (0x01&(x))) +#define DCDC_CONFIG_SETTING(x) subWriteReg(0x4000f014,18,15, (0x0f&(x))) +/* + 0x4000f0c4 is AON-SLEEP_R[1], used for xtal tracking +*/ +#define AON_CLEAR_XTAL_TRACKING_AND_CALIB AP_AON->SLEEP_R[1]=0 + +#define AON_SAVE_RC32K_CALIB_FLG(x) subWriteReg(0x4000f0c4, 7, 7, (0x01&(x))) +#define AON_LOAD_RC32K_CALIB_FLG (((*(volatile uint32_t*)0x4000f0c4) & 0x80) == 0x80) + +#define AON_SAVE_XTAL_TRACKING_RST_FLG(x) subWriteReg(0x4000f0c4, 3, 2, (0x03&(x))) +#define AON_SAVE_XTAL_TRACKING_RST_NUMBER(x) subWriteReg(0x4000f0c4,15, 8, (0xff&(x))) +#define AON_LOAD_XTAL_TRACKING_RST_NUMBER (((*(volatile uint32_t*)0x4000f0c4) & 0xff00)>>8) +/* + crystal 16M matching cap control for ana. + 5'b0 means 5pF,5'b11110 means 17pF.step size is 2.step value is 0.8pF. +*/ +#define XTAL16M_CAP_SETTING(x) subWriteReg(0x4000f0bc, 4, 0, (0x1f&(x))) + +#define XTAL16M_CURRENT_SETTING(x) subWriteReg(0x4000f0bc, 6, 5, (0x03&(x))) +#define DIG_LDO_CURRENT_SETTING(x) subWriteReg(0x4000f014,22,21, (0x03&(x))) + +#define RF_PHY_LO_LDO_SETTING(x) subWriteReg(0x400300cc,11,10, (0x03&(x))) +#define RF_PHY_PA_VTRIM_SETTING(x) subWriteReg(0x400300dc, 9, 7, (0x03&(x))) +#define RF_PHY_LNA_LDO_SETTING(x) subWriteReg(0x400300dc, 6, 5, (0x03&(x))) + + +#define RF_PHY_TPCAL_CALC(tp0,tp1,chn) ((tp0)>(tp1) ?(((tp0<<5)-(tp0-tp1)*(chn)+16)>>5) : tp0 ) +//DTM STATE +#define RF_PHY_DTM_IDL 0 +#define RF_PHY_DTM_CMD 1 +#define RF_PHY_DTM_EVT 2 +#define RF_PHY_DTM_TEST 3 + +#define RF_PHY_DTM_SYNC_WORD 0x71764129 +#define RF_PHY_DTM_PRBS9_SEED 0xffffffff +#define RF_PHY_DTM_CRC_WT 0x00555555 + +//DTM MODE TYPE +#define RF_PHY_DTM_MODE_RESET 0 +#define RF_PHY_DTM_MODE_TX_BURST 2 +#define RF_PHY_DTM_MODE_TX_CTMOD 4 +#define RF_PHY_DTM_MODE_TX_SINGLE 6 +#define RF_PHY_DTM_MODE_RX_PER 8 +#define RF_PHY_DTM_MODE_TEST_END 10 +#define RF_PHY_DTM_MODE_SET_LENGTH_UP2BIT 12 + +#define RF_PHY_DTM_MODE_SET_PHY_1M 16 +#define RF_PHY_DTM_MODE_SET_PHY_2M 18 +#define RF_PHY_DTM_MODE_SET_PHY_500K 20 +#define RF_PHY_DTM_MODE_SET_PHY_125K 22 +#define RF_PHY_DTM_MODE_SET_PHY_ZB 24 + +#define RF_PHY_DTM_MODE_ASSUME_TX_MOD_INDX_STANDARD 32 +#define RF_PHY_DTM_MODE_ASSUME_TX_MOD_INDX_STABLE 34 +#define RF_PHY_DTM_MODE_READ_SUPPORTED_TEST_CASE 36 +#define RF_PHY_DTM_MODE_READ_MAX_TX_OCTETS 38 +#define RF_PHY_DTM_MODE_READ_MAX_TX_TIME 40 +#define RF_PHY_DTM_MODE_READ_MAX_RX_OCTETS 42 +#define RF_PHY_DTM_MODE_READ_MAX_RX_TIME 44 + +#define RF_PHY_DTM_MODE_SET_ACCCODE_0 114 +#define RF_PHY_DTM_MODE_SET_ACCCODE_1 116 +#define RF_PHY_DTM_MODE_SET_ACCCODE_2 118 +#define RF_PHY_DTM_MODE_SET_ACCCODE_3 120 + +#define RF_PHY_DTM_MODE_SET_FREQ_FOFF 122 +#define RF_PHY_DTM_MODE_SET_TPCAL_MANUAL 124 +#define RF_PHY_DTM_MODE_SET_XTAL_CAP 126 +#define RF_PHY_DTM_MODE_SET_TX_POWER 128 +#define RF_PHY_DTM_MODE_GET_FOFF 130 +#define RF_PHY_DTM_MODE_GET_TPCAL 132 +#define RF_PHY_DTM_MODE_GET_RSSI 134 +#define RF_PHY_DTM_MODE_GET_CARR_SENS 136 +#define RF_PHY_DTM_MODE_GET_PER_AUTO 138 + +#define RF_PHY_DTM_MODE_ATE_SET_PKTFMT 0xd0 //208 +#define RF_PHY_DTM_MODE_ATE_SET_TXPOWER 0xd1 + +#define RF_PHY_DTM_MODE_ATE_TX_BURST 0xe0 //224 +#define RF_PHY_DTM_MODE_ATE_TX_MOD 0xe1 +#define RF_PHY_DTM_MODE_ATE_TX_CARR 0xe2 +#define RF_PHY_DTM_MODE_ATE_RX_AUTOGAIN 0xe3 +#define RF_PHY_DTM_MODE_ATE_RX_FIXGAIN 0xe4 +#define RF_PHY_DTM_MODE_ATE_RX_DEMOD 0xe5 +#define RF_PHY_DTM_MODE_ATE_RX2TX 0xe6 +#define RF_PHY_DTM_MODE_ATE_TX2RX 0xe7 + +#define RF_PHY_DTM_MODE_ATE_RESET 0xef + +#define RF_PHY_DTM_MODE_ERROR 254 + + +/******************************************************************************* + CONSTANTS +*/ +#define PKT_FMT_ZIGBEE 0 +#define PKT_FMT_BLE1M 1 +#define PKT_FMT_BLE2M 2 +#define PKT_FMT_BLR500K 3 +#define PKT_FMT_BLR125K 4 + + +#if (SDK_VER_CHIP==__DEF_CHIP_QFN32__) + #define RF_PHY_TX_POWER_EXTRA_MAX 0x3f + #define RF_PHY_TX_POWER_MAX 0x1f + #define RF_PHY_TX_POWER_MIN 0x00 + + #define RF_PHY_TX_POWER_5DBM 0x3f + #define RF_PHY_TX_POWER_0DBM 0x1f + #define RF_PHY_TX_POWER_N2DBM 0x0f + #define RF_PHY_TX_POWER_N5DBM 0x0a + #define RF_PHY_TX_POWER_N20DBM 0x01 + + #elif(SDK_VER_CHIP==__DEF_CHIP_TSOP16__) + #define RF_PHY_TX_POWER_EXTRA_MAX 0x3f + #define RF_PHY_TX_POWER_MAX 0x1f + #define RF_PHY_TX_POWER_MIN 0x00 + + #define RF_PHY_TX_POWER_5DBM 0x1d + #define RF_PHY_TX_POWER_4DBM 0x17 + #define RF_PHY_TX_POWER_3DBM 0x15 + #define RF_PHY_TX_POWER_0DBM 0x0d + + #define RF_PHY_TX_POWER_N2DBM 0x0a + #define RF_PHY_TX_POWER_N5DBM 0x06 + #define RF_PHY_TX_POWER_N6DBM 0x05 + #define RF_PHY_TX_POWER_N10DBM 0x03 + #define RF_PHY_TX_POWER_N15DBM 0x02 + #define RF_PHY_TX_POWER_N20DBM 0x01 +#else + #warning" CHECK Chip Version " +#endif + +#define RF_PHY_FREQ_FOFF_00KHZ 0 +#define RF_PHY_FREQ_FOFF_20KHZ 5 +#define RF_PHY_FREQ_FOFF_40KHZ 10 +#define RF_PHY_FREQ_FOFF_60KHZ 15 +#define RF_PHY_FREQ_FOFF_80KHZ 20 +#define RF_PHY_FREQ_FOFF_100KHZ 25 +#define RF_PHY_FREQ_FOFF_120KHZ 30 +#define RF_PHY_FREQ_FOFF_140KHZ 35 +#define RF_PHY_FREQ_FOFF_160KHZ 40 +#define RF_PHY_FREQ_FOFF_180KHZ 45 +#define RF_PHY_FREQ_FOFF_200KHZ 50 +#define RF_PHY_FREQ_FOFF_N20KHZ -5 +#define RF_PHY_FREQ_FOFF_N40KHZ -10 +#define RF_PHY_FREQ_FOFF_N60KHZ -15 +#define RF_PHY_FREQ_FOFF_N80KHZ -20 +#define RF_PHY_FREQ_FOFF_N100KHZ -25 +#define RF_PHY_FREQ_FOFF_N120KHZ -30 +#define RF_PHY_FREQ_FOFF_N140KHZ -35 +#define RF_PHY_FREQ_FOFF_N160KHZ -40 +#define RF_PHY_FREQ_FOFF_N180KHZ -45 +#define RF_PHY_FREQ_FOFF_N200KHZ -50 + + +#define RF_PHY_DTM_MANUL_NULL 0x00 +#define RF_PHY_DTM_MANUL_FOFF 0x01 +#define RF_PHY_DTM_MANUL_TXPOWER 0x02 +#define RF_PHY_DTM_MANUL_XTAL_CAP 0x04 +#define RF_PHY_DTM_MANUL_MAX_GAIN 0x08 + +#define RF_PHY_DTM_MANUL_ALL 0xFF +/******************************************************************************* + FUNCION DEFINE +*/ +/************************************************************************************** + @fn rf_phy_ini + + @brief This function process for rf phy ini call api + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void rf_phy_ini (void); + +/************************************************************************************** + @fn rf_phy_ana_cfg + + @brief This function process for rf phy analog block config, + include PLL, RX_FRONT_END,PA Power. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void rf_phy_ana_cfg (void); + +/************************************************************************************** + @fn rf_phy_bb_cfg + + @brief This function process for rf phy baseband tx and rx config. + + input parameters + + @param pktMod:0 for Zigbee, 1 for BLE1M, 2 for BLE2M, 3or4 for BLELR. + + output parameters + + @param None. + + @return None. +*/ +void rf_phy_bb_cfg (uint8_t pktFmt); + + +void rf_phy_change_cfg0(uint8_t pktFmt); +/************************************************************************************** + @fn rf_tpCal_cfg + + @brief This function process for rf tpCal config + + input parameters + + @param rfChn: two point calibration rf channel setting(0-80)->2400-2480MHz. + + output parameters + + @param None. + + @return None. +*/ +void rf_tpCal_cfg (uint8_t rfChn); + +/************************************************************************************** + @fn rf_tp_cal + + @brief This function process for tx tp calibration. + + input parameters + + @param rfChn : rfFreq=2400+rfChn + fDev : used to config the tpCal fDelt, 0 for 0.5M, 1 for 1M + + + output parameters + + @param none + + @return kCal : cal result for rfChn. +*/ +uint8_t rf_tp_cal (uint8_t rfChn,uint8_t fDev); + +/************************************************************************************** + @fn rf_rxDcoc_cfg + + @brief This function process for rx dc offset calibration and canncellation config. + + input parameters + + @param rfChn : rfFreq=2400+rfChn + bwSet : used to config rx complex filter bandwitdh. 1 for 1MHz, other for 2MHz + + + output parameters + + @param dcCal : cal result for rxdc, dcQ[13:8],dcI[5:0] + + @return none +*/ +void rf_rxDcoc_cfg (uint8_t rfChn,uint8_t bwSet,volatile uint32* dcCal); + +/************************************************************************************** + @fn rf_tpCal_gen_cap_arrary + + @brief This function process for tx tp calibration,genearte the tpCal cap arrary. + + input parameters + + @param + + output parameters + + @param none + + @return kCal : cal result for rfChn. +*/ +void rf_tpCal_gen_cap_arrary(void); + +/************************************************************************************** + @fn rf_phy_direct_test + + @brief This function process for rf phy direct test. + + input parameters + + @param none + + output parameters + + @param none + + @return none +*/ +void rf_phy_direct_test (void); + +/************************************************************************************** + @fn rf_phy_dtm_cmd_parse + + @brief This function process for rf phy direct test,cmd parse + + input parameters + + @param none + + output parameters + + @param none + + @return none +*/ +void rf_phy_dtm_cmd_parse(void); + +/************************************************************************************** + @fn rf_phy_dtm_evt_send + + @brief This function process for rf phy direct test, test mode trigged + + input parameters + + @param none + + output parameters + + @param none + + @return none +*/ +void rf_phy_dtm_evt_send (uint8_t dtmType); + +/************************************************************************************** + @fn rf_phy_dtm_trigged + + @brief This function process for rf phy direct test, test mode trigged + + input parameters + + @param none + + output parameters + + @param none + + @return none +*/ +void rf_phy_dtm_trigged (void); + +/************************************************************************************** + @fn rf_phy_get_pktFoot + + @brief This function process to get pkt foot + + input parameters + + @param none + + output parameters + + @param rssi : recv signal strength indicator(-dBm) + foff : estimated freq offset by rx BB ,foff-512-->[-512 511]KHz + carrSens: sync qualitiy indicator, estimated by rx BB. + + @return none +*/ +void rf_phy_get_pktFoot (uint8* rssi, uint16* foff,uint8* carrSens); +void rf_phy_get_pktFoot_fromPkt(uint32 pktFoot0, uint32 pktFoot1,uint8* rssi, uint16* foff,uint8* carrSens); + +/************************************************************************************** + @fn rf_phy_set_txPower + + @brief This function process for rf phy tx power config + + input parameters + + @param txPower : tx pa power setting (0~0x1f) + + output parameters + + @param none + + @return none +*/ +void rf_phy_set_txPower (uint8 txPower); + +uint8_t rf_phy_direct_test_ate(uint32_t cmdWord,uint8_t regPatchNum,uint32_t* regPatchAddr,uint32_t* regPatchVal,uint8_t* dOut); + +void rf_phy_dtm_ext_rx_demod_burst(uint8_t rfChnIdx,int8_t rfFoff,uint8_t xtal_cap,uint8_t pktLength,uint32 rxTimeOut,uint32 rxWindow, + uint16_t* rxEstFoff,uint8_t* rxEstRssi,uint8_t* rxEstCarrSens,uint16_t* rxPktNum); + +void rf_phy_dtm_zigbee_pkt_gen(void); + +void TRNG_INIT(void); + +uint8_t TRNG_Rand(uint8_t* buf,uint8_t len); +#endif diff --git a/src/components/ble/hci/hci_data.h b/src/components/ble/hci/hci_data.h new file mode 100644 index 0000000..7b24b48 --- /dev/null +++ b/src/components/ble/hci/hci_data.h @@ -0,0 +1,81 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + Filename: hci_c_data.h + Revised: $Date: 2011-08-22 08:41:40 -0700 (Mon, 22 Aug 2011) $ + Revision: $Revision: 27235 $ + + Description: This file handles HCI data for the BLE Controller. + + +*******************************************************************************/ + +#ifndef HCI_C_DATA_H +#define HCI_C_DATA_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* + INCLUDES +*/ + +/******************************************************************************* + MACROS +*/ + +/******************************************************************************* + CONSTANTS +*/ + +/******************************************************************************* + TYPEDEFS +*/ + +/******************************************************************************* + LOCAL VARIABLES +*/ + +/******************************************************************************* + GLOBAL VARIABLES +*/ + +/* +** HCI Data API +*/ + + +/******************************************************************************* + @fn HCI_ReverseBytes + + @brief This function is used to reverse the order of the bytes in + an array in place. + + input parameters + + @param *buf - Pointer to buffer containing bytes to be reversed. + @param len - Number of bytes in buffer. + + Note: The length must be even. + + Note: The maximum length is 128 bytes. + + output parameters + + @param None. + + @return None. +*/ +extern void HCI_ReverseBytes( uint8* buf, + uint8 len ); + + +#ifdef __cplusplus +} +#endif + +#endif /* HCI_C_DATA_H */ diff --git a/src/components/ble/hci/hci_event.h b/src/components/ble/hci/hci_event.h new file mode 100644 index 0000000..97e3ebb --- /dev/null +++ b/src/components/ble/hci/hci_event.h @@ -0,0 +1,275 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + Filename: hci_c_event.h + Revised: $Date: 2012-05-01 12:13:50 -0700 (Tue, 01 May 2012) $ + Revision: $Revision: 30418 $ + + Description: This file contains the HCI Event types, contants, + external functions etc. for the BLE Controller. + + +*******************************************************************************/ + +#ifndef HCI_C_EVENT_H +#define HCI_C_EVENT_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* + INCLUDES +*/ +#include "hci_tl.h" + +extern uint32 bleEvtMask; +extern uint8 pHciEvtMask[]; + +/******************************************************************************* + MACROS +*/ + +/******************************************************************************* + CONSTANTS +*/ + +// Event Mask Default Values +#define BT_EVT_MASK_BYTE0 0xFF +#define BT_EVT_MASK_BYTE1 0xFF +#define BT_EVT_MASK_BYTE2 0xFF +#define BT_EVT_MASK_BYTE3 0xFF +#define BT_EVT_MASK_BYTE4 0xFF +#define BT_EVT_MASK_BYTE5 0x9F +#define BT_EVT_MASK_BYTE6 0x00 +#define BT_EVT_MASK_BYTE7 0x20 +// +#define LE_EVT_MASK_DEFAULT 0x00005F + +/******************************************************************************* + TYPEDEFS +*/ + +/******************************************************************************* + LOCAL VARIABLES +*/ + +/******************************************************************************* + GLOBAL VARIABLES +*/ + +/* +** Internal Functions +*/ + +extern void hciInitEventMasks( void ); + +/* +** HCI Controller Events +*/ + +/******************************************************************************* + @fn HCI_DataBufferOverflowEvent + + @brief This function sends the Data Buffer Overflow Event to the Host. + + input parameters + + @param linkType - HCI_LINK_TYPE_SCO_BUFFER_OVERFLOW, + HCI_LINK_TYPE_ACL_BUFFER_OVERFLOW + + output parameters + + @param None. + + @return None. +*/ +extern void HCI_DataBufferOverflowEvent( uint8 linkType ); + + +/******************************************************************************* + @fn HCI_NumOfCompletedPacketsEvent + + @brief This function sends the Number of Completed Packets Event to + the Host. + + Note: Currently, the number of handles is always one. + + input parameters + + @param numHandles - Number of handles. + @param handlers - Array of connection handles. + @param numCompletedPkts - Array of number of completed packets for + each handle. + + output parameters + + @param None. + + @return None. +*/ +extern void HCI_NumOfCompletedPacketsEvent( uint8 numHandles, + uint16* handlers, + uint16* numCompletedPackets ); + + +/******************************************************************************* + @fn HCI_CommandCompleteEvent + + @brief This function sends a Command Complete Event to the Host. + + input parameters + + @param opcode - The opcode of the command that generated this event. + @param numParam - The number of parameters in the event. + @param param - The event parameters associated with the command. + + output parameters + + @param None. + + @return None. +*/ +extern void HCI_CommandCompleteEvent( uint16 opcode, + uint8 numParam, + uint8* param ); + + +/******************************************************************************* + @fn HCI_VendorSpecifcCommandCompleteEvent + + @brief This function sends a Vendor Specific Command Complete Event to + the Host. + + input parameters + + @param opcode - The opcode of the command that generated this event. + @param numParam - The number of parameters in the event. + @param param - The event parameters associated with the command. + + output parameters + + @param None. + + @return None. +*/ +extern void HCI_VendorSpecifcCommandCompleteEvent( uint16 opcode, + uint8 len, + uint8* param ); + + +/******************************************************************************* + @fn HCI_CommandStatusEvent + + @brief This function sends a Command Status Event to the Host. + + input parameters + + @param status - The resulting status of the comamnd. + @param opcode - The opcode of the command that generated this event. + + output parameters + + @param None. + + @return None. +*/ +extern void HCI_CommandStatusEvent( uint8 status, + uint16 opcode ); + + +/******************************************************************************* + @fn HCI_HardwareErrorEvent + + @brief This function sends a Hardware Error Event to the Host. + + input parameters + + @param hwErrorCode - The hardware error code. + + output parameters + + @param None. + + @return None. +*/ +extern void HCI_HardwareErrorEvent( uint8 hwErrorCode ); + + +/******************************************************************************* + @fn HCI_SendCommandStatusEvent + + @brief This generic function sends a Command Status event to the Host. + It is provided as a direct call so the Host can use it directly. + + input parameters + + @param eventCode - The event code. + @param status - The resulting status of the comamnd. + @param opcode - The opcode of the command that generated this event. + + output parameters + + @param None. + + @return None. +*/ +extern void HCI_SendCommandStatusEvent ( uint8 eventCode, + uint16 status, + uint16 opcode ); + + +/******************************************************************************* + @fn HCI_SendCommandCompleteEvent + + @brief This generic function sends a Command Complete or a Vendor + Specific Command Complete Event to the Host. + + input parameters + + @param eventCode - The event code. + @param opcode - The opcode of the command that generated this event. + @param numParam - The number of parameters in the event. + @param param - The event parameters associated with the command. + + output parameters + + @param None. + + @return None. +*/ +extern void HCI_SendCommandCompleteEvent ( uint8 eventCode, + uint16 opcode, + uint8 numParam, + uint8* param ); + + +/******************************************************************************* + @fn HCI_SendControllerToHostEvent + + @brief This generic function sends a Controller to Host Event. + + input parameters + + @param eventCode - Bluetooth event code. + @param dataLen - Length of dataField. + @param pData - Pointer to data. + + output parameters + + @param None. + + @return None. +*/ +extern void HCI_SendControllerToHostEvent( uint8 eventCode, + uint8 dataLen, + uint8* pData ); + +#ifdef __cplusplus +} +#endif + +#endif /* HCI_C_EVENT_H */ diff --git a/src/components/ble/hci/hci_host.h b/src/components/ble/hci/hci_host.h new file mode 100644 index 0000000..2602602 --- /dev/null +++ b/src/components/ble/hci/hci_host.h @@ -0,0 +1,63 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +/************************************************************************************************* +**************************************************************************************************/ +#ifndef HCI_HOST_H +#define HCI_HOST_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ +#include "OSAL.h" +#include "osal_bufmgr.h" +#include "hci.h" +#include "hci_task.h" + + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/* HCI packet header length */ +#define HCI_EVT_HEADER_LEN 3 /* packet type + evt code(1) + len(1) */ +#define HCI_DATA_HEADER_LEN 5 /* packet type + connection handle(2) + len(2) */ + +/* First 12 bits of the HCI data packet is connection handle */ +#define HCI_CONNECTION_HANDLE_MASK 0x0FFF +#define HCI_PB_MASK 0x03 +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + + +/********************************************************************* + FUNCTIONS - API +*/ + + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* HCI_HOST_H */ + + diff --git a/src/components/ble/hci/hci_task.h b/src/components/ble/hci/hci_task.h new file mode 100644 index 0000000..c965199 --- /dev/null +++ b/src/components/ble/hci/hci_task.h @@ -0,0 +1,88 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************* +**************************************************************************************************/ +#ifndef HCI_TASK_H +#define HCI_TASK_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ +#include "OSAL.h" +#include "hci.h" +#include "uart.h" +#include "hci_host.h" + +#include "hal.h" // added by ZJP + + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + + +/* UART port */ +#define HCI_UART_PORT HAL_UART_PORT_0 +#define HCI_UART_BR HAL_UART_BR_38400 +#define HCI_UART_FC TRUE +#define HCI_UART_FC_THRESHOLD 48 +#define HCI_UART_RX_BUF_SIZE 128 +#define HCI_UART_TX_BUF_SIZE 128 +#define HCI_UART_IDLE_TIMEOUT 6 +#define HCI_UART_INT_ENABLE TRUE + +/* HCI Event List */ +#define HCI_EVENT_SEND_DATA 0x01 +#define HCI_EVENT_SEND_CMD 0x02 +#define HCI_HOST_PARSE_EVT 0x04 +#define HCI_HOST_INCOMING_EVT 0x08 +#define HCI_HOST_INCOMING_DATA 0x10 + + +/* Define the osal queue size for data and cmd */ +#define HCI_HOST_MAX_DATAQUEUE_SIZE 20 +#define HCI_HOST_MAX_CMDQUEUE_SIZE 20 + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ +osal_msg_q_t HCI_HostDataQueue; + +uint8 hciHostNumQueuedData; /* Number of data packets queued */ +const uint8 hciHostMaxNumDataQueue; /* Max number of data packets queued */ + +/********************************************************************* + FUNCTIONS - API +*/ +extern Status_t HCI_AddDataQueue( void* buf ); +extern Status_t HCI_AddCmdQueue( void* buf ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* HCI_TASK_H */ + + + + + + diff --git a/src/components/ble/hci/hci_tl.h b/src/components/ble/hci/hci_tl.h new file mode 100644 index 0000000..4bc3596 --- /dev/null +++ b/src/components/ble/hci/hci_tl.h @@ -0,0 +1,402 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + Filename: hci_tl.h + Revised: $Date: 2012-04-20 15:24:45 -0700 (Fri, 20 Apr 2012) $ + Revision: $Revision: 30292 $ + + Description: This file contains the types, contants, external functions + etc. for the BLE HCI Transport Layer. + +*******************************************************************************/ + +#ifndef HCI_TL_H +#define HCI_TL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* + INCLUDES +*/ + +#include "hci.h" +#include "OSAL.h" +#include "uart.h" +#include "hci_data.h" +#include "hci_event.h" + +extern uint8 hciTaskID; +// +extern uint8 hciTestTaskID; +extern uint8 hciGapTaskID; +extern uint8 hciL2capTaskID; +extern uint8 hciSmpTaskID; + +/******************************************************************************* + MACROS +*/ + +#define HCI_ASSERT(condition) HAL_ASSERT(condition) + +/******************************************************************************* + CONSTANTS +*/ + +// OSAL Task Events +#define HCI_TX_PROCESS_EVENT 0x0001 +#define HCI_TEST_UART_SEND_EVENT 0x0002 +#define HCI_BDADDR_UPDATED_EVENT 0x4000 +#define HCI_OSAL_MSG_EVENT SYS_EVENT_MSG + +// OSAL Message Header Events +#define HCI_CTRL_TO_HOST_EVENT 0x01 +#define HCI_HOST_TO_CTRL_CMD_EVENT 0x02 +#define HCI_HOST_TO_CTRL_DATA_EVENT 0x03 + +#define HCI_BDADDR_LEN 6 + +// Max Allowed HCI Packet +#define HCI_MAX_CMD_PKT_SIZE 0xFF +#define HCI_MAX_DATA_PKT_SIZE 0xFFFF + +// Max Data Length in Packet +#define HCI_DATA_MAX_DATA_LENGTH 27 + +// +// Minimum length for CMD packet is 1+2+1 +// | Packet Type (1) | OPCode(2) | Length(1) | +// +#define HCI_CMD_MIN_LENGTH 4 + +// +// Minimum length for EVENT packet is 1+1+1 +// | Packet Type (1) | Event Code(1) | Length(1) | +// +#define HCI_EVENT_MIN_LENGTH 3 + +// +// Minimum length for DATA packet is 1+2+2 +// | Packet Type (1) | Handler(2) | Length(2) | +// +#define HCI_DATA_MIN_LENGTH 5 + +// Max Number of Connections +#define HCI_MAX_NUM_CONNECTIONS 0x03 +// +#define HCI_TX_DATA_ANY_CONNECTION 0xFF + +// HCI Packet Types +#define HCI_CMD_PACKET 0x01 +#define HCI_ACL_DATA_PACKET 0x02 +#define HCI_SCO_DATA_PACKET 0x03 +#define HCI_EVENT_PACKET 0x04 + +/* +** HCI Command Opcodes +*/ + +// Link Control Commands +#define HCI_DISCONNECT 0x0406 +#define HCI_READ_REMOTE_VERSION_INFO 0x041D + +// Controller and Baseband Commands +#define HCI_SET_EVENT_MASK 0x0C01 +#define HCI_RESET 0x0C03 +#define HCI_READ_TRANSMIT_POWER 0x0C2D +#define HCI_SET_CONTROLLER_TO_HOST_FLOW_CONTROL 0x0C31 +#define HCI_HOST_BUFFER_SIZE 0x0C33 +#define HCI_HOST_NUM_COMPLETED_PACKETS 0x0C35 + +// Information Parameters +#define HCI_READ_LOCAL_VERSION_INFO 0x1001 +#define HCI_READ_LOCAL_SUPPORTED_COMMANDS 0x1002 +#define HCI_READ_LOCAL_SUPPORTED_FEATURES 0x1003 +#define HCI_READ_BDADDR 0x1009 + +// Status Parameters +#define HCI_READ_RSSI 0x1405 + +// LE Commands +#define HCI_LE_SET_EVENT_MASK 0x2001 +#define HCI_LE_READ_BUFFER_SIZE 0x2002 +#define HCI_LE_READ_LOCAL_SUPPORTED_FEATURES 0x2003 +#define HCI_LE_SET_RANDOM_ADDR 0x2005 +#define HCI_LE_SET_ADV_PARAM 0x2006 +#define HCI_LE_READ_ADV_CHANNEL_TX_POWER 0x2007 +#define HCI_LE_SET_ADV_DATA 0x2008 +#define HCI_LE_SET_SCAN_RSP_DATA 0x2009 +#define HCI_LE_SET_ADV_ENABLE 0x200A +#define HCI_LE_SET_SCAN_PARAM 0x200B +#define HCI_LE_SET_SCAN_ENABLE 0x200C +#define HCI_LE_CREATE_CONNECTION 0x200D +#define HCI_LE_CREATE_CONNECTION_CANCEL 0x200E +#define HCI_LE_READ_WHITE_LIST_SIZE 0x200F +#define HCI_LE_CLEAR_WHITE_LIST 0x2010 +#define HCI_LE_ADD_WHITE_LIST 0x2011 +#define HCI_LE_REMOVE_WHITE_LIST 0x2012 +#define HCI_LE_CONNECTION_UPDATE 0x2013 +#define HCI_LE_SET_HOST_CHANNEL_CLASSIFICATION 0x2014 +#define HCI_LE_READ_CHANNEL_MAP 0x2015 +#define HCI_LE_READ_REMOTE_USED_FEATURES 0x2016 +#define HCI_LE_ENCRYPT 0x2017 +#define HCI_LE_RAND 0x2018 +#define HCI_LE_START_ENCRYPTION 0x2019 +#define HCI_LE_LTK_REQ_REPLY 0x201A +#define HCI_LE_LTK_REQ_NEG_REPLY 0x201B +#define HCI_LE_READ_SUPPORTED_STATES 0x201C +#define HCI_LE_RECEIVER_TEST 0x201D +#define HCI_LE_TRANSMITTER_TEST 0x201E +#define HCI_LE_TEST_END 0x201F + +#define HCI_LE_SET_DATA_LENGTH 0x2022 +#define HCI_LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH 0x2023 +#define HCI_LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH 0x2024 + +// 0x2025, 0x2026 for P256 & DHkey + +#define HCI_LE_ADD_DEVICE_TO_RESOLVING_LIST 0x2027 +#define HCI_LE_REMOVE_DEVICE_FROM_RESOLVING_LIST 0x2028 +#define HCI_LE_CLEAR_RESOLVING_LIST 0x2029 +#define HCI_LE_READ_RESOLVING_LIST_SIZE 0x202A +#define HCI_LE_READ_PEER_RESOLVABLE_ADDRESS 0x202B // optional +#define HCI_LE_READ_LOCAL_RESOLVABLE_ADDRESS 0x202C // optional +#define HCI_LE_SET_ADDRESS_RESOLUTION_ENABLE 0x202D +#define HCI_LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TO 0x202E + +#define HCI_LE_READ_MAXIMUM_DATA_LENGTH 0x202F +#define HCI_LE_READ_PHY 0x2030 +#define HCI_LE_SET_DEFAULT_PHY 0x2031 +#define HCI_LE_SET_PHY 0x2032 + + +#define HCI_LE_SET_ADVERTISING_SET_RANDOM_ADDRESS 0x2035 +#define HCI_LE_SET_EXTENDER_ADVERTISING_PARAMETERS 0x2036 +#define HCI_LE_SET_EXTENDED_ADVERTISING_DATA 0x2037 +#define HCI_LE_Set_EXTENDED_SCAN_RESPONSE_DATA 0x2038 +#define HCI_LE_Set_EXTENDED_ADVERTISING_ENABLE 0x2039 +#define HCI_LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH 0x203A +#define HCI_LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS 0x203B +#define HCI_LE_REMOVE_ADVERTISING_SET 0x203C +#define HCI_LE_CLEAR_ADVERTISING_SETS 0x203D + +#define HCI_LE_SET_PERIODIC_ADVERTISING_PARAMETERS 0x203E +#define HCI_LE_SET_PERIODIC_ADVERTISING_DATA 0x203F +#define HCI_LE_Set_PERIODIC_ADVERTISING_ENABLE 0x2040 + +#define HCI_LE_SET_EXTENDED_SCAN_PARAMETERS 0x2041 +#define HCI_LE_SET_EXTENDED_SCAN_ENABLE 0x2042 +#define HCI_LE_EXTENDED_CREATE_CONNECTION 0x2043 + +#define HCI_LE_PERIODIC_ADVERTISING_CREATE_SYNC 0x2044 +#define HCI_LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL 0x2045 +#define HCI_LE_PERIODIC_ADVERTISING_TERMINATE_SYNC 0x2046 + +#define HCI_LE_ADD_DEVICE_TO_PERIODIC_ADVERTISER_LIST 0x2047 +#define HCI_LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISER_LIST 0x2048 +#define HCI_LE_CLEAR_PERIODIC_ADVERTISER_LIST 0x2049 +#define HCI_LE_READ_PERIODIC_ADVERTISER_LIST_SIZE 0x204A + + +/* Power config */ +#define HCI_LE_READ_TRANSMIT_POWER 0x204B +#define HCI_LE_READ_RF_PATH_COMPENSATION 0x204C +#define HCI_LE_WRITE_RF_PATH_COMPENSATION 0x204D + +/* privacy mode */ +#define HCI_LE_SET_PRIVACY_MODE 0x204E + + +/* CTE */ +#define HCI_LE_SET_CONNLESS_CTE_TRANS_PARAMETER 0x2051 +#define HCI_LE_SET_CONNLESS_CTE_TRANS_ENABLE 0x2052 +#define HCI_LE_SET_CONNLESS_IQ_SAMPLE_ENABLE 0x2053 +#define HCI_LE_SET_CONNCTE_RECV_PARAMETER 0x2054 +#define HCI_LE_SET_CONN_CTE_TRANSMIT_PARAMETER 0x2055 +#define HCI_LE_CONN_CTE_REQUEST_ENABLE 0x2056 +#define HCI_LE_CONN_CTE_RESPONSE_ENABLE 0x2057 +#define HCI_LE_READ_ANTENNA_INFO 0x2058 + +// LE Vendor Specific LL Extension Commands +#define HCI_EXT_SET_RX_GAIN 0xFC00 +#define HCI_EXT_SET_TX_POWER 0xFC01 +#define HCI_EXT_ONE_PKT_PER_EVT 0xFC02 +#define HCI_EXT_CLK_DIVIDE_ON_HALT 0xFC03 +#define HCI_EXT_DECLARE_NV_USAGE 0xFC04 +#define HCI_EXT_DECRYPT 0xFC05 +#define HCI_EXT_SET_LOCAL_SUPPORTED_FEATURES 0xFC06 +#define HCI_EXT_SET_FAST_TX_RESP_TIME 0xFC07 +#define HCI_EXT_MODEM_TEST_TX 0xFC08 +#define HCI_EXT_MODEM_HOP_TEST_TX 0xFC09 +#define HCI_EXT_MODEM_TEST_RX 0xFC0A +#define HCI_EXT_END_MODEM_TEST 0xFC0B +#define HCI_EXT_SET_BDADDR 0xFC0C +#define HCI_EXT_SET_SCA 0xFC0D +#define HCI_EXT_ENABLE_PTM 0xFC0E // Not a supported HCI command! Application only. +#define HCI_EXT_SET_FREQ_TUNE 0xFC0F +#define HCI_EXT_SAVE_FREQ_TUNE 0xFC10 +#define HCI_EXT_SET_MAX_DTM_TX_POWER 0xFC11 +#define HCI_EXT_MAP_PM_IO_PORT 0xFC12 +#define HCI_EXT_DISCONNECT_IMMED 0xFC13 +#define HCI_EXT_PER 0xFC14 +#define HCI_EXT_PER_BY_CHAN 0xFC15 // Not a supported HCI command! Application only. +#define HCI_EXT_EXTEND_RF_RANGE 0xFC16 +#define HCI_EXT_ADV_EVENT_NOTICE 0xFC17 // Not a supported HCI command! Application only. +#define HCI_EXT_CONN_EVENT_NOTICE 0xFC18 // Not a supported HCI command! Application only. +#define HCI_EXT_HALT_DURING_RF 0xFC19 +#define HCI_EXT_OVERRIDE_SL 0xFC1A +#define HCI_EXT_BUILD_REVISION 0xFC1B +#define HCI_EXT_DELAY_SLEEP 0xFC1C +#define HCI_EXT_RESET_SYSTEM 0xFC1D +#define HCI_EXT_OVERLAPPED_PROCESSING 0xFC1E +#define HCI_EXT_NUM_COMPLETED_PKTS_LIMIT 0xFC1F + +/* +** HCI Event Codes +*/ + +// BT Events +#define HCI_DISCONNECTION_COMPLETE_EVENT_CODE 0x05 +#define HCI_ENCRYPTION_CHANGE_EVENT_CODE 0x08 +#define HCI_READ_REMOTE_INFO_COMPLETE_EVENT_CODE 0x0C +#define HCI_COMMAND_COMPLETE_EVENT_CODE 0x0E +#define HCI_COMMAND_STATUS_EVENT_CODE 0x0F +#define HCI_BLE_HARDWARE_ERROR_EVENT_CODE 0x10 +#define HCI_NUM_OF_COMPLETED_PACKETS_EVENT_CODE 0x13 +#define HCI_DATA_BUFFER_OVERFLOW_EVENT 0x1A +#define HCI_KEY_REFRESH_COMPLETE_EVENT_CODE 0x30 + +// LE Event Code (for LE Meta Events) +#define HCI_LE_EVENT_CODE 0x3E + +// LE Meta Event Codes +#define HCI_BLE_CONNECTION_COMPLETE_EVENT 0x01 +#define HCI_BLE_ADV_REPORT_EVENT 0x02 +#define HCI_BLE_CONN_UPDATE_COMPLETE_EVENT 0x03 +#define HCI_BLE_READ_REMOTE_FEATURE_COMPLETE_EVENT 0x04 +#define HCI_BLE_LTK_REQUESTED_EVENT 0x05 +#define HCI_BLE_REMOTE_CONN_PARAMETER_REQUEST_EVENT 0X06 +#define HCI_BLE_DATA_LENGTH_CHANGE_EVENT 0x07 +#define HCI_BLE_READ_LOCAL_P256_PUB_KEY_COMPLETE_EVENT 0x08 +#define HCI_BLE_GENERATE_DHKEY_COMPLETE_EVENT 0x09 + +#define HCI_BLE_ENHANCED_CONNECTION_COMPLETE_EVENT 0x0A +#define HCI_BLE_DIRECTED_ADVERTISING_REPORT_EVENT 0x0B + +#define HCI_BLE_PHY_UPDATE_COMPLETE_EVENT 0x0C + +#define HCI_BLE_EXT_ADV_REPORT_EVENT 0x0D +#define HCI_BLE_PERIODIC_ADV_SYNC_ESTABLISHED_EVENT 0x0E +#define HCI_BLE_PERIODIC_ADV_REPORT_EVENT 0x0F +#define HCI_BLE_PERIODIC_ADV_SYNC_LOST_EVENT 0x10 + +#define HCI_LE_ADVERTISING_SET_TERMINATED 0x12 +#define HCI_LE_SCAN_REQUEST_RECEIVED 0x13 +#define HCI_LE_CHANNEL_SELECTION_ALGORITHM_EVENT 0x14 + +//2020-01-14 AOA/AOD Report event +#define HCI_LE_CONNECTIONLESS_IQ_REPORT_EVENT 0x15 +#define HCI_LE_CONNECTION_IQ_REPORT_EVENT 0x16 +#define HCI_LE_CTE_REQUEST_FAILED_REPORT 0x17 + + +// Vendor Specific Event Code +#define HCI_VE_EVENT_CODE 0xFF + +// LE Vendor Specific LL Extension Events +#define HCI_EXT_SET_RX_GAIN_EVENT 0x0400 +#define HCI_EXT_SET_TX_POWER_EVENT 0x0401 +#define HCI_EXT_ONE_PKT_PER_EVT_EVENT 0x0402 +#define HCI_EXT_CLK_DIVIDE_ON_HALT_EVENT 0x0403 +#define HCI_EXT_DECLARE_NV_USAGE_EVENT 0x0404 +#define HCI_EXT_DECRYPT_EVENT 0x0405 +#define HCI_EXT_SET_LOCAL_SUPPORTED_FEATURES_EVENT 0x0406 +#define HCI_EXT_SET_FAST_TX_RESP_TIME_EVENT 0x0407 +#define HCI_EXT_MODEM_TEST_TX_EVENT 0x0408 +#define HCI_EXT_MODEM_HOP_TEST_TX_EVENT 0x0409 +#define HCI_EXT_MODEM_TEST_RX_EVENT 0x040A +#define HCI_EXT_END_MODEM_TEST_EVENT 0x040B +#define HCI_EXT_SET_BDADDR_EVENT 0x040C +#define HCI_EXT_SET_SCA_EVENT 0x040D +#define HCI_EXT_ENABLE_PTM_EVENT 0x040E // Not a supported HCI command! Application only. +#define HCI_EXT_SET_FREQ_TUNE_EVENT 0x040F +#define HCI_EXT_SAVE_FREQ_TUNE_EVENT 0x0410 +#define HCI_EXT_SET_MAX_DTM_TX_POWER_EVENT 0x0411 +#define HCI_EXT_MAP_PM_IO_PORT_EVENT 0x0412 +#define HCI_EXT_DISCONNECT_IMMED_EVENT 0x0413 +#define HCI_EXT_PER_EVENT 0x0414 +#define HCI_EXT_PER_BY_CHAN_EVENT 0x0415 // Not a supported HCI command! Application only. +#define HCI_EXT_EXTEND_RF_RANGE_EVENT 0x0416 +#define HCI_EXT_ADV_EVENT_NOTICE_EVENT 0x0417 // Not a supported HCI command! Application only. +#define HCI_EXT_CONN_EVENT_NOTICE_EVENT 0x0418 // Not a supported HCI command! Application only. +#define HCI_EXT_HALT_DURING_RF_EVENT 0x0419 +#define HCI_EXT_OVERRIDE_SL_EVENT 0x041A +#define HCI_EXT_BUILD_REVISION_EVENT 0x041B +#define HCI_EXT_DELAY_SLEEP_EVENT 0x041C +#define HCI_EXT_RESET_SYSTEM_EVENT 0x041D +#define HCI_EXT_OVERLAPPED_PROCESSING_EVENT 0x041E +#define HCI_EXT_NUM_COMPLETED_PKTS_LIMIT_EVENT 0x041F + +/******************************************************************************* + TYPEDEFS +*/ + +/******************************************************************************* + LOCAL VARIABLES +*/ + +/******************************************************************************* + GLOBAL VARIABLES +*/ + +/* +** HCI OSAL API +*/ + +/******************************************************************************* + @fn HCI_Init + + @brief This is the HCI OSAL task initialization routine. + + input parameters + + @param taskID - The HCI OSAL task identifer. + + output parameters + + @param None. + + @return None. +*/ +extern void HCI_Init( uint8 taskID ); + + +/******************************************************************************* + @fn HCI_ProcessEvent + + @brief This is the HCI OSAL task process event handler. + + input parameters + + @param taskID - The HCI OSAL task identifer. + @param events - HCI OSAL task events. + + output parameters + + @param None. + + @return Unprocessed events. +*/ +extern uint16 HCI_ProcessEvent( uint8 task_id, + uint16 events ); + + +#ifdef __cplusplus +} +#endif + +#endif /* HCI_TL_H */ diff --git a/src/components/ble/host/att_internal.h b/src/components/ble/host/att_internal.h new file mode 100644 index 0000000..9569c4c --- /dev/null +++ b/src/components/ble/host/att_internal.h @@ -0,0 +1,63 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + + +**************************************************************************************************/ + +#ifndef ATT_INTERNAL_H +#define ATT_INTERNAL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ +#include "osal_cbtimer.h" + +#include "l2cap.h" +#include "att.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +// Function prototype to build an attribute protocol message +typedef uint16 (*attBuildMsg_t)( uint8* pBuf, uint8* pMsg ); + +/********************************************************************* + VARIABLES +*/ + +/********************************************************************* + FUNCTIONS +*/ + +extern uint16 attBuildExecuteWriteRsp( uint8* pBuf, uint8* pMsg ); + +extern uint16 attBuildHandleValueCfm( uint8* pBuf, uint8* pMsg ); + +extern bStatus_t attSendMsg( uint16 connHandle, attBuildMsg_t pfnBuildMsg, + uint8 opcode, uint8* pMsg ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* ATT_INTERNAL_H */ diff --git a/src/components/ble/host/gap_internal.h b/src/components/ble/host/gap_internal.h new file mode 100644 index 0000000..2526998 --- /dev/null +++ b/src/components/ble/host/gap_internal.h @@ -0,0 +1,474 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +/************************************************************************************************** +**************************************************************************************************/ + +#ifndef GAP_INTERNAL_H +#define GAP_INTERNAL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + * INCLUDES + */ +#include "bcomdef.h" +#include "hci.h" +#include "l2cap.h" +#include "gap.h" + +/********************************************************************* + * MACROS + */ + +/********************************************************************* + * CONSTANTS + */ + +// GAP OSAL Events +#define GAP_OSAL_TIMER_SCAN_DURATION_EVT 0x0001 +#define GAP_END_ADVERTISING_EVT 0x0002 +#define GAP_CHANGE_RESOLVABLE_PRIVATE_ADDR_EVT 0x0004 + +#define ADDRTYPE_RANDOM 1 // Not public + +#define GAP_PRIVATE_ADDR_CHANGE_RESOLUTION 0xEA60 // Timer resolution is 1 minute + +#define ADV_TOKEN_HDR 2 + +// Address header bits +#define RANDOM_ADDR_HDR 0xC0 // Used for LL RANDOM Address +#define STATIC_ADDR_HDR 0xC0 // Host Static Address, same as RANDOM address +#define PRIVATE_RESOLVE_ADDR_HDR 0x40 + +#if defined ( TESTMODES ) + // GAP TestModes + #define GAP_TESTMODE_OFF 0 // No Test mode + #define GAP_TESTMODE_NO_RESPONSE 1 // Don't respond to any GAP message +#endif // TESTMODES + +// L2CAP Connection Parameters Update Request event +#define L2CAP_PARAM_UPDATE 0xFFFF + +/********************************************************************* + * TYPEDEFS + */ + +typedef struct gapAdvToken +{ + struct gapAdvToken *pNext; // Pointer to next item in link list + gapAdvDataToken_t *pToken; // Pointer to data token +} gapAdvToken_t; + +/** Advertising and Scan Response Data **/ +typedef struct +{ + uint8 dataLen; // Number of bytes used in "dataField" + uint8 dataField[B_MAX_ADV_LEN]; // Data field of the advertisement or SCAN_RSP +} gapAdvertisingData_t; + +typedef struct +{ + uint8 dataLen; // length (in bytes) of "dataField" + uint8 dataField[1]; // This is just a place holder size + // The dataField will be allocated bigger +} gapAdvertRecData_t; + +// Temporary advertising record +typedef struct +{ + uint8 eventType; // Avertisement or SCAN_RSP + uint8 addrType; // Advertiser's address type + uint8 addr[B_ADDR_LEN]; // Advertiser's address + gapAdvertRecData_t *pAdData; // Advertising data field. This space is allocated. + gapAdvertRecData_t *pScanData; // SCAN_RSP data field. This space is allocated. +} gapAdvertRec_t; + +typedef enum +{ + GAP_ADSTATE_SET_PARAMS, // Setting the advertisement parameters + GAP_ADSTATE_SET_MODE, // Turning on advertising + GAP_ADSTATE_ADVERTISING, // Currently Advertising + GAP_ADSTATE_ENDING // Turning off advertising +} gapAdvertStatesIDs_t; + +// Advertising State Information +typedef struct +{ + uint8 taskID; // App that started an advertising period + gapAdvertStatesIDs_t state; // Make Discoverable state + gapAdvertisingParams_t params; // Advertisement parameters +} gapAdvertState_t; + +typedef struct +{ + uint8 state; // Authentication states + uint16 connectionHandle; // Connection Handle from controller, + smLinkSecurityReq_t secReqs; // Pairing Control info + + // The following are only used if secReqs.bondable == BOUND, which means that + // the device is already bound and we should use the security information and + // keys + smSecurityInfo_t *pSecurityInfo; // BOUND - security information + smIdentityInfo_t *pIdentityInfo; // BOUND - identity information + smSigningInfo_t *pSigningInfo; // Signing information +} gapAuthStateParams_t; + +// Callback when an HCI Command Event has been received on the Central. +typedef uint8 (*gapProcessHCICmdEvt_t)( uint16 cmdOpcode, hciEvt_CmdComplete_t *pMsg ); + +// Callback when an Scanning Report has been received on the Central. +typedef void (*gapProcessScanningEvt_t)( hciEvt_BLEAdvPktReport_t *pMsg ); + +// Callback to cancel a connection initiation on the Central. +typedef bStatus_t (*gapCancelLinkReq_t)( uint8 taskID, uint16 connectionHandle ); + +// Callback when a connection-related event has been received on the Central. +typedef uint8(*gapProcessConnEvt_t)( uint16 cmdOpcode, hciEvt_CommandStatus_t *pMsg ); + +// Callback when an HCI Command Command Event on the Peripheral. +typedef uint8 (*gapProcessHCICmdCompleteEvt_t)( hciEvt_CmdComplete_t *pMsg ); + +// Callback when an Advertising Event has been received on the Peripheral. +typedef void (*gapProcessAdvertisingEvt_t)( uint8 timeout ); + +// Callback when a Set Advertising Params has been received on the Peripheral. +typedef bStatus_t (*gapSetAdvParams_t)( void ); + +// Central callback structure - must be setup by the Central. +typedef struct +{ + gapProcessHCICmdEvt_t pfnProcessHCICmdEvt; // When HCI Command Event received + gapProcessScanningEvt_t pfnProcessScanningEvt; // When Scanning Report received +} gapCentralCBs_t; + +// Central connection-related callback structure - must be setup by the Central. +typedef struct +{ + gapCancelLinkReq_t pfnCancelLinkReq; // When cancel connection initiation requested + gapProcessConnEvt_t pfnProcessConnEvt; // When connection-related event received +} gapCentralConnCBs_t; + +// Peripheral callback structure - must be setup by the Peripheral. +typedef struct +{ + gapProcessHCICmdCompleteEvt_t pfnProcessHCICmdCompleteEvt; // When HCI Command Complete Event received + gapProcessAdvertisingEvt_t pfnProcessAdvertisingEvt; // When Advertising Event received + gapSetAdvParams_t pfnSetAdvParams; // When Set Advertising Params received +} gapPeripheralCBs_t; + +/********************************************************************* + * GLOBAL VARIABLES + */ + +extern uint8 gapTaskID; +extern uint8 gapUnwantedTaskID; + +extern uint8 gapAppTaskID; // default task ID to send events +extern uint8 gapProfileRole; // device GAP Profile Role(s) + +extern uint8 gapDeviceAddrMode; // ADDRTYPE_PUBLIC, ADDRTYPE_STATIC, + // ADDRTYPE_PRIVATE_NONRESOLVE + // or ADDRTYPE_PRIVATE_RESOLVE + +// Central Peripheral variables +extern gapDevDiscReq_t *pGapDiscReq; +extern gapEstLinkReq_t *pEstLink; +extern gapCentralConnCBs_t *pfnCentralConnCBs; + +// Peripheral variables +extern gapAdvertState_t *pGapAdvertState; +extern gapPeripheralCBs_t *pfnPeripheralCBs; + +// Common variables +extern gapAuthStateParams_t* pAuthLink[]; +extern uint16 gapPrivateAddrChangeTimeout; +extern uint8 gapAutoAdvPrivateAddrChange; + +/********************************************************************* + * FUNCTIONS - API + */ + +/********************************************************************* + * Application Level Functions + */ + + /* + * gapSetScanParamStatus - Process HCI Command Complete Event status for + * the call to HCI_BLESetScanParamCmd(). + */ + extern uint8 gapSetScanParamStatus( uint8 status ); + + /* + * gapSetAdvParamsStatus - Process HCI Command Complete Event status for + * the call to HCI_BLESetAdvParamCmd(). + */ + extern uint8 gapSetAdvParamsStatus( uint8 status ); + + /* + * gapWriteAdvEnableStatus - Process HCI Command Complete Event status for + * the call to HCI_BLEWriteAdvEnableCmd(). + */ + extern uint8 gapWriteAdvEnableStatus( uint8 status, uint16 interval ); + + /* + * gapWriteAdvDataStatus - Process HCI Command Complete Event status for + * the call to HCI_BLEWriteAdvDataCmd() or + * HCI_BLEWriteScanRspDataCmd(). + */ + extern void gapWriteAdvDataStatus( uint8 adType, uint8 status ); + + /* + * gapReadBD_ADDRStatus - Process the HCI Command Complete Event for the + * call to HCI_ReadBDADDRCmd(). + */ + extern uint8 gapReadBD_ADDRStatus( uint8 status, uint8 *pBdAddr ); + + /* + * gapReadBufSizeCmdStatus - Process the HCI Command Complete Event for the + * call to HCI_BLEReadBufSizeCmd(). + */ + extern uint8 gapReadBufSizeCmdStatus( hciRetParam_LeReadBufSize_t *pCmdStat ); + + /* + * gapProcessConnectionCompleteEvt - Process the HCI Connection Complete + * event for the call to HCI_BLECreateLLConnCmd(). + */ + extern void gapProcessConnectionCompleteEvt( hciEvt_BLEConnComplete_t *pPkt ); + + /* + * gapProcessConnUpdateCompleteEvt - Process the HCI Connection Parameters + * Update Complete event for the call to HCI_BLEUpdateLLConnCmd(). + */ + extern void gapProcessConnUpdateCompleteEvt( hciEvt_BLEConnUpdateComplete_t *pPkt ); + + /* + * gapProcessDisconnectCompleteEvt - Process the LL Disconnection Complete Event + * for the call to HCI_DisconnectCmd(). + */ + extern void gapProcessDisconnectCompleteEvt( hciEvt_DisconnComplete_t *pPkt ); + + /* + * gapProcessCreateLLConnCmdStatus - Process the status for the HCI_BLECreateLLConnCmd(). + */ + extern void gapProcessCreateLLConnCmdStatus( uint8 status ); + + /* + * gapProcessConnUpdateCmdStatus - Process the status for the HCI_LE_ConnUpdateCmd(). + */ + extern void gapProcessConnUpdateCmdStatus( uint8 status ); + + /* + * gapProcessNewAddr - Process message SM + */ + extern bStatus_t gapProcessNewAddr( uint8 *pNewAddr ); + + /* + * gapAddAddrAdj - Add the top two bits based on the address type. + */ + extern uint8 gapAddAddrAdj( uint8 addrType, uint8 *pAddr ); + + /* + * gapDetermineAddrType - Convert from LL address type to host address type. + */ + extern uint8 gapDetermineAddrType( uint8 addrType, uint8 *pAddr ); + + /* + * gapProcessRandomAddrComplete - Process message HCI + */ + extern void gapProcessRandomAddrComplete( uint8 status ); + + /* + * gapGetSRK - Get pointer to the SRK + */ + extern uint8 *gapGetSRK( void ); + + /* + * gapGetSignCounter - Get the signature counter + */ + extern uint32 gapGetSignCounter( void ); + + /* + * gapIncSignCounter - Increment the signature counter + */ + extern void gapIncSignCounter( void ); + + /* + * gapUpdateConnSignCounter - Update a connection's signature's counter + */ + extern void gapUpdateConnSignCounter( uint16 connHandle, uint32 newSignCounter ); + + /* + * gapLinkCheck - linkDB callback function + */ + extern void gapLinkCheck( uint16 connectionHandle, uint8 changeType ); + + /* + * gapGetDevAddressMode - Get the device address mode. + */ + extern uint8 gapGetDevAddressMode( void ); + + /* + * gapGetDevAddress - Get the device address. + * real - TRUE if you always want BD_ADDR, FALSE will allow random addresses. + */ + extern uint8 *gapGetDevAddress( uint8 real ); + + /* + * gapGetIRK - Get the device's IRK. + */ + extern uint8 *gapGetIRK( void ); + + /* + * gapPasskeyNeededCB - Callback function to ask for passkey + */ + extern void gapPasskeyNeededCB( uint16 connectionHandle, uint8 type ); + + /* + * gapPairingCompleteCB - Callback function to inform pairing process complete. + */ + extern void gapPairingCompleteCB( uint8 status, uint8 initiatorRole, + uint16 connectionHandle, + uint8 authState, + smSecurityInfo_t *pEncParams, + smSecurityInfo_t *pDevEncParams, + smIdentityInfo_t *pIdInfo, + smSigningInfo_t *pSigningInfo ); + + /* + * gapTerminateConnComplete - Process command complete for HCI_BLECreateLLConnCancelCmd. + */ + extern void gapTerminateConnComplete( void ); + + /* + * gapSendSlaveSecurityReqEvent - Generate a Slave Security Request event to the app. + */ + extern void gapSendSlaveSecurityReqEvent( uint8 taskID, uint16 connHandle, uint8 *pDevAddr, uint8 authReq ); + + /* + * gapSetAdvParams - Send the advertisement parameters to the LL. + */ + extern bStatus_t gapSetAdvParams( void ); + + /* + * gapAddAdvToken - Add token to the end of the list. + */ + extern bStatus_t gapAddAdvToken( gapAdvDataToken_t *pToken ); + + /* + * gapDeleteAdvToken - Remove a token from the list. + */ + extern gapAdvDataToken_t *gapDeleteAdvToken( uint8 ADType ); + + /* + * gapFindAdvToken - Find a Advertisement data token from the advertisement type. + */ + extern gapAdvToken_t *gapFindAdvToken( uint8 ADType ); + + /* + * gapCalcAdvTokenDataLen - Find a Advertisement data token from the advertisement type. + */ + extern void gapCalcAdvTokenDataLen( uint8 *pAdLen, uint8 *pSrLen ); + + /* + * gapValidADType - Is a Advertisement Data Type valid. + */ + extern uint8 gapValidADType( uint8 adType ); + + /* + * gapBuildADTokens - Is a Advertisement Data Type valid. + */ + extern bStatus_t gapBuildADTokens( void ); + + /* + * gapSendBondCompleteEvent - Indicate that a bond has occurred. + */ + extern void gapSendBondCompleteEvent( uint8 status, uint16 connectionHandle ); + + /* + * gapSendPairingReqEvent - Indicate that an unexpected Pairing Request was received. + */ + extern void gapSendPairingReqEvent( uint8 status, uint16 connectionHandle, + uint8 ioCap, + uint8 oobDataFlag, + uint8 authReq, + uint8 maxEncKeySize, + keyDist_t keyDist ); + + /* + * gapFindADType - Find Advertisement Data Type field in advertising data + * field. + */ + extern uint8 *gapFindADType( uint8 adType, uint8 *pAdLen, + uint8 dataLen, uint8 *pDataField ); + + /* + * gapRegisterCentral - Register Central's processing function with GAP task + */ + extern void gapRegisterCentral( gapCentralCBs_t *pfnCBs ); + + /* + * gapRegisterCentralConn - Register Central's connection-related processing function with GAP task + */ + extern void gapRegisterCentralConn( gapCentralConnCBs_t *pfnCBs); + + /* + * gapRegisterPeripheral - Register Peripheral's processing function with GAP task + */ + extern void gapRegisterPeripheral( gapPeripheralCBs_t *pfnCBs ); + + /* + * gapIsAdvertising - Check if we are currently advertising. + */ + extern uint8 gapIsAdvertising( void ); + + /* + * gapIsScanning - Check if we are currently scanning. + */ + extern uint8 gapIsScanning( void ); + + /* + * gapCancelLinkReq - Cancel a connection create request. + */ + extern bStatus_t gapCancelLinkReq( uint8 taskID, uint16 connectionHandle ); + + /* + * gapFreeEstLink - Free the establish link memory. + */ + extern void gapFreeEstLink( void ); + + /* + * sendEstLinkEvent - Build and send the GAP_LINK_ESTABLISHED_EVENT to the app. + */ + extern void sendEstLinkEvent( uint8 status, uint8 taskID, uint8 devAddrType, + uint8 *pDevAddr, uint16 connectionHandle, + uint16 connInterval, uint16 connLatency, + uint16 connTimeout, uint16 clockAccuracy ); + + /* + * gapSendLinkUpdateEvent - Build and send the GAP_LINK_PARAM_UPDATE_EVENT to the app. + * + */ + extern void gapSendLinkUpdateEvent( uint8 status, uint16 connectionHandle, + uint16 connInterval, uint16 connLatency, + uint16 connTimeout ); + + /* + * gapProcessL2CAPSignalEvt - Process L2CAP Signaling messages. + */ + extern void gapProcessL2CAPSignalEvt( l2capSignalEvent_t *pCmd ); + + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* GAP_INTERNAL_H */ diff --git a/src/components/ble/host/gapgattserver.h b/src/components/ble/host/gapgattserver.h new file mode 100644 index 0000000..7039d69 --- /dev/null +++ b/src/components/ble/host/gapgattserver.h @@ -0,0 +1,184 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: gapgattserver.h + Revised: + Revision: + + Description: This file contains GAP GATT attribute definitions + and prototypes. + + + +**************************************************************************************************/ + +#ifndef GAPGATTSERVER_H +#define GAPGATTSERVER_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + CONSTANTS +*/ + +#define GAP_DEVICE_NAME_LEN (20+1) + +// Privacy Flag States +#define GAP_PRIVACY_DISABLED 0x00 +#define GAP_PRIVACY_ENABLED 0x01 + +// GAP GATT Server Parameters +#define GGS_DEVICE_NAME_ATT 0 // RW uint8[GAP_DEVICE_NAME_LEN] +#define GGS_APPEARANCE_ATT 1 // RW uint16 +#define GGS_PERI_PRIVACY_FLAG_ATT 2 // RW uint8 +#define GGS_RECONNCT_ADDR_ATT 3 // RW uint8[B_ADDR_LEN] +#define GGS_PERI_CONN_PARAM_ATT 4 // RW sizeof(gapPeriConnectParams_t) +#define GGS_PERI_PRIVACY_FLAG_PROPS 5 // RW uint8 +#define GGS_W_PERMIT_DEVICE_NAME_ATT 6 // W uint8 +#define GGS_W_PERMIT_APPEARANCE_ATT 7 // W uint8 +#define GGS_W_PERMIT_PRIVACY_FLAG_ATT 8 // W uint8 + +// GAP Services bit fields +#define GAP_SERVICE 0x00000001 + +// Attribute ID used with application's callback when attribute value is changed OTA +#define GGS_DEVICE_NAME_ID 0 +#define GGS_APPEARANCE_ID 1 + +#if defined ( TESTMODES ) +// GGS TestModes +#define GGS_TESTMODE_OFF 0 // No Test mode +#define GGS_TESTMODE_W_PERMIT_DEVICE_NAME 1 // Make Device Name attribute writable +#define GGS_TESTMODE_W_PERMIT_APPEARANCE 2 // Make Appearance attribute writable +#define GGS_TESTMODE_W_PERMIT_PRIVACY_FLAG 3 // Make Peripheral Privacy Flag attribute writable with authentication +#endif // TESTMODES + +/********************************************************************* + TYPEDEFS +*/ +// Callback to notify when attribute value is changed over the air. +typedef void (*ggsAttrValueChange_t)( uint8 attrId ); + +// GAP GATT Server callback structure +typedef struct +{ + ggsAttrValueChange_t pfnAttrValueChange; // When attribute value is changed OTA +} ggsAppCBs_t; + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + Profile Callbacks +*/ + +/********************************************************************* + API FUNCTIONS +*/ + +/** + @brief Set a GAP GATT Server parameter. + + @param param - Profile parameter ID
+ @param len - length of data to right + @param value - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer).
+ + @return bStatus_t +*/ +extern bStatus_t GGS_SetParameter( uint8 param, uint8 len, void* value ); + +/** + @brief Get a GAP GATT Server parameter. + + @param param - Profile parameter ID
+ @param value - pointer to data to put. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer).
+ + @return bStatus_t +*/ +extern bStatus_t GGS_GetParameter( uint8 param, void* value ); + +/** + @brief Add function for the GAP GATT Service. + + @param services - services to add. This is a bit map and can + contain more than one service. + + @return SUCCESS: Service added successfully.
+ INVALIDPARAMETER: Invalid service field.
+ FAILURE: Not enough attribute handles available.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t GGS_AddService( uint32 services ); + +/** + @brief Delete function for the GAP GATT Service. + + @param services - services to delete. This is a bit map and can + contain more than one service. + + @return SUCCESS: Service deleted successfully.
+ FAILURE: Service not found.
+*/ +extern bStatus_t GGS_DelService( uint32 services ); + +/** + @brief Registers the application callback function. + + Note: Callback registration is needed only when the + Device Name is made writable. The application + will be notified when the Device Name is changed + over the air. + + @param appCallbacks - pointer to application callbacks. + + @return none +*/ +extern void GGS_RegisterAppCBs( ggsAppCBs_t* appCallbacks ); + +/** + @brief Set a GGS Parameter value. Use this function to change + the default GGS parameter values. + + @param value - new GGS param value + + @return void +*/ +extern void GGS_SetParamValue( uint16 value ); + +/** + @brief Get a GGS Parameter value. + + @param none + + @return GGS Parameter value +*/ +extern uint16 GGS_GetParamValue( void ); + +/********************************************************************* + TASK FUNCTIONS - Don't call these. These are system functions. +*/ + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* GAPGATTSERVER_H */ diff --git a/src/components/ble/host/gatt_internal.h b/src/components/ble/host/gatt_internal.h new file mode 100644 index 0000000..7ff48d2 --- /dev/null +++ b/src/components/ble/host/gatt_internal.h @@ -0,0 +1,87 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** +**************************************************************************************************/ + +#ifndef GATT_INTERNAL_H +#define GATT_INTERNAL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ +#include "osal_cbtimer.h" + +#include "att.h" +#include "gatt.h" + +/********************************************************************* + MACROS +*/ +#define TIMER_VALID( id ) ( ( (id) != INVALID_TIMER_ID ) && \ + ( (id) != TIMEOUT_TIMER_ID ) ) + +#define TIMER_STATUS( id ) ( (id) == TIMEOUT_TIMER_ID ? bleTimeout : \ + (id) == INVALID_TIMER_ID ? SUCCESS : blePending ) + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ +// Srtucture for Attribute Version Information attribute +typedef struct +{ + uint8 attVersion; // Attribute Protocol Version + uint8 gattVersion; // Generic Attribute Profile Version + uint16 manufacturerName; // Manufacturer Name +} gattVersionInfo_t; + +// Function prototype to parse an attribute protocol request message +typedef bStatus_t (*gattParseReq_t)( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ); + +// Function prototype to parse an attribute protocol response message +typedef bStatus_t (*gattParseRsp_t)( uint8* pParams, uint16 len, attMsg_t* pMsg ); + +// Function prototype to process an attribute protocol message +typedef bStatus_t (*gattProcessMsg_t)( uint16 connHandle, attPacket_t* pPkt ); + +// Function prototype to process an attribute protocol request message +typedef bStatus_t (*gattProcessReq_t)( uint16 connHandle, attMsg_t* pMsg ); + +/********************************************************************* + VARIABLES +*/ +extern uint8 gattTaskID; + +/********************************************************************* + FUNCTIONS +*/ +extern void gattRegisterServer( gattProcessMsg_t pfnProcessMsg ); + +extern void gattRegisterClient( gattProcessMsg_t pfnProcessMsg ); + +extern bStatus_t gattNotifyEvent( uint8 taskId, uint16 connHandle, uint8 status, + uint8 method, gattMsg_t* pMsg ); + +extern void gattStartTimer( pfnCbTimer_t pfnCbTimer, uint8* pData, + uint16 timeout, uint8* pTimerId ); + +extern void gattStopTimer( uint8* pTimerId ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* GATT_INTERNAL_H */ diff --git a/src/components/ble/host/gatt_profile_uuid.h b/src/components/ble/host/gatt_profile_uuid.h new file mode 100644 index 0000000..b3a59f6 --- /dev/null +++ b/src/components/ble/host/gatt_profile_uuid.h @@ -0,0 +1,239 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: gatt_profile_uuid.h + Revised: + Revision: + + Description: This file contains GATT Profile UUID types. + + + +**************************************************************************************************/ + +#ifndef GATT_PROFILE_UUID_H +#define GATT_PROFILE_UUID_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + CONSTANTS +*/ + +/* + WARNING: The 16-bit UUIDs are assigned by the Bluetooth SIG and published + in the Bluetooth Assigned Numbers page. Do not change these values. + Changing them will cause Bluetooth interoperability issues. +*/ + +/** + GATT Service UUIDs +*/ +#define IMMEDIATE_ALERT_SERV_UUID 0x1802 // Immediate Alert +#define LINK_LOSS_SERV_UUID 0x1803 // Link Loss +#define TX_PWR_LEVEL_SERV_UUID 0x1804 // Tx Power +#define CURRENT_TIME_SERV_UUID 0x1805 // Current Time Service +#define REF_TIME_UPDATE_SERV_UUID 0x1806 // Reference Time Update Service +#define NEXT_DST_CHANGE_SERV_UUID 0x1807 // Next DST Change Service +#define GLUCOSE_SERV_UUID 0x1808 // Glucose +#define THERMOMETER_SERV_UUID 0x1809 // Health Thermometer +#define DEVINFO_SERV_UUID 0x180A // Device Information +#define NWA_SERV_UUID 0x180B // Network Availability +#define HEARTRATE_SERV_UUID 0x180D // Heart Rate +#define PHONE_ALERT_STS_SERV_UUID 0x180E // Phone Alert Status Service +#define BATT_SERV_UUID 0x180F // Battery Service +#define BLOODPRESSURE_SERV_UUID 0x1810 // Blood Pressure +#define ALERT_NOTIF_SERV_UUID 0x1811 // Alert Notification Service +#define HID_SERV_UUID 0x1812 // Human Interface Device +#define SCAN_PARAM_SERV_UUID 0x1813 // Scan Parameters +#define RSC_SERV_UUID 0x1814 // Running Speed and Cadence +#define CSC_SERV_UUID 0x1816 // Cycling Speed and Cadence +#define CYCPWR_SERV_UUID 0x1818 // Cycling Power +#define LOC_NAV_SERV_UUID 0x1819 // Location and Navigation + + +/** + GATT Characteristic UUIDs +*/ +#define ALERT_LEVEL_UUID 0x2A06 // Alert Level +#define TX_PWR_LEVEL_UUID 0x2A07 // Tx Power Level +#define DATE_TIME_UUID 0x2A08 // Date Time +#define DAY_OF_WEEK_UUID 0x2A09 // Day of Week +#define DAY_DATE_TIME_UUID 0x2A0A // Day Date Time +#define EXACT_TIME_256_UUID 0x2A0C // Exact Time 256 +#define DST_OFFSET_UUID 0x2A0D // DST Offset +#define TIME_ZONE_UUID 0x2A0E // Time Zone +#define LOCAL_TIME_INFO_UUID 0x2A0F // Local Time Information +#define TIME_WITH_DST_UUID 0x2A11 // Time with DST +#define TIME_ACCURACY_UUID 0x2A12 // Time Accuracy +#define TIME_SOURCE_UUID 0x2A13 // Time Source +#define REF_TIME_INFO_UUID 0x2A14 // Reference Time Information +#define TIME_UPDATE_CTRL_PT_UUID 0x2A16 // Time Update Control Point +#define TIME_UPDATE_STATE_UUID 0x2A17 // Time Update State +#define GLUCOSE_MEAS_UUID 0x2A18 // Glucose Measurement +#define BATT_LEVEL_UUID 0x2A19 // Battery Level +#define TEMP_MEAS_UUID 0x2A1C // Temperature Measurement +#define TEMP_TYPE_UUID 0x2A1D // Temperature Type +#define IMEDIATE_TEMP_UUID 0x2A1E // Intermediate Temperature +#define MEAS_INTERVAL_UUID 0x2A21 // Measurement Interval +#define BOOT_KEY_INPUT_UUID 0x2A22 // Boot Keyboard Input Report +#define SYSTEM_ID_UUID 0x2A23 // System ID +#define MODEL_NUMBER_UUID 0x2A24 // Model Number String +#define SERIAL_NUMBER_UUID 0x2A25 // Serial Number String +#define FIRMWARE_REV_UUID 0x2A26 // Firmware Revision String +#define HARDWARE_REV_UUID 0x2A27 // Hardware Revision String +#define SOFTWARE_REV_UUID 0x2A28 // Software Revision String +#define MANUFACTURER_NAME_UUID 0x2A29 // Manufacturer Name String +#define IEEE_11073_CERT_DATA_UUID 0x2A2A // IEEE 11073-20601 Regulatory Certification Data List +#define CURRENT_TIME_UUID 0x2A2B // Current Time +#define SCAN_REFRESH_UUID 0x2A31 // Scan Refresh +#define BOOT_KEY_OUTPUT_UUID 0x2A32 // Boot Keyboard Output Report +#define BOOT_MOUSE_INPUT_UUID 0x2A33 // Boot Mouse Input Report +#define GLUCOSE_CONTEXT_UUID 0x2A34 // Glucose Measurement Context +#define BLOODPRESSURE_MEAS_UUID 0x2A35 // Blood Pressure Measurement +#define IMEDIATE_CUFF_PRESSURE_UUID 0x2A36 // Intermediate Cuff Pressure +#define HEARTRATE_MEAS_UUID 0x2A37 // Heart Rate Measurement +#define BODY_SENSOR_LOC_UUID 0x2A38 // Body Sensor Location +#define HEARTRATE_CTRL_PT_UUID 0x2A39 // Heart Rate Control Point +#define NETWORK_AVAIL_UUID 0x2A3E // Network Availability +#define ALERT_STATUS_UUID 0x2A3F // Alert Status +#define RINGER_CTRL_PT_UUID 0x2A40 // Ringer Control Point +#define RINGER_SETTING_UUID 0x2A41 // Ringer Setting +#define ALERT_CAT_ID_BMASK_UUID 0x2A42 // Alert Category ID Bit Mask +#define ALERT_CAT_ID_UUID 0x2A43 // Alert Category ID +#define ALERT_NOTIF_CTRL_PT_UUID 0x2A44 // Alert Notification Control Point +#define UNREAD_ALERT_STATUS_UUID 0x2A45 // Unread Alert Status +#define NEW_ALERT_UUID 0x2A46 // New Alert +#define SUP_NEW_ALERT_CAT_UUID 0x2A47 // Supported New Alert Category +#define SUP_UNREAD_ALERT_CAT_UUID 0x2A48 // Supported Unread Alert Category +#define BLOODPRESSURE_FEATURE_UUID 0x2A49 // Blood Pressure Feature +#define HID_INFORMATION_UUID 0x2A4A // HID Information +#define REPORT_MAP_UUID 0x2A4B // Report Map +#define HID_CTRL_PT_UUID 0x2A4C // HID Control Point +#define REPORT_UUID 0x2A4D // Report +#define PROTOCOL_MODE_UUID 0x2A4E // Protocol Mode +#define SCAN_INTERVAL_WINDOW_UUID 0x2A4F // Scan Interval Window +#define PNP_ID_UUID 0x2A50 // PnP ID +#define GLUCOSE_FEATURE_UUID 0x2A51 // Glucose Feature +#define RECORD_CTRL_PT_UUID 0x2A52 // Record Access Control Point +#define RSC_MEAS_UUID 0x2A53 // RSC Measurement +#define RSC_FEATURE_UUID 0x2A54 // RSC Feature +#define SC_CTRL_PT_UUID 0x2A55 // SC Control Point +#define CSC_MEAS_UUID 0x2A5B // CSC Measurement +#define CSC_FEATURE_UUID 0x2A5C // CSC Feature +#define SENSOR_LOC_UUID 0x2A5D // Sensor Location +#define CYCPWR_MEAS_UUID 0x2A63 // Cycling Power Measurement +#define CYCPWR_VECTOR_UUID 0x2A64 // Cycling Power Vector +#define CYCPWR_FEATURE_UUID 0x2A65 // Cycling Power Feature +#define CYCPWR_CTRL_PT_UUID 0x2A66 // Cycling Power Control Point +#define LOC_SPEED_UUID 0x2A67 // Location and Speed +#define NAV_UUID 0x2A68 // Navigation +#define POS_QUALITY_UUID 0x2A69 // Position Quality +#define LN_FEATURE_UUID 0x2A6A // LN Feature +#define LN_CTRL_PT_UUID 0x2A6B // LN Control Point + + +/** + GATT Unit UUIDs +*/ +#define GATT_UNITLESS_UUID 0x2700 // , +#define GATT_UNIT_LENGTH_METER_UUID 0x2701 // m, m +#define GATT_UNIT_MASS_KGRAM_UUID 0x2702 // kg, kg +#define GATT_UNIT_TIME_SECOND_UUID 0x2703 // s, s +#define GATT_UNIT_ELECTRIC_CURRENT_A_UUID 0x2704 // A, A +#define GATT_UNIT_THERMODYN_TEMP_K_UUID 0x2705 // K, K +#define GATT_UNIT_AMOUNT_SUBSTANCE_M_UUID 0x2706 // mol, mol +#define GATT_UNIT_LUMINOUS_INTENSITY_C_UUID 0x2707 // cd, cd + +#define GATT_UNIT_AREA_SQ_MTR_UUID 0x2710 // m^2, m^2 +#define GATT_UNIT_VOLUME_CUBIC_MTR_UUID 0x2711 // m^3, m^3 +#define GATT_UNIT_VELOCITY_MPS_UUID 0x2712 // m/s, m s^-1 +#define GATT_UNIT_ACCELERATION_MPS_SQ_UUID 0x2713 // m/s^2, m s^-2 +#define GATT_UNIT_WAVENUMBER_RM_UUID 0x2714 // ó, m^-1 +#define GATT_UNIT_DENSITY_KGPCM_UUID 0x2715 // p, kg m^-3 +#define GATT_UNIT_SURFACE_DENSITY_KGPSM_UUID 0x2716 // pA, kg m^-2 +#define GATT_UNIT_SPECIFIC_VOLUME_CMPKG_UUID 0x2717 // v, m^3 kg^-1 +#define GATT_UNIT_CURRENT_DENSITY_APSM_UUID 0x2718 // j, A m^-2 +#define GATT_UNIT_MAG_FIELD_STRENGTH_UUID 0x2719 // H, A m +#define GATT_UNIT_AMOUNT_CONC_MPCM_UUID 0x271A // c, mol m^-3 +#define GATT_UNIT_MASS_CONC_KGPCM_UUID 0x271B // c, kg m^-3 +#define GATT_UNIT_LUMINANCE_CPSM_UUID 0x271C // Lv, cd m^-2 +#define GATT_UNIT_REFRACTIVE_INDEX_UUID 0x271D // n, 1 +#define GATT_UNIT_RELATIVE_PERMEABLILTY_UUID 0x271E // u, 1 +#define GATT_UNIT_PLANE_ANGLE_RAD_UUID 0x2720 // rad, m m-1 +#define GATT_UNIT_SOLID_ANGLE_STERAD_UUID 0x2721 // sr, m2 m-2 +#define GATT_UNIT_FREQUENCY_HTZ_UUID 0x2722 // Hz, s-1 +#define GATT_UNIT_FORCE_NEWTON_UUID 0x2723 // N, m kg s-2 +#define GATT_UNIT_PRESSURE_PASCAL_UUID 0x2724 // Pa, N/m2 = m2 kg s-2 +#define GATT_UNIT_ENERGY_JOULE_UUID 0x2725 // J, N m = m2 kg s-2 +#define GATT_UNIT_POWER_WATT_UUID 0x2726 // W, J/s = m2 kg s-3 +#define GATT_UNIT_E_CHARGE_C_UUID 0x2727 // C, sA +#define GATT_UNIT_E_POTENTIAL_DIF_V_UUID 0x2728 // V, W/A = m2 kg s-3 A-1 + +#define GATT_UNIT_CELSIUS_TEMP_DC_UUID 0x272F // oC, t/oC = T/K - 273.15 + +#define GATT_UNIT_TIME_MINUTE_UUID 0x2760 // min, 60 s +#define GATT_UNIT_TIME_HOUR_UUID 0x2761 // h, 3600 s +#define GATT_UNIT_TIME_DAY_UUID 0x2762 // d, 86400 s +#define GATT_UNIT_PLANE_ANGLE_DEGREE_UUID 0x2763 // o, (pi/180) rad +#define GATT_UNIT_PLANE_ANGLE_MINUTE_UUID 0x2764 // ', (pi/10800) rad +#define GATT_UNIT_PLANE_ANGLE_SECOND_UUID 0x2765 // '', (pi/648000) rad +#define GATT_UNIT_AREA_HECTARE_UUID 0x2766 // ha, 10^4 m^2 +#define GATT_UNIT_VOLUME_LITRE_UUID 0x2767 // l, 10^-3 m^3 +#define GATT_UNIT_MASS_TONNE_UUID 0x2768 // t, 10^3 kg + +#define GATT_UINT_LENGTH_YARD_UUID 0x27A0 // yd, 0.9144 m +#define GATT_UNIT_LENGTH_PARSEC_UUID 0x27A1 // pc, 3.085678 × 1016 m +#define GATT_UNIT_LENGTH_INCH_UUID 0x27A2 // in, 0.0254 m +#define GATT_UNIT_LENGTH_FOOT_UUID 0x27A3 // ft, 0.3048 m +#define GATT_UNIT_LENGTH_MILE_UUID 0x27A4 // mi, 1609.347 m +#define GATT_UNIT_PRESSURE_PFPSI_UUID 0x27A5 // psi, 6.894757 × 103 Pa +#define GATT_UNIT_VELOCITY_KMPH_UUID 0x27A6 // km/h, 0.2777778 m^s-1 +#define GATT_UNIT_VELOCITY_MPH_UUID 0x27A7 // mi/h, 0.44704 m^ s-1 +#define GATT_UNIT_ANGULAR_VELOCITY_RPM_UUID 0x27A8 // r/min, 0.1047198 rad s-1 +#define GATT_UNIT_ENERGY_GCAL_UUID 0x27A9 // +#define GATT_UNIT_ENERGY_KCAL_UUID 0x27AA // kcal, 4190.02 J +#define GATT_UNIT_ENERGY_KWH_UUID 0x27AB // kWh, 3600000 J +#define GATT_UNIT_THERMODYN_TEMP_DF_UUID 0x27AC // oF, t/oF = T/K × 1.8 - 459.67 +#define GATT_UNIT_PERCENTAGE_UUID 0x27AD // % +#define GATT_UNIT_PER_MILE_UUID 0x27AE // +#define GATT_UNIT_PERIOD_BPM_UUID 0x27AF // +#define GATT_UNIT_E_CHARGE_AH_UUID 0x27B0 // +#define GATT_UNIT_MASS_DENSITY_MGPD_UUID 0x27B1 // +#define GATT_UNIT_MASS_DENSITY_MMPL_UUID 0x27B2 // +#define GATT_UNIT_TIME_YEAR_UUID 0x27B3 // +#define GATT_UNIT_TIME_MONTH_UUID 0x27B4 // + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + VARIABLES +*/ + +/********************************************************************* + FUNCTIONS +*/ + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* GATT_PROFILE_UUID_H */ diff --git a/src/components/ble/host/gattservapp.h b/src/components/ble/host/gattservapp.h new file mode 100644 index 0000000..f8fb063 --- /dev/null +++ b/src/components/ble/host/gattservapp.h @@ -0,0 +1,632 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +/** + @headerfile: gattservapp.h + $Date: + $Revision: + + @mainpage BLE GATT Server Application API + + Description: This file contains the GATT Server Application (GATTServApp) + definitions and prototypes.

+ + +**************************************************************************************************/ + +#ifndef GATTSERVAPP_H +#define GATTSERVAPP_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + * INCLUDES + */ +#include "bcomdef.h" +#include "OSAL.h" + +/********************************************************************* + * CONSTANTS + */ + +/** @defgroup GATT_SERV_MSG_EVENT_DEFINES GATT Server Message IDs + * @{ + */ + +#define GATT_CLIENT_CHAR_CFG_UPDATED_EVENT 0x00 //!< Sent when a Client Characteristic Configuration is updated. This event is sent as an OSAL message defined as gattCharCfgUpdatedEvent_t. + +/** @} End GATT_SERV_MSG_EVENT_DEFINES */ + + +/** @defgroup GATT_PROP_BITMAPS_DEFINES GATT Characteristic Properties Bit Fields + * @{ + */ + +#define GATT_PROP_BCAST 0x01 //!< Permits broadcasts of the Characteristic Value +#define GATT_PROP_READ 0x02 //!< Permits reads of the Characteristic Value +#define GATT_PROP_WRITE_NO_RSP 0x04 //!< Permits writes of the Characteristic Value without response +#define GATT_PROP_WRITE 0x08 //!< Permits writes of the Characteristic Value with response +#define GATT_PROP_NOTIFY 0x10 //!< Permits notifications of a Characteristic Value without acknowledgement +#define GATT_PROP_INDICATE 0x20 //!< Permits indications of a Characteristic Value with acknowledgement +#define GATT_PROP_AUTHEN 0x40 //!< Permits signed writes to the Characteristic Value +#define GATT_PROP_EXTENDED 0x80 //!< Additional characteristic properties are defined in the Characteristic Extended Properties Descriptor + +/** @} End GATT_PROP_BITMAPS_DEFINES */ + +/** @defgroup GATT_EXT_PROP_BITMAPS_DEFINES GATT Characteristic Extended Properties Bit Fields + * @{ + */ + +#define GATT_EXT_PROP_RELIABLE_WRITE 0x0001 //!< Permits reliable writes of the Characteristic Value +#define GATT_EXT_PROP_WRITABLE_AUX 0x0002 //!< Permits writes to the characteristic descriptor + +/** @} End GATT_EXT_PROP_BITMAPS_DEFINES */ + +/** @defgroup GATT_CLIENT_CFG_BITMAPS_DEFINES GATT Client Characteristic Configuration Bit Fields + * @{ + */ + +#define GATT_CLIENT_CFG_NOTIFY 0x0001 //!< The Characteristic Value shall be notified +#define GATT_CLIENT_CFG_INDICATE 0x0002 //!< The Characteristic Value shall be indicated + +/** @} End GATT_CLIENT_CFG_BITMAPS_DEFINES */ + +/** @defgroup GATT_SERV_CFG_BITMAPS_DEFINES GATT Server Characteristic Configuration Bit Fields + * @{ + */ + +#define GATT_SERV_CFG_BCAST 0x0001 //!< The Characteristic Value shall be broadcast when the server is in the broadcast procedure if advertising data resources are available + +/** @} End GATT_SERV_CFG_BITMAPS_DEFINES */ + +#define GATT_CFG_NO_OPERATION 0x0000 // No operation + +/** @defgroup GATT_FORMAT_TYPES_DEFINES GATT Characteristic Format Types + * @{ + */ + +#define GATT_FORMAT_BOOL 0x01 //!< Unsigned 1 bit; 0 = false, 1 = true +#define GATT_FORMAT_2BIT 0x02 //!< Unsigned 2 bit integer +#define GATT_FORMAT_NIBBLE 0x03 //!< Unsigned 4 bit integer +#define GATT_FORMAT_UINT8 0x04 //!< Unsigned 8 bit integer +#define GATT_FORMAT_UINT12 0x05 //!< Unsigned 12 bit integer +#define GATT_FORMAT_UINT16 0x06 //!< Unsigned 16 bit integer +#define GATT_FORMAT_UINT24 0x07 //!< Unsigned 24 bit integer +#define GATT_FORMAT_UINT32 0x08 //!< Unsigned 32 bit integer +#define GATT_FORMAT_UINT48 0x09 //!< Unsigned 48 bit integer +#define GATT_FORMAT_UINT64 0x0a //!< Unsigned 64 bit integer +#define GATT_FORMAT_UINT128 0x0b //!< Unsigned 128 bit integer +#define GATT_FORMAT_SINT8 0x0c //!< Signed 8 bit integer +#define GATT_FORMAT_SINT12 0x0d //!< Signed 12 bit integer +#define GATT_FORMAT_SINT16 0x0e //!< Signed 16 bit integer +#define GATT_FORMAT_SINT24 0x0f //!< Signed 24 bit integer +#define GATT_FORMAT_SINT32 0x10 //!< Signed 32 bit integer +#define GATT_FORMAT_SINT48 0x11 //!< Signed 48 bit integer +#define GATT_FORMAT_SINT64 0x12 //!< Signed 64 bit integer +#define GATT_FORMAT_SINT128 0x13 //!< Signed 128 bit integer +#define GATT_FORMAT_FLOAT32 0x14 //!< IEEE-754 32 bit floating point +#define GATT_FORMAT_FLOAT64 0x15 //!< IEEE-754 64 bit floating point +#define GATT_FORMAT_SFLOAT 0x16 //!< IEEE-11073 16 bit SFLOAT +#define GATT_FORMAT_FLOAT 0x17 //!< IEEE-11073 32 bit FLOAT +#define GATT_FORMAT_DUINT16 0x18 //!< IEEE-20601 format +#define GATT_FORMAT_UTF8S 0x19 //!< UTF-8 string +#define GATT_FORMAT_UTF16S 0x1a //!< UTF-16 string +#define GATT_FORMAT_STRUCT 0x1b //!< Opaque structure + +/** @} End GATT_FORMAT_TYPES_DEFINES */ + +/** @defgroup GATT_NS_TYPES_DEFINES GATT Namespace Types + * @{ + */ + +#define GATT_NS_NONE 0x00 //!< No namespace +#define GATT_NS_BT_SIG 0x01 //!< Bluetooth SIG namespace + +/** @} End GATT_NS_TYPES_DEFINES */ + +/** @defgroup GATT_NS_BT_DESC_DEFINES GATT Bluetooth Namespace Descriptions + * @{ + */ + +#define GATT_NS_BT_DESC_UNKNOWN 0x0000 //!< The description is unknown + +/** @} End GATT_NS_BT_DESC_DEFINES */ + +// All profile services bit fields +#define GATT_ALL_SERVICES 0xFFFFFFFF + +// GATT Services bit fields +#define GATT_SERVICE 0x00000001 + +#if defined ( TESTMODES ) + // GATT Test Modes + #define GATT_TESTMODE_OFF 0 // Test mode off + #define GATT_TESTMODE_NO_RSP 1 // Ignore incoming request + #define GATT_TESTMODE_PREPARE_WRITE 2 // Forward Prepare Write Request right away + #define GATT_TESTMODE_MAX_MTU_SIZE 3 // Use Max ATT MTU size with Exchange MTU Rsp + #define GATT_TESTMODE_CORRUPT_PW_DATA 4 // Corrupt incoming Prepare Write Request data +#endif + +// GATT Server Parameters +#define GATT_PARAM_NUM_PREPARE_WRITES 0 // RW uint8 + +/********************************************************************* + * VARIABLES + */ + +/********************************************************************* + * MACROS + */ + +// The number of attribute records in a given attribute table +#define GATT_NUM_ATTRS( attrs ) ( sizeof( attrs ) / sizeof( gattAttribute_t ) ) + +// The handle of a service is the handle of the first attribute +#define GATT_SERVICE_HANDLE( attrs ) ( (attrs)[0].handle ) + +// The handle of the first included service (i = 1) is the value of the second attribute +#define GATT_INCLUDED_HANDLE( attrs, i ) ( *((uint16 *)((attrs)[(i)].pValue)) ) + +/********************************************************************* + * TYPEDEFS + */ + +/** + * @defgroup GATT_SERV_APP_CB_API GATT Server App Callback API Functions + * + * @{ + */ + +/** + * @brief Callback function prototype to read an attribute value. + * + * @param connHandle - connection request was received on + * @param pAttr - pointer to attribute + * @param pValue - pointer to data to be read (to be returned) + * @param pLen - length of data (to be returned) + * @param offset - offset of the first octet to be read + * @param maxLen - maximum length of data to be read + * + * @return SUCCESS: Read was successfully.
+ * Error, otherwise: ref ATT_ERR_CODE_DEFINES.
+ */ +typedef bStatus_t (*pfnGATTReadAttrCB_t)( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, + uint8 maxLen ); +/** + * @brief Callback function prototype to write an attribute value. + * + * @param connHandle - connection request was received on + * @param pAttr - pointer to attribute + * @param pValue - pointer to data to be written + * @param pLen - length of data + * @param offset - offset of the first octet to be written + * + * @return SUCCESS: Write was successfully.
+ * Error, otherwise: ref ATT_ERR_CODE_DEFINES.
+ */ +typedef bStatus_t (*pfnGATTWriteAttrCB_t)( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ); +/** + * @brief Callback function prototype to authorize a Read or Write operation + * on a given attribute. + * + * @param connHandle - connection request was received on + * @param pAttr - pointer to attribute + * @param opcode - request opcode (ATT_READ_REQ or ATT_WRITE_REQ) + * + * @return SUCCESS: Operation authorized.
+ * ATT_ERR_INSUFFICIENT_AUTHOR: Authorization required.
+ */ +typedef bStatus_t (*pfnGATTAuthorizeAttrCB_t)( uint16 connHandle, gattAttribute_t *pAttr, + uint8 opcode ); +/** + * @} + */ + +/** + * GATT Structure for Characteristic Presentation Format Value. + */ +typedef struct +{ + uint8 format; //!< Format of the value of this characteristic + int8 exponent; //!< A sign integer which represents the exponent of an integer + uint16 unit; //!< Unit of this attribute as defined in the data dictionary + uint8 nameSpace; //!< Name space of the description + uint16 desc; //!< Description of this attribute as defined in a higher layer profile +} gattCharFormat_t; + +/** + * GATT Structure for Client Characteristic Configuration. + */ +typedef struct +{ + uint16 connHandle; //!< Client connection handle + uint8 value; //!< Characteristic configuration value for this client +} gattCharCfg_t; + +/** + * GATT Structure for service callback functions - must be setup by the application + * and used when GATTServApp_RegisterService() is called. + */ +typedef struct +{ + pfnGATTReadAttrCB_t pfnReadAttrCB; //!< Read callback function pointer + pfnGATTWriteAttrCB_t pfnWriteAttrCB; //!< Write callback function pointer + pfnGATTAuthorizeAttrCB_t pfnAuthorizeAttrCB; //!< Authorization callback function pointer +} gattServiceCBs_t; + +/** + * GATT Server App event header format. + */ +typedef struct +{ + osal_event_hdr_t hdr; //!< GATT_SERV_MSG_EVENT and status + uint16 connHandle; //!< Connection message was received on + uint8 method; //!< GATT type of command. Ref: @ref GATT_SERV_MSG_EVENT_DEFINES +} gattEventHdr_t; + +/** + * GATT_CLIENT_CHAR_CFG_UPDATED_EVENT message format. This message is sent to + * the app when a Client Characteristic Configuration is updated. + */ +typedef struct +{ + osal_event_hdr_t hdr; //!< GATT_SERV_MSG_EVENT and status + uint16 connHandle; //!< Connection message was received on + uint8 method; //!< GATT_CLIENT_CHAR_CFG_UPDATED_EVENT + uint16 attrHandle; //!< attribute handle + uint16 value; //!< attribute new value +} gattClientCharCfgUpdatedEvent_t; + + + +typedef void (*gattServMsgCB_t)( gattMsgEvent_t*pMsg); + +/********************************************************************* + * VARIABLES + */ + +/********************************************************************* + * API FUNCTIONS + */ + +/** + * @defgroup GATT_SERV_APP_API GATT Server App API Functions + * + * @{ + */ + +/** + * @brief Register your task ID to receive event messages + * from the GATT Server Application. + * + * @param taskID - Default task ID to send events. + * + * @return none + */ +extern void GATTServApp_RegisterForMsg( uint8 taskID ); + +/** + * @brief Register a service's attribute list and callback functions with + * the GATT Server Application. + * + * @param pAttrs - Array of attribute records to be registered + * @param numAttrs - Number of attributes in array + * @param pServiceCBs - Service callback function pointers + * + * @return SUCCESS: Service registered successfully.
+ * INVALIDPARAMETER: Invalid service field.
+ * FAILURE: Not enough attribute handles available.
+ * bleMemAllocError: Memory allocation error occurred.
+ */ +extern bStatus_t GATTServApp_RegisterService( gattAttribute_t *pAttrs, uint16 numAttrs, + CONST gattServiceCBs_t *pServiceCBs ); +/** + * @brief Deregister a service's attribute list and callback functions from + * the GATT Server Application. + * + * NOTE: It's the caller's responsibility to free the service attribute + * list returned from this API. + * + * @param handle - handle of service to be deregistered + * @param p2pAttrs - pointer to array of attribute records (to be returned) + * + * @return SUCCESS: Service deregistered successfully. + * FAILURE: Service not found. + */ +bStatus_t GATTServApp_DeregisterService( uint16 handle, gattAttribute_t **p2pAttrs ); + +/** + * @brief Find the attribute record within a service attribute + * table for a given attribute value pointer. + * + * @param pAttrTbl - pointer to attribute table + * @param numAttrs - number of attributes in attribute table + * @param pValue - pointer to attribute value + * + * @return Pointer to attribute record. NULL, if not found. + */ +extern gattAttribute_t *GATTServApp_FindAttr( gattAttribute_t *pAttrTbl, + uint16 numAttrs, uint8 *pValue ); +/** + * @brief Add function for the GATT Service. + * + * @param services - services to add. This is a bit map and can + * contain more than one service. + * + * @return SUCCESS: Service added successfully.
+ * INVALIDPARAMETER: Invalid service field.
+ * FAILURE: Not enough attribute handles available.
+ * bleMemAllocError: Memory allocation error occurred.
+ */ +extern bStatus_t GATTServApp_AddService( uint32 services ); + +/** + * @brief Delete function for the GATT Service. + * + * @param services - services to delete. This is a bit map and can + * contain more than one service. + * + * @return SUCCESS: Service deleted successfully.
+ * FAILURE: Service not found.
+ */ +extern bStatus_t GATTServApp_DelService( uint32 services ); + +/** + * @brief Set a GATT Server parameter. + * + * @param param - Profile parameter ID + * @param len - length of data to right + * @param pValue - pointer to data to write. This is dependent on the + * parameter ID and WILL be cast to the appropriate + * data type (example: data type of uint16 will be cast + * to uint16 pointer). + * + * @return SUCCESS: Parameter set successful + * FAILURE: Parameter in use + * INVALIDPARAMETER: Invalid parameter + * bleInvalidRange: Invalid value + * bleMemAllocError: Memory allocation failed + */ +extern bStatus_t GATTServApp_SetParameter( uint8 param, uint8 len, void *pValue ); + +/** + * @brief Get a GATT Server parameter. + * + * @param param - Profile parameter ID + * @param pValue - pointer to data to put. This is dependent on the + * parameter ID and WILL be cast to the appropriate + * data type (example: data type of uint16 will be + * cast to uint16 pointer). + * + * @return SUCCESS: Parameter get successful + * INVALIDPARAMETER: Invalid parameter + */ +extern bStatus_t GATTServApp_GetParameter( uint8 param, void *pValue ); + +/** + * @brief Update the Client Characteristic Configuration for a given + * Client. + * + * Note: This API should only be called from the Bond Manager. + * + * @param connHandle - connection handle. + * @param attrHandle - attribute handle. + * @param value - characteristic configuration value. + * + * @return SUCCESS: Parameter get successful + * INVALIDPARAMETER: Invalid parameter + */ +extern bStatus_t GATTServApp_UpdateCharCfg( uint16 connHandle, uint16 attrHandle, uint16 value ); + +/** + * @brief Initialize the client characteristic configuration table. + * + * Note: Each client has its own instantiation of the Client + * Characteristic Configuration. Reads/Writes of the Client + * Characteristic Configuration only only affect the + * configuration of that client. + * + * @param connHandle - connection handle (0xFFFF for all connections). + * @param charCfgTbl - client characteristic configuration table. + * + * @return none + */ +extern void GATTServApp_InitCharCfg( uint16 connHandle, gattCharCfg_t *charCfgTbl ); + +/** + * @brief Read the client characteristic configuration for a given + * client. + * + * Note: Each client has its own instantiation of the Client + * Characteristic Configuration. Reads of the Client + * Characteristic Configuration only shows the configuration + * for that client. + * + * @param connHandle - connection handle. + * @param charCfgTbl - client characteristic configuration table. + * + * @return attribute value + */ +extern uint16 GATTServApp_ReadCharCfg( uint16 connHandle, gattCharCfg_t *charCfgTbl ); + +/** + * @brief Write the client characteristic configuration for a given + * client. + * + * Note: Each client has its own instantiation of the Client + * Characteristic Configuration. Writes of the Client + * Characteristic Configuration only only affect the + * configuration of that client. + * + * @param connHandle - connection handle. + * @param charCfgTbl - client characteristic configuration table. + * @param value - attribute new value. + * + * @return Success or Failure + */ +extern uint8 GATTServApp_WriteCharCfg( uint16 connHandle, gattCharCfg_t *charCfgTbl, uint16 value ); + +/** + * @brief Process the client characteristic configuration + * write request for a given client. + * + * @param connHandle - connection message was received on. + * @param pAttr - pointer to attribute. + * @param pValue - pointer to data to be written. + * @param len - length of data. + * @param offset - offset of the first octet to be written. + * @param validCfg - valid configuration. + * + * @return Success or Failure + */ +extern bStatus_t GATTServApp_ProcessCCCWriteReq( uint16 connHandle, gattAttribute_t *pAttr, + uint8 *pValue, uint8 len, uint16 offset, + uint16 validCfg ); + +/** + * @brief Process Client Charateristic Configuration change. + * + * @param charCfgTbl - characteristic configuration table. + * @param pValue - pointer to attribute value. + * @param authenticated - whether an authenticated link is required. + * @param attrTbl - attribute table. + * @param numAttrs - number of attributes in attribute table. + * @param taskId - task to be notified of confirmation. + * + * @return Success or Failure + */ +extern bStatus_t GATTServApp_ProcessCharCfg( gattCharCfg_t *charCfgTbl, uint8 *pValue, + uint8 authenticated, gattAttribute_t *attrTbl, + uint16 numAttrs, uint8 taskId ); + +/** + * @brief Build and send the GATT_CLIENT_CHAR_CFG_UPDATED_EVENT to + * the application. + * + * @param connHandle - connection handle + * @param attrHandle - attribute handle + * @param value - attribute new value + * + * @return none + */ +extern void GATTServApp_SendCCCUpdatedEvent( uint16 connHandle, uint16 attrHandle, uint16 value ); + +/** + * @brief Send out a Service Changed Indication. + * + * @param connHandle - connection to use + * @param taskId - task to be notified of confirmation + * + * @return SUCCESS: Indication was sent successfully.
+ * FAILURE: Service Changed attribute not found.
+ * INVALIDPARAMETER: Invalid connection handle or request field.
+ * MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ * bleNotConnected: Connection is down.
+ * blePending: A confirmation is pending with this client.
+ */ +extern bStatus_t GATTServApp_SendServiceChangedInd( uint16 connHandle, uint8 taskId ); + +/** + * @brief Read an attribute. If the format of the attribute value + * is unknown to GATT Server, use the callback function + * provided by the Service. + * + * @param connHandle - connection message was received on + * @param pAttr - pointer to attribute + * @param service - handle of owner service + * @param pValue - pointer to data to be read + * @param pLen - length of data to be read + * @param offset - offset of the first octet to be read + * @param maxLen - maximum length of data to be read + * + * @return Success or Failure + */ +extern uint8 GATTServApp_ReadAttr( uint16 connHandle, gattAttribute_t* pAttr, + uint16 service, uint8* pValue, uint16* pLen, + uint16 offset, uint8 maxLen ); + +/** + * @brief Write attribute data + * + * @param connHandle - connection message was received on + * @param handle - attribute handle + * @param pValue - pointer to data to be written + * @param len - length of data + * @param offset - offset of the first octet to be written + * + * @return Success or Failure + */ +extern uint8 GATTServApp_WriteAttr( uint16 connHandle, uint16 handle, + uint8 *pValue, uint16 len, uint16 offset ); + +/** + * @} + */ + +/** + * @brief Set a GATT Server Application Parameter value. Use this + * function to change the default GATT parameter values. + * + * @param value - new param value + * + * @return void + */ +extern void GATTServApp_SetParamValue( uint16 value ); + +/** + * @brief Get a GATT Server Application Parameter value. + * + * @param none + * + * @return GATT Parameter value + */ +extern uint16 GATTServApp_GetParamValue( void ); + +/*------------------------------------------------------------------- + * TASK API - These functions must only be called by OSAL. + */ + +/** + * @internal + * + * @brief Initialize the GATT Server Test Application. + * + * @param taskId - Task identifier for the desired task + * + * @return void + * + */ +extern void GATTServApp_Init( uint8 taskId ); + +/** + * @internal + * + * @brief GATT Server Application Task event processor. This function + * is called to process all events for the task. Events include + * timers, messages and any other user defined events. + * + * @param task_id - The OSAL assigned task ID. + * @param events - events to process. This is a bit map and can + * contain more than one event. + * + * @return none + */ +extern uint16 GATTServApp_ProcessEvent( uint8 taskId, uint16 events ); + +bStatus_t gattServApp_RegisterCB(gattServMsgCB_t cb); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* GATTSERVAPP_H */ diff --git a/src/components/ble/host/gatttest.h b/src/components/ble/host/gatttest.h new file mode 100644 index 0000000..3d56312 --- /dev/null +++ b/src/components/ble/host/gatttest.h @@ -0,0 +1,152 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** +**************************************************************************************************/ + +#ifndef GATTTEST_H +#define GATTTEST_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" + +/********************************************************************* + CONSTANTS +*/ +// Length of attribute +#define GATT_TEST_ATTR_LEN 20 + +// Length of long attribute +#define GATT_TEST_LONG_ATTR_LEN 50 + +// GATT Test Services bit fields +#define GATT_TEST_SERVICE 0x00000001 // GATT Test +#define GATT_BATT_STATE_SERVICE 0x00000002 // Battery State +#define GATT_THERMO_HUMID_SERVICE 0x00000004 // Thermometer Humidity +#define GATT_WEIGHT_SERVICE 0x00000008 // Weight +#define GATT_POSITION_SERVICE 0x00000010 // Position +#define GATT_ALERT_SERVICE 0x00000020 // Alert +#define GATT_MANUFACT_SENSOR_SERVICE 0x00000040 // Sensor Manufacturer +#define GATT_MANUFACT_SCALES_SERVICE 0x00000080 // Scales Manufacturer +#define GATT_ADDRESS_SERVICE 0x00000100 // Address +#define GATT_128BIT_UUID1_SERVICE 0x00000200 // 128-bit UUID 1 +#define GATT_128BIT_UUID2_SERVICE 0x00000400 // 128-bit UUID 2 +#define GATT_128BIT_UUID3_SERVICE 0x00000800 // 128-bit UUID 3 + +/********************************************************************* + VARIABLES +*/ + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + VARIABLES +*/ + +/********************************************************************* + FUNCTIONS +*/ + +/** + @brief Add function for the GATT Test Services. + + @param services - services to add. This is a bit map and can + contain more than one service. + + @return SUCCESS: Service added successfully. + INVALIDPARAMETER: Invalid service field. + FAILURE: Not enough attribute handles available. + bleMemAllocError: Memory allocation error occurred. +*/ +extern bStatus_t GATTTest_AddService( uint32 services ); + +/** + @brief Delete function for the GATT Test Services. + + @param services - services to delete. This is a bit map and can + contain more than one service. + + @return SUCCESS: Service deleted successfully. + FAILURE: Service not found. +*/ +extern bStatus_t GATTTest_DelService( uint32 services ); + +/* ------------------------------------------------------------------- + TASK API - These functions must only be called by OSAL. +*/ + +/** + @internal + + @brief Initialize the GATT Test Application. + + @param taskId - Task identifier for the desired task + + @return void + +*/ +extern void GATTTest_Init( uint8 taskId ); + +/** + @internal + + @brief GATT Test Application Task event processor. This function + is called to process all events for the task. Events include + timers, messages and any other user defined events. + + @param task_id - The OSAL assigned task ID. + @param events - events to process. This is a bit map and can + contain more than one event. + + @return none +*/ +extern uint16 GATTTest_ProcessEvent( uint8 task_id, uint16 events ); + +/** + @brief Add function for the GATT Qualification Services. + + @param services - services to add. This is a bit map and can + contain more than one service. + + @return SUCCESS: Service added successfully. + INVALIDPARAMETER: Invalid service field. + FAILURE: Not enough attribute handles available. + bleMemAllocError: Memory allocation error occurred. +*/ +extern bStatus_t GATTQual_AddService( uint32 services ); + +/** + @brief Delete function for the GATT Qualification Services. + + @param services - services to delete. This is a bit map and can + contain more than one service. + + @return SUCCESS: Service deleted successfully. + FAILURE: Service not found. +*/ +extern bStatus_t GATTQual_DelService( uint32 services ); + + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* GATTTEST_H */ diff --git a/src/components/ble/host/l2cap_internal.h b/src/components/ble/host/l2cap_internal.h new file mode 100644 index 0000000..598bee9 --- /dev/null +++ b/src/components/ble/host/l2cap_internal.h @@ -0,0 +1,276 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** +**************************************************************************************************/ + +#ifndef L2CAP_INTERNAL_H +#define L2CAP_INTERNAL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ +#include "hci.h" +#include "l2cap.h" + +/********************************************************************* + MACROS +*/ + +// Macro to see if a given channel is a fixed channel +#define FIX_CHANNEL( CID ) ( (CID) == L2CAP_CID_GENERIC ||\ + (CID) == L2CAP_CID_SIG ||\ + (CID) == L2CAP_CID_ATT ||\ + (CID) == L2CAP_CID_SMP ) + +// Marco to convert a channel ID to an index into L2CAP Channel table +#define CID_TO_INDEX( CID ) ( (CID) - BASE_DYNAMIC_CID ) + +// Marco to convert a fixed channel ID to an index into L2CAP Fixed Channel table +#define FCID_TO_INDEX( CID ) ( (CID) - L2CAP_CID_ATT ) + +// Macro to return the record maintained a given fix channel +#define FIX_CHANNEL_REC( CID ) ( l2capFixedChannels[FCID_TO_INDEX( CID )] ) + +/********************************************************************* + CONSTANTS +*/ +// Signaling command header: Code (1 byte) + Identifier (1 byte) + Length (2 bytes) +#define SIGNAL_HDR_SIZE 4 + +// Maximum size of data field of Signaling commands +#define SIGNAL_DATA_SIZE ( L2CAP_SIG_MTU_SIZE - SIGNAL_HDR_SIZE ) + +/********************************************************************* + L2CAP Channel States: states used for l2capChannel 'state' field +*/ +// Closed - no channel associated with this CID +#define L2CAP_CLOSED 0x00 + +// Waiting for Echo Response +#define L2CAP_W4_ECHO_RSP 0x01 + +// Waiting for Info Response +#define L2CAP_W4_INFO_RSP 0x02 + +// Waiting for Connection Parameter Update Response +#define L2CAP_W4_PARAM_UPDATE_RSP 0x03 + +/********************************************************************* + TYPEDEFS +*/ + +// L2CAP Channel structure. Allocated one per application connection +// between two devices. CID assignment is relative to a particular device +// and a device can assign CIDs independently from other devices (except +// for the reserved CIDs). The CIDs are dynamically allocated in the range +// from 0x0040 to 0xFFFF. +typedef struct +{ + // Channel info + uint8 state; // Channel connection state + uint16 CID; // Local channel id + uint8 id; // Local identifier - matches responses with requests + + // Link info + uint16 connHandle; // link connection handle + + // Application info + uint8 taskId; // task that channel belongs to + + // Timer id + uint8 timerId; +} l2capChannel_t; + +// L2CAP Fixed Channel structure. Allocated one for each fixed channel. +typedef struct +{ + uint16 CID; // channel id + uint8 taskId; // task registered with channel +} l2capFixedChannel_t; + +// Signaling packet header format +typedef struct +{ + uint8 opcode; // type of command + uint8 id; // identifier - matches responses with requests + uint16 len; // length of data field (doesn't cover Code, Identifier and Length fields) +} l2capSignalHdr_t; + +/** + @brief Callback function prototype for building a Signaling command. + + @param pBuf - pointer to buffer to hold command data + @param pData - pointer to command data + + @return length of the command data +*/ +typedef uint16 (*pfnL2CAPBuildCmd_t)( uint8* pBuf, uint8* pData ); + +/********************************************************************* + GLOBAL VARIABLES +*/ +extern uint8 l2capTaskID; +extern l2capChannel_t l2capChannels[]; +extern l2capFixedChannel_t l2capFixedChannels[]; + +/********************************************************************* + FUNCTIONS - API +*/ + +/* + Send L2CAP Command. +*/ +extern bStatus_t l2capSendCmd( uint16 connHandle, uint8 opcode, uint8 id, + uint8* pCmd, pfnL2CAPBuildCmd_t pfnBuildCmd ); +/* + Send L2CAP Request. +*/ +extern bStatus_t l2capSendReq( uint16 connHandle, uint8 opcode, uint8* pReq, + pfnL2CAPBuildCmd_t pfnBuildCmd, uint8 state, uint8 taskId ); +/* + Build Echo Request. +*/ +extern uint16 l2capBuildEchoReq( uint8* pBuf, uint8* pCmd ); + +/* + Build Info Request. +*/ +extern uint16 l2capBuildInfoReq( uint8* pBuf, uint8* pCmd ); + +/* + Build Parameter Update Request. +*/ +extern uint16 l2capBuildParamUpdateReq( uint8* pBuf, uint8* pData ); + +/* + Encapsulate and send L2CAP packet. +*/ +extern bStatus_t l2capEncapSendData( uint16 connHandle, l2capPacket_t* pPkt ); + +/* + Parse L2CAP packet. +*/ +extern uint8 l2capParsePacket( l2capPacket_t* pPkt, hciDataEvent_t* pHciMsg ); + +/* + Parse L2CAP Signaling header. +*/ +extern void l2capParseSignalHdr( l2capSignalHdr_t* pHdr, uint8* pData ); + +/* + Build Echo Response. +*/ +extern uint16 l2capBuildEchoRsp( uint8* pBuf, uint8* pCmd ); + +/* + Parse Command Reject. +*/ +extern bStatus_t l2capParseCmdReject( l2capSignalCmd_t* pCmd, uint8* pData, uint16 len ); + +/* + Parse Echo Response. +*/ +extern bStatus_t l2capParseEchoRsp( l2capSignalCmd_t* pCmd, uint8* pData, uint16 len ); + +/* + Parse Information Response. +*/ +extern bStatus_t l2capParseInfoRsp( l2capSignalCmd_t* pCmd, uint8* pData, uint16 len ); + +/* + Parse Connection Parameter Update Response. +*/ +extern bStatus_t l2capParseParamUpdateRsp( l2capSignalCmd_t* pCmd, uint8* pData, uint16 len ); + +/* + Find a channel using the local identifier. +*/ +extern l2capChannel_t* l2capFindLocalId( uint8 id ); + +/* + Free a channel. +*/ +extern void l2capFreeChannel( l2capChannel_t* pChannel ); + +/* + Stop an active timer for a given channel. +*/ +extern void l2capStopTimer( l2capChannel_t* pChannel ); + +/* + Handle an incoming packet error. +*/ +extern void l2capHandleRxError( uint16 connHandle ); + +/* + Forward a data message to upper layer application. +*/ +extern bStatus_t l2capNotifyData( uint8 taskId, uint16 connHandle, l2capPacket_t* pPkt ); + +/* + Send a Signaling command to upper layer application. +*/ +extern void l2capNotifySignal( uint8 taskId, uint16 connHandle, uint8 status, + uint8 opcode, uint8 id, l2capSignalCmd_t* pCmd ); + +extern void* L2CAP_Fragment_bm_alloc( uint16 size ); + +extern uint8 L2CAP_Fragment_SendDataPkt( uint16 connHandle, uint8 fragFlg,uint16 pktLen, uint8* pBuf ); + + +/********************************************************************* + @fn l2capInfoRsp + + @brief Send Info Response. + + Use like: l2capInfoRsp( uint16 connHandle, uint8 id, l2capInfoRsp_t *pInfoRsp ); + + @param connHandle - connection to use + @param id - identifier received in request + @param pInfoRsp - pointer to Info Response to be sent + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Data can not fit into one packet. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +#define l2capInfoRsp( connHandle, id, pInfoRsp ) l2capSendCmd( (connHandle), L2CAP_INFO_RSP, (id),\ + (uint8 *)(pInfoRsp), L2CAP_BuildInfoRsp ) + +/********************************************************************* + @fn l2capEchoRsp + + @brief Send Ehco Response. + + Use like: l2capEchoRsp( uint16 connHandle, uint8 id, l2capEchoRsp_t *pEchoRsp ); + + @param connHandle - connection to use + @param id - identifier received in request + @param pEchoRsp - pinter to Echo Response to be sent + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Data can not fit into one packet. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +#define l2capEchoRsp( connHandle, id, pEchoRsp ) l2capSendCmd( (connHandle), L2CAP_ECHO_RSP, (id),\ + (uint8 *)(pEchoRsp), l2capBuildEchoRsp ) + + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* L2CAP_INTERNAL_H */ diff --git a/src/components/ble/host/linkdb.h b/src/components/ble/host/linkdb.h new file mode 100644 index 0000000..a73ae02 --- /dev/null +++ b/src/components/ble/host/linkdb.h @@ -0,0 +1,209 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +/************************************************************************************************** + Filename: linkdb.h + Revised: + Revision: + + Description: This file contains the linkDB interface. + + +**************************************************************************************************/ + +#ifndef LINKDB_H +#define LINKDB_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + * INCLUDES + */ + +/********************************************************************* + * MACROS + */ + +/********************************************************************* + * CONSTANTS + */ + +// Special case connection handles +#define INVALID_CONNHANDLE 0xFFFF // Invalid connection handle, used for no connection handle +#define LOOPBACK_CONNHANDLE 0xFFFE // Loopback connection handle, used to loopback a message + +// Link state flags +#define LINK_NOT_CONNECTED 0x00 // Link isn't connected +#define LINK_CONNECTED 0x01 // Link is connected +#define LINK_AUTHENTICATED 0x02 // Link is authenticated +#define LINK_BOUND 0x04 // Link is bonded +#define LINK_ENCRYPTED 0x10 // Link is encrypted + +// Link Database Status callback changeTypes +#define LINKDB_STATUS_UPDATE_NEW 0 // New connection created +#define LINKDB_STATUS_UPDATE_REMOVED 1 // Connection was removed +#define LINKDB_STATUS_UPDATE_STATEFLAGS 2 // Connection state flag changed + +// Link Authentication Errors +#define LINKDB_ERR_INSUFFICIENT_AUTHEN 0x05 // Link isn't even encrypted +#define LINBDB_ERR_INSUFFICIENT_KEYSIZE 0x0c // Link is encrypted but the key size is too small +#define LINKDB_ERR_INSUFFICIENT_ENCRYPTION 0x0f // Link is encrypted but it's not authenticated + +/********************************************************************* + * TYPEDEFS + */ + +typedef struct +{ + uint8 srk[KEYLEN]; // Signature Resolving Key + uint32 signCounter; // Sign Counter +} linkSec_t; + +typedef struct +{ + uint8 ltk[KEYLEN]; // Long Term Key + uint16 div; // Diversifier + uint8 rand[B_RANDOM_NUM_SIZE]; // random number + uint8 keySize; // LTK Key Size +} encParams_t; + +typedef struct +{ + uint8 taskID; // Application that controls the link + uint16 connectionHandle; // Controller connection handle + uint8 stateFlags; // LINK_CONNECTED, LINK_AUTHENTICATED... + uint8 role; // 2020-04-22 add (case for multi-role SMP ) + uint8 addrType; // Address type of connected device + uint8 addr[B_ADDR_LEN]; // Other Device's address + uint16 connInterval; // The connection's interval (n * 1.23 ms) + linkSec_t sec; // Connection Security related items + encParams_t *pEncParams; // pointer to LTK, ediv, rand. if needed. +} linkDBItem_t; + +// function pointer used to register for a status callback +typedef void (*pfnLinkDBCB_t)( uint16 connectionHandle, uint8 changeType ); + +// function pointer used to perform specialized link database searches +typedef void (*pfnPerformFuncCB_t)( linkDBItem_t *pLinkItem ); + +/********************************************************************* + * GLOBAL VARIABLES + */ + +/********************************************************************* + * PUBLIC FUNCTIONS + */ + /* + * linkDB_Init - Initialize the Link Database. + */ + extern void linkDB_Init( void ); + + /* + * linkDB_Register - Register with this function to receive a callback when + * status changes on a connection. + */ + extern uint8 linkDB_Register( pfnLinkDBCB_t pFunc ); + + /* + * linkDB_Add - Adds a record to the link database. + */ +extern uint8 linkDB_Add( uint8 taskID, uint16 connectionHandle, uint8 stateFlags, uint8 role, + uint8 addrType, uint8* pAddr, uint16 connInterval ); + + /* + * linkDB_Remove - Removes a record from the link database. + */ + extern uint8 linkDB_Remove( uint16 connectionHandle ); + + /* + * linkDB_Update - This function is used to update the stateFlags of + * a link record. + */ + extern uint8 linkDB_Update( uint16 connectionHandle, uint8 newState ); + + /* + * linkDB_NumActive - returns the number of active connections. + */ + extern uint8 linkDB_NumActive( void ); + + /* + * linkDB_Find - Find link database item (link information) + * + * returns a pointer to the link item, NULL if not found + */ + extern linkDBItem_t *linkDB_Find( uint16 connectionHandle ); + + /* + * linkDB_FindFirst - Find the first link that matches the taskID. + * + * returns a pointer to the link item, NULL if not found + */ + extern linkDBItem_t *linkDB_FindFirst( uint8 taskID ); + + /* + * linkDB_State - Check to see if a physical link is in a specific state. + * + * returns TRUE is the link is in state. FALSE, otherwise. + */ + extern uint8 linkDB_State( uint16 connectionHandle, uint8 state ); + + /* + * linkDB_Authen - Check to see if the physical link is encrypted and authenticated. + * returns SUCCESS if the link is authenticated or + * bleNotConnected - connection handle is invalid, + * LINKDB_ERR_INSUFFICIENT_AUTHEN - link is not encrypted, + * LINBDB_ERR_INSUFFICIENT_KEYSIZE - key size encrypted is not large enough, + * LINKDB_ERR_INSUFFICIENT_ENCRYPTION - link is encrypted, but not authenticated + */ + extern uint8 linkDB_Authen( uint16 connectionHandle, uint8 keySize, uint8 mitmRequired ); + + /* + * linkDB_PerformFunc - Perform a function of each connection in the link database. + */ + extern void linkDB_PerformFunc( pfnPerformFuncCB_t cb ); + + /* + * linkDB_Up - Check to see if a physical link is up (connected). + * Use like: uint8 linkDB_Up( uint16 connectionHandle ); + * connectionHandle - controller link connection handle. + * returns TRUE if the link is up. FALSE, otherwise. + */ + #define linkDB_Up( connectionHandle ) linkDB_State( (connectionHandle), LINK_CONNECTED ) + + /* + * linkDB_Encrypted - Check to see if the physical link is encrypted. + * Use like: linkDB_Encrypted( uint16 connectionHandle ); + * connectionHandle - controller link connection handle. + * returns TRUE if the link is encrypted. FALSE, otherwise. + */ + #define linkDB_Encrypted( connectionHandle ) linkDB_State( (connectionHandle), LINK_ENCRYPTED ) + + /* + * linkDB_Authenticated - Check to see if the physical link is authenticated. + * Use like: linkDB_Authenticated( uint16 connectionHandle ); + * connectionHandle - controller link connection handle. + * returns TRUE if the link is authenticated. FALSE, otherwise. + */ + #define linkDB_Authenticated( connectionHandle ) linkDB_State( (connectionHandle), LINK_AUTHENTICATED ) + + /* + * linkDB_Bonded - Check to see if the physical link is bonded. + * Use like: linkDB_Bonded( uint16 connectionHandle ); + * connectionHandle - controller link connection handle. + * returns TRUE if the link is bonded. FALSE, otherwise. + */ + #define linkDB_Bonded( connectionHandle ) linkDB_State( (connectionHandle), LINK_BOUND ) + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* LINKDB_H */ diff --git a/src/components/ble/host/sm_internal.h b/src/components/ble/host/sm_internal.h new file mode 100644 index 0000000..92f3b00 --- /dev/null +++ b/src/components/ble/host/sm_internal.h @@ -0,0 +1,365 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +/************************************************************************************************** +**************************************************************************************************/ + +#ifndef SM_INTERNAL_H +#define SM_INTERNAL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + * INCLUDES + */ +#include "bcomdef.h" +#include "l2cap.h" +#include "smp.h" +#include "linkdb.h" + +/********************************************************************* + * MACROS + */ + +/********************************************************************* + * CONSTANTS + */ + +// Security Manager Task Events +#define SM_TIMEOUT_EVT 0x0001 // Message timeout event +#define SM_PAIRING_STATE_EVT 0x0002 // Event used to progress to the next pairing state + +// Pairing states +#define SM_PAIRING_STATE_INITIALIZE 0 // Pairing has started +#define SM_PAIRING_STATE_PAIRING_REQ_SENT 1 // Initiator: Pairing Request has been sent, Responder: waiting for Pairing Request. +#define SM_PAIRING_STATE_WAIT_CONFIRM 2 // Waiting for Confirm message +#define SM_PAIRING_STATE_WAIT_PASSKEY 3 // Waiting for Passkey from app/profile +#define SM_PAIRING_STATE_WAIT_CONFIRM_PASSKEY 4 // Received Initiator Confirm message and waiting for Passkey from app/profile (responder only) +#define SM_PAIRING_STATE_WAIT_RANDOM 5 // Waiting for Random message +#define SM_PAIRING_STATE_WAIT_STK 6 // Waiting for STK process to finish +#define SM_PAIRING_STATE_WAIT_SLAVE_ENCRYPTION_INFO 7 // Waiting for Slave Encryption Info to be sent +#define SM_PAIRING_STATE_WAIT_SLAVE_MASTER_INFO 8 // Waiting for Slave Master Info to be sent +#define SM_PAIRING_STATE_WAIT_SLAVE_IDENTITY_INFO 9 // Waiting for Slave Identity Info to be sent +#define SM_PAIRING_STATE_WAIT_SLAVE_IDENTITY_ADDR_INFO 10 // Waiting for Slave Identity Addr Info to be sent +#define SM_PAIRING_STATE_WAIT_SLAVE_SIGNING_INFO 11 // Waiting for Slave Signing Info to be sent +#define SM_PAIRING_STATE_WAIT_MASTER_ENCRYPTION_INFO 12 // Waiting for Master Encryption Info to be sent +#define SM_PAIRING_STATE_WAIT_MASTER_MASTER_INFO 13 // Waiting for Master Master Info to be sent +#define SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_INFO 14 // Waiting for Master Identity Info to be sent +#define SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_ADDR_INFO 15 // Waiting for Master Identity Addr Info to be sent +#define SM_PAIRING_STATE_WAIT_MASTER_SIGNING_INFO 16 // Waiting for Master Signing Info to be sent +#define SM_PAIRING_STATE_WAIT_ENCRYPT 17 // Waiting for LTK process to finish +#define SM_PAIRING_STATE_DONE 18 // Closing out the pairing process + +#if defined ( TESTMODES ) + // SM TestModes + #define SM_TESTMODE_OFF 0 // No Test mode + #define SM_TESTMODE_NO_RESPONSE 1 // Don't respond to any SM message + #define SM_TESTMODE_SEND_BAD_CONFIRM 2 // Force a bad confirm value in the Confirm Message + #define SM_TESTMODE_BAD_CONFIRM_VERIFY 3 // Force a bad confirm check of the received Confirm Message + #define SM_TESTMODE_SEND_CONFIRM 4 // Force a SMP Confirm message +#endif // TESTMODES + +// Pairing Types +#define SM_PAIRING_TYPE_INIT 0 // Pairing has been started but the type hasn't been determined yet +#define SM_PAIRING_TYPE_JUST_WORKS 1 // Pairing is Just Works +#define SM_PAIRING_TYPE_PASSKEY_INITIATOR_INPUTS 2 // Pairing is MITM Passkey with initiator inputs passkey +#define SM_PAIRING_TYPE_PASSKEY_RESPONDER_INPUTS 3 // Pairing is MITM Passkey with responder inputs passkey +#define SM_PAIRING_TYPE_PASSKEY_BOTH_INPUTS 4 // Pairing is MITM Passkey with both initiator and responder input passkey +#define SM_PAIRING_TYPE_OOB 5 // Pairing is MITM OOB + +#define SM_PAIRING_STATE_WAIT 500 // The default wait time between key distribution messages. + +/********************************************************************* + * TYPEDEFS + */ + +typedef struct +{ + uint8 confirm[KEYLEN]; // calculated confirm value + uint8 rand[SMP_RANDOM_LEN]; // First MRand or Srand, then RAND +} devPairing_t; + +typedef struct +{ + // From the start + uint8 initiator; // TRUE if initiator + uint8 state; // Pairing state + uint8 taskID; // Task ID of the app/profile that requested the pairing + + uint8 timerID; // 2021-03-29 add , timerid for simultaneously SMP for multi-role(the same as single connection ) + uint8 stateID; // 2021-03-29 add , stateid for simultaneously SMP pairing state change idx + uint16 connectionHandle; // Connection Handle from controller, + smLinkSecurityReq_t *pSecReqs; // Pairing Control info + uint8 tk[KEYLEN]; // Holds tk from app + uint8 authState; // uses SM_AUTH_STATE_AUTHENTICATED & SM_AUTH_STATE_BONDING + + // During pairing + smpPairingReq_t *pPairDev; // Info of paired device. + uint8 type; // ie. SM_PAIRING_TYPE_JUST_WORKS + + // device information + devPairing_t myComp; // This device's pairing components + devPairing_t devComp; // The other device's components + + // Encrypt Params + smSecurityInfo_t *pEncParams; // Your (device's) encryption parameters + smSecurityInfo_t *pDevEncParams; // Connected device's encryption parameters + smIdentityInfo_t *pIdInfo; // Connected device's identity parameters + smSigningInfo_t *pSigningInfo; // Connected device's signing parameters + +} smPairingParams_t; + +// Callback when an SMP message has been received on the Initiator or Responder. +typedef uint8 (*smProcessMsg_t)( linkDBItem_t *pLinkItem, uint8 cmdID, smpMsgs_t *pParsedMsg ); + +// Callback to send next key message, and sets state for next event on the Initiator or Responder. +typedef void (*smSendNextKeyInfo_t)( uint16 connectionHandle ); + +// Callback to send Start Encrypt through HCI on the Initiator. +typedef bStatus_t (*smStartEncryption_t)( uint16 connHandle, uint8 *pLTK, uint16 div, + uint8 *pRandNum, uint8 keyLen ); + +// Callback when an HCI BLE LTK Request has been received on the Responder. +typedef uint8 (*smProcessLTKReq_t)( uint16 connectionHandle, uint8 *pRandom, uint16 encDiv ); + +// Initiator callback structure - must be setup by the Initiator. +typedef struct +{ + smProcessMsg_t pfnProcessMsg; // When SMP message received + smSendNextKeyInfo_t pfnSendNextKeyInfo; // When need to send next key message + smStartEncryption_t pfnStartEncryption; // When Start Encrypt requested +} smInitiatorCBs_t; + +// Responder callback structure - must be setup by the Initiator. +typedef struct +{ + smProcessMsg_t pfnProcessMsg; // When SMP message received + smSendNextKeyInfo_t pfnSendNextKeyInfo; // When need to send next key message + smProcessLTKReq_t pfnProcessLTKReq; // When HCI BLE LTK Request received +} smResponderCBs_t; + +/********************************************************************* + * GLOBAL VARIABLES + */ + +// Security Manager's OSAL task ID +extern uint8 smTaskID; + +extern smPairingParams_t* pPairingParams[]; + +extern smResponderCBs_t *pfnResponderCBs; + +/********************************************************************* + * FUNCTIONS - API + */ + +/********************************************************************* + * Application Level Functions + */ + + /* + * smLinkCheck - link database callback function. + */ + extern void smLinkCheck( uint16 connectionHandle, uint8 changeType ); + + /* + * smProcessRandComplete - Process the HCI Random Complete Event. + */ + extern uint8 smProcessRandComplete( uint8 status, uint8 *rand ); + + /* + * smTimedOut - Process the SM timeout. + */ +extern void smTimedOut( uint16 connectionHandle ); + + /* + * smStartRspTimer - Start the SM Response Timer. +*/ +extern void smStartRspTimer( uint16 connectionHandle ); + +/* + smStopRspTimer - Stop the SM Response Timer. +*/ +extern void smStopRspTimer( uint16 connectionHandle ); + + /* + * smProcessDataMsg - Process incoming L2CAP messages. + */ + extern void smProcessDataMsg( l2capDataEvent_t *pMsg ); + + /* + * smProcessEncryptChange - Process the HCI BLE Encrypt Change Event. + */ + extern uint8 smProcessEncryptChange( uint16 connectionHandle, uint8 reason ); + + /* + * smInProcess - Is SM already processing something? + */ + extern uint8 smInProcess( void ); + + /* + * sm_d1 - SM diversifying function d1 + */ + extern bStatus_t sm_d1( uint8 *pK, uint16 d, uint8 *pD1 ); + + /* + * sm_ah - Random address hash function + */ + extern bStatus_t sm_ah( uint8 *pK, uint8 *pR, uint8 *pAh ); + + /* + * sm_dm - SM DIV Maxk generation function dm + */ + extern bStatus_t sm_dm( uint8 *pK, uint8 *pR, uint16 *pDm ); + +/* + sm_c1 - SM Confirm value generation function c1 +*/ +extern bStatus_t sm_c1( uint16 connectionHandle,uint8* pK, uint8* pR, uint8* pC1 ); + +/* + sm_c1new - SM Confirm value generation function c1 +*/ +extern bStatus_t sm_c1new( uint8* pK, uint8* pR, uint8* pRes, uint8* pReq, + uint8 iat, uint8* pIA, uint8 rat, uint8* pRA, uint8* pC1 ); +/* + sm_s1 - SM key generation function s1 +*/ +extern bStatus_t sm_s1( uint8* pK, uint8* pR1, uint8* pR2, uint8* pS1 ); + +/* + smGenerateRandBuf - generate a buffer of random numbers +*/ +extern void smGenerateRandBuf( uint8* pRandNum, uint8 len ); + +/* + smEncLTK - start LTK Encryption +*/ +extern void smEncLTK( uint16 connectionHandle ); + +/* + smNextPairingState - trigger next state machine +*/ +extern void smNextPairingState( uint16 connectionHandle ); + +/* + smAuthReqToUint8 - conversion function +*/ +extern uint8 smAuthReqToUint8( authReq_t* pAuthReq ); + +/* + smUint8ToAuthReq - conversion function +*/ +extern void smUint8ToAuthReq( authReq_t* pAuthReq, uint8 authReqUint8 ); + +/* + smpResponderProcessPairingReq - Process an incoming Pairing Request message +*/ +extern uint8 smpResponderProcessPairingReq( uint16 connectionHandle,smpPairingReq_t* pParsedMsg ); + +/* + smSendFailAndEnd - Send the pairing failed message and end existing pairing +*/ +extern bStatus_t smSendFailAndEnd( uint16 connHandle, smpPairingFailed_t* pFailedMsg ); + +/* + generateRandMsg - Generate a Pairing Random +*/ +extern bStatus_t smGenerateRandMsg( uint16 connectionHandle); + +/* + smSavePairInfo - Save the Pairing Req or Rsp information +*/ +extern bStatus_t smSavePairInfo( uint16 connectionHandle,smpPairingReq_t* pPair ); + +/* + generateConfirm - Generate a Pairing Confirm +*/ +extern bStatus_t smGenerateConfirm( uint16 connectionHandle ); + +/* + smEndPairing - Pairing mode has ended. Yeah. Notify the GAP and free + up the memory used. +*/ +extern void smEndPairing( uint16 connectionHandle,uint8 status ); + +/* + determineKeySize - Determine the maximum encryption key size +*/ +extern uint8 smDetermineKeySize( uint16 connectionHandle ); + +/* + smGeneratePairingReqRsp - Generate a pairing req or response +*/ +extern bStatus_t smGeneratePairingReqRsp( uint16 connectionHandle ); + + /* + * smPairingSendEncInfo - Send SM Encryption Information message + */ + extern void smPairingSendEncInfo( uint16 connHandle, uint8 *pLTK ); + + /* + * smPairingSendMasterID - Send SM Master Identification message + */ + extern void smPairingSendMasterID( uint16 connHandle, uint16 ediv, uint8 *pRand ); + + /* + * smPairingSendIdentityInfo - Send SM Identity Information message + */ + extern void smPairingSendIdentityInfo( uint16 connHandle, uint8 *pIRK ); + + /* + * smPairingSendIdentityAddrInfo - Send SM Identity Addr Information message + */ + extern void smPairingSendIdentityAddrInfo( uint16 connHandle, uint8 addrType, uint8 *pMACAddr ); + + /* + * smPairingSendSingingInfo - Send SM Signing Information message + */ + extern void smPairingSendSingingInfo( uint16 connHandle, uint8 *pSRK ); + + /* + * smPairingSendEncInfo - Send SM Encryption Information message + */ + extern void smPairingSendEncInfo( uint16 connHandle, uint8 *pLTK ); + + /* + * smProcessPairingReq - Process Pairing Request + */ + extern void smProcessPairingReq( linkDBItem_t *pLinkItem, gapPairingReq_t *pPairReq ); + + /* + * smStartEncryption - Perform Encrypt through HCI + */ + extern bStatus_t smStartEncryption( uint16 connHandle, uint8 *pLTK, uint16 div, + uint8 *pRandNum, uint8 keyLen ); + + /* + * smRegisterInitiator - egister Initiator's processing function with SM task + */ + extern void smRegisterInitiator( smInitiatorCBs_t *pfnCBs ); + + /* + * smRegisterResponder - Register Responder's processing function with SM task + */ + extern void smRegisterResponder( smResponderCBs_t *pfnCBs ); + +/* + smp timerout callback for SMP Timeout and pairing state +*/ +extern void smTo_timerCB( uint8* pData ); +extern void smState_timerCB( uint8* pData ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* SM_INTERNAL_H */ diff --git a/src/components/ble/host/smp.h b/src/components/ble/host/smp.h new file mode 100644 index 0000000..99c89c2 --- /dev/null +++ b/src/components/ble/host/smp.h @@ -0,0 +1,380 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** +**************************************************************************************************/ + +#ifndef SMP_H +#define SMP_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" + +#include "sm_internal.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +// Code field of the SMP Command format +#define SMP_PAIRING_REQ 0x01 +#define SMP_PAIRING_RSP 0x02 +#define SMP_PAIRING_CONFIRM 0x03 +#define SMP_PAIRING_RANDOM 0x04 +#define SMP_PAIRING_FAILED 0x05 +#define SMP_ENCRYPTION_INFORMATION 0x06 +#define SMP_MASTER_IDENTIFICATION 0x07 +#define SMP_IDENTITY_INFORMATION 0x08 +#define SMP_IDENTITY_ADDR_INFORMATION 0x09 +#define SMP_SIGNING_INFORMATION 0x0A +#define SMP_SECURITY_REQUEST 0x0B + +// Pairing Request & Response - IO Capabilities +#define SMP_IO_CAP_DISPLAY_ONLY 0x00 +#define SMP_IO_CAP_DISPLAY_YES_NO 0x01 +#define SMP_IO_CAP_KEYBOARD_ONLY 0x02 +#define SMP_IO_CAP_NO_INPUT_NO_OUTPUT 0x03 +#define SMP_IO_CAP_KEYBOARD_DISPLAY 0x04 + +// Pairing Request & Response - Out Of Bound (OOB) data flag values +#define SMP_OOB_AUTH_DATA_NOT_PRESENT 0x00 +#define SMP_OOB_AUTH_DATA_REMOTE_DEVICE_PRESENT 0x01 + +// Pairing Request & Response - authReq field +// - This field contains 2 sub-fields: +// bonding flags - bits 1 & 0 +#define SMP_AUTHREQ_BONDING 0x01 +// Man-In-The-Middle (MITM) - bit 2 +#define SMP_AUTHREQ_MITM 0x04 + +#define SMP_CONFIRM_LEN 16 +#define SMP_RANDOM_LEN 16 + +// Pairing Failed - "reason" field +#define SMP_PAIRING_FAILED_PASSKEY_ENTRY_FAILED 0x01 //!< The user input of the passkey failed, for example, the user cancelled the operation. +#define SMP_PAIRING_FAILED_OOB_NOT_AVAIL 0x02 //!< The OOB data is not available +#define SMP_PAIRING_FAILED_AUTH_REQ 0x03 //!< The pairing procedure can't be performed as authentication requirements can't be met due to IO capabilities of one or both devices +#define SMP_PAIRING_FAILED_CONFIRM_VALUE 0x04 //!< The confirm value doesn't match the calculated compare value +#define SMP_PAIRING_FAILED_NOT_SUPPORTED 0x05 //!< Pairing isn't supported by the device +#define SMP_PAIRING_FAILED_ENC_KEY_SIZE 0x06 //!< The resultant encryption key size is insufficient for the security requirements of this device. +#define SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED 0x07 //!< The SMP command received is not supported on this device. +#define SMP_PAIRING_FAILED_UNSPECIFIED 0x08 //!< Pairing failed due to an unspecified reason +#define SMP_PAIRING_FAILED_REPEATED_ATTEMPTS 0x09 //!< Pairing or authenication procedure is disallowed because too little time has elapsed since the last pairing request or security request. + +#define SMP_PAIRING_FAILED_LOCAL_KEY_FAILURE 0x0A // Local value - not sent over the air + +// Message lengths +#define SMP_PAIRING_REQ_LEN 7 +#define SMP_PAIRING_RSP_LEN 7 +#define SMP_PAIRING_CONFIRM_LEN 17 +#define SMP_PAIRING_RANDOM_LEN 17 +#define SMP_PAIRING_FAILED_LEN 2 +#define SMP_ENCRYPTION_INFORMATION_LEN 17 +#define SMP_MASTER_IDENTIFICATION_LEN 11 +#define SMP_IDENTITY_INFORMATION_LEN 17 +#define SMP_IDENTITY_ADDR_INFORMATION_LEN 8 +#define SMP_SIGNING_INFORMATION_LEN 17 +#define SMP_SECURITY_REQUEST_LEN 2 + +// Macros to use the smSendSMMsg() function to send all of the Security Manager Protocol messages +#define smSendPairingReq( connHandle, msgStruct ) \ + smSendSMMsg( (connHandle), SMP_PAIRING_REQ_LEN, \ + (smpMsgs_t *)(msgStruct), \ + (pfnSMBuildCmd_t)(smpBuildPairingReq) ) + +#define smSendPairingRsp( connHandle, msgStruct ) \ + smSendSMMsg( (connHandle), SMP_PAIRING_RSP_LEN, \ + (smpMsgs_t *)(msgStruct), \ + (pfnSMBuildCmd_t)(smpBuildPairingRsp) ) + +#define smSendPairingConfirm( connHandle, msgStruct ) \ + smSendSMMsg( (connHandle), SMP_PAIRING_CONFIRM_LEN, \ + (smpMsgs_t *)(msgStruct), \ + (pfnSMBuildCmd_t)(smpBuildPairingConfirm) ) + +#define smSendPairingRandom( connHandle, msgStruct ) \ + smSendSMMsg( (connHandle), SMP_PAIRING_RANDOM_LEN, \ + (smpMsgs_t *)(msgStruct), \ + (pfnSMBuildCmd_t)(smpBuildPairingRandom) ) + +#define smSendPairingFailed( connHandle, msgStruct ) \ + smSendSMMsg( (connHandle), SMP_PAIRING_FAILED_LEN, \ + (smpMsgs_t *)(msgStruct), \ + (pfnSMBuildCmd_t)(smpBuildPairingFailed) ) + +#define smSendEncInfo( connHandle, msgStruct ) \ + smSendSMMsg( (connHandle), SMP_ENCRYPTION_INFORMATION_LEN, \ + (smpMsgs_t *)(msgStruct), \ + (pfnSMBuildCmd_t)(smpBuildEncInfo) ) + +#define smSendMasterID( connHandle, msgStruct ) \ + smSendSMMsg( (connHandle), SMP_MASTER_IDENTIFICATION_LEN, \ + (smpMsgs_t *)(msgStruct), \ + (pfnSMBuildCmd_t)(smpBuildMasterID) ) + +#define smSendIdentityInfo( connHandle, msgStruct ) \ + smSendSMMsg( (connHandle), SMP_IDENTITY_INFORMATION_LEN, \ + (smpMsgs_t *)(msgStruct), \ + (pfnSMBuildCmd_t)(smpBuildIdentityInfo) ) + +#define smSendIdentityAddrInfo( connHandle, msgStruct ) \ + smSendSMMsg( (connHandle), SMP_IDENTITY_ADDR_INFORMATION_LEN, \ + (smpMsgs_t *)(msgStruct), \ + (pfnSMBuildCmd_t)(smpBuildIdentityAddrInfo) ) + +#define smSendSigningInfo( connHandle, msgStruct ) \ + smSendSMMsg( (connHandle), SMP_SIGNING_INFORMATION_LEN, \ + (smpMsgs_t *)(msgStruct), \ + (pfnSMBuildCmd_t)(smpBuildSigningInfo) ) + +#define smSendSecurityReq( connHandle, msgStruct ) \ + smSendSMMsg( (connHandle), SMP_SECURITY_REQUEST_LEN, \ + (smpMsgs_t *)(msgStruct), \ + (pfnSMBuildCmd_t)(smpBuildSecurityReq) ) + +/********************************************************************* + TYPEDEFS +*/ + +// Pairing Request +typedef struct +{ + uint8 ioCapability; // ex. SMP_IO_CAP_DISPLAY_YES_NO + uint8 oobDataFlag; // Out of Bound data flag + authReq_t authReq; // Authentication fields + uint8 maxEncKeySize; // Encryption Key size max bytes (7 - 16) + keyDist_t keyDist; // Key Distribution Field - bit struct +} smpPairingReq_t; + +// Pairing Response - same as Pairing Request +typedef smpPairingReq_t smpPairingRsp_t; + +// Pairing Confirm +typedef struct +{ + uint8 confirmValue[SMP_CONFIRM_LEN]; +} smpPairingConfirm_t; + +// Pairing Random +typedef struct +{ + uint8 randomValue[SMP_RANDOM_LEN]; +} smpPairingRandom_t; + +// Pairing Failed +typedef struct +{ + uint8 reason; +} smpPairingFailed_t; + +// Encryption Information +typedef struct +{ + uint8 ltk[KEYLEN]; +} smpEncInfo_t; + +// Master Identification +typedef struct +{ + uint16 ediv; + uint16 rand[B_RANDOM_NUM_SIZE]; +} smpMasterID_t; + +// Identity Information +typedef struct +{ + uint8 irk[KEYLEN]; +} smpIdentityInfo_t; + +// Identity Address Information +typedef struct +{ + uint8 addrType; + uint8 bdAddr[B_ADDR_LEN]; +} smpIdentityAddrInfo_t; + +// Signing Information +typedef struct +{ + uint8 signature[KEYLEN]; +} smpSigningInfo_t; + +// Slave Security Request +typedef struct +{ + authReq_t authReq; +} smpSecurityReq_t; + +// Union with all of the SM messages. +typedef union +{ + smpPairingReq_t pairingReq; + smpPairingReq_t pairingRsp; + smpPairingConfirm_t pairingConfirm; + smpPairingRandom_t pairingRandom; + smpPairingFailed_t pairingFailed; + smpEncInfo_t encInfo; + smpMasterID_t masterID; + smpIdentityInfo_t idInfo; + smpIdentityAddrInfo_t idAddrInfo; + smpSigningInfo_t signingInfo; + smpSecurityReq_t secReq; +} smpMsgs_t; + +typedef uint8 (*pfnSMBuildCmd_t)( smpMsgs_t* pMsgStruct, uint8* pBuf ); + +/********************************************************************* + GLOBAL VARIABLES +*/ +extern smpPairingReq_t pairingReg; + +/********************************************************************* + FUNCTIONS +*/ + +/* + smpBuildPairingReq - Build an SM Pairing Request +*/ +extern bStatus_t smpBuildPairingReq( smpPairingReq_t* pPairingReq, uint8* pBuf ); + +/* + smpBuildPairingRsp - Build an SM Pairing Response +*/ +extern bStatus_t smpBuildPairingRsp( smpPairingRsp_t* pPairingRsp, uint8* pBuf ); + +/* + smpBuildPairingReqRsp - Build an SM Pairing Request or Response +*/ +extern bStatus_t smpBuildPairingReqRsp( uint8 opCode, smpPairingReq_t* pPairingReq, uint8* pBuf ); + +/* + smpParsePairingReq - Parse an SM Pairing Request +*/ +extern bStatus_t smpParsePairingReq( uint8* pBuf, smpPairingReq_t* pPairingReq ); + +/* + smpParsePairingRsp - Parse an SM Pairing Response +*/ +#define smpParsePairingRsp( a, b ) smpParsePairingReq( (a), (b) ) + +/* + smpBuildPairingConfirm - Build an SM Pairing Confirm +*/ +extern bStatus_t smpBuildPairingConfirm( smpPairingConfirm_t* pPairingConfirm, + uint8* pBuf ); + +/* + smpParsePairingConfirm - Parse an SM Pairing Confirm +*/ +extern bStatus_t smpParsePairingConfirm( uint8* pBuf, + smpPairingConfirm_t* pPairingConfirm ); + +/* + smpBuildPairingRandom - Build an SM Pairing Random +*/ +extern bStatus_t smpBuildPairingRandom( smpPairingRandom_t* pPairingRandom, + uint8* pBuf ); + +/* + smpParsePairingRandom - Parse an SM Pairing Random +*/ +extern bStatus_t smpParsePairingRandom( uint8* pBuf, + smpPairingRandom_t* pPairingRandom ); + +/* + smpBuildPairingFailed - Build an SM Pairing Failed +*/ +extern bStatus_t smpBuildPairingFailed( smpPairingFailed_t* pPairingFailed, + uint8* pBuf ); + +/* + smpParsePairingFailed - Parse an SM Pairing Failed +*/ +extern bStatus_t smpParsePairingFailed( uint8* pBuf, + smpPairingFailed_t* pPairingFailed ); + +/* + smpBuildEncInfo - Build an SM Encryption Information +*/ +extern bStatus_t smpBuildEncInfo( smpEncInfo_t* pEncInfo, uint8* pBuf ); + +/* + smpParseEncInfo - Parse an SM Encryption Information +*/ +extern bStatus_t smpParseEncInfo( uint8* buf, smpEncInfo_t* encInfo ); + +/* + smpBuildMasterID - Build an SM Master Identification +*/ +extern bStatus_t smpBuildMasterID( smpMasterID_t* pMasterID, uint8* pBuf ); + +/* + smpParseMasterID - Parse an SM Master Identification +*/ +extern bStatus_t smpParseMasterID( uint8* pBuf, smpMasterID_t* pMasterID ); + +/* + smpBuildIdentityInfo - Build an SM Identity Information +*/ +extern bStatus_t smpBuildIdentityInfo( smpIdentityInfo_t* pIdInfo, uint8* pBuf ); + +/* + smpBuildIdentityAddrInfo - Build an SM Identity Address Information +*/ +extern bStatus_t smpBuildIdentityAddrInfo( smpIdentityAddrInfo_t* pIdInfo, uint8* pBuf ); + +/* + smpParseIdentityInfo - Parse an SM Identity Information +*/ +extern bStatus_t smpParseIdentityInfo( uint8* pBuf, smpIdentityInfo_t* pIdInfo ); + +/* + smpParseIdentityAddrInfo - Parse an SM Identity Address Information +*/ +extern bStatus_t smpParseIdentityAddrInfo( uint8* pBuf, smpIdentityAddrInfo_t* pIdInfo ); + +/* + smpBuildSigningInfo - Build an SM Signing Information +*/ +extern bStatus_t smpBuildSigningInfo( smpSigningInfo_t* pSigningInfo, uint8* pBuf ); + +/* + smpParseSigningInfo - Parse an SM Signing Information +*/ +extern bStatus_t smpParseSigningInfo( uint8* pBuf, smpSigningInfo_t* pSigningInfo ); + +/* + smpBuildSecurityReq - Build an SM Slave Security Request +*/ +extern bStatus_t smpBuildSecurityReq( smpSecurityReq_t* pSecReq, uint8* pBuf ); + +/* + smpParseSecurityReq - Parse an SM Slave Security Request +*/ +extern bStatus_t smpParseSecurityReq( uint8* pBuf, smpSecurityReq_t* pSecReq ); + +/* + smSendSMMsg - Generic Send L2CAP SM message function +*/ +extern bStatus_t smSendSMMsg( uint16 connHandle, uint8 bufLen, smpMsgs_t* pMsg, pfnSMBuildCmd_t buildFn ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* SMP_H */ diff --git a/src/components/ble/include/att.h b/src/components/ble/include/att.h new file mode 100644 index 0000000..c2afe88 --- /dev/null +++ b/src/components/ble/include/att.h @@ -0,0 +1,1251 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/** + @headerfile: att.h + + +**************************************************************************************************/ + +#ifndef ATT_H +#define ATT_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" + +#include "l2cap.h" + +/********************************************************************* + CONSTANTS +*/ + +// The Exchanging MTU Size is defined as the maximum size of any packet +// transmitted between a client and a server. A higher layer specification +// defines the default ATT MTU value. The ATT MTU value should be within +// the range 23 to 517 inclusive. +#define ATT_MTU_SIZE L2CAP_MTU_SIZE //!< Minimum ATT MTU size +#define ATT_MAX_MTU_SIZE 517 //!< Maximum ATT MTU size +#define ATT_MTU_SIZE_MIN 23 +/** @defgroup ATT_METHOD_DEFINES ATT Methods + @{ +*/ + +#define ATT_ERROR_RSP 0x01 //!< ATT Error Response +#define ATT_EXCHANGE_MTU_REQ 0x02 //!< ATT Exchange MTU Request +#define ATT_EXCHANGE_MTU_RSP 0x03 //!< ATT Exchange MTU Response +#define ATT_FIND_INFO_REQ 0x04 //!< ATT Find Information Request +#define ATT_FIND_INFO_RSP 0x05 //!< ATT Find Information Response +#define ATT_FIND_BY_TYPE_VALUE_REQ 0x06 //!< ATT Find By Type Vaue Request +#define ATT_FIND_BY_TYPE_VALUE_RSP 0x07 //!< ATT Find By Type Vaue Response +#define ATT_READ_BY_TYPE_REQ 0x08 //!< ATT Read By Type Request +#define ATT_READ_BY_TYPE_RSP 0x09 //!< ATT Read By Type Response +#define ATT_READ_REQ 0x0a //!< ATT Read Request +#define ATT_READ_RSP 0x0b //!< ATT Read Response +#define ATT_READ_BLOB_REQ 0x0c //!< ATT Read Blob Request +#define ATT_READ_BLOB_RSP 0x0d //!< ATT Read Blob Response +#define ATT_READ_MULTI_REQ 0x0e //!< ATT Read Multiple Request +#define ATT_READ_MULTI_RSP 0x0f //!< ATT Read Multiple Response +#define ATT_READ_BY_GRP_TYPE_REQ 0x10 //!< ATT Read By Group Type Request +#define ATT_READ_BY_GRP_TYPE_RSP 0x11 //!< ATT Read By Group Type Response +#define ATT_WRITE_REQ 0x12 //!< ATT Write Request +#define ATT_WRITE_RSP 0x13 //!< ATT Write Response +#define ATT_PREPARE_WRITE_REQ 0x16 //!< ATT Prepare Write Request +#define ATT_PREPARE_WRITE_RSP 0x17 //!< ATT Prepare Write Response +#define ATT_EXECUTE_WRITE_REQ 0x18 //!< ATT Execute Write Request +#define ATT_EXECUTE_WRITE_RSP 0x19 //!< ATT Execute Write Response +#define ATT_HANDLE_VALUE_NOTI 0x1b //!< ATT Handle Value Notification +#define ATT_HANDLE_VALUE_IND 0x1d //!< ATT Handle Value Indication +#define ATT_HANDLE_VALUE_CFM 0x1e //!< ATT Handle Value Confirmation + +#define ATT_WRITE_CMD 0x52 //!< ATT Write Command +#define ATT_SIGNED_WRITE_CMD 0xD2 //!< ATT Signed Write Command + +/** @} End ATT_METHOD_DEFINES */ + +/*** Opcode fields: bitmasks ***/ +// Method (bits 5-0) +#define ATT_METHOD_BITS 0x3f + +// Command Flag (bit 6) +#define ATT_CMD_FLAG_BIT 0x40 + +// Authentication Signature Flag (bit 7) +#define ATT_AUTHEN_SIG_FLAG_BIT 0x80 + +// Size of 16-bit Bluetooth UUID +#define ATT_BT_UUID_SIZE 2 + +// Size of 128-bit UUID +#define ATT_UUID_SIZE 16 + +// ATT Response or Confirmation timeout +#define ATT_MSG_TIMEOUT 30 + +// Authentication Signature status for received PDU; it's TRUE or FALSE for PDU to be sent +#define ATT_SIG_NOT_INCLUDED 0x00 // Signature not included +#define ATT_SIG_VALID 0x01 // Included signature valid +#define ATT_SIG_INVALID 0x02 // Included signature not valid + +/********************************************************************* + Error Response: Error Code +*/ + +/** @defgroup ATT_ERR_CODE_DEFINES ATT Error Codes + @{ +*/ + +#define ATT_ERR_INVALID_HANDLE 0x01 //!< Attribute handle value given was not valid on this attribute server +#define ATT_ERR_READ_NOT_PERMITTED 0x02 //!< Attribute cannot be read +#define ATT_ERR_WRITE_NOT_PERMITTED 0x03 //!< Attribute cannot be written +#define ATT_ERR_INVALID_PDU 0x04 //!< The attribute PDU was invalid +#define ATT_ERR_INSUFFICIENT_AUTHEN 0x05 //!< The attribute requires authentication before it can be read or written +#define ATT_ERR_UNSUPPORTED_REQ 0x06 //!< Attribute server doesn't support the request received from the attribute client +#define ATT_ERR_INVALID_OFFSET 0x07 //!< Offset specified was past the end of the attribute +#define ATT_ERR_INSUFFICIENT_AUTHOR 0x08 //!< The attribute requires an authorization before it can be read or written +#define ATT_ERR_PREPARE_QUEUE_FULL 0x09 //!< Too many prepare writes have been queued +#define ATT_ERR_ATTR_NOT_FOUND 0x0a //!< No attribute found within the given attribute handle range +#define ATT_ERR_ATTR_NOT_LONG 0x0b //!< Attribute cannot be read or written using the Read Blob Request or Prepare Write Request +#define ATT_ERR_INSUFFICIENT_KEY_SIZE 0x0c //!< The Encryption Key Size used for encrypting this link is insufficient +#define ATT_ERR_INVALID_VALUE_SIZE 0x0d //!< The attribute value length is invalid for the operation +#define ATT_ERR_UNLIKELY 0x0e //!< The attribute request that was requested has encountered an error that was very unlikely, and therefore could not be completed as requested +#define ATT_ERR_INSUFFICIENT_ENCRYPT 0x0f //!< The attribute requires encryption before it can be read or written +#define ATT_ERR_UNSUPPORTED_GRP_TYPE 0x10 //!< The attribute type is not a supported grouping attribute as defined by a higher layer specification +#define ATT_ERR_INSUFFICIENT_RESOURCES 0x11 //!< Insufficient Resources to complete the request + +/*** Reserved for future use: 0x12 - 0x7F ***/ + +/*** Application error code defined by a higher layer specification: 0x80-0x9F ***/ + +#define ATT_ERR_INVALID_VALUE 0x80 //!< The attribute value is invalid for the operation + +/** @} End ATT_ERR_CODE_DEFINES */ + +/********************************************************************* + Find Information Response: UUID Format +*/ +// Handle and 16-bit Bluetooth UUID +#define ATT_HANDLE_BT_UUID_TYPE 0x01 + +// Handle and 128-bit UUID +#define ATT_HANDLE_UUID_TYPE 0x02 + +// Maximum number of handle and 16-bit UUID pairs in a single Find Info Response +#define ATT_MAX_NUM_HANDLE_BT_UUID ( ( ATT_MTU_SIZE_MIN - 2 ) / ( 2 + ATT_BT_UUID_SIZE ) ) + +// Maximum number of handle and 128-bit UUID pairs in a single Find Info Response +#define ATT_MAX_NUM_HANDLE_UUID ( ( ATT_MTU_SIZE_MIN - 2 ) / ( 2 + ATT_UUID_SIZE ) ) + +/********************************************************************* + Find By Type Value Response: Handles Infomation (Found Attribute Handle and Group End Handle) +*/ +// Maximum number of handles info in a single Find By Type Value Response +#define ATT_MAX_NUM_HANDLES_INFO ( ( ATT_MTU_SIZE - 1 ) / 4 ) + +/********************************************************************* + Read Multiple Request: Handles +*/ +// Maximum number of handles in a single Read Multiple Request +#define ATT_MAX_NUM_HANDLES ( ( ATT_MTU_SIZE - 1 ) / 2 ) + +// Minimum number of handles in a single Read Multiple Request +#define ATT_MIN_NUM_HANDLES 2 + +/********************************************************************* + Execute Write Request: Flags +*/ +// Cancel all prepared writes +#define ATT_CANCEL_PREPARED_WRITES 0x00 + +// Immediately write all pending prepared values +#define ATT_WRITE_PREPARED_VALUES 0x01 + +#if defined ( TESTMODES ) +// ATT Test Modes +#define ATT_TESTMODE_OFF 0 // Test mode off +#define ATT_TESTMODE_UNAUTHEN_SIG 1 // Do not authenticate incoming signature +#endif + +/********************************************************************* + Size of mandatory fields of ATT requests +*/ +// Length of Read By Type Request's fixed fields: First handle number (2) + Last handle number (2) +#define READ_BY_TYPE_REQ_FIXED_SIZE 4 + +// Length of Prepare Write Request's fixed size: Attribute Handle (2) + Value Offset (2) +#define PREPARE_WRITE_REQ_FIXED_SIZE 4 + +/********************************************************************* + VARIABLES +*/ +extern CONST uint8 btBaseUUID[ATT_UUID_SIZE]; + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/** + Attribute Protocol PDU format. +*/ +typedef struct +{ + uint8 sig; //!< Authentication Signature status (not included (0), valid (1), invalid (2)) + uint8 cmd; //!< Command Flag + uint8 method; //!< Method + uint16 len; //!< Length of Attribute Parameters + uint8* pParams; //!< Attribute Parameters +} attPacket_t; + +/** + Attribute Type format (2 or 16 octet UUID). +*/ +typedef struct +{ + uint8 len; //!< Length of UUID + uint8 uuid[ATT_UUID_SIZE]; //!< 16 or 128 bit UUID +} attAttrType_t; + +/** + Attribute Type format (2-octet Bluetooth UUID). +*/ +typedef struct +{ + uint8 len; //!< Length of UUID + uint8 uuid[ATT_BT_UUID_SIZE]; //!< 16 bit UUID +} attAttrBtType_t; + +/** + Error Response format. +*/ +typedef struct +{ + uint8 reqOpcode; //!< Request that generated this error response + uint16 handle; //!< Attribute handle that generated error response + uint8 errCode; //!< Reason why the request has generated error response +} attErrorRsp_t; + +/** + Exchange MTU Request format. +*/ +typedef struct +{ + uint16 clientRxMTU; //!< Client receive MTU size +} attExchangeMTUReq_t; + +/** + Exchange MTU Response format. +*/ +typedef struct +{ + uint16 serverRxMTU; //!< Server receive MTU size +} attExchangeMTURsp_t; + +typedef struct +{ + uint16 clientMTU; + uint16 serverMTU; +} attMTU_t; + +/** + Find Information Request format. +*/ +typedef struct +{ + uint16 startHandle; //!< First requested handle number (must be first field) + uint16 endHandle; //!< Last requested handle number +} attFindInfoReq_t; + +/** + Handle and its 16-bit Bluetooth UUIDs. +*/ +typedef struct +{ + uint16 handle; //!< Handle + uint8 uuid[ATT_BT_UUID_SIZE]; //!< 2-octet Bluetooth UUID +} attHandleBtUUID_t; + +/** + Handle and its 128-bit UUID. +*/ +typedef struct +{ + uint16 handle; //!< Handle + uint8 uuid[ATT_UUID_SIZE]; //!< 16-octect UUID +} attHandleUUID_t; + +/** + Info data format for Find Information Response (handle-UUID pair). +*/ +typedef union +{ + attHandleBtUUID_t btPair[ATT_MAX_NUM_HANDLE_BT_UUID]; //!< A list of 1 or more handles with their 16-bit Bluetooth UUIDs + attHandleUUID_t pair[ATT_MAX_NUM_HANDLE_UUID]; //!< A list of 1 or more handles with their 128-bit UUIDs +} attFindInfo_t; + +/** + Find Information Response format. +*/ +typedef struct +{ + uint8 numInfo; //!< Number of attribute handle-UUID pairs found + uint8 format; //!< Format of information data + attFindInfo_t info; //!< Information data whose format is determined by format field +} attFindInfoRsp_t; + +/** + Find By Type Value Request format. +*/ +typedef struct +{ + uint16 startHandle; //!< First requested handle number (must be first field) + uint16 endHandle; //!< Last requested handle number + attAttrBtType_t type; //!< 2-octet UUID to find +// uint8 len; //!< Length of value + uint16 len; //!< Length of value + uint8 value[ATT_MTU_SIZE-7]; //!< Attribute value to find +} attFindByTypeValueReq_t; + +/** + Handles Infomation format. +*/ +typedef struct +{ + uint16 handle; //!< Found attribute handle + uint16 grpEndHandle; //!< Group end handle +} attHandlesInfo_t; + +/** + Find By Type Value Response format. +*/ +typedef struct +{ + uint8 numInfo; //!< Number of handles information found + attHandlesInfo_t handlesInfo[ATT_MAX_NUM_HANDLES_INFO]; //!< List of 1 or more handles information +} attFindByTypeValueRsp_t; + +/** + Read By Type Request format. +*/ +typedef struct +{ + uint16 startHandle; //!< First requested handle number (must be first field) + uint16 endHandle; //!< Last requested handle number + attAttrType_t type; //!< Requested type (2 or 16 octet UUID) +} attReadByTypeReq_t; + +/** + Read By Type Response format. +*/ +typedef struct +{ + uint8 numPairs; //!< Number of attribute handle-UUID pairs found +// uint8 len; //!< Size of each attribute handle-value pair + uint16 len; + uint8 dataList[ATT_MTU_SIZE-2]; //!< List of 1 or more attribute handle-value pairs +} attReadByTypeRsp_t; + +/** + Read Request format. +*/ +typedef struct +{ + uint16 handle; //!< Handle of the attribute to be read (must be first field) +} attReadReq_t; + +/** + Read Response format. +*/ +typedef struct +{ +// uint8 len; //!< Length of value + uint16 len; + uint8 value[ATT_MTU_SIZE-1]; //!< Value of the attribute with the handle given +} attReadRsp_t; + +/** + Read Blob Req format. +*/ +typedef struct +{ + uint16 handle; //!< Handle of the attribute to be read (must be first field) + uint16 offset; //!< Offset of the first octet to be read +} attReadBlobReq_t; + +/** + Read Blob Response format. +*/ +typedef struct +{ +// uint8 len; //!< Length of value + uint16 len; + uint8 value[ATT_MTU_SIZE-1]; //!< Part of the value of the attribute with the handle given +} attReadBlobRsp_t; + +/** + Read Multiple Request format. +*/ +typedef struct +{ + uint16 handle[ATT_MAX_NUM_HANDLES]; //!< Set of two or more attribute handles (must be first field) + uint8 numHandles; //!< Number of attribute handles +} attReadMultiReq_t; + +/** + Read Multiple Response format. +*/ +typedef struct +{ +// uint8 len; //!< Length of values + uint16 len; + uint8 values[ATT_MTU_SIZE-1]; //!< Set of two or more values +} attReadMultiRsp_t; + +/** + Read By Group Type Request format. +*/ +typedef struct +{ + uint16 startHandle; //!< First requested handle number (must be first field) + uint16 endHandle; //!< Last requested handle number + attAttrType_t type; //!< Requested group type (2 or 16 octet UUID) +} attReadByGrpTypeReq_t; + +/** + Read By Group Type Response format. +*/ +typedef struct +{ + uint8 numGrps; //!< Number of attribute handle, end group handle and value sets found +// uint8 len; //!< Length of each attribute handle, end group handle and value set + uint16 len; + uint8 dataList[ATT_MTU_SIZE-2]; //!< List of 1 or more attribute handle, end group handle and value +} attReadByGrpTypeRsp_t; + +/** + Write Request format. +*/ +typedef struct +{ + uint16 handle; //!< Handle of the attribute to be written (must be first field) +// uint8 len; //!< Length of value + uint16 len; + uint8 value[ATT_MTU_SIZE-3]; //!< Value of the attribute to be written + uint8 sig; //!< Authentication Signature status (not included (0), valid (1), invalid (2)) + uint8 cmd; //!< Command Flag +} attWriteReq_t; + +/** + Prepare Write Request format. +*/ +typedef struct +{ + uint16 handle; //!< Handle of the attribute to be written (must be first field) + uint16 offset; //!< Offset of the first octet to be written +// uint8 len; //!< Length of value + uint16 len; + uint8 value[ATT_MTU_SIZE-5]; //!< Part of the value of the attribute to be written +} attPrepareWriteReq_t; + +/** + Prepare Write Response format. +*/ +typedef struct +{ + uint16 handle; //!< Handle of the attribute that has been read + uint16 offset; //!< Offset of the first octet to be written +// uint8 len; //!< Length of value + uint16 len; + uint8 value[ATT_MTU_SIZE-5]; //!< Part of the value of the attribute to be written +} attPrepareWriteRsp_t; + +/** + Execute Write Request format. +*/ +typedef struct +{ + uint8 flags; //!< 0x00 - cancel all prepared writes. + //!< 0x01 - immediately write all pending prepared values. +} attExecuteWriteReq_t; + +/** + Handle Value Notification format. +*/ +typedef struct +{ + uint16 handle; //!< Handle of the attribute that has been changed (must be first field) +// uint8 len; //!< Length of value + uint16 len; //!< Length of value + uint8 value[ATT_MTU_SIZE-3]; //!< New value of the attribute +} attHandleValueNoti_t; + +/** + Handle Value Indication format. +*/ +typedef struct +{ + uint16 handle; //!< Handle of the attribute that has been changed (must be first field) +// uint8 len; //!< Length of value + uint16 len; + uint8 value[ATT_MTU_SIZE-3]; //!< New value of the attribute +} attHandleValueInd_t; + +/** + ATT Message format. It's a union of all attribute protocol messages used + between the attribute protocol and upper layer profile/application. +*/ +typedef union +{ + // Request messages + attExchangeMTUReq_t exchangeMTUReq; //!< ATT Exchange MTU Request + attFindInfoReq_t findInfoReq; //!< ATT Find Information Request + attFindByTypeValueReq_t findByTypeValueReq; //!< ATT Find By Type Vaue Request + attReadByTypeReq_t readByTypeReq; //!< ATT Read By Type Request + attReadReq_t readReq; //!< ATT Read Request + attReadBlobReq_t readBlobReq; //!< ATT Read Blob Request + attReadMultiReq_t readMultiReq; //!< ATT Read Multiple Request + attReadByGrpTypeReq_t readByGrpTypeReq; //!< ATT Read By Group Type Request + attWriteReq_t writeReq; //!< ATT Write Request + attPrepareWriteReq_t prepareWriteReq; //!< ATT Prepare Write Request + attExecuteWriteReq_t executeWriteReq; //!< ATT Execute Write Request + + // Response messages + attErrorRsp_t errorRsp; //!< ATT Error Response + attExchangeMTURsp_t exchangeMTURsp; //!< ATT Exchange MTU Response + attFindInfoRsp_t findInfoRsp; //!< ATT Find Information Response + attFindByTypeValueRsp_t findByTypeValueRsp; //!< ATT Find By Type Vaue Response + attReadByTypeRsp_t readByTypeRsp; //!< ATT Read By Type Response + attReadRsp_t readRsp; //!< ATT Read Response + attReadBlobRsp_t readBlobRsp; //!< ATT Read Blob Response + attReadMultiRsp_t readMultiRsp; //!< ATT Read Multiple Response + attReadByGrpTypeRsp_t readByGrpTypeRsp; //!< ATT Read By Group Type Response + attPrepareWriteRsp_t prepareWriteRsp; //!< ATT Prepare Write Response + + // Indication and Notification messages + attHandleValueNoti_t handleValueNoti; //!< ATT Handle Value Notification + attHandleValueInd_t handleValueInd; //!< ATT Handle Value Indication +} attMsg_t; + +/********************************************************************* + VARIABLES +*/ + +/********************************************************************* + API FUNCTIONS +*/ + +/* ------------------------------------------------------------------- + General Utility APIs +*/ + +/* + Parse an attribute protocol message. +*/ +extern uint8 ATT_ParsePacket( l2capDataEvent_t* pL2capMsg, attPacket_t* pPkt ); + +/* + Compare two UUIDs. The UUIDs are converted if necessary. +*/ +extern uint8 ATT_CompareUUID( const uint8* pUUID1, uint16 len1, + const uint8* pUUID2, uint16 len2 ); +/* + Convert a 16-bit UUID to 128-bit UUID. +*/ +extern uint8 ATT_ConvertUUIDto128( const uint8* pUUID16, uint8* pUUID128 ); + +/* + Convert a 128-bit UUID to 16-bit UUID. +*/ +extern uint8 ATT_ConvertUUIDto16( const uint8* pUUID128, uint8* pUUID16 ); + + +/* ------------------------------------------------------------------- + Attribute Client Utility APIs +*/ + +/* + Build Error Response. +*/ +extern uint16 ATT_BuildErrorRsp( uint8* pBuf, uint8* pMsg ); + +/* + Parse Error Response. +*/ +extern bStatus_t ATT_ParseErrorRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Build Exchange MTU Request. +*/ +extern uint16 ATT_BuildExchangeMTUReq( uint8* pBuf, uint8* pMsg ); + +/* + Build Exchange MTU Respnose. +*/ +extern uint16 ATT_BuildExchangeMTURsp( uint8* pBuf, uint8* pMsg ); + +/* + Parse Exchange MTU Response. +*/ +extern bStatus_t ATT_ParseExchangeMTURsp( uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Build Find Information Request. +*/ +extern uint16 ATT_BuildFindInfoReq( uint8* pBuf, uint8* pMsg ); + +/* + Parse Find Information Response. +*/ +extern bStatus_t ATT_ParseFindInfoRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Build Find Information Response. +*/ +extern uint16 ATT_BuildFindInfoRsp( uint8* pBuf, uint8* pMsg ); + +/* + Build Find By Type Value Request. +*/ +extern uint16 ATT_BuildFindByTypeValueReq( uint8* pBuf, uint8* pMsg ); + +/* + Build Find By Type Value Response. +*/ +extern uint16 ATT_BuildFindByTypeValueRsp( uint8* pBuf, uint8* pMsg ); + +/* + Parse Find By Type Value Response. +*/ +extern bStatus_t ATT_ParseFindByTypeValueRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Build Read By Type Request. +*/ +extern uint16 ATT_BuildReadByTypeReq( uint8* pBuf, uint8* pMsg ); + +/* + Build Read By Type Response. +*/ +extern uint16 ATT_BuildReadByTypeRsp( uint8* pBuf, uint8* pMsg ); + +/* + Parse Read By Type Response. +*/ +extern bStatus_t ATT_ParseReadByTypeRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Build Read Request. +*/ +extern uint16 ATT_BuildReadReq( uint8* pBuf, uint8* pMsg ); + +/* + Build Read Response. +*/ +extern uint16 ATT_BuildReadRsp( uint8* pBuf, uint8* pMsg ); + +/* + Parse Read Response. +*/ +extern bStatus_t ATT_ParseReadRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Build Read Blob Request. +*/ +extern uint16 ATT_BuildReadBlobReq( uint8* pBuf, uint8* pMsg ); + +/* + Build Read Blob Response. +*/ +extern uint16 ATT_BuildReadBlobRsp( uint8* pBuf, uint8* pMsg ); + +/* + Parse Read Blob Response. +*/ +extern bStatus_t ATT_ParseReadBlobRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Build Read Multiple Request. +*/ +extern uint16 ATT_BuildReadMultiReq( uint8* pBuf, uint8* pMsg ); + +/* + Build Read Multiple Response. +*/ +extern uint16 ATT_BuildReadMultiRsp( uint8* pBuf, uint8* pMsg ); + +/* + Parse Read Multiple Response. +*/ +extern bStatus_t ATT_ParseReadMultiRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Build Read By Group Type Response. +*/ +extern uint16 ATT_BuildReadByGrpTypeRsp( uint8* pBuf, uint8* pMsg ); + +/* + Parse Read By Group Type Response. +*/ +extern bStatus_t ATT_ParseReadByGrpTypeRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Build Write Request. +*/ +extern uint16 ATT_BuildWriteReq( uint8* pBuf, uint8* pMsg ); + +/* + Parse Write Response. +*/ +extern bStatus_t ATT_ParseWriteRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Build Prepare Write Request. +*/ +extern uint16 ATT_BuildPrepareWriteReq( uint8* pBuf, uint8* pMsg ); + +/* + Build Prepare Write Response. +*/ +extern uint16 ATT_BuildPrepareWriteRsp( uint8* pBuf, uint8* pMsg ); + +/* + Parse Prepare Write Response. +*/ +extern bStatus_t ATT_ParsePrepareWriteRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Build Execute Write Request. +*/ +extern uint16 ATT_BuildExecuteWriteReq( uint8* pBuf, uint8* pMsg ); + +/* + Parse Execute Write Response. +*/ +extern bStatus_t ATT_ParseExecuteWriteRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Build Handle Value Indication. +*/ +extern uint16 ATT_BuildHandleValueInd( uint8* pBuf, uint8* pMsg ); + +/* + Parse Handle Value Indication. +*/ +extern bStatus_t ATT_ParseHandleValueInd( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ); + + +/* ------------------------------------------------------------------- + Attribute Server Utility APIs +*/ + +/* + Parse Exchange MTU Request. +*/ +extern bStatus_t ATT_ParseExchangeMTUReq( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Parse Find Information Request. +*/ +extern bStatus_t ATT_ParseFindInfoReq( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Parse Find By Type Value Request. +*/ +extern bStatus_t ATT_ParseFindByTypeValueReq( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Parse Read By Type Request. +*/ +extern bStatus_t ATT_ParseReadByTypeReq( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Parse Read Request. +*/ +extern bStatus_t ATT_ParseReadReq( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Parse Write Blob Request. +*/ +extern bStatus_t ATT_ParseReadBlobReq( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Parse Read Multiple Request. +*/ +extern bStatus_t ATT_ParseReadMultiReq( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Parse Write Request. +*/ +extern bStatus_t ATT_ParseWriteReq( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Parse Execute Write Request. +*/ +extern bStatus_t ATT_ParseExecuteWriteReq( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Parse Prepare Write Request. +*/ +extern bStatus_t ATT_ParsePrepareWriteReq( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ); + +/* + Parse Handle Value Confirmation. +*/ +extern bStatus_t ATT_ParseHandleValueCfm( uint8* pParams, uint16 len, attMsg_t* pMsg ); + + +/* ------------------------------------------------------------------- + Attribute Client Public APIs +*/ + +/** + @defgroup ATT_CLIENT_API ATT Client API Functions + + @{ +*/ + +/** + @brief Send Exchange MTU Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_ExchangeMTUReq( uint16 connHandle, attExchangeMTUReq_t* pReq ); + +/** + @brief Send Find Information Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_FindInfoReq( uint16 connHandle, attFindInfoReq_t* pReq ); + +/** + @brief Send Find By Type Value Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_FindByTypeValueReq( uint16 connHandle, attFindByTypeValueReq_t* pReq ); + +/** + @brief Send Read By Type Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_ReadByTypeReq( uint16 connHandle, attReadByTypeReq_t* pReq ); + +/** + @brief Send Read Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_ReadReq( uint16 connHandle, attReadReq_t* pReq ); + +/** + @brief Send Read Blob Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_ReadBlobReq( uint16 connHandle, attReadBlobReq_t* pReq ); + +/** + @brief Send Read Multiple Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_ReadMultiReq( uint16 connHandle, attReadMultiReq_t* pReq ); + +/** + @brief Send Read By Group Type Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_ReadByGrpTypeReq( uint16 connHandle, attReadByGrpTypeReq_t* pReq ); + +/** + @brief Send Write Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+ bleLinkEncrypted: Connection is already encrypted.
+*/ +extern bStatus_t ATT_WriteReq( uint16 connHandle, attWriteReq_t* pReq ); + +/** + @brief Send Prepare Write Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_PrepareWriteReq( uint16 connHandle, attPrepareWriteReq_t* pReq ); + +/** + @brief Send Execute Write Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_ExecuteWriteReq( uint16 connHandle, attExecuteWriteReq_t* pReq ); + +/** + @brief Send Handle Value Confirmation. + + @param connHandle - connection to use + + @return SUCCESS: Confirmation was sent successfully.
+ INVALIDPARAMETER: Invalid confirmation field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_HandleValueCfm( uint16 connHandle ); + +/** + @} +*/ + +/* ------------------------------------------------------------------- + Attribute Server Public APIs +*/ + +/** + @defgroup ATT_SERVER_API ATT Server API Functions + + @{ +*/ + +/** + @brief Send Error Response. + + @param connHandle - connection to use + @param pRsp - pointer to error response to be sent + + @return SUCCESS: Response was sent successfully.
+ INVALIDPARAMETER: Invalid response field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_ErrorRsp( uint16 connHandle, attErrorRsp_t* pRsp ); + +/** + @brief Send Exchange MTU Response. + + @param connHandle - connection to use + @param pRsp - pointer to request to be sent + + @return SUCCESS: Response was sent successfully.
+ INVALIDPARAMETER: Invalid response field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_ExchangeMTURsp( uint16 connHandle, attExchangeMTURsp_t* pRsp ); + +/** + @brief Send Find Information Response. + + @param connHandle - connection to use + @param pRsp - pointer to response to be sent + + @return SUCCESS: Response was sent successfully.
+ INVALIDPARAMETER: Invalid response field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_FindInfoRsp( uint16 connHandle, attFindInfoRsp_t* pRsp ); + +/** + @brief Send Find By Tyep Value Response. + + @param connHandle - connection to use + @param pRsp - pointer to response to be sent + + @return SUCCESS: Response was sent successfully.
+ INVALIDPARAMETER: Invalid response field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_FindByTypeValueRsp( uint16 connHandle, attFindByTypeValueRsp_t* pRsp ); + +/** + @brief Send Read By Type Respond. + + @param connHandle - connection to use + @param pRsp - pointer to response to be sent + + @return SUCCESS: Response was sent successfully.
+ INVALIDPARAMETER: Invalid response field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_ReadByTypeRsp( uint16 connHandle, attReadByTypeRsp_t* pRsp ); + +/** + @brief Send Read Response. + + @param connHandle - connection to use + @param pRsp - pointer to response to be sent + + @return SUCCESS: Response was sent successfully.
+ INVALIDPARAMETER: Invalid response field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_ReadRsp( uint16 connHandle, attReadRsp_t* pRsp ); + +/** + @brief Send Read Blob Response. + + @param connHandle - connection to use + @param pRsp - pointer to response to be sent + + @return SUCCESS: Response was sent successfully.
+ INVALIDPARAMETER: Invalid response field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_ReadBlobRsp( uint16 connHandle, attReadBlobRsp_t* pRsp ); + +/** + @brief Send Read Multiple Response. + + @param connHandle - connection to use + @param pRsp - pointer to response to be sent + + @return SUCCESS: Response was sent successfully.
+ INVALIDPARAMETER: Invalid response field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_ReadMultiRsp( uint16 connHandle, attReadMultiRsp_t* pRsp ) ; + +/** + @brief Send Read By Group Type Respond. + + @param connHandle - connection to use + @param pRsp - pointer to response to be sent + + @return SUCCESS: Response was sent successfully.
+ INVALIDPARAMETER: Invalid response field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_ReadByGrpTypeRsp( uint16 connHandle, attReadByGrpTypeRsp_t* pRsp ); + +/** + @brief Send Write Response. + + @param connHandle - connection to use + + @return SUCCESS: Response was sent successfully.
+ INVALIDPARAMETER: Invalid response field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_WriteRsp( uint16 connHandle ); + +/** + @brief Send Prepare Write Response. + + @param connHandle - connection to use + @param pRsp - pointer to response to be sent + + @return SUCCESS: Response was sent successfully.
+ INVALIDPARAMETER: Invalid response field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_PrepareWriteRsp( uint16 connHandle, attPrepareWriteRsp_t* pRsp ); + +/** + @brief Send Execute Write Response. + + @param connHandle - connection to use + + @return SUCCESS: Response was sent successfully.
+ INVALIDPARAMETER: Invalid response field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_ExecuteWriteRsp( uint16 connHandle ); + +/** + @brief Send Handle Value Notification. + + @param connHandle - connection to use + @param pNoti - pointer to notification to be sent + + @return SUCCESS: Notification was sent successfully.
+ INVALIDPARAMETER: Invalid notification field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_HandleValueNoti( uint16 connHandle, attHandleValueNoti_t* pNoti ); + +/** + @brief Send Handle Value Indication. + + @param connHandle - connection to use + @param pInd - pointer to indication to be sent + + @return SUCCESS: Indication was sent successfully.
+ INVALIDPARAMETER: Invalid indication field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t ATT_HandleValueInd( uint16 connHandle, attHandleValueInd_t* pInd ); + +/** + @} +*/ + +/** + @brief Set a ATT Parameter value. Use this function to change + the default ATT parameter values. + + @param value - new param value + + @return void +*/ +extern void ATT_SetParamValue( uint16 value ); + +/** + @brief Get a ATT Parameter value. + + @param none + + @return ATT Parameter value +*/ +extern uint16 ATT_GetParamValue( void ); + +extern uint16 ATT_GetCurrentMTUSize( uint16 connHandle ); +extern void ATT_UpdateMtuSize(uint16 connHandle, uint16 mtuSize); +extern void ATT_SetMTUSizeMax(uint16 mtuSize); +extern void ATT_MTU_SIZE_UPDATE(uint8 mtuSize); + +extern void ATT_InitMtuSize(void); + +//extern uint16 g_ATT_MTU_SIZE; +extern uint16 g_ATT_MTU_SIZE_MAX; +extern uint16 g_ATT_MAX_NUM_HANDLES; +extern uint16 g_ATT_MAX_NUM_HANDLES_INFO; +//extern uint16 g_ATT_MAX_NUM_HANDLE_BT_UUID; +extern attMTU_t g_attMtuClientServer; + + +// for multi-role +extern uint16 gAttMtuSize[]; + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* ATT_H */ diff --git a/src/components/ble/include/bcomdef.h b/src/components/ble/include/bcomdef.h new file mode 100644 index 0000000..e086cda --- /dev/null +++ b/src/components/ble/include/bcomdef.h @@ -0,0 +1,251 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/** + @headerfile: bcomdef.h + + +**************************************************************************************************/ + +#ifndef BCOMDEF_H +#define BCOMDEF_H + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/********************************************************************* + INCLUDES +*/ +#include "rom_sym_def.h" + +#include "comdef.h" +#include "log.h" + +//#define LOG_DEBUG(...) +//#define LOG(...) +//#define OM_LOG(...) +/********************************************************************* + CONSTANTS +*/ + +#define CTRL_CONFIG ( ADV_NCONN_CFG | ADV_CONN_CFG | SCAN_CFG | INIT_CFG ) + +//#if defined ( HOST_CONFIG ) +// // Set the Controller Configuration + +/* + // #if ( HOST_CONFIG == ( CENTRAL_CFG | PERIPHERAL_CFG ) ) + // #define CTRL_CONFIG ( ADV_NCONN_CFG | ADV_CONN_CFG | SCAN_CFG | INIT_CFG ) + // #elif ( HOST_CONFIG == ( CENTRAL_CFG | BROADCASTER_CFG ) ) + // #define CTRL_CONFIG ( ADV_NCONN_CFG | SCAN_CFG | INIT_CFG ) + // #elif ( HOST_CONFIG == ( PERIPHERAL_CFG | OBSERVER_CFG ) ) + // #define CTRL_CONFIG ( ADV_NCONN_CFG | ADV_CONN_CFG | SCAN_CFG ) + // #elif ( HOST_CONFIG == ( BROADCASTER_CFG | OBSERVER_CFG ) ) + // #define CTRL_CONFIG ( ADV_NCONN_CFG | SCAN_CFG ) + // #elif ( HOST_CONFIG == CENTRAL_CFG ) + // #define CTRL_CONFIG ( SCAN_CFG | INIT_CFG ) + // #elif ( HOST_CONFIG == PERIPHERAL_CFG ) + // #define CTRL_CONFIG ( ADV_NCONN_CFG | ADV_CONN_CFG ) + // #elif ( HOST_CONFIG == OBSERVER_CFG ) + // #define CTRL_CONFIG SCAN_CFG + // #elif ( HOST_CONFIG == BROADCASTER_CFG ) + // #define CTRL_CONFIG ADV_NCONN_CFG + // #else + // #error "Build Configuration Error: Invalid Host Role!" + // #endif + + //#else + // // Controller Sanity Check: Stop build when no configuration is defined. + // #if !defined( CTRL_CONFIG ) || !( CTRL_CONFIG & ( ADV_NCONN_CFG | \ + // ADV_CONN_CFG | \ + // SCAN_CFG | \ + // INIT_CFG ) ) + // #error "Build Configuration Error: At least one Controller build component required!" + // #endif // no Controller build components defined + //#endif +*/ + +#if !defined ( MAX_NUM_LL_CONN ) +#if ( CTRL_CONFIG & INIT_CFG ) +#define MAX_NUM_LL_CONN 8 +#elif ( !( CTRL_CONFIG & INIT_CFG ) && ( CTRL_CONFIG & ADV_CONN_CFG ) ) +#define MAX_NUM_LL_CONN 1 +#else // no connection needed +#define MAX_NUM_LL_CONN 0 +#endif // CTRL_CONFIG=INIT_CFG +#endif // !MAX_NUM_LL_CONN + +#define MAX_NUM_LL_CONN_ROM_LIMT 16 //hard code for BBB ROM define + +#if (MAX_NUM_LL_CONN_ROM_LIMT MAX_NUM_LL_CONN_ROM" +#endif + +/** @defgroup BLE_COMMON_DEFINES BLE Common Defines + @{ +*/ +//! Default Public and Random Address Length +#define B_ADDR_LEN 6 + +//! Default key length +#define KEYLEN 16 + +//! BLE Channel Map length +#define B_CHANNEL_MAP_LEN 5 + +//! BLE Event mask length +#define B_EVENT_MASK_LEN 8 + +//! BLE Local Name length +#define B_LOCAL_NAME_LEN 248 + +//! BLE Maximum Advertising Packet Length +#define B_MAX_ADV_LEN 31 + +#define B_MAX_EXT_ADV_LEN 229 +#define B_MAX_PERIOD_ADV_LEN 247 + +// 2020-01-14 AOA/AOD IQ Sample LEN +#define B_MAX_IQ_LEN 0x52 + +//! BLE Random Number Size +#define B_RANDOM_NUM_SIZE 8 + +//! BLE Feature Supported length +#define B_FEATURE_SUPPORT_LENGTH 8 + +/** @defgroup BLE_STATUS_VALUES BLE Default BLE Status Values + returned as bStatus_t + @{ +*/ +#define bleInvalidTaskID INVALID_TASK //!< Task ID isn't setup properly +#define bleNotReady 0x10 //!< Not ready to perform task +#define bleAlreadyInRequestedMode 0x11 //!< Already performing that task +#define bleIncorrectMode 0x12 //!< Not setup properly to perform that task +#define bleMemAllocError 0x13 //!< Memory allocation error occurred +#define bleNotConnected 0x14 //!< Can't perform function when not in a connection +#define bleNoResources 0x15 //!< There are no resource available +#define blePending 0x16 //!< Waiting +#define bleTimeout 0x17 //!< Timed out performing function +#define bleInvalidRange 0x18 //!< A parameter is out of range +#define bleLinkEncrypted 0x19 //!< The link is already encrypted +#define bleProcedureComplete 0x1A //!< The Procedure is completed + +// GAP Status Return Values - returned as bStatus_t +#define bleGAPUserCanceled 0x30 //!< The user canceled the task +#define bleGAPConnNotAcceptable 0x31 //!< The connection was not accepted +#define bleGAPBondRejected 0x32 //!< The bound information was rejected. + +// ATT Status Return Values - returned as bStatus_t +#define bleInvalidPDU 0x40 //!< The attribute PDU is invalid +#define bleInsufficientAuthen 0x41 //!< The attribute has insufficient authentication +#define bleInsufficientEncrypt 0x42 //!< The attribute has insufficient encryption +#define bleInsufficientKeySize 0x43 //!< The attribute has insufficient encryption key size + +// L2CAP Status Return Values - returned as bStatus_t + +#define INVALID_TASK_ID 0xFF //!< Task ID isn't setup properly +/** @} End BLE_STATUS_VALUES */ + +/** @defgroup BLE_NV_IDS BLE Non-volatile IDs + @{ +*/ +// Device NV Items - Range 0 - 0x1F +#define BLE_NVID_IRK 0x02 //!< The Device's IRK +#define BLE_NVID_CSRK 0x03 //!< The Device's CSRK +#define BLE_NVID_SIGNCOUNTER 0x04 //!< The Device's Sign Counter + +// Bonding NV Items - Range 0x20 - 0x5F - This allows for 10 bondings +#define BLE_NVID_GAP_BOND_START 0x20 //!< Start of the GAP Bond Manager's NV IDs +#define BLE_NVID_GAP_BOND_END 0x5f //!< End of the GAP Bond Manager's NV IDs Range + +// GATT Configuration NV Items - Range 0x70 - 0x79 - This must match the number of Bonding entries +#define BLE_NVID_GATT_CFG_START 0x70 //!< Start of the GATT Configuration NV IDs +#define BLE_NVID_GATT_CFG_END 0x79 //!< End of the GATT Configuration NV IDs +/** @} End BLE_NV_IDS */ + +/********************************************************************* + BLE OSAL GAP GLOBAL Events +*/ +#define GAP_EVENT_SIGN_COUNTER_CHANGED 0x4000 //!< The device level sign counter changed + + +/** @defgroup BLE_MSG_IDS BLE OSAL Message ID Events + Reserved Message ID Event Values:
+ 0xC0 - Key Presses
+ 0xE0 to 0xFC - App
+ @{ +*/ +// GAP - Messages IDs (0xD0 - 0xDF) +#define GAP_MSG_EVENT 0xD0 //!< Incoming GAP message + +// SM - Messages IDs (0xC1 - 0xCF) +#define SM_NEW_RAND_KEY_EVENT 0xC1 //!< New Rand Key Event message + +// GATT - Messages IDs (0xB0 - 0xBF) +#define GATT_MSG_EVENT 0xB0 //!< Incoming GATT message +#define GATT_SERV_MSG_EVENT 0xB1 //!< Incoming GATT Serv App message + +// L2CAP - Messages IDs (0xA0 - 0xAF) +#define L2CAP_DATA_EVENT 0xA0 //!< Incoming data on a channel +#define L2CAP_SIGNAL_EVENT 0xA2 //!< Incoming Signaling message + +// HCI - Messages IDs (0x90 - 0x9F) +#define HCI_DATA_EVENT 0x90 //!< HCI Data Event message +#define HCI_GAP_EVENT_EVENT 0x91 //!< GAP Event message +#define HCI_SMP_EVENT_EVENT 0x92 //!< SMP Event message +#define HCI_EXT_CMD_EVENT 0x93 //!< HCI Extended Command Event message +/** @} End BLE_MSG_IDS */ + +/********************************************************************* + TYPEDEFS +*/ + +//! BLE Generic Status return: @ref BLE_STATUS_VALUES +typedef Status_t bStatus_t; + +/** @} End GAP_MSG_EVENT_DEFINES */ + + +/********************************************************************* + System Events +*/ + +/********************************************************************* + Global System Messages +*/ + +/********************************************************************* + MACROS +*/ + +#define TI_BASE_UUID_128( uuid ) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, \ + 0x00, 0x40, 0x51, 0x04, LO_UINT16( uuid ), HI_UINT16( uuid ), 0x00, 0xF0 + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + FUNCTIONS +*/ + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* BCOMDEF_H */ diff --git a/src/components/ble/include/gap.h b/src/components/ble/include/gap.h new file mode 100644 index 0000000..bf038e0 --- /dev/null +++ b/src/components/ble/include/gap.h @@ -0,0 +1,1154 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/** + @headerfile: gap.h + $Date: + $Revision: + +*/ + + +#ifndef GAP_H +#define GAP_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* ------------------------------------------------------------------- + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "sm.h" + +/* ------------------------------------------------------------------- + MACROS +*/ + +/* ------------------------------------------------------------------- + CONSTANTS +*/ + +/** @defgroup BLE_GAP_DEFINES BLE GAP Constants and Structures + @{ +*/ + +/** @defgroup GAP_MSG_EVENT_DEFINES GAP Message IDs + @{ +*/ +#define GAP_DEVICE_INIT_DONE_EVENT 0x00 //!< Sent when the Device Initialization is complete. This event is sent as an OSAL message defined as gapDeviceInitDoneEvent_t. +#define GAP_DEVICE_DISCOVERY_EVENT 0x01 //!< Sent when the Device Discovery Process is complete. This event is sent as an OSAL message defined as gapDevDiscEvent_t. +#define GAP_ADV_DATA_UPDATE_DONE_EVENT 0x02 //!< Sent when the Advertising Data or SCAN_RSP Data has been updated. This event is sent as an OSAL message defined as gapAdvDataUpdateEvent_t. +#define GAP_MAKE_DISCOVERABLE_DONE_EVENT 0x03 //!< Sent when the Make Discoverable Request is complete. This event is sent as an OSAL message defined as gapMakeDiscoverableRspEvent_t. +#define GAP_END_DISCOVERABLE_DONE_EVENT 0x04 //!< Sent when the Advertising has ended. This event is sent as an OSAL message defined as gapEndDiscoverableRspEvent_t. +#define GAP_LINK_ESTABLISHED_EVENT 0x05 //!< Sent when the Establish Link Request is complete. This event is sent as an OSAL message defined as gapEstLinkReqEvent_t. +#define GAP_LINK_TERMINATED_EVENT 0x06 //!< Sent when a connection was terminated. This event is sent as an OSAL message defined as gapTerminateLinkEvent_t. +#define GAP_LINK_PARAM_UPDATE_EVENT 0x07 //!< Sent when an Update Parameters Event is received. This event is sent as an OSAL message defined as gapLinkUpdateEvent_t. +#define GAP_RANDOM_ADDR_CHANGED_EVENT 0x08 //!< Sent when a random address was changed. This event is sent as an OSAL message defined as gapRandomAddrEvent_t. +#define GAP_SIGNATURE_UPDATED_EVENT 0x09 //!< Sent when the device's signature counter is updated. This event is sent as an OSAL message defined as gapSignUpdateEvent_t. +#define GAP_AUTHENTICATION_COMPLETE_EVENT 0x0A //!< Sent when the Authentication (pairing) process is complete. This event is sent as an OSAL message defined as gapAuthCompleteEvent_t. +#define GAP_PASSKEY_NEEDED_EVENT 0x0B //!< Sent when a Passkey is needed. This is part of the pairing process. This event is sent as an OSAL message defined as gapPasskeyNeededEvent_t. +#define GAP_SLAVE_REQUESTED_SECURITY_EVENT 0x0C //!< Sent when a Slave Security Request is received. This event is sent as an OSAL message defined as gapSlaveSecurityReqEvent_t. +#define GAP_DEVICE_INFO_EVENT 0x0D //!< Sent during the Device Discovery Process when a device is discovered. This event is sent as an OSAL message defined as gapDeviceInfoEvent_t. +#define GAP_BOND_COMPLETE_EVENT 0x0E //!< Sent when the bonding(bound) process is complete. This event is sent as an OSAL message defined as gapBondCompleteEvent_t. +#define GAP_PAIRING_REQ_EVENT 0x0F //!< Sent when an unexpected Pairing Request is received. This event is sent as an OSAL message defined as gapPairingReqEvent_t. +/** @} End GAP_MSG_EVENT_DEFINES */ + +/** @defgroup GAP_CONN_HANDLE_DEFINES GAP Special Connection Handles + Used by GAP_TerminateLinkReq() + @{ +*/ +#define GAP_CONNHANDLE_INIT 0xFFFE //!< terminates a link create +#define GAP_CONNHANDLE_ALL 0xFFFF //!< terminates all links for the matching task ID. +/** @} End GAP_CONN_HANDLE_DEFINES */ + +/** @defgroup GAP_PROFILE_ROLE_DEFINES GAP Profile Roles + Bit mask values + @{ +*/ +#define GAP_PROFILE_BROADCASTER 0x01 //!< A device that sends advertising events only. +#define GAP_PROFILE_OBSERVER 0x02 //!< A device that receives advertising events only. +#define GAP_PROFILE_PERIPHERAL 0x04 //!< A device that accepts the establishment of an LE physical link using the connection establishment procedure +#define GAP_PROFILE_CENTRAL 0x08 //!< A device that supports the Central role initiates the establishment of a physical connection +/** @} End GAP_PROFILE_ROLE_DEFINES */ + +/** + @defgroup GAP_PARAMETER_ID_DEFINES GAP Parameter IDs + Used in place of gapParamIDs_t. + @{ +*/ +// Timers +#define TGAP_GEN_DISC_ADV_MIN 0 //!< Minimum time to remain advertising, when in Discoverable mode (mSec). Setting this parameter to 0 turns off the timeout (default). +#define TGAP_LIM_ADV_TIMEOUT 1 //!< Maximum time to remain advertising, when in Limited Discoverable mode. In seconds (default 180 seconds) +#define TGAP_GEN_DISC_SCAN 2 //!< Minimum time to perform scanning, when performing General Discovery proc (mSec) +#define TGAP_LIM_DISC_SCAN 3 //!< Minimum time to perform scanning, when performing Limited Discovery proc (mSec) +#define TGAP_CONN_EST_ADV_TIMEOUT 4 //!< Advertising timeout, when performing Connection Establishment proc (mSec) +#define TGAP_CONN_PARAM_TIMEOUT 5 //!< Link Layer connection parameter update notification timer, connection parameter update proc (mSec) + +// Constants +#define TGAP_LIM_DISC_ADV_INT_MIN 6 //!< Minimum advertising interval, when in limited discoverable mode (n * 0.625 mSec) +#define TGAP_LIM_DISC_ADV_INT_MAX 7 //!< Maximum advertising interval, when in limited discoverable mode (n * 0.625 mSec) +#define TGAP_GEN_DISC_ADV_INT_MIN 8 //!< Minimum advertising interval, when in General discoverable mode (n * 0.625 mSec) +#define TGAP_GEN_DISC_ADV_INT_MAX 9 //!< Maximum advertising interval, when in General discoverable mode (n * 0.625 mSec) +#define TGAP_CONN_ADV_INT_MIN 10 //!< Minimum advertising interval, when in Connectable mode (n * 0.625 mSec) +#define TGAP_CONN_ADV_INT_MAX 11 //!< Maximum advertising interval, when in Connectable mode (n * 0.625 mSec) +#define TGAP_CONN_SCAN_INT 12 //!< Scan interval used during Link Layer Initiating state, when in Connectable mode (n * 0.625 mSec) +#define TGAP_CONN_SCAN_WIND 13 //!< Scan window used during Link Layer Initiating state, when in Connectable mode (n * 0.625 mSec) +#define TGAP_CONN_HIGH_SCAN_INT 14 //!< Scan interval used during Link Layer Initiating state, when in Connectable mode, high duty scan cycle scan paramaters (n * 0.625 mSec) +#define TGAP_CONN_HIGH_SCAN_WIND 15 //!< Scan window used during Link Layer Initiating state, when in Connectable mode, high duty scan cycle scan paramaters (n * 0.625 mSec) +#define TGAP_GEN_DISC_SCAN_INT 16 //!< Scan interval used during Link Layer Scanning state, when in General Discovery proc (n * 0.625 mSec) +#define TGAP_GEN_DISC_SCAN_WIND 17 //!< Scan window used during Link Layer Scanning state, when in General Discovery proc (n * 0.625 mSec) +#define TGAP_LIM_DISC_SCAN_INT 18 //!< Scan interval used during Link Layer Scanning state, when in Limited Discovery proc (n * 0.625 mSec) +#define TGAP_LIM_DISC_SCAN_WIND 19 //!< Scan window used during Link Layer Scanning state, when in Limited Discovery proc (n * 0.625 mSec) +#define TGAP_CONN_EST_ADV 20 //!< Advertising interval, when using Connection Establishment proc (n * 0.625 mSec). Obsolete - Do not use. +#define TGAP_CONN_EST_INT_MIN 21 //!< Minimum Link Layer connection interval, when using Connection Establishment proc (n * 1.25 mSec) +#define TGAP_CONN_EST_INT_MAX 22 //!< Maximum Link Layer connection interval, when using Connection Establishment proc (n * 1.25 mSec) +#define TGAP_CONN_EST_SCAN_INT 23 //!< Scan interval used during Link Layer Initiating state, when using Connection Establishment proc (n * 0.625 mSec) +#define TGAP_CONN_EST_SCAN_WIND 24 //!< Scan window used during Link Layer Initiating state, when using Connection Establishment proc (n * 0.625 mSec) +#define TGAP_CONN_EST_SUPERV_TIMEOUT 25 //!< Link Layer connection supervision timeout, when using Connection Establishment proc (n * 10 mSec) +#define TGAP_CONN_EST_LATENCY 26 //!< Link Layer connection slave latency, when using Connection Establishment proc (in number of connection events) +#define TGAP_CONN_EST_MIN_CE_LEN 27 //!< Local informational parameter about min len of connection needed, when using Connection Establishment proc (n * 0.625 mSec) +#define TGAP_CONN_EST_MAX_CE_LEN 28 //!< Local informational parameter about max len of connection needed, when using Connection Establishment proc (n * 0.625 mSec) +#define TGAP_PRIVATE_ADDR_INT 29 //!< Minimum Time Interval between private (resolvable) address changes. In minutes (default 15 minutes) +#define TGAP_CONN_PAUSE_CENTRAL 30 //!< Central idle timer. In seconds (default 1 second) +#define TGAP_CONN_PAUSE_PERIPHERAL 31 //!< Minimum time upon connection establishment before the peripheral starts a connection update procedure. In seconds (default 5 seconds) + +// Proprietary +#define TGAP_SM_TIMEOUT 32 //!< SM Message Timeout (milliseconds). Default 30 seconds. +#define TGAP_SM_MIN_KEY_LEN 33 //!< SM Minimum Key Length supported. Default 7. +#define TGAP_SM_MAX_KEY_LEN 34 //!< SM Maximum Key Length supported. Default 16. +#define TGAP_FILTER_ADV_REPORTS 35 //!< Filter duplicate advertising reports. Default TRUE. +#define TGAP_SCAN_RSP_RSSI_MIN 36 //!< Minimum RSSI required for scan responses to be reported to the app. Default -127. +#define TGAP_REJECT_CONN_PARAMS 37 //!< Whether or not to reject Connection Parameter Update Request received on Central device. Default FALSE. + +#if !defined ( TESTMODES ) +#define TGAP_AUTH_TASK_ID 38 //!< Task ID override for Task Authentication control (for stack internal use only) +#define TGAP_PARAMID_MAX 39 //!< ID MAX-valid Parameter ID +#else +#define TGAP_GAP_TESTCODE 38 //!< GAP TestCodes - puts GAP into a test mode +#define TGAP_SM_TESTCODE 39 //!< SM TestCodes - puts SM into a test mode +#define TGAP_AUTH_TASK_ID 40 //!< Task ID override for Task Authentication control (for stack internal use only) +#define TGAP_PARAMID_MAX 41 //!< ID MAX-valid Parameter ID + +#define TGAP_GATT_TESTCODE 100 //!< GATT TestCodes - puts GATT into a test mode (paramValue maintained by GATT) +#define TGAP_ATT_TESTCODE 101 //!< ATT TestCodes - puts ATT into a test mode (paramValue maintained by ATT) +#define TGAP_GGS_TESTCODE 102 //!< GGS TestCodes - puts GGS into a test mode (paramValue maintained by GGS) +#endif + +/** @} End GAP_PARAMETER_ID_DEFINES */ + +/** @defgroup GAP_DEVDISC_MODE_DEFINES GAP Device Discovery Modes + @{ +*/ +#define DEVDISC_MODE_NONDISCOVERABLE 0x00 //!< No discoverable setting +#define DEVDISC_MODE_GENERAL 0x01 //!< General Discoverable devices +#define DEVDISC_MODE_LIMITED 0x02 //!< Limited Discoverable devices +#define DEVDISC_MODE_ALL 0x03 //!< Not filtered +/** @} End GAP_DEVDISC_MODE_DEFINES */ + +/** @defgroup GAP_ADDR_TYPE_DEFINES GAP Address Types + @{ +*/ +#define ADDRTYPE_PUBLIC 0x00 //!< Use the BD_ADDR +#define ADDRTYPE_STATIC 0x01 //!< Static address +#define ADDRTYPE_PRIVATE_NONRESOLVE 0x02 //!< Generate Non-Resolvable Private Address +#define ADDRTYPE_PRIVATE_RESOLVE 0x03 //!< Generate Resolvable Private Address +/** @} End GAP_ADDR_TYPE_DEFINES */ + +/** @defgroup GAP_ADVERTISEMENT_TYPE_DEFINES GAP Advertising Event Types + for eventType field in gapAdvertisingParams_t + @{ +*/ +#define GAP_ADTYPE_ADV_IND 0x00 //!< Connectable undirected advertisement +#define GAP_ADTYPE_ADV_HDC_DIRECT_IND 0x01 //!< Connectable high duty cycle directed advertisement +#define GAP_ADTYPE_ADV_SCAN_IND 0x02 //!< Scannable undirected advertisement +#define GAP_ADTYPE_ADV_NONCONN_IND 0x03 //!< Non-Connectable undirected advertisement +#define GAP_ADTYPE_ADV_LDC_DIRECT_IND 0x04 //!< Connectable low duty cycle directed advertisement +/** @} End GAP_ADVERTISEMENT_TYPE_DEFINES */ + +/** @defgroup GAP_ADVERTISEMENT_REPORT_TYPE_DEFINES GAP Advertising Report Event Types + for eventType field in gapDevRec_t and gapDeviceInfoEvent_t + @{ +*/ +#define GAP_ADRPT_ADV_IND 0x00 //!< Connectable undirected advertisement +#define GAP_ADRPT_ADV_DIRECT_IND 0x01 //!< Connectable directed advertisement +#define GAP_ADRPT_ADV_SCAN_IND 0x02 //!< Scannable undirected advertisement +#define GAP_ADRPT_ADV_NONCONN_IND 0x03 //!< Non-Connectable undirected advertisement +#define GAP_ADRPT_SCAN_RSP 0x04 //!< Scan Response +/** @} End GAP_ADVERTISEMENT_REPORT_TYPE_DEFINES */ + +/** @defgroup GAP_FILTER_POLICY_DEFINES GAP Advertiser Filter Scan Parameters + @{ +*/ +#define GAP_FILTER_POLICY_ALL 0x00 //!< Allow Scan Request from Any, Allow Connect Request from Any (default). +#define GAP_FILTER_POLICY_WHITE_SCAN 0x01 //!< Allow Scan Request from White List Only, Allow Connect from Any +#define GAP_FILTER_POLICY_WHITE_CON 0x02 //!< Allow Scan Request from Any, Connect from White List Only +#define GAP_FILTER_POLICY_WHITE 0x03 //!< Allow Scan Request and Connect from White List Only +/** @} End GAP_FILTER_POLICY_DEFINES */ + +//! Advertiser Channel Map +#define ADV_CHANMAP_SIZE 5 + +//! Maximum Pairing Passcode/Passkey value. Range of a passkey can be 0 - 999,999. +#define GAP_PASSCODE_MAX 999999 + +/** Sign Counter Initialized - Sign counter hasn't been used yet. Used when setting up + a connection's signing information. +*/ +#define GAP_INIT_SIGN_COUNTER 0xFFFFFFFF + +/** @defgroup GAP_ADVCHAN_DEFINES GAP Advertisement Channel Map + @{ +*/ +#define GAP_ADVCHAN_37 0x01 //!< Advertisement Channel 37 +#define GAP_ADVCHAN_38 0x02 //!< Advertisement Channel 38 +#define GAP_ADVCHAN_39 0x04 //!< Advertisement Channel 39 +#define GAP_ADVCHAN_ALL (GAP_ADVCHAN_37 | GAP_ADVCHAN_38 | GAP_ADVCHAN_39) //!< All Advertisement Channels Enabled +/** @} End GAP_ADVCHAN_DEFINES */ + +/** @defgroup GAP_WHITELIST_DEFINES GAP White List Options + @{ +*/ +#define WL_NOTUSED 0x00 //!< White list not used but the advertiser's address in this command is used +#define WL_USED 0x01 //!< White list is used and the advertiser's address in this command is not used. +/** @} End GAP_WHITELIST_DEFINES */ + +/** @defgroup GAP_ADTYPE_DEFINES GAP Advertisment Data Types + These are the data type identifiers for the data tokens in the advertisement data field. + @{ +*/ +#define GAP_ADTYPE_FLAGS 0x01 //!< Discovery Mode: @ref GAP_ADTYPE_FLAGS_MODES +#define GAP_ADTYPE_16BIT_MORE 0x02 //!< Service: More 16-bit UUIDs available +#define GAP_ADTYPE_16BIT_COMPLETE 0x03 //!< Service: Complete list of 16-bit UUIDs +#define GAP_ADTYPE_32BIT_MORE 0x04 //!< Service: More 32-bit UUIDs available +#define GAP_ADTYPE_32BIT_COMPLETE 0x05 //!< Service: Complete list of 32-bit UUIDs +#define GAP_ADTYPE_128BIT_MORE 0x06 //!< Service: More 128-bit UUIDs available +#define GAP_ADTYPE_128BIT_COMPLETE 0x07 //!< Service: Complete list of 128-bit UUIDs +#define GAP_ADTYPE_LOCAL_NAME_SHORT 0x08 //!< Shortened local name +#define GAP_ADTYPE_LOCAL_NAME_COMPLETE 0x09 //!< Complete local name +#define GAP_ADTYPE_POWER_LEVEL 0x0A //!< TX Power Level: 0xXX: -127 to +127 dBm +#define GAP_ADTYPE_OOB_CLASS_OF_DEVICE 0x0D //!< Simple Pairing OOB Tag: Class of device (3 octets) +#define GAP_ADTYPE_OOB_SIMPLE_PAIRING_HASHC 0x0E //!< Simple Pairing OOB Tag: Simple Pairing Hash C (16 octets) +#define GAP_ADTYPE_OOB_SIMPLE_PAIRING_RANDR 0x0F //!< Simple Pairing OOB Tag: Simple Pairing Randomizer R (16 octets) +#define GAP_ADTYPE_SM_TK 0x10 //!< Security Manager TK Value +#define GAP_ADTYPE_SM_OOB_FLAG 0x11 //!< Secutiry Manager OOB Flags +#define GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE 0x12 //!< Min and Max values of the connection interval (2 octets Min, 2 octets Max) (0xFFFF indicates no conn interval min or max) +#define GAP_ADTYPE_SIGNED_DATA 0x13 //!< Signed Data field +#define GAP_ADTYPE_SERVICES_LIST_16BIT 0x14 //!< Service Solicitation: list of 16-bit Service UUIDs +#define GAP_ADTYPE_SERVICES_LIST_128BIT 0x15 //!< Service Solicitation: list of 128-bit Service UUIDs +#define GAP_ADTYPE_SERVICE_DATA 0x16 //!< Service Data +#define GAP_ADTYPE_APPEARANCE 0x19 //!< Appearance +#define GAP_ADTYPE_MANUFACTURER_SPECIFIC 0xFF //!< Manufacturer Specific Data: first 2 octets contain the Company Identifier Code followed by the additional manufacturer specific data +/** @} End GAP_ADTYPE_DEFINES */ + +/** @defgroup GAP_ADTYPE_FLAGS_MODES GAP ADTYPE Flags Discovery Modes + @{ +*/ +#define GAP_ADTYPE_FLAGS_LIMITED 0x01 //!< Discovery Mode: LE Limited Discoverable Mode +#define GAP_ADTYPE_FLAGS_GENERAL 0x02 //!< Discovery Mode: LE General Discoverable Mode +#define GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED 0x04 //!< Discovery Mode: BR/EDR Not Supported +/** @} End GAP_ADTYPE_FLAGS_MODES */ + +/** @defgroup GAP_APPEARANCE_VALUES GAP Appearance Values + @{ +*/ +#define GAP_APPEARE_UNKNOWN 0x0000 //!< Unknown +#define GAP_APPEARE_GENERIC_PHONE 0x0040 //!< Generic Phone +#define GAP_APPEARE_GENERIC_COMPUTER 0x0080 //!< Generic Computer +#define GAP_APPEARE_GENERIC_WATCH 0x00C0 //!< Generic Watch +#define GAP_APPEARE_WATCH_SPORTS 0x00C1 //!< Watch: Sports Watch +#define GAP_APPEARE_GENERIC_CLOCK 0x0100 //!< Generic Clock +#define GAP_APPEARE_GENERIC_DISPLAY 0x0140 //!< Generic Display +#define GAP_APPEARE_GENERIC_RC 0x0180 //!< Generic Remote Control +#define GAP_APPEARE_GENERIC_EYE_GALSSES 0x01C0 //!< Generic Eye-glasses +#define GAP_APPEARE_GENERIC_TAG 0x0200 //!< Generic Tag +#define GAP_APPEARE_GENERIC_KEYRING 0x0240 //!< Generic Keyring +#define GAP_APPEARE_GENERIC_MEDIA_PLAYER 0x0280 //!< Generic Media Player +#define GAP_APPEARE_GENERIC_BARCODE_SCANNER 0x02C0 //!< Generic Barcode Scanner +#define GAP_APPEARE_GENERIC_THERMOMETER 0x0300 //!< Generic Thermometer +#define GAP_APPEARE_GENERIC_THERMO_EAR 0x0301 //!< Thermometer: Ear +#define GAP_APPEARE_GENERIC_HR_SENSOR 0x0340 //!< Generic Heart rate Sensor +#define GAP_APPEARE_GENERIC_HRS_BELT 0x0341 //!< Heart Rate Sensor: Heart Rate Belt +#define GAP_APPEARE_GENERIC_BLOOD_PRESSURE 0x0380 //!< Generic Blood Pressure +#define GAP_APPEARE_GENERIC_BP_ARM 0x0381 //!< Blood Pressure: Arm +#define GAP_APPEARE_GENERIC_BP_WRIST 0x0382 //!< Blood Pressure: Wrist +#define GAP_APPEARE_GENERIC_HID 0x03C0 //!< Generic Human Interface Device (HID) +#define GAP_APPEARE_HID_KEYBOARD 0x03C1 //!< HID Keyboard +#define GAP_APPEARE_HID_MOUSE 0x03C2 //!< HID Mouse +#define GAP_APPEARE_HID_JOYSTIC 0x03C3 //!< HID Joystick +#define GAP_APPEARE_HID_GAMEPAD 0x03C4 //!< HID Gamepad +#define GAP_APPEARE_HID_DIGITIZER_TYABLET 0x03C5 //!< HID Digitizer Tablet +#define GAP_APPEARE_HID_DIGITAL_CARDREADER 0x03C6 //!< HID Card Reader +#define GAP_APPEARE_HID_DIGITAL_PEN 0x03C7 //!< HID Digital Pen +#define GAP_APPEARE_HID_BARCODE_SCANNER 0x03C8 //!< HID Barcode Scanner +/** @} End GAP_APPEARANCE_VALUES */ + +/* ------------------------------------------------------------------- + TYPEDEFS - Initialization and Configuration +*/ + +/** + GAP Parameters IDs: @ref GAP_PARAMETER_ID_DEFINES +*/ +typedef uint16 gapParamIDs_t; + +/** + GAP event header format. +*/ +typedef struct +{ + osal_event_hdr_t hdr; //!< GAP_MSG_EVENT and status + uint8 opcode; //!< GAP type of command. Ref: @ref GAP_MSG_EVENT_DEFINES +} gapEventHdr_t; + +/** + GAP_RANDOM_ADDR_CHANGED_EVENT message format. This message is sent to the + app when the random address changes. +*/ +typedef struct +{ + osal_event_hdr_t hdr; //!< GAP_MSG_EVENT and status + uint8 opcode; //!< GAP_RANDOM_ADDR_CHANGED_EVENT + uint8 addrType; //!< Address type: @ref GAP_ADDR_TYPE_DEFINES + uint8 newRandomAddr[B_ADDR_LEN]; //!< the new calculated private addr +} gapRandomAddrEvent_t; + +/** + Connection parameters for the peripheral device. These numbers are used + to compare against connection events and request connection parameter + updates with the master. +*/ +typedef struct +{ + /** Minimum value for the connection event (interval. 0x0006 - 0x0C80 * 1.25 ms) */ + uint16 intervalMin; + /** Maximum value for the connection event (interval. 0x0006 - 0x0C80 * 1.25 ms) */ + uint16 intervalMax; + /** Number of LL latency connection events (0x0000 - 0x03e8) */ + uint16 latency; + /** Connection Timeout (0x000A - 0x0C80 * 10 ms) */ + uint16 timeout; +} gapPeriConnectParams_t; + +/** + GAP_DEVICE_INIT_DONE_EVENT message format. This message is sent to the + app when the Device Initialization is done [initiated by calling + GAP_DeviceInit()]. +*/ +typedef struct +{ + osal_event_hdr_t hdr; //!< GAP_MSG_EVENT and status + uint8 opcode; //!< GAP_DEVICE_INIT_DONE_EVENT + uint8 devAddr[B_ADDR_LEN]; //!< Device's BD_ADDR + uint16 dataPktLen; //!< HC_LE_Data_Packet_Length + uint8 numDataPkts; //!< HC_Total_Num_LE_Data_Packets +} gapDeviceInitDoneEvent_t; + +/** + GAP_SIGNATURE_UPDATED_EVENT message format. This message is sent to the + app when the signature counter has changed. This message is to inform the + application in case it wants to save it to be restored on reboot or reconnect. + This message is sent to update a connection's signature counter and to update + this device's signature counter. If devAddr == BD_ADDR, then this message pertains + to this device. +*/ +typedef struct +{ + osal_event_hdr_t hdr; //!< GAP_MSG_EVENT and status + uint8 opcode; //!< GAP_SIGNATURE_UPDATED_EVENT + uint8 addrType; //!< Device's address type for devAddr + uint8 devAddr[B_ADDR_LEN]; //!< Device's BD_ADDR, could be own address + uint32 signCounter; //!< new Signed Counter +} gapSignUpdateEvent_t; + +/** + GAP_DEVICE_INFO_EVENT message format. This message is sent to the + app during a Device Discovery Request, when a new advertisement or scan + response is received. +*/ +typedef struct +{ + osal_event_hdr_t hdr; //!< GAP_MSG_EVENT and status + uint8 opcode; //!< GAP_DEVICE_INFO_EVENT + uint8 eventType; //!< Advertisement Type: @ref GAP_ADVERTISEMENT_REPORT_TYPE_DEFINES + uint8 addrType; //!< address type: @ref GAP_ADDR_TYPE_DEFINES + uint8 addr[B_ADDR_LEN]; //!< Address of the advertisement or SCAN_RSP + int8 rssi; //!< Advertisement or SCAN_RSP RSSI + uint8 dataLen; //!< Length (in bytes) of the data field (evtData) + uint8* pEvtData; //!< Data field of advertisement or SCAN_RSP +} gapDeviceInfoEvent_t; + +/* ------------------------------------------------------------------- + TYPEDEFS - Device Discovery +*/ + +/** + Type of device discovery (Scan) to perform. +*/ +typedef struct +{ + uint8 taskID; //!< Requesting App's Task ID, used to return results + uint8 mode; //!< Discovery Mode: @ref GAP_DEVDISC_MODE_DEFINES + uint8 activeScan; //!< TRUE for active scanning + uint8 whiteList; //!< TRUE to only allow advertisements from devices in the white list. +} gapDevDiscReq_t; + +/** + Type of device discovery (Scan) to perform. +*/ +typedef struct +{ + uint8 eventType; //!< Indicates advertising event type used by the advertiser: @ref GAP_ADVERTISEMENT_REPORT_TYPE_DEFINES + uint8 addrType; //!< Address Type: @ref GAP_ADDR_TYPE_DEFINES + uint8 addr[B_ADDR_LEN]; //!< Device's Address +} gapDevRec_t; + +/** + GAP_DEVICE_DISCOVERY_EVENT message format. This message is sent to the + Application after a scan is performed. +*/ +typedef struct +{ + osal_event_hdr_t hdr; //!< GAP_MSG_EVENT and status + uint8 opcode; //!< GAP_DEVICE_DISCOVERY_EVENT + uint8 numDevs; //!< Number of devices found during scan + gapDevRec_t* pDevList; //!< array of device records +} gapDevDiscEvent_t; + +/** + Advertising Parameters +*/ +typedef struct +{ + uint8 eventType; //!< Advertise Event Type: @ref GAP_ADVERTISEMENT_TYPE_DEFINES + uint8 initiatorAddrType; //!< Initiator's address type: @ref GAP_ADDR_TYPE_DEFINES + uint8 initiatorAddr[B_ADDR_LEN]; //!< Initiator's addr - used only with connectable directed eventType (ADV_EVTTYPE_CONNECTABLE_DIRECTED). + uint8 channelMap; //!< Channel Map: Bit mask @ref GAP_ADVCHAN_DEFINES + uint8 filterPolicy; //!< Filer Policy: @ref GAP_FILTER_POLICY_DEFINES. Ignored when directed advertising is used. +} gapAdvertisingParams_t; + +/** + GAP_MAKE_DISCOVERABLE_DONE_EVENT message format. This message is sent to the + app when the Advertise config is complete. +*/ +typedef struct +{ + osal_event_hdr_t hdr; //!< GAP_MSG_EVENT and status + uint8 opcode; //!< GAP_MAKE_DISCOVERABLE_DONE_EVENT + uint16 interval; //!< actual advertising interval selected by controller +} gapMakeDiscoverableRspEvent_t; + +/** + GAP_END_DISCOVERABLE_DONE_EVENT message format. This message is sent to the + app when the Advertising has stopped. +*/ +typedef struct +{ + osal_event_hdr_t hdr; //!< GAP_MSG_EVENT and status + uint8 opcode; //!< GAP_END_DISCOVERABLE_DONE_EVENT +} gapEndDiscoverableRspEvent_t; + +/** + GAP_ADV_DATA_UPDATE_DONE_EVENT message format. This message is sent to the + app when Advertising Data Update is complete. +*/ +typedef struct +{ + osal_event_hdr_t hdr; //!< GAP_MSG_EVENT and status + uint8 opcode; //!< GAP_ADV_DATA_UPDATE_DONE_EVENT + uint8 adType; //!< TRUE if advertising data, FALSE if SCAN_RSP +} gapAdvDataUpdateEvent_t; + +/* ------------------------------------------------------------------- + TYPEDEFS - Link Establishment +*/ + +/** + Establish Link Request parameters +*/ +typedef struct +{ + uint8 taskID; //!< Requesting App/Profile's Task ID + uint8 highDutyCycle; //!< TRUE to high duty cycle scan, FALSE if not. + uint8 whiteList; //!< Determines use of the white list: @ref GAP_WHITELIST_DEFINES + uint8 addrTypePeer; //!< Address type of the advertiser: @ref GAP_ADDR_TYPE_DEFINES + uint8 peerAddr[B_ADDR_LEN]; //!< Advertiser's address +} gapEstLinkReq_t; + +/** + Update Link Parameters Request parameters +*/ +typedef struct +{ + uint16 connectionHandle; //!< Connection handle of the update + uint16 intervalMin; //!< Minimum Connection Interval + uint16 intervalMax; //!< Maximum Connection Interval + uint16 connLatency; //!< Connection Latency + uint16 connTimeout; //!< Connection Timeout +} gapUpdateLinkParamReq_t; + +/** + GAP_LINK_ESTABLISHED_EVENT message format. This message is sent to the app + when the link request is complete.
+
+ For an Observer, this message is sent to complete the Establish Link Request.
+ For a Peripheral, this message is sent to indicate that a link has been created. +*/ +typedef struct +{ + osal_event_hdr_t hdr; //!< GAP_MSG_EVENT and status + uint8 opcode; //!< GAP_LINK_ESTABLISHED_EVENT + uint8 devAddrType; //!< Device address type: @ref GAP_ADDR_TYPE_DEFINES + uint8 devAddr[B_ADDR_LEN]; //!< Device address of link + uint16 connectionHandle; //!< Connection Handle from controller used to ref the device + uint16 connInterval; //!< Connection Interval + uint16 connLatency; //!< Conenction Latency + uint16 connTimeout; //!< Connection Timeout + uint8 clockAccuracy; //!< Clock Accuracy +} gapEstLinkReqEvent_t; + +/** + GAP_LINK_PARAM_UPDATE_EVENT message format. This message is sent to the app + when the connection parameters update request is complete. +*/ +typedef struct +{ + osal_event_hdr_t hdr; //!< GAP_MSG_EVENT and status + uint8 opcode; //!< GAP_LINK_PARAM_UPDATE_EVENT + uint8 status; //!< bStatus_t + uint16 connectionHandle; //!< Connection handle of the update + uint16 connInterval; //!< Requested connection interval + uint16 connLatency; //!< Requested connection latency + uint16 connTimeout; //!< Requested connection timeout +} gapLinkUpdateEvent_t; + +/** + GAP_LINK_TERMINATED_EVENT message format. This message is sent to the + app when a link to a device is terminated. +*/ +typedef struct +{ + osal_event_hdr_t hdr; //!< GAP_MSG_EVENT and status + uint8 opcode; //!< GAP_LINK_TERMINATED_EVENT + uint16 connectionHandle; //!< connection Handle + uint8 reason; //!< termination reason from LL +} gapTerminateLinkEvent_t; + +/* ------------------------------------------------------------------- + TYPEDEFS - Authentication, Bounding and Pairing +*/ + +/** + GAP_PASSKEY_NEEDED_EVENT message format. This message is sent to the + app when a Passkey is needed from the app's user interface. +*/ +typedef struct +{ + osal_event_hdr_t hdr; //!< GAP_MSG_EVENT and status + uint8 opcode; //!< GAP_PASSKEY_NEEDED_EVENT + uint8 deviceAddr[B_ADDR_LEN]; //!< address of device to pair with, and could be either public or random. + uint16 connectionHandle; //!< Connection handle + uint8 uiInputs; //!< Pairing User Interface Inputs - Ask user to input passcode + uint8 uiOutputs; //!< Pairing User Interface Outputs - Display passcode +} gapPasskeyNeededEvent_t; + +/** + GAP_AUTHENTICATION_COMPLETE_EVENT message format. This message is sent to the app + when the authentication request is complete. +*/ +typedef struct +{ + osal_event_hdr_t hdr; //!< GAP_MSG_EVENT and status + uint8 opcode; //!< GAP_AUTHENTICATION_COMPLETE_EVENT + uint16 connectionHandle; //!< Connection Handle from controller used to ref the device + uint8 authState; //!< TRUE if the pairing was authenticated (MITM) + smSecurityInfo_t* pSecurityInfo; //!< BOUND - security information from this device + smSigningInfo_t* pSigningInfo; //!< Signing information + smSecurityInfo_t* pDevSecInfo; //!< BOUND - security information from connected device + smIdentityInfo_t* pIdentityInfo; //!< BOUND - identity information +} gapAuthCompleteEvent_t; + +/** + securityInfo and identityInfo are only used if secReqs.bondable == BOUND, which means that + the device is already bound and we should use the security information and keys. +*/ +typedef struct +{ + uint16 connectionHandle; //!< Connection Handle from controller, + smLinkSecurityReq_t secReqs; //!< Pairing Control info +} gapAuthParams_t; + +/** + GAP_SLAVE_REQUESTED_SECURITY_EVENT message format. This message is sent to the app + when a Slave Security Request is received. +*/ +typedef struct +{ + osal_event_hdr_t hdr; //!< GAP_MSG_EVENT and status + uint8 opcode; //!< GAP_SLAVE_REQUESTED_SECURITY_EVENT + uint16 connectionHandle; //!< Connection Handle + uint8 deviceAddr[B_ADDR_LEN]; //!< address of device requesting security + uint8 authReq; //!< Authentication Requirements: Bit 2: MITM, Bits 0-1: bonding (0 - no bonding, 1 - bonding) + +} gapSlaveSecurityReqEvent_t; + +/** + GAP_BOND_COMPLETE_EVENT message format. This message is sent to the + app when a bonding is complete. This means that a key is loaded and the link is encrypted. +*/ +typedef struct +{ + osal_event_hdr_t hdr; //!< GAP_MSG_EVENT and status + uint8 opcode; //!< GAP_BOND_COMPLETE_EVENT + uint16 connectionHandle; //!< connection Handle +} gapBondCompleteEvent_t; + +/** + Pairing Request fields - the parsed fields of the SMP Pairing Request command. +*/ +typedef struct +{ + uint8 ioCap; //!< Pairing Request ioCap field + uint8 oobDataFlag; //!< Pairing Request OOB Data Flag field + uint8 authReq; //!< Pairing Request Auth Req field + uint8 maxEncKeySize; //!< Pairing Request Maximum Encryption Key Size field + keyDist_t keyDist; //!< Pairing Request Key Distribution field +} gapPairingReq_t; + +/** + GAP_PAIRING_REQ_EVENT message format.
+
+ This message is sent to the + app when an unexpected Pairing Request is received. The application is + expected to setup for a Security Manager pairing/bonding.
+
+ To setup an SM Pairing, the application should call GAP_Authenticate() with these "pairReq" fields.
+
+ NOTE: This message should only be sent to peripheral devices. +*/ +typedef struct +{ + osal_event_hdr_t hdr; //!< GAP_MSG_EVENT and status + uint8 opcode; //!< GAP_PAIRING_REQ_EVENT + uint16 connectionHandle; //!< connection Handle + gapPairingReq_t pairReq; //!< The Pairing Request fields received. +} gapPairingReqEvent_t; + +/** + GAP Advertisement/Scan Response Data Token - These data items are stored as low byte first (OTA + format). The data space for these items are passed in and maintained by + the calling application +*/ +typedef struct +{ + uint8 adType; //!< ADTYPE value: @ref GAP_ADTYPE_DEFINES + uint8 attrLen; //!< Number of bytes in the attribute data + uint8* pAttrData; //!< pointer to Attribute data +} gapAdvDataToken_t; + +/** @} End BLE_GAP_DEFINES */ + +/* ------------------------------------------------------------------- + GLOBAL VARIABLES +*/ + +/** + @defgroup GAP_API GAP API Functions + + @{ +*/ + +/* ------------------------------------------------------------------- + FUNCTIONS - Initialization and Configuation +*/ + +/** + @brief Called to setup the device. Call just once on initialization. + + NOTE: When initialization is complete, the calling app will be + sent the GAP_DEVICE_INIT_DONE_EVENT + + @param taskID - Default task ID to send events. + @param profileRole - GAP Profile Roles: @ref GAP_PROFILE_ROLE_DEFINES + @param maxScanResponses - maximum number to scan responses + we can receive during a device discovery. + @param pIRK - pointer to Identity Root Key, NULLKEY (all zeroes) if the app + wants the GAP to generate the key. + @param pSRK - pointer to Sign Resolving Key, NULLKEY if the app + wants the GAP to generate the key. + @param pSignCounter - 32 bit value used in the SM Signing + algorithm that shall be initialized to zero and incremented + with every new signing. This variable must also be maintained + by the application. + + @return SUCCESS - Processing, expect GAP_DEVICE_INIT_DONE_EVENT,
+ INVALIDPARAMETER - for invalid profile role or role combination,
+ bleIncorrectMode - trouble communicating with HCI +*/ +extern bStatus_t GAP_DeviceInit( uint8 taskID, + uint8 profileRole, + uint8 maxScanResponses, + uint8* pIRK, + uint8* pSRK, + uint32* pSignCounter ); + +/** + @brief Called to setup a GAP Advertisement/Scan Response data token. + + NOTE: The data in these items are stored as low byte first (OTA format). + The passed in structure "token" should be allocated by the calling app/profile + and not released until after calling GAP_RemoveAdvToken(). + + @param pToken - Advertisement/Scan response token to write. + + @return SUCCESS - advertisement token added to the GAP list
+ INVALIDPARAMETER - Invalid Advertisement Type or pAttrData is NULL
+ INVALID_MEM_SIZE - The tokens take up too much space and don't fit into Advertisment data and Scan Response Data
+ bleInvalidRange - token ID already exists.
+ bleIncorrectMode - not a peripheral device
+ bleMemAllocError - memory allocation failure, +*/ +extern bStatus_t GAP_SetAdvToken( gapAdvDataToken_t* pToken ); + +/** + @brief Called to read a GAP Advertisement/Scan Response data token. + + @param adType - Advertisement type to get + + @return pointer to the advertisement data token structure, NULL if not found. +*/ +extern gapAdvDataToken_t* GAP_GetAdvToken( uint8 adType ); + +/** + @brief Called to remove a GAP Advertisement/Scan Response data token. + + @param adType - Advertisement type to remove + + @return pointer to the token structure removed from the GAP ADType list + NULL if the requested adType wasn't found. +*/ +extern gapAdvDataToken_t* GAP_RemoveAdvToken( uint8 adType ); + +/** + @brief Called to rebuild and load Advertisement and Scan Response data from existing + GAP Advertisement Tokens. + + @return SUCCESS or bleIncorrectMode +*/ +extern bStatus_t GAP_UpdateAdvTokens( void ); + +/** + @brief Set a GAP Parameter value. Use this function to change + the default GAP parameter values. + + @param paramID - parameter ID: @ref GAP_PARAMETER_ID_DEFINES + @param paramValue - new param value + + @return SUCCESS or INVALIDPARAMETER (invalid paramID) +*/ +extern bStatus_t GAP_SetParamValue( gapParamIDs_t paramID, uint16 paramValue ); + +/** + @brief Get a GAP Parameter value. + + @param paramID - parameter ID: @ref GAP_PARAMETER_ID_DEFINES + + @return GAP Parameter value or 0xFFFF if invalid +*/ +extern uint16 GAP_GetParamValue( gapParamIDs_t paramID ); + +/** + @brief Setup the device's address type. If ADDRTYPE_PRIVATE_RESOLVE + is selected, the address will change periodically. + + @param addrType - @ref GAP_ADDR_TYPE_DEFINES + @param pStaticAddr - Only used with ADDRTYPE_STATIC + or ADDRTYPE_PRIVATE_NONRESOLVE type.
+ NULL to auto generate otherwise the application + can specify the address value + + @return SUCCESS: address type updated,
+ bleNotReady: Can't be called until GAP_DeviceInit() is called + and the init process is completed,
+ bleIncorrectMode: can't change with an active connection,
+ or INVALIDPARAMETER.
+ + If return value isn't SUCCESS, the address type remains + the same as before this call. +*/ +extern bStatus_t GAP_ConfigDeviceAddr( uint8 addrType, uint8* pStaticAddr ); + +/** + @brief Register your task ID to receive extra (unwanted) + HCI status and complete events. + + @param taskID - Default task ID to send events. + + @return none +*/ +extern void GAP_RegisterForHCIMsgs( uint8 taskID ); + +/* ------------------------------------------------------------------- + FUNCTIONS - Device Discovery +*/ + +/** + @brief Start a device discovery scan. + + @param pParams - Device Discovery parameters + + @return SUCCESS: scan started,
+ bleIncorrectMode: invalid profile role,
+ bleAlreadyInRequestedMode: not available
+*/ +extern bStatus_t GAP_DeviceDiscoveryRequest( gapDevDiscReq_t* pParams ); + +/** + @brief Cancel an existing device discovery request. + + @param taskID - used to return GAP_DEVICE_DISCOVERY_EVENT + + @return SUCCESS: cancel started,
+ bleInvalidTaskID: Not the task that started discovery,
+ bleIncorrectMode: not in discovery mode
+*/ +extern bStatus_t GAP_DeviceDiscoveryCancel( uint8 taskID ); + +/** + @brief Setup or change advertising. Also starts advertising. + + @param taskID - used to return GAP_DISCOVERABLE_RESPONSE_EVENT + @param pParams - advertising parameters + + @return SUCCESS: advertising started,
+ bleIncorrectMode: invalid profile role,
+ bleAlreadyInRequestedMode: not available at this time,
+ bleNotReady: advertising data isn't set up yet.
+*/ +extern bStatus_t GAP_MakeDiscoverable( uint8 taskID, gapAdvertisingParams_t* pParams ); + +/** + @brief Setup or change advertising and scan response data. + + NOTE: if the return status from this function is SUCCESS, + the task isn't complete until the GAP_ADV_DATA_UPDATE_DONE_EVENT + is sent to the calling application task. + + @param taskID - task ID of the app requesting the change + @param adType - TRUE - advertisement data, FALSE - scan response data + @param dataLen - Octet length of advertData + @param pAdvertData - advertising or scan response data + + @return SUCCESS: data accepted,
+ bleIncorrectMode: invalid profile role,
+*/ +extern bStatus_t GAP_UpdateAdvertisingData( uint8 taskID, uint8 adType, + uint8 dataLen, uint8* pAdvertData ); + +/** + @brief Stops advertising. + + @param taskID - of task that called GAP_MakeDiscoverable + + @return SUCCESS: stopping discoverable mode,
+ bleIncorrectMode: not in discoverable mode,
+ bleInvalidTaskID: not correct task
+*/ +extern bStatus_t GAP_EndDiscoverable( uint8 taskID ); + +/** + @brief Resolves a private address against an IRK. + + @param pIRK - pointer to the IRK + @param pAddr - pointer to the Resovable Private address + + @return SUCCESS: match,
+ FAILURE: don't match,
+ INVALIDPARAMETER: parameters invalid
+*/ +extern bStatus_t GAP_ResolvePrivateAddr( uint8* pIRK, uint8* pAddr ); + +/* ------------------------------------------------------------------- + FUNCTIONS - Link Establishment +*/ + +/** + @brief Establish a link to a slave device. + + @param pParams - link establishment parameters + + @return SUCCESS: started establish link process,
+ bleIncorrectMode: invalid profile role,
+ bleNotReady: a scan is in progress,
+ bleAlreadyInRequestedMode: can’t process now,
+ bleNoResources: Too many links
+*/ +extern bStatus_t GAP_EstablishLinkReq( gapEstLinkReq_t* pParams ); + +/** + @brief Terminate a link connection. + + @param taskID - requesting app's task id. + @param connectionHandle - connection handle of link to terminate + or @ref GAP_CONN_HANDLE_DEFINES + @param reason - terminate reason. + + @return SUCCESS: Terminate started,
+ bleIncorrectMode: No Link to terminate,
+ bleInvalidTaskID: not app that established link
+*/ +extern bStatus_t GAP_TerminateLinkReq( uint8 taskID, uint16 connectionHandle, uint8 reason ); + +/** + @brief Update the link parameters to a slave device. + + @param pParams - link update parameters + + @return SUCCESS: started update link process,
+ bleIncorrectMode: invalid profile role,
+ bleNotConnected: not in a connection
+*/ +extern bStatus_t GAP_UpdateLinkParamReq( gapUpdateLinkParamReq_t* pParams ); + +/** + @brief Returns the number of active connections. + + @return Number of active connections. +*/ +extern uint8 GAP_NumActiveConnections( void ); + +/* ------------------------------------------------------------------- + FUNCTIONS - Pairing +*/ + +/** + @brief Start the Authentication process with the requested device. + This function is used to Initiate/Allow pairing. + Called by both master and slave device (Central and Peripheral). + + NOTE: This function is called after the link is established. + + @param pParams - Authentication parameters + @param pPairReq - Enter these parameters if the Pairing Request was already received. + NULL, if waiting for Pairing Request or if initiating. + + @return SUCCESS,
+ bleIncorrectMode: Not correct profile role,
+ INVALIDPARAMETER,
+ bleNotConnected,
+ bleAlreadyInRequestedMode,
+ FAILURE - not workable.
+*/ +extern bStatus_t GAP_Authenticate( gapAuthParams_t* pParams, gapPairingReq_t* pPairReq ); + +/** + @brief Send a Pairing Failed message and end any existing pairing. + + @param connectionHandle - connection handle. + @param reason - Pairing Failed reason code. + + @return SUCCESS - function was successful,
+ bleMemAllocError - memory allocation error,
+ INVALIDPARAMETER - one of the parameters were invalid,
+ bleNotConnected - link not found,
+ bleInvalidRange - one of the parameters were not within range. +*/ +extern bStatus_t GAP_TerminateAuth( uint16 connectionHandle, uint8 reason ); + +/** + @brief Update the passkey in string format. This function is called by the + application/profile in response to receiving the + GAP_PASSKEY_NEEDED_EVENT message. + + NOTE: This function is the same as GAP_PasscodeUpdate(), except that + the passkey is passed in as a string format. + + @param pPasskey - new passkey - pointer to numeric string (ie. "019655" ). + This string's range is "000000" to "999999". + @param connectionHandle - connection handle. + + @return SUCCESS: will start pairing with this entry,
+ bleIncorrectMode: Link not found,
+ INVALIDPARAMETER: passkey == NULL or passkey isn't formatted properly.
+*/ +extern bStatus_t GAP_PasskeyUpdate( uint8* pPasskey, uint16 connectionHandle ); + +/** + @brief Update the passkey in a numeric value (not string). + This function is called by the application/profile in response + to receiving the GAP_PASSKEY_NEEDED_EVENT message. + + NOTE: This function is the same as GAP_PasskeyUpdate(), except that + the passkey is passed in as a non-string format. + + @param passcode - not string - range: 0 - 999,999. + @param connectionHandle - connection handle. + + @return SUCCESS: will start pairing with this entry,
+ bleIncorrectMode: Link not found,
+ INVALIDPARAMETER: passkey == NULL or passkey isn't formatted properly.
+*/ +extern bStatus_t GAP_PasscodeUpdate( uint32 passcode, uint16 connectionHandle ); + +/** + @brief Generate a Slave Requested Security message to the master. + + @param connectionHandle - connection handle. + @param authReq - Authentication Requirements: Bit 2: MITM, Bits 0-1: bonding (0 - no bonding, 1 - bonding) + + @return SUCCESS: will send,
+ bleNotConnected: Link not found,
+ bleIncorrectMode: wrong GAP role, must be a Peripheral Role
+*/ +extern bStatus_t GAP_SendSlaveSecurityRequest( uint16 connectionHandle, uint8 authReq ); + +/** + @brief Set up the connection to accept signed data. + + NOTE: This function is called after the link is established. + + @param connectionHandle - connection handle of the signing information + @param authenticated - TRUE if the signing information is authenticated, FALSE otherwise + @param pParams - signing parameters + + @return SUCCESS,
+ bleIncorrectMode: Not correct profile role,
+ INVALIDPARAMETER,
+ bleNotConnected,
+ FAILURE: not workable.
+*/ +extern bStatus_t GAP_Signable( uint16 connectionHandle, uint8 authenticated, smSigningInfo_t* pParams ); + +/** + @brief Set up the connection's bound paramaters. + + NOTE: This function is called after the link is established. + + @param connectionHandle - connection handle of the signing information + @param authenticated - this connection was previously authenticated + @param pParams - the connected device's security parameters + @param startEncryption - whether or not to start encryption + + @return SUCCESS,
+ bleIncorrectMode: Not correct profile role,
+ INVALIDPARAMETER,
+ bleNotConnected,
+ FAILURE: not workable.
+*/ +extern bStatus_t GAP_Bond( uint16 connectionHandle, uint8 authenticated, + smSecurityInfo_t* pParams, uint8 startEncryption ); + +/** + @} End GAP_API +*/ + +/* ------------------------------------------------------------------- + Internal API - These functions are only called from gap.c module. +*/ + +/** + @internal + + @brief Setup the device configuration parameters. + + @param taskID - Default task ID to send events. + @param profileRole - GAP Profile Roles + + @return SUCCESS or bleIncorrectMode +*/ +extern bStatus_t GAP_ParamsInit( uint8 taskID, uint8 profileRole ); + +/** + @internal + + @brief Setup the device security configuration parameters. + + @param pIRK - pointer to Identity Root Key, NULLKEY (all zeroes) if the app + wants the GAP to generate the key. + @param pSRK - pointer to Sign Resolving Key, NULLKEY if the app + wants the GAP to generate the key. + @param pSignCounter - 32 bit value used in the SM Signing + algorithm that shall be initialized to zero and incremented + with every new signing. This variable must also be maintained + by the application. + + @return none +*/ +extern void GAP_SecParamsInit( uint8* pIRK, uint8* pSRK, uint32* pSignCounter ); + +/** + @internal + + @brief Initialize the GAP Peripheral Dev Manager. + + @param none + + @return SUCCESS or bleMemAllocError +*/ +extern bStatus_t GAP_PeriDevMgrInit( void ); + +/** + @internal + + @brief Initialize the GAP Central Dev Manager. + + @param maxScanResponses - maximum number to scan responses + we can receive during a device discovery. + + @return SUCCESS or bleMemAllocError +*/ +extern bStatus_t GAP_CentDevMgrInit( uint8 maxScanResponses ); + +/** + @internal + + @brief Register the GAP Central Connection processing functions. + + @param none + + @return none +*/ +extern void GAP_CentConnRegister( void ); + + +/* ------------------------------------------------------------------- + TASK API - These functions must only be called OSAL. +*/ + +/** + @internal + + @brief GAP Task initialization function. + + @param taskID - GAP task ID. + + @return void +*/ +extern void GAP_Init( uint8 task_id ); + +/** + @internal + + @brief GAP Task event processing function. + + @param taskID - GAP task ID + @param events - GAP events. + + @return events not processed +*/ +extern uint16 GAP_ProcessEvent( uint8 task_id, uint16 events ); + + +/* ------------------------------------------------------------------- + -------------------------------------------------------------------*/ + +#ifdef __cplusplus +} +#endif + +#endif /* GAP_H */ diff --git a/src/components/ble/include/gatt.h b/src/components/ble/include/gatt.h new file mode 100644 index 0000000..4e6272a --- /dev/null +++ b/src/components/ble/include/gatt.h @@ -0,0 +1,1379 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/** + @headerfile: gatt.h + $Date: + $Revision: + + @mainpage BLE GATT API + + Description: This file contains Generic Attribute Profile (GATT) + definitions and prototypes.

+ + +*/ + +#ifndef GATT_H +#define GATT_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" + +#include "att.h" + +/********************************************************************* + CONSTANTS +*/ + +/** @defgroup GATT_PERMIT_BITMAPS_DEFINES GATT Attribute Access Permissions Bit Fields + @{ +*/ + +#define GATT_PERMIT_READ 0x01 //!< Attribute is Readable +#define GATT_PERMIT_WRITE 0x02 //!< Attribute is Writable +#define GATT_PERMIT_AUTHEN_READ 0x04 //!< Read requires Authentication +#define GATT_PERMIT_AUTHEN_WRITE 0x08 //!< Write requires Authentication +#define GATT_PERMIT_AUTHOR_READ 0x10 //!< Read requires Authorization +#define GATT_PERMIT_AUTHOR_WRITE 0x20 //!< Write requires Authorization +#define GATT_PERMIT_ENCRYPT_READ 0x40 //!< Read requires Encryption +#define GATT_PERMIT_ENCRYPT_WRITE 0x80 //!< Write requires Encryption + +/** @} End GATT_PERMIT_BITMAPS_DEFINES */ + + +/** @defgroup GATT_NUM_PREPARE_WRITES_DEFINES GATT Maximum Number of Prepare Writes + @{ +*/ +#define PREPARE_QUEUE_STATIC +#if !defined( GATT_MAX_NUM_PREPARE_WRITES ) +#define GATT_MAX_NUM_PREPARE_WRITES 1//20 //!< GATT Maximum number of attributes that Attribute Server can prepare for writing per Attribute Client +#endif + +/** @} End GATT_NUM_PREPARE_WRITES_DEFINES */ + + +/** @defgroup GATT_ENCRYPT_KEY_SIZE_DEFINES GATT Encryption Key Size + @{ +*/ + +#define GATT_ENCRYPT_KEY_SIZE 16 //!< GATT Encryption Key Size used for encrypting a link + +/** @} End GATT_ENCRYPT_KEY_SIZE_DEFINES */ + + +/** @defgroup GATT_MAX_ATTR_SIZE_DEFINES GATT Maximum Attribute Value Length + @{ +*/ + +#define GATT_MAX_ATTR_SIZE 512 //!< GATT Maximum length of an attribute value + +/** @} End GATT_MAX_ATTR_SIZE_DEFINES */ + +// GATT Maximum number of connections (including loopback) +#define GATT_MAX_NUM_CONN ( MAX_NUM_LL_CONN + 1 ) + +// GATT Base Method +#define GATT_BASE_METHOD 0x40 + +// Attribute handle defintions +#define GATT_INVALID_HANDLE 0x0000 // Invalid attribute handle +#define GATT_MIN_HANDLE 0x0001 // Minimum attribute handle +#define GATT_MAX_HANDLE 0xFFFF // Maximum attribute handle + +/********************************************************************* + VARIABLES +*/ + +/********************************************************************* + MACROS +*/ + +// Attribute Access Permissions +#define gattPermitRead( a ) ( (a) & GATT_PERMIT_READ ) +#define gattPermitWrite( a ) ( (a) & GATT_PERMIT_WRITE ) +#define gattPermitAuthenRead( a ) ( (a) & GATT_PERMIT_AUTHEN_READ ) +#define gattPermitAuthenWrite( a ) ( (a) & GATT_PERMIT_AUTHEN_WRITE ) +#define gattPermitAuthorRead( a ) ( (a) & GATT_PERMIT_AUTHOR_READ ) +#define gattPermitAuthorWrite( a ) ( (a) & GATT_PERMIT_AUTHOR_WRITE ) +#define gattPermitEncryptRead( a ) ( (a) & GATT_PERMIT_ENCRYPT_READ ) +#define gattPermitEncryptWrite( a ) ( (a) & GATT_PERMIT_ENCRYPT_WRITE ) + +// Check for different UUID types +#define gattPrimaryServiceType( t ) ( ATT_CompareUUID( primaryServiceUUID, ATT_BT_UUID_SIZE, \ + (t).uuid, (t).len ) ) +#define gattSecondaryServiceType( t ) ( ATT_CompareUUID( secondaryServiceUUID, ATT_BT_UUID_SIZE, \ + (t).uuid, (t).len ) ) +#define gattCharacterType( t ) ( ATT_CompareUUID( characterUUID, ATT_BT_UUID_SIZE, \ + (t).uuid, (t).len ) ) +#define gattIncludeType( t ) ( ATT_CompareUUID( includeUUID, ATT_BT_UUID_SIZE, \ + (t).uuid, (t).len ) ) +#define gattServiceType( t ) ( gattPrimaryServiceType( (t) ) || \ + gattSecondaryServiceType( (t) ) ) + +/********************************************************************* + TYPEDEFS +*/ + +/** + GATT Read By Type Request format. +*/ +typedef struct +{ + uint8 discCharsByUUID; //!< Whether this is a GATT Discover Characteristics by UUID sub-procedure + attReadByTypeReq_t req; //!< Read By Type Request +} gattReadByTypeReq_t; + +/** + GATT Prepare Write Request format. +*/ +typedef struct +{ + uint16 handle; //!< Handle of the attribute to be written (must be first field) + uint16 offset; //!< Offset of the first octet to be written + uint8 len; //!< Length of value + uint8* pValue; //!< Part of the value of the attribute to be written (must be allocated) +} gattPrepareWriteReq_t; + +/** + GATT Write Long Request format. Do not change the order of the members. +*/ +typedef struct +{ + uint8 reliable; //!< Whether reliable writes requested (always FALSE for Write Long) + gattPrepareWriteReq_t req; //!< GATT Prepare Write Request + uint16 lastOffset; //!< Offset of last Prepare Write Request sent +} gattWriteLongReq_t; + +/** + GATT Reliable Writes Request format. Do not change the order of the members. +*/ +typedef struct +{ + uint8 reliable; //!< Whether reliable writes requested (always TRUE for Reliable Writes) + attPrepareWriteReq_t* pReqs; //!< Arrary of Prepare Write Requests (must be allocated) + uint8 numReqs; //!< Number of Prepare Write Requests + uint8 index; //!< Index of last Prepare Write Request sent + uint8 flags; //!< 0x00 - cancel all prepared writes. + //!< 0x01 - immediately write all pending prepared values. +} gattReliableWritesReq_t; + +/** + GATT Message format. It's a union of all attribute protocol/profile messages + used between the attribute protocol/profile and upper layer application. +*/ +typedef union +{ + // Request messages + attExchangeMTUReq_t exchangeMTUReq; //!< ATT Exchange MTU Request + attFindInfoReq_t findInfoReq; //!< ATT Find Information Request + attFindByTypeValueReq_t findByTypeValueReq; //!< ATT Find By Type Vaue Request + attReadByTypeReq_t readByTypeReq; //!< ATT Read By Type Request + attReadReq_t readReq; //!< ATT Read Request + attReadBlobReq_t readBlobReq; //!< ATT Read Blob Request + attReadMultiReq_t readMultiReq; //!< ATT Read Multiple Request + attReadByGrpTypeReq_t readByGrpTypeReq; //!< ATT Read By Group Type Request + attWriteReq_t writeReq; //!< ATT Write Request + attPrepareWriteReq_t prepareWriteReq; //!< ATT Prepare Write Request + attExecuteWriteReq_t executeWriteReq; //!< ATT Execute Write Request + gattReadByTypeReq_t gattReadByTypeReq; //!< GATT Read By Type Request + gattWriteLongReq_t gattWriteLongReq; //!< GATT Long Write Request + gattReliableWritesReq_t gattReliableWritesReq; //!< GATT Reliable Writes Request + + // Response messages + attErrorRsp_t errorRsp; //!< ATT Error Response + attExchangeMTURsp_t exchangeMTURsp; //!< ATT Exchange MTU Response + attFindInfoRsp_t findInfoRsp; //!< ATT Find Information Response + attFindByTypeValueRsp_t findByTypeValueRsp; //!< ATT Find By Type Vaue Response + attReadByTypeRsp_t readByTypeRsp; //!< ATT Read By Type Response + attReadRsp_t readRsp; //!< ATT Read Response + attReadBlobRsp_t readBlobRsp; //!< ATT Read Blob Response + attReadMultiRsp_t readMultiRsp; //!< ATT Read Multiple Response + attReadByGrpTypeRsp_t readByGrpTypeRsp; //!< ATT Read By Group Type Response + attPrepareWriteRsp_t prepareWriteRsp; //!< ATT Prepare Write Response + + // Indication and Notification messages + attHandleValueNoti_t handleValueNoti; //!< ATT Handle Value Notification + attHandleValueInd_t handleValueInd; //!< ATT Handle Value Indication +} gattMsg_t; + +/** + GATT OSAL GATT_MSG_EVENT message format. This message is used to forward an + incoming attribute protocol/profile message up to upper layer application. +*/ +typedef struct +{ + osal_event_hdr_t hdr; //!< GATT_MSG_EVENT and status + uint16 connHandle; //!< Connection message was received on + uint8 method; //!< Type of message + gattMsg_t msg; //!< Attribute protocol/profile message +} gattMsgEvent_t; + +/** + GATT Attribute Type format. +*/ +typedef struct +{ + uint8 len; //!< Length of UUID + const uint8* uuid; //!< Pointer to UUID +} gattAttrType_t; + +/** + GATT Attribute format. +*/ +typedef struct attAttribute_t +{ + gattAttrType_t type; //!< Attribute type (2 or 16 octet UUIDs) + uint8 permissions; //!< Attribute permissions + uint16 handle; //!< Attribute handle - assigned internally by attribute server + uint8* const pValue; //!< Attribute value - encoding of the octet array is defined in + //!< the applicable profile. The maximum length of an attribute + //!< value shall be 512 octets. +} gattAttribute_t; + +/** + GATT Service format. +*/ +typedef struct +{ + uint16 numAttrs; //!< Number of attributes in attrs + + /** Array of attribute records. + NOTE: The list must start with a Service attribute followed by + all attributes associated with this Service attribute. + */ + gattAttribute_t* attrs; +} gattService_t; + +/********************************************************************* + VARIABLES +*/ + +/********************************************************************* + API FUNCTIONS +*/ + +/* ------------------------------------------------------------------- + GATT Client Public APIs +*/ + +/** + @defgroup GATT_CLIENT_API GATT Client API Functions + + @{ +*/ + +/** + @brief Initialize the Generic Attribute Profile Client. + + @return SUCCESS +*/ +extern bStatus_t GATT_InitClient( void ); + +/** + @brief Register to receive incoming ATT Indications or Notifications + of attribute values. + + @param taskId ? task to forward indications or notifications to + + @return void +*/ +extern void GATT_RegisterForInd( uint8 taskId ); + +/** + @brief The Prepare Write Request is used to request the server to + prepare to write the value of an attribute. + + Note: This function is needed only for GATT testing. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A response is pending with this server.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_PrepareWriteReq( uint16 connHandle, attPrepareWriteReq_t* pReq, uint8 taskId ); + +/** + @brief The Execute Write Request is used to request the server to + write or cancel the write of all the prepared values currently + held in the prepare queue from this client. + + Note: This function is needed only for GATT testing. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A response is pending with this server.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_ExecuteWriteReq( uint16 connHandle, attExecuteWriteReq_t* pReq, uint8 taskId ); + +/** + @} +*/ + +/* ------------------------------------------------------------------- + GATT Server Public APIs +*/ + +/** + @defgroup GATT_SERVER_API GATT Server API Functions + + @{ +*/ + +/** + @brief Initialize the Generic Attribute Profile Server. + + @return SUCCESS +*/ +extern bStatus_t GATT_InitServer( void ); + +/** + @brief Register a service attribute list with the GATT Server. A service + is composed of characteristics or references to other services. + Each characteristic contains a value and may contain optional + information about the value. There are two types of services: + primary service and secondary service. + + A service definition begins with a service declaration and ends + before the next service declaration or the maximum Attribute Handle. + + A characteristic definition begins with a characteristic declaration + and ends before the next characteristic or service declaration or + maximum Attribute Handle. + + The attribute server will only keep a pointer to the attribute + list, so the calling application will have to maintain the code + and RAM associated with this list. + + @param pService - pointer to service attribute list to be registered + + @return SUCCESS: Service registered successfully.
+ INVALIDPARAMETER: Invalid service field.
+ FAILURE: Not enough attribute handles available.
+ bleMemAllocError: Memory allocation error occurred.
+*/ +extern bStatus_t GATT_RegisterService( gattService_t* pService ); + +/** + @brief Deregister a service attribute list with the GATT Server. + + NOTE: It's the caller's responsibility to free the service attribute + list returned from this API. + + @param handle - handle of service to be deregistered + @param pService - pointer to deregistered service (to be returned) + + @return SUCCESS: Service deregistered successfully.
+ FAILURE: Service not found.
+*/ +extern bStatus_t GATT_DeregisterService( uint16 handle, gattService_t* pService ); + +/** + @brief Register to receive incoming ATT Requests. + + @param taskId ? task to forward requests to + + @return void +*/ +extern void GATT_RegisterForReq( uint8 taskId ); + +/** + @brief Verify the permissions of an attribute for reading. + + @param connHandle - connection to use + @param permissions - attribute permissions + + @return SUCCESS: Attribute can be read.
+ ATT_ERR_READ_NOT_PERMITTED: Attribute cannot be read.
+ ATT_ERR_INSUFFICIENT_AUTHEN: Attribute requires authentication.
+ ATT_ERR_INSUFFICIENT_KEY_SIZE: Key Size used for encrypting is insufficient.
+ ATT_ERR_INSUFFICIENT_ENCRYPT: Attribute requires encryption.
+*/ +extern bStatus_t GATT_VerifyReadPermissions( uint16 connHandle, uint8 permissions ); + +/** + @brief Verify the permissions of an attribute for writing. + + @param connHandle - connection to use + @param permissions - attribute permissions + @param pReq - pointer to write request + + @return SUCCESS: Attribute can be written.
+ ATT_ERR_READ_NOT_PERMITTED: Attribute cannot be written.
+ ATT_ERR_INSUFFICIENT_AUTHEN: Attribute requires authentication.
+ ATT_ERR_INSUFFICIENT_KEY_SIZE: Key Size used for encrypting is insufficient.
+ ATT_ERR_INSUFFICIENT_ENCRYPT: Attribute requires encryption.
+*/ +extern bStatus_t GATT_VerifyWritePermissions( uint16 connHandle, uint8 permissions, attWriteReq_t* pReq ); + +/** + @brief Send out a Service Changed Indication. + + @param connHandle - connection to use + @param taskId - task to be notified of confirmation + + @return SUCCESS: Indication was sent successfully.
+ FAILURE: Service Changed attribute not found.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A confirmation is pending with this client.
+*/ +extern uint8 GATT_ServiceChangedInd( uint16 connHandle, uint8 taskId ); + +/** + @brief Find the attribute record for a given handle and UUID. + + @param startHandle - first handle to look for + @param endHandle - last handle to look for + @param pUUID - pointer to UUID to look for + @param len - length of UUID + @param pHandle - handle of owner of attribute (to be returned) + + @return Pointer to attribute record. NULL, otherwise. +*/ +extern gattAttribute_t* GATT_FindHandleUUID( uint16 startHandle, uint16 endHandle, const uint8* pUUID, + uint16 len, uint16* pHandle ); +/** + @brief Find the attribute record for a given handle + + @param handle - handle to look for + @param pHandle - handle of owner of attribute (to be returned) + + @return Pointer to attribute record. NULL, otherwise. +*/ +extern gattAttribute_t* GATT_FindHandle( uint16 handle, uint16* pHandle ); + +/** + @brief Find the next attribute of the same type for a given attribute. + + @param pAttr - pointer to attribute to find a next for + @param endHandle - last handle to look for + @param service - handle of owner service + @param pLastHandle - handle of last attribute (to be returned) + + @return Pointer to next attribute record. NULL, otherwise. +*/ +extern gattAttribute_t* GATT_FindNextAttr( gattAttribute_t* pAttr, uint16 endHandle, + uint16 service, uint16* pLastHandle ); +/** + @brief Get the number of attributes for a given service + + @param handle - service handle to look for + + @return Number of attributes. 0, otherwise. +*/ +extern uint16 GATT_ServiceNumAttrs( uint16 handle ); + +/** + @} +*/ + +/* ------------------------------------------------------------------- + GATT Server Sub-Procedure APIs +*/ + +/** + @defgroup GATT_SERVER_SUB_PROCEDURE_API GATT Server Sub-Procedure API Functions + + @{ +*/ + +/** + @brief This sub-procedure is used when a server is configured to + indicate a characteristic value to a client and expects an + attribute protocol layer acknowledgement that the indication + was successfully received. + + The ATT Handle Value Indication is used in this sub-procedure. + + If the return status from this function is SUCCESS, the calling + application task will receive an OSAL GATT_MSG_EVENT message. + The type of the message will be ATT_HANDLE_VALUE_CFM. + + Note: This sub-procedure is complete when ATT_HANDLE_VALUE_CFM + (with SUCCESS or bleTimeout status) is received by the + calling application task. + + @param connHandle - connection to use + @param pInd - pointer to indication to be sent + @param authenticated - whether an authenticated link is required + @param taskId - task to be notified of response + + @return SUCCESS: Indication was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A confirmation is pending with this client.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_Indication( uint16 connHandle, attHandleValueInd_t* pInd, + uint8 authenticated, uint8 taskId ); +/** + @brief This sub-procedure is used when a server is configured to + notify a characteristic value to a client without expecting + any attribute protocol layer acknowledgement that the + notification was successfully received. + + The ATT Handle Value Notification is used in this sub-procedure. + + Note: A notification may be sent at any time and does not + invoke a confirmation. + + No confirmation will be sent to the calling application task for + this sub-procedure. + + @param connHandle - connection to use + @param pNoti - pointer to notification to be sent + @param authenticated - whether an authenticated link is required + + @return SUCCESS: Notification was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_Notification( uint16 connHandle, attHandleValueNoti_t* pNoti, + uint8 authenticated ); +/** + @} +*/ + +/* ------------------------------------------------------------------- + GATT Client Sub-Procedure APIs +*/ + +/** + @defgroup GATT_CLIENT_SUB_PROCEDURE_API GATT Client Sub-Procedure API Functions + + @{ +*/ + +/** + @brief This sub-procedure is used by the client to set the ATT_MTU + to the maximum possible value that can be supported by both + devices when the client supports a value greater than the + default ATT_MTU for the Attribute Protocol. This sub-procedure + shall only be initiated once during a connection. + + The ATT Exchange MTU Request is used by this sub-procedure. + + If the return status from this function is SUCCESS, the calling + application task will receive an OSAL GATT_MSG_EVENT message. + The type of the message will be either ATT_EXCHANGE_MTU_RSP or + ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_EXCHANGE_MTU_RSP + (with SUCCESS or bleTimeout status) or ATT_ERROR_RSP (with + SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A response is pending with this server.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_ExchangeMTU( uint16 connHandle, attExchangeMTUReq_t* pReq, uint8 taskId ); + +/** + @brief This sub-procedure is used by a client to discover all + the primary services on a server. + + The ATT Read By Group Type Request is used with the Attribute + Type parameter set to the UUID for "Primary Service". The + Starting Handle is set to 0x0001 and the Ending Handle is + set to 0xFFFF. + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_READ_BY_GRP_TYPE_RSP + or ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_READ_BY_GRP_TYPE_RSP + (with bleProcedureComplete or bleTimeout status) or ATT_ERROR_RSP + (with SUCCESS status) is received by the calling application + task. + + @param connHandle - connection to use + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A response is pending with this server.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_DiscAllPrimaryServices( uint16 connHandle, uint8 taskId ); + +/** + @brief This sub-procedure is used by a client to discover a specific + primary service on a server when only the Service UUID is + known. The primary specific service may exist multiple times + on a server. The primary service being discovered is identified + by the service UUID. + + The ATT Find By Type Value Request is used with the Attribute + Type parameter set to the UUID for "Primary Service" and the + Attribute Value set to the 16-bit Bluetooth UUID or 128-bit + UUID for the specific primary service. The Starting Handle shall + be set to 0x0001 and the Ending Handle shall be set to 0xFFFF. + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_FIND_BY_TYPE_VALUE_RSP + or ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_FIND_BY_TYPE_VALUE_RSP + (with bleProcedureComplete or bleTimeout status) or ATT_ERROR_RSP + (with SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pValue - pointer to value to look for + @param len - length of value + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A response is pending with this server.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_DiscPrimaryServiceByUUID( uint16 connHandle, uint8* pValue, + uint8 len, uint8 taskId ); +/** + @brief This sub-procedure is used by a client to find include + service declarations within a service definition on a + server. The service specified is identified by the service + handle range. + + The ATT Read By Type Request is used with the Attribute + Type parameter set to the UUID for "Included Service". The + Starting Handle is set to starting handle of the specified + service and the Ending Handle is set to the ending handle + of the specified service. + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_READ_BY_TYPE_RSP + or ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_READ_BY_TYPE_RSP + (with bleProcedureComplete or bleTimeout status) or ATT_ERROR_RSP + (with SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param startHandle - starting handle + @param endHandle - end handle + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A response is pending with this server.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_FindIncludedServices( uint16 connHandle, uint16 startHandle, + uint16 endHandle, uint8 taskId ); +/** + @brief This sub-procedure is used by a client to find all the + characteristic declarations within a service definition on + a server when only the service handle range is known. The + service specified is identified by the service handle range. + + The ATT Read By Type Request is used with the Attribute Type + parameter set to the UUID for "Characteristic". The Starting + Handle is set to starting handle of the specified service and + the Ending Handle is set to the ending handle of the specified + service. + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_READ_BY_TYPE_RSP + or ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_READ_BY_TYPE_RSP + (with bleProcedureComplete or bleTimeout status) or ATT_ERROR_RSP + (with SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param startHandle - starting handle + @param endHandle - end handle + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A response is pending with this server.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_DiscAllChars( uint16 connHandle, uint16 startHandle, + uint16 endHandle, uint8 taskId ); +/** + @brief This sub-procedure is used by a client to discover service + characteristics on a server when only the service handle + ranges are known and the characteristic UUID is known. + The specific service may exist multiple times on a server. + The characteristic being discovered is identified by the + characteristic UUID. + + The ATT Read By Type Request is used with the Attribute Type + is set to the UUID for "Characteristic" and the Starting + Handle and Ending Handle parameters is set to the service + handle range. + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_READ_BY_TYPE_RSP + or ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_READ_BY_TYPE_RSP + (with bleProcedureComplete or bleTimeout status) or ATT_ERROR_RSP + (with SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A response is pending with this server.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_DiscCharsByUUID( uint16 connHandle, attReadByTypeReq_t* pReq, uint8 taskId ); + +/** + @brief This sub-procedure is used by a client to find all the + characteristic descriptor’s Attribute Handles and Attribute + Types within a characteristic definition when only the + characteristic handle range is known. The characteristic + specified is identified by the characteristic handle range. + + The ATT Find Information Request is used with the Starting + Handle set to starting handle of the specified characteristic + and the Ending Handle set to the ending handle of the specified + characteristic. The UUID Filter parameter is NULL (zero length). + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_FIND_INFO_RSP or + ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_FIND_INFO_RSP + (with bleProcedureComplete or bleTimeout status) or ATT_ERROR_RSP + (with SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param startHandle - starting handle + @param endHandle - end handle + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A response is pending with this server.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_DiscAllCharDescs( uint16 connHandle, uint16 startHandle, + uint16 endHandle, uint8 taskId ); +/** + @brief This sub-procedure is used to read a Characteristic Value + from a server when the client knows the Characteristic Value + Handle. The ATT Read Request is used with the Attribute Handle + parameter set to the Characteristic Value Handle. The Read + Response returns the Characteristic Value in the Attribute + Value parameter. + + The Read Response only contains a Characteristic Value that + is less than or equal to (ATT_MTU ? 1) octets in length. If + the Characteristic Value is greater than (ATT_MTU ? 1) octets + in length, the Read Long Characteristic Value procedure may + be used if the rest of the Characteristic Value is required. + + If the return status from this function is SUCCESS, the calling + application task will receive an OSAL GATT_MSG_EVENT message. + The type of the message will be either ATT_READ_RSP or + ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_READ_RSP + (with SUCCESS or bleTimeout status) or ATT_ERROR_RSP (with + SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A response is pending with this server.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_ReadCharValue( uint16 connHandle, attReadReq_t* pReq, uint8 taskId ); + +/** + @brief This sub-procedure is used to read a Characteristic Value + from a server when the client only knows the characteristic + UUID and does not know the handle of the characteristic. + + The ATT Read By Type Request is used to perform the sub-procedure. + The Attribute Type is set to the known characteristic UUID and + the Starting Handle and Ending Handle parameters shall be set + to the range over which this read is to be performed. This is + typically the handle range for the service in which the + characteristic belongs. + + If the return status from this function is SUCCESS, the calling + application task will receive an OSAL GATT_MSG_EVENT messages. + The type of the message will be either ATT_READ_BY_TYPE_RSP + or ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_READ_BY_TYPE_RSP + (with SUCCESS or bleTimeout status) or ATT_ERROR_RSP (with + SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A response is pending with this server.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_ReadUsingCharUUID( uint16 connHandle, attReadByTypeReq_t* pReq, uint8 taskId ); +/** + @brief This sub-procedure is used to read a Characteristic Value from + a server when the client knows the Characteristic Value Handle + and the length of the Characteristic Value is longer than can + be sent in a single Read Response Attribute Protocol message. + + The ATT Read Blob Request is used in this sub-procedure. + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_READ_BLOB_RSP or + ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_READ_BLOB_RSP + (with bleProcedureComplete or bleTimeout status) or ATT_ERROR_RSP + (with SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A response is pending with this server.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_ReadLongCharValue( uint16 connHandle, attReadBlobReq_t* pReq, uint8 taskId ); + +/** + @brief This sub-procedure is used to read multiple Characteristic Values + from a server when the client knows the Characteristic Value + Handles. The Attribute Protocol Read Multiple Requests is used + with the Set Of Handles parameter set to the Characteristic Value + Handles. The Read Multiple Response returns the Characteristic + Values in the Set Of Values parameter. + + The ATT Read Multiple Request is used in this sub-procedure. + + If the return status from this function is SUCCESS, the calling + application task will receive an OSAL GATT_MSG_EVENT message. + The type of the message will be either ATT_READ_MULTI_RSP + or ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_READ_MULTI_RSP + (with SUCCESS or bleTimeout status) or ATT_ERROR_RSP (with + SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A response is pending with this server.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_ReadMultiCharValues( uint16 connHandle, attReadMultiReq_t* pReq, uint8 taskId ); + +/** + @brief This sub-procedure is used to write a Characteristic Value + to a server when the client knows the Characteristic Value + Handle and the client does not need an acknowledgement that + the write was successfully performed. This sub-procedure + only writes the first (ATT_MTU ? 3) octets of a Characteristic + Value. This sub-procedure can not be used to write a long + characteristic; instead the Write Long Characteristic Values + sub-procedure should be used. + + The ATT Write Command is used for this sub-procedure. The + Attribute Handle parameter shall be set to the Characteristic + Value Handle. The Attribute Value parameter shall be set to + the new Characteristic Value. + + No response will be sent to the calling application task for this + sub-procedure. If the Characteristic Value write request is the + wrong size, or has an invalid value as defined by the profile, + then the write will not succeed and no error will be generated + by the server. + + @param connHandle - connection to use + @param pReq - pointer to command to be sent + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_WriteNoRsp( uint16 connHandle, attWriteReq_t* pReq ); + +/** + @brief This sub-procedure is used to write a Characteristic Value + to a server when the client knows the Characteristic Value + Handle and the ATT Bearer is not encrypted. This sub-procedure + shall only be used if the Characteristic Properties authenticated + bit is enabled and the client and server device share a bond as + defined in the GAP. + + This sub-procedure only writes the first (ATT_MTU ? 15) octets + of an Attribute Value. This sub-procedure cannot be used to + write a long Attribute. + + The ATT Write Command is used for this sub-procedure. The + Attribute Handle parameter shall be set to the Characteristic + Value Handle. The Attribute Value parameter shall be set to + the new Characteristic Value authenticated by signing the + value, as defined in the Security Manager. + + No response will be sent to the calling application task for this + sub-procedure. If the authenticated Characteristic Value that is + written is the wrong size, or has an invalid value as defined by + the profile, or the signed value does not authenticate the client, + then the write will not succeed and no error will be generated by + the server. + + @param connHandle - connection to use + @param pReq - pointer to command to be sent + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ bleMemAllocError: Memory allocation error occurred.
+ bleLinkEncrypted: Connection is already encrypted.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_SignedWriteNoRsp( uint16 connHandle, attWriteReq_t* pReq ); + +/** + @brief This sub-procedure is used to write a characteristic value + to a server when the client knows the characteristic value + handle. This sub-procedure only writes the first (ATT_MTU-3) + octets of a characteristic value. This sub-procedure can not + be used to write a long attribute; instead the Write Long + Characteristic Values sub-procedure should be used. + + The ATT Write Request is used in this sub-procedure. The + Attribute Handle parameter shall be set to the Characteristic + Value Handle. The Attribute Value parameter shall be set to + the new characteristic. + + If the return status from this function is SUCCESS, the calling + application task will receive an OSAL GATT_MSG_EVENT message. + The type of the message will be either ATT_WRITE_RSP + or ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_WRITE_RSP + (with SUCCESS or bleTimeout status) or ATT_ERROR_RSP (with + SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A response is pending with this server.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_WriteCharValue( uint16 connHandle, attWriteReq_t* pReq, uint8 taskId ); + +/** + @brief This sub-procedure is used to write a Characteristic Value to + a server when the client knows the Characteristic Value Handle + but the length of the Characteristic Value is longer than can + be sent in a single Write Request Attribute Protocol message. + + The ATT Prepare Write Request and Execute Write Request are + used to perform this sub-procedure. + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_PREPARE_WRITE_RSP, + ATT_EXECUTE_WRITE_RSP or ATT_ERROR_RSP (if an error occurred on + the server). + + Note: This sub-procedure is complete when either ATT_PREPARE_WRITE_RSP + (with bleTimeout status), ATT_EXECUTE_WRITE_RSP (with SUCCESS + or bleTimeout status), or ATT_ERROR_RSP (with SUCCESS status) + is received by the calling application task. + + Note: The 'pReq->pValue' pointer will be freed when the sub-procedure + is complete. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A response is pending with this server.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_WriteLongCharValue( uint16 connHandle, gattPrepareWriteReq_t* pReq, uint8 taskId ); + +/** + @brief This sub-procedure is used to write a Characteristic Value to + a server when the client knows the Characteristic Value Handle, + and assurance is required that the correct Characteristic Value + is going to be written by transferring the Characteristic Value + to be written in both directions before the write is performed. + This sub-procedure can also be used when multiple values must + be written, in order, in a single operation. + + The sub-procedure has two phases, the first phase prepares the + characteristic values to be written. Once this is complete, + the second phase performs the execution of all of the prepared + characteristic value writes on the server from this client. + + In the first phase, the ATT Prepare Write Request is used. + In the second phase, the attribute protocol Execute Write + Request is used. + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_PREPARE_WRITE_RSP, + ATT_EXECUTE_WRITE_RSP or ATT_ERROR_RSP (if an error occurred on + the server). + + Note: This sub-procedure is complete when either ATT_PREPARE_WRITE_RSP + (with bleTimeout status), ATT_EXECUTE_WRITE_RSP (with SUCCESS + or bleTimeout status), or ATT_ERROR_RSP (with SUCCESS status) + is received by the calling application task. + + Note: The 'pReqs' pointer will be freed when the sub-procedure is + complete. + + @param connHandle - connection to use + @param pReqs - pointer to requests to be sent (must be allocated) + @param numReqs - number of requests in pReq + @param flags - execute write request flags + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A response is pending with this server.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_ReliableWrites( uint16 connHandle, attPrepareWriteReq_t* pReqs, + uint8 numReqs, uint8 flags, uint8 taskId ); +/** + @brief This sub-procedure is used to read a characteristic descriptor + from a server when the client knows the characteristic descriptor + declaration’s Attribute handle. + + The ATT Read Request is used for this sub-procedure. The Read + Request is used with the Attribute Handle parameter set to the + characteristic descriptor handle. The Read Response returns the + characteristic descriptor value in the Attribute Value parameter. + + If the return status from this function is SUCCESS, the calling + application task will receive an OSAL GATT_MSG_EVENT message. + The type of the message will be either ATT_READ_RSP or + ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_READ_RSP + (with SUCCESS or bleTimeout status) or ATT_ERROR_RSP (with + SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A response is pending with this server.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_ReadCharDesc( uint16 connHandle, attReadReq_t* pReq, uint8 taskId ); + +/** + @brief This sub-procedure is used to read a characteristic descriptor + from a server when the client knows the characteristic descriptor + declaration’s Attribute handle and the length of the characteristic + descriptor declaration is longer than can be sent in a single Read + Response attribute protocol message. + + The ATT Read Blob Request is used to perform this sub-procedure. + The Attribute Handle parameter shall be set to the characteristic + descriptor handle. The Value Offset parameter shall be the offset + within the characteristic descriptor to be read. + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_READ_BLOB_RSP or + ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_READ_BLOB_RSP + (with bleProcedureComplete or bleTimeout status) or ATT_ERROR_RSP + (with SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A response is pending with this server.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_ReadLongCharDesc( uint16 connHandle, attReadBlobReq_t* pReq, uint8 taskId ); + +/** + @brief This sub-procedure is used to write a characteristic + descriptor value to a server when the client knows the + characteristic descriptor handle. + + The ATT Write Request is used for this sub-procedure. The + Attribute Handle parameter shall be set to the characteristic + descriptor handle. The Attribute Value parameter shall be + set to the new characteristic descriptor value. + + If the return status from this function is SUCCESS, the calling + application task will receive an OSAL GATT_MSG_EVENT message. + The type of the message will be either ATT_WRITE_RSP + or ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_WRITE_RSP + (with SUCCESS or bleTimeout status) or ATT_ERROR_RSP (with + SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.
+ MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A response is pending with this server.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_WriteCharDesc( uint16 connHandle, attWriteReq_t* pReq, uint8 taskId ); + +/** + @brief This sub-procedure is used to write a Characteristic Value to + a server when the client knows the Characteristic Value Handle + but the length of the Characteristic Value is longer than can + be sent in a single Write Request Attribute Protocol message. + + The ATT Prepare Write Request and Execute Write Request are + used to perform this sub-procedure. + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_PREPARE_WRITE_RSP, + ATT_EXECUTE_WRITE_RSP or ATT_ERROR_RSP (if an error occurred on + the server). + + Note: This sub-procedure is complete when either ATT_PREPARE_WRITE_RSP + (with bleTimeout status), ATT_EXECUTE_WRITE_RSP (with SUCCESS + or bleTimeout status), or ATT_ERROR_RSP (with SUCCESS status) + is received by the calling application task. + + Note: The 'pReq->pValue' pointer will be freed when the sub-procedure + is complete. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully.
+ INVALIDPARAMETER: Invalid connection handle or request field.v + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.
+ bleNotConnected: Connection is down.
+ blePending: A response is pending with this server.
+ bleMemAllocError: Memory allocation error occurred.
+ bleTimeout: Previous transaction timed out.
+*/ +extern bStatus_t GATT_WriteLongCharDesc( uint16 connHandle, gattPrepareWriteReq_t* pReq, uint8 taskId ); + +/** + @} +*/ + +/* ------------------------------------------------------------------- + GATT Flow Control APIs +*/ + +/** + @defgroup GATT_FLOW_CTRL_API GATT Flow Control API Functions + + @{ +*/ + +/** + @brief This API is used by the Application to turn flow control on + or off for GATT messages sent from the Host to the Application. + + Note: If the flow control is enabled then the Application must + call the GATT_AppCompletedMsg() API when it completes + processing an incoming GATT message. + + @param flowCtrlMode ? flow control mode: TRUE or FALSE + + @return void +*/ +extern void GATT_SetHostToAppFlowCtrl( uint16 hostBufSize,uint8 flowCtrlMode ); + +/** + @brief This API is used by the Application to notify GATT that + the processing of a message has been completed. + + @param pMsg ? pointer to the processed GATT message + + @return void +*/ +extern void GATT_AppCompletedMsg( gattMsgEvent_t* pMsg ); + +/** + @} +*/ + +/* ------------------------------------------------------------------- + Internal API - This function is only called from GATT Qualification modules. +*/ + +/** + @internal + + @brief Set the next available attribute handle. + + @param handle - next attribute handle. + + @return none +*/ +extern void GATT_SetNextHandle( uint16 handle ); + +/* ------------------------------------------------------------------- + TASK API - These functions must only be called by OSAL. +*/ + +/** + @internal + + @brief GATT Task initialization function. + + @param taskId - GATT task ID. + + @return void +*/ +extern void GATT_Init( uint8 taskId ); + +/** + @internal + + @brief GATT Task event processing function. + + @param taskId - GATT task ID + @param events - GATT events. + + @return events not processed +*/ +extern uint16 GATT_ProcessEvent( uint8 taskId, uint16 events ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* GATT_H */ diff --git a/src/components/ble/include/gatt_uuid.h b/src/components/ble/include/gatt_uuid.h new file mode 100644 index 0000000..9c46ccb --- /dev/null +++ b/src/components/ble/include/gatt_uuid.h @@ -0,0 +1,139 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: gatt_uuid.h + Revised: + Revision: + + Description: This file contains Generic Attribute Profile (GATT) + UUID types. + + +**************************************************************************************************/ + +#ifndef GATT_UUID_H +#define GATT_UUID_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + CONSTANTS +*/ + +/* + WARNING: The 16-bit UUIDs are assigned by the Bluetooth SIG and published + in the Bluetooth Assigned Numbers page. Do not change these values. + Changing them will cause Bluetooth interoperability issues. +*/ + +/** + GATT Services +*/ +#define GAP_SERVICE_UUID 0x1800 // Generic Access Profile +#define GATT_SERVICE_UUID 0x1801 // Generic Attribute Profile + +/** + GATT Declarations +*/ +#define GATT_PRIMARY_SERVICE_UUID 0x2800 // Primary Service +#define GATT_SECONDARY_SERVICE_UUID 0x2801 // Secondary Service +#define GATT_INCLUDE_UUID 0x2802 // Include +#define GATT_CHARACTER_UUID 0x2803 // Characteristic + +/** + GATT Descriptors +*/ +#define GATT_CHAR_EXT_PROPS_UUID 0x2900 // Characteristic Extended Properties +#define GATT_CHAR_USER_DESC_UUID 0x2901 // Characteristic User Description +#define GATT_CLIENT_CHAR_CFG_UUID 0x2902 // Client Characteristic Configuration +#define GATT_SERV_CHAR_CFG_UUID 0x2903 // Server Characteristic Configuration +#define GATT_CHAR_FORMAT_UUID 0x2904 // Characteristic Presentation Format +#define GATT_CHAR_AGG_FORMAT_UUID 0x2905 // Characteristic Aggregate Format +#define GATT_VALID_RANGE_UUID 0x2906 // Valid Range +#define GATT_EXT_REPORT_REF_UUID 0x2907 // External Report Reference Descriptor +#define GATT_REPORT_REF_UUID 0x2908 // Report Reference Descriptor + +/** + GATT Characteristics +*/ +#define DEVICE_NAME_UUID 0x2A00 // Device Name +#define APPEARANCE_UUID 0x2A01 // Appearance +#define PERI_PRIVACY_FLAG_UUID 0x2A02 // Peripheral Privacy Flag +#define RECONNECT_ADDR_UUID 0x2A03 // Reconnection Address +#define PERI_CONN_PARAM_UUID 0x2A04 // Peripheral Preferred Connection Parameters +#define SERVICE_CHANGED_UUID 0x2A05 // Service Changed + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + VARIABLES +*/ + +/** + GATT Services +*/ +extern CONST uint8 gapServiceUUID[]; +extern CONST uint8 gattServiceUUID[]; + +/** + GATT Attribute Types +*/ +extern CONST uint8 primaryServiceUUID[]; +extern CONST uint8 secondaryServiceUUID[]; +extern CONST uint8 includeUUID[]; +extern CONST uint8 characterUUID[]; + +/** + GATT Characteristic Descriptors +*/ +extern CONST uint8 charExtPropsUUID[]; +extern CONST uint8 charUserDescUUID[]; +extern CONST uint8 clientCharCfgUUID[]; +extern CONST uint8 servCharCfgUUID[]; +extern CONST uint8 charFormatUUID[]; +extern CONST uint8 charAggFormatUUID[]; +extern CONST uint8 validRangeUUID[]; +extern CONST uint8 extReportRefUUID[]; +extern CONST uint8 reportRefUUID[]; + +/** + GATT Characteristic Types +*/ +extern CONST uint8 deviceNameUUID[]; +extern CONST uint8 appearanceUUID[]; +extern CONST uint8 periPrivacyFlagUUID[]; +extern CONST uint8 reconnectAddrUUID[]; +extern CONST uint8 periConnParamUUID[]; +extern CONST uint8 serviceChangedUUID[]; +extern CONST uint8 manuNameUUID[]; +extern CONST uint8 serialNumUUID[]; +extern CONST uint8 manuAddrUUID[]; + +/********************************************************************* + FUNCTIONS +*/ +extern const uint8* GATT_FindUUIDRec( const uint8* pUUID, uint8 len ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* GATT_UUID_H */ diff --git a/src/components/ble/include/hci.h b/src/components/ble/include/hci.h new file mode 100644 index 0000000..411f2dc --- /dev/null +++ b/src/components/ble/include/hci.h @@ -0,0 +1,3122 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + Filename: hci.h + Revised: + Revision: + + Description: This file contains the Host Controller Interface (HCI) API. + It provides the defines, types, and functions for all + supported Bluetooth Low Energy (BLE) commands. + + All Bluetooth and BLE commands are based on: + Bluetooth Core Specification, V4.0.0, Vol. 2, Part E. + + +*******************************************************************************/ + +#ifndef HCI_H +#define HCI_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "ll.h" +//#include "hal_assert.h" + +/******************************************************************************* + MACROS +*/ + +/******************************************************************************* + CONSTANTS +*/ + +/* +** HCI Status +** +** Per the Bluetooth Core Specification, V4.0.0, Vol. 2, Part D. +*/ +#define HCI_SUCCESS 0x00 +#define HCI_ERROR_CODE_UNKNOWN_HCI_CMD 0x01 +#define HCI_ERROR_CODE_UNKNOWN_CONN_ID 0x02 +#define HCI_ERROR_CODE_HW_FAILURE 0x03 +#define HCI_ERROR_CODE_PAGE_TIMEOUT 0x04 +#define HCI_ERROR_CODE_AUTH_FAILURE 0x05 +#define HCI_ERROR_CODE_PIN_KEY_MISSING 0x06 +#define HCI_ERROR_CODE_MEM_CAP_EXCEEDED 0x07 +#define HCI_ERROR_CODE_CONN_TIMEOUT 0x08 +#define HCI_ERROR_CODE_CONN_LIMIT_EXCEEDED 0x09 +#define HCI_ERROR_CODE_SYNCH_CONN_LIMIT_EXCEEDED 0x0A +#define HCI_ERROR_CODE_ACL_CONN_ALREADY_EXISTS 0x0B +#define HCI_ERROR_CODE_CMD_DISALLOWED 0x0C +#define HCI_ERROR_CODE_CONN_REJ_LIMITED_RESOURCES 0x0D +#define HCI_ERROR_CODE_CONN_REJECTED_SECURITY_REASONS 0x0E +#define HCI_ERROR_CODE_CONN_REJECTED_UNACCEPTABLE_BDADDR 0x0F +#define HCI_ERROR_CODE_CONN_ACCEPT_TIMEOUT_EXCEEDED 0x10 +#define HCI_ERROR_CODE_UNSUPPORTED_FEATURE_PARAM_VALUE 0x11 +#define HCI_ERROR_CODE_INVALID_HCI_CMD_PARAMS 0x12 +#define HCI_ERROR_CODE_REMOTE_USER_TERM_CONN 0x13 +#define HCI_ERROR_CODE_REMOTE_DEVICE_TERM_CONN_LOW_RESOURCES 0x14 +#define HCI_ERROR_CODE_REMOTE_DEVICE_TERM_CONN_POWER_OFF 0x15 +#define HCI_ERROR_CODE_CONN_TERM_BY_LOCAL_HOST 0x16 +#define HCI_ERROR_CODE_REPEATED_ATTEMPTS 0x17 +#define HCI_ERROR_CODE_PAIRING_NOT_ALLOWED 0x18 +#define HCI_ERROR_CODE_UNKNOWN_LMP_PDU 0x19 +#define HCI_ERROR_CODE_UNSUPPORTED_REMOTE_FEATURE 0x1A +#define HCI_ERROR_CODE_SCO_OFFSET_REJ 0x1B +#define HCI_ERROR_CODE_SCO_INTERVAL_REJ 0x1C +#define HCI_ERROR_CODE_SCO_AIR_MODE_REJ 0x1D +#define HCI_ERROR_CODE_INVALID_LMP_PARAMS 0x1E +#define HCI_ERROR_CODE_UNSPECIFIED_ERROR 0x1F +#define HCI_ERROR_CODE_UNSUPPORTED_LMP_PARAM_VAL 0x20 +#define HCI_ERROR_CODE_ROLE_CHANGE_NOT_ALLOWED 0x21 +#define HCI_ERROR_CODE_LMP_LL_RESP_TIMEOUT 0x22 +#define HCI_ERROR_CODE_LMP_ERR_TRANSACTION_COLLISION 0x23 +#define HCI_ERROR_CODE_LMP_PDU_NOT_ALLOWED 0x24 +#define HCI_ERROR_CODE_ENCRYPT_MODE_NOT_ACCEPTABLE 0x25 +#define HCI_ERROR_CODE_LINK_KEY_CAN_NOT_BE_CHANGED 0x26 +#define HCI_ERROR_CODE_REQ_QOS_NOT_SUPPORTED 0x27 +#define HCI_ERROR_CODE_INSTANT_PASSED 0x28 +#define HCI_ERROR_CODE_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED 0x29 +#define HCI_ERROR_CODE_DIFFERENT_TRANSACTION_COLLISION 0x2A +#define HCI_ERROR_CODE_RESERVED1 0x2B +#define HCI_ERROR_CODE_QOS_UNACCEPTABLE_PARAM 0x2C +#define HCI_ERROR_CODE_QOS_REJ 0x2D +#define HCI_ERROR_CODE_CHAN_ASSESSMENT_NOT_SUPPORTED 0x2E +#define HCI_ERROR_CODE_INSUFFICIENT_SECURITY 0x2F +#define HCI_ERROR_CODE_PARAM_OUT_OF_MANDATORY_RANGE 0x30 +#define HCI_ERROR_CODE_RESERVED2 0x31 +#define HCI_ERROR_CODE_ROLE_SWITCH_PENDING 0x32 +#define HCI_ERROR_CODE_RESERVED3 0x33 +#define HCI_ERROR_CODE_RESERVED_SLOT_VIOLATION 0x34 +#define HCI_ERROR_CODE_ROLE_SWITCH_FAILED 0x35 +#define HCI_ERROR_CODE_EXTENDED_INQUIRY_RESP_TOO_LARGE 0x36 +#define HCI_ERROR_CODE_SIMPLE_PAIRING_NOT_SUPPORTED_BY_HOST 0x37 +#define HCI_ERROR_CODE_HOST_BUSY_PAIRING 0x38 +#define HCI_ERROR_CODE_CONN_REJ_NO_SUITABLE_CHAN_FOUND 0x39 +#define HCI_ERROR_CODE_CONTROLLER_BUSY 0x3A +#define HCI_ERROR_CODE_UNACCEPTABLE_CONN_INTERVAL 0x3B +#define HCI_ERROR_CODE_DIRECTED_ADV_TIMEOUT 0x3C +#define HCI_ERROR_CODE_CONN_TERM_MIC_FAILURE 0x3D +#define HCI_ERROR_CODE_CONN_FAILED_TO_ESTABLISH 0x3E +#define HCI_ERROR_CODE_MAC_CONN_FAILED 0x3F + +/* +** Max Buffers Supported +*/ +#define HCI_MAX_NUM_DATA_BUFFERS LL_MAX_NUM_DATA_BUFFERS +#define HCI_MAX_NUM_CMD_BUFFERS LL_MAX_NUM_CMD_BUFFERS + +/* +** HCI Command API Parameters +*/ + +// Send Data Packet Boundary Flags +#define FIRST_PKT_HOST_TO_CTRL LL_DATA_FIRST_PKT_HOST_TO_CTRL +#define CONTINUING_PKT LL_DATA_CONTINUATION_PKT +#define FIRST_PKT_CTRL_TO_HOST LL_DATA_FIRST_PKT_CTRL_TO_HOST + +// Receive Data Packet +#define HCI_RSSI_NOT_AVAILABLE LL_RSSI_NOT_AVAILABLE + +// Disconnect Reasons +#define HCI_DISCONNECT_AUTH_FAILURE HCI_ERROR_CODE_AUTH_FAILURE +#define HCI_DISCONNECT_REMOTE_USER_TERM HCI_ERROR_CODE_REMOTE_USER_TERM_CONN +#define HCI_DISCONNECT_REMOTE_DEV_LOW_RESOURCES HCI_ERROR_CODE_REMOTE_DEVICE_TERM_CONN_LOW_RESOURCES +#define HCI_DISCONNECT_REMOTE_DEV_POWER_OFF HCI_ERROR_CODE_REMOTE_DEVICE_TERM_CONN_POWER_OFF +#define HCI_DISCONNECT_UNSUPPORTED_REMOTE_FEATURE HCI_ERROR_CODE_UNSUPPORTED_REMOTE_FEATURE +#define HCI_DISCONNECT_KEY_PAIRING_NOT_SUPPORTED HCI_ERROR_CODE_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED +#define HCI_DISCONNECT_UNACCEPTABLE_CONN_INTERVAL HCI_ERROR_CODE_UNACCEPTABLE_CONN_INTERVAL + +// Tx Power Types +#define HCI_READ_CURRENT_TX_POWER_LEVEL LL_READ_CURRENT_TX_POWER_LEVEL +#define HCI_READ_MAX_TX_POWER_LEVEL LL_READ_MAX_TX_POWER_LEVEL + +// Host Flow Control +#define HCI_CTRL_TO_HOST_FLOW_CTRL_OFF 0 +#define HCI_CTRL_TO_HOST_FLOW_CTRL_ACL_ON_SYNCH_OFF 1 +#define HCI_CTRL_TO_HOST_FLOW_CTRL_ACL_OFF_SYNCH_ON 2 +#define HCI_CTRL_TO_HOST_FLOW_CTRL_ACL_ON_SYNCH_ON 3 + +// Device Address Type +#define HCI_PUBLIC_DEVICE_ADDRESS LL_DEV_ADDR_TYPE_PUBLIC +#define HCI_RANDOM_DEVICE_ADDRESS LL_DEV_ADDR_TYPE_RANDOM + +// Advertiser Events +#define HCI_CONNECTABLE_UNDIRECTED_ADV LL_ADV_CONNECTABLE_UNDIRECTED_EVT +#define HCI_CONNECTABLE_DIRECTED_HDC_ADV LL_ADV_CONNECTABLE_DIRECTED_HDC_EVT +#define HCI_SCANNABLE_UNDIRECTED LL_ADV_SCANNABLE_UNDIRECTED_EVT +#define HCI_NONCONNECTABLE_UNDIRECTED_ADV LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT +#define HCI_CONNECTABLE_DIRECTED_LDC_ADV LL_ADV_CONNECTABLE_DIRECTED_LDC_EVT + +// Advertiser Channels +#define HCI_ADV_CHAN_37 LL_ADV_CHAN_37 +#define HCI_ADV_CHAN_38 LL_ADV_CHAN_38 +#define HCI_ADV_CHAN_39 LL_ADV_CHAN_39 +#define HCI_ADV_CHAN_ALL (LL_ADV_CHAN_37 | LL_ADV_CHAN_38 | LL_ADV_CHAN_39) + +// Advertiser White List Policy +#define HCI_ADV_WL_POLICY_ANY_REQ LL_ADV_WL_POLICY_ANY_REQ +#define HCI_ADV_WL_POLICY_WL_SCAN_REQ LL_ADV_WL_POLICY_WL_SCAN_REQ +#define HCI_ADV_WL_POLICY_WL_CONNECT_REQ LL_ADV_WL_POLICY_WL_CONNECT_REQ +#define HCI_ADV_WL_POLICY_WL_ALL_REQ LL_ADV_WL_POLICY_WL_ALL_REQ + +// Advertiser Commands +#define HCI_ENABLE_ADV LL_ADV_MODE_ON +#define HCI_DISABLE_ADV LL_ADV_MODE_OFF + +// Scan Types +#define HCI_SCAN_PASSIVE LL_SCAN_PASSIVE +#define HCI_SCAN_ACTIVE LL_SCAN_ACTIVE + +// Scan White List Policy +#define HCI_SCAN_WL_POLICY_ANY_ADV_PKTS LL_SCAN_WL_POLICY_ANY_ADV_PKTS +#define HCI_SCAN_WL_POLICY_USE_WHITE_LIST LL_SCAN_WL_POLICY_USE_WHITE_LIST + +// Scan Filtering +#define HCI_FILTER_REPORTS_DISABLE LL_FILTER_REPORTS_DISABLE +#define HCI_FILTER_REPORTS_ENABLE LL_FILTER_REPORTS_ENABLE + +// Scan Commands +#define HCI_SCAN_STOP LL_SCAN_STOP +#define HCI_SCAN_START LL_SCAN_START + +// Initiator White List Policy +#define HCI_INIT_WL_POLICY_USE_PEER_ADDR LL_INIT_WL_POLICY_USE_PEER_ADDR +#define HCI_INIT_WL_POLICY_USE_WHITE_LIST LL_INIT_WL_POLICY_USE_WHITE_LIST + +// Encryption Related +#define HCI_ENCRYPTION_OFF LL_ENCRYPTION_OFF +#define HCI_ENCRYPTION_ON LL_ENCRYPTION_ON + +// Direct Test Mode +#define HCI_DTM_NUMBER_RF_CHANS LL_DIRECT_TEST_NUM_RF_CHANS +#define HCI_DIRECT_TEST_MAX_PAYLOAD_LEN LL_DIRECT_TEST_MAX_PAYLOAD_LEN +// +#define HCI_DIRECT_TEST_PAYLOAD_PRBS9 LL_DIRECT_TEST_PAYLOAD_PRBS9 +#define HCI_DIRECT_TEST_PAYLOAD_0x0F LL_DIRECT_TEST_PAYLOAD_0x0F +#define HCI_DIRECT_TEST_PAYLOAD_0x55 LL_DIRECT_TEST_PAYLOAD_0x55 +#define HCI_DIRECT_TEST_PAYLOAD_PRBS15 LL_DIRECT_TEST_PAYLOAD_PRBS15 +#define HCI_DIRECT_TEST_PAYLOAD_0xFF LL_DIRECT_TEST_PAYLOAD_0xFF +#define HCI_DIRECT_TEST_PAYLOAD_0x00 LL_DIRECT_TEST_PAYLOAD_0x00 +#define HCI_DIRECT_TEST_PAYLOAD_0xF0 LL_DIRECT_TEST_PAYLOAD_0xF0 +#define HCI_DIRECT_TEST_PAYLOAD_0xAA LL_DIRECT_TEST_PAYLOAD_0xAA + +// Vendor Specific +#define HCI_EXT_RX_GAIN_STD LL_EXT_RX_GAIN_STD +#define HCI_EXT_RX_GAIN_HIGH LL_EXT_RX_GAIN_HIGH +// +#define HCI_EXT_TX_POWER_MINUS_23_DBM LL_EXT_TX_POWER_MINUS_23_DBM +#define HCI_EXT_TX_POWER_MINUS_6_DBM LL_EXT_TX_POWER_MINUS_6_DBM +#define HCI_EXT_TX_POWER_0_DBM LL_EXT_TX_POWER_0_DBM +#define HCI_EXT_TX_POWER_4_DBM LL_EXT_TX_POWER_4_DBM +// +#define HCI_EXT_ENABLE_ONE_PKT_PER_EVT LL_EXT_ENABLE_ONE_PKT_PER_EVT +#define HCI_EXT_DISABLE_ONE_PKT_PER_EVT LL_EXT_DISABLE_ONE_PKT_PER_EVT +// +#define HCI_EXT_ENABLE_CLK_DIVIDE_ON_HALT LL_EXT_ENABLE_CLK_DIVIDE_ON_HALT +#define HCI_EXT_DISABLE_CLK_DIVIDE_ON_HALT LL_EXT_DISABLE_CLK_DIVIDE_ON_HALT +// +#define HCI_EXT_NV_IN_USE LL_EXT_NV_IN_USE +#define HCI_EXT_NV_NOT_IN_USE LL_EXT_NV_NOT_IN_USE +// +#define HCI_EXT_ENABLE_FAST_TX_RESP_TIME LL_EXT_ENABLE_FAST_TX_RESP_TIME +#define HCI_EXT_DISABLE_FAST_TX_RESP_TIME LL_EXT_DISABLE_FAST_TX_RESP_TIME +// +#define HCI_EXT_ENABLE_SL_OVERRIDE LL_EXT_ENABLE_SL_OVERRIDE +#define HCI_EXT_DISABLE_SL_OVERRIDE LL_EXT_DISABLE_SL_OVERRIDE +// +#define HCI_EXT_TX_MODULATED_CARRIER LL_EXT_TX_MODULATED_CARRIER +#define HCI_EXT_TX_UNMODULATED_CARRIER LL_EXT_TX_UNMODULATED_CARRIER +// +#define HCI_PTM_SET_FREQ_TUNE_DOWN LL_EXT_SET_FREQ_TUNE_DOWN +#define HCI_PTM_SET_FREQ_TUNE_UP LL_EXT_SET_FREQ_TUNE_UP +// +#define HCI_EXT_PM_IO_PORT_P0 LL_EXT_PM_IO_PORT_P0 +#define HCI_EXT_PM_IO_PORT_P1 LL_EXT_PM_IO_PORT_P1 +#define HCI_EXT_PM_IO_PORT_P2 LL_EXT_PM_IO_PORT_P2 +#define HCI_EXT_PM_IO_PORT_NONE LL_EXT_PM_IO_PORT_NONE +// +#define HCI_EXT_PM_IO_PORT_PIN0 LL_EXT_PM_IO_PORT_PIN0 +#define HCI_EXT_PM_IO_PORT_PIN1 LL_EXT_PM_IO_PORT_PIN1 +#define HCI_EXT_PM_IO_PORT_PIN2 LL_EXT_PM_IO_PORT_PIN2 +#define HCI_EXT_PM_IO_PORT_PIN3 LL_EXT_PM_IO_PORT_PIN3 +#define HCI_EXT_PM_IO_PORT_PIN4 LL_EXT_PM_IO_PORT_PIN4 +#define HCI_EXT_PM_IO_PORT_PIN5 LL_EXT_PM_IO_PORT_PIN5 +#define HCI_EXT_PM_IO_PORT_PIN6 LL_EXT_PM_IO_PORT_PIN6 +#define HCI_EXT_PM_IO_PORT_PIN7 LL_EXT_PM_IO_PORT_PIN7 +// +#define HCI_EXT_PER_RESET LL_EXT_PER_RESET +#define HCI_EXT_PER_READ LL_EXT_PER_READ +// +#define HCI_EXT_HALT_DURING_RF_DISABLE LL_EXT_HALT_DURING_RF_DISABLE +#define HCI_EXT_HALT_DURING_RF_ENABLE LL_EXT_HALT_DURING_RF_ENABLE +// +#define HCI_EXT_SET_USER_REVISION LL_EXT_SET_USER_REVISION +#define HCI_EXT_READ_BUILD_REVISION LL_EXT_READ_BUILD_REVISION +// +#define HCI_EXT_RESET_SYSTEM_HARD LL_EXT_RESET_SYSTEM_HARD +#define HCI_EXT_RESET_SYSTEM_SOFT LL_EXT_RESET_SYSTEM_SOFT +// +#define HCI_EXT_DISABLE_OVERLAPPED_PROCESSING LL_EXT_DISABLE_OVERLAPPED_PROCESSING +#define HCI_EXT_ENABLE_OVERLAPPED_PROCESSING LL_EXT_ENABLE_OVERLAPPED_PROCESSING +// +#define HCI_EXT_DISABLE_NUM_COMPL_PKTS_ON_EVENT LL_EXT_DISABLE_NUM_COMPL_PKTS_ON_EVENT +#define HCI_EXT_ENABLE_NUM_COMPL_PKTS_ON_EVENT LL_EXT_ENABLE_NUM_COMPL_PKTS_ON_EVENT + +/* +** HCI Event Parameters +*/ + +// HCI Link Type for Buffer Overflow +#define HCI_LINK_TYPE_SCO_BUFFER_OVERFLOW 0 +#define HCI_LINK_TYPE_ACL_BUFFER_OVERFLOW 1 + +/******************************************************************************* + TYPEDEFS +*/ + +typedef uint8 hciStatus_t; + +/* +** LE Events +*/ + +// LE Connection Complete Event +typedef struct +{ + osal_event_hdr_t hdr; + uint8 BLEEventCode; + uint8 status; + uint16 connectionHandle; + uint8 role; + uint8 peerAddrType; + uint8 peerAddr[B_ADDR_LEN]; + uint16 connInterval; + uint16 connLatency; + uint16 connTimeout; + uint8 clockAccuracy; +} hciEvt_BLEConnComplete_t; + +// LE Connection Complete Event +typedef struct +{ + osal_event_hdr_t hdr; + uint8 BLEEventCode; + uint8 status; + uint16 connectionHandle; + uint8 role; + uint8 peerAddrType; + uint8 peerAddr[B_ADDR_LEN]; + uint8 localRpaAddr[B_ADDR_LEN]; + uint8 peerRpaAddr[B_ADDR_LEN]; + uint16 connInterval; + uint16 connLatency; + uint16 connTimeout; + uint8 clockAccuracy; +} hciEvt_BLEEnhConnComplete_t; + +// LE Advertising Report Event +typedef struct +{ + uint8 eventType; // advertisment or scan response event type + uint8 addrType; // public or random address type + uint8 addr[B_ADDR_LEN]; // device address + uint8 dataLen; // length of report data + uint8 rspData[B_MAX_ADV_LEN]; // report data given by dataLen + int8 rssi; // report RSSI +} hciEvt_DevInfo_t; + +typedef struct +{ + osal_event_hdr_t hdr; + uint8 BLEEventCode; + uint8 numDevices; + hciEvt_DevInfo_t* devInfo; // pointer to the array of devInfo +} hciEvt_BLEAdvPktReport_t; + +// LE Connection Update Complete Event +typedef struct +{ + osal_event_hdr_t hdr; + uint8 BLEEventCode; + uint8 status; + uint16 connectionHandle; + uint16 connInterval; + uint16 connLatency; + uint16 connTimeout; +} hciEvt_BLEConnUpdateComplete_t; + +// LE Read Remote Used Features Complete Event +typedef struct +{ + osal_event_hdr_t hdr; + uint8 BLEEventCode; + uint8 status; + uint16 connectionHandle; + uint8 features[8]; +} hciEvt_BLEReadRemoteFeatureComplete_t; + +// LE Encryption Change Event +typedef struct +{ + osal_event_hdr_t hdr; + uint8 BLEEventCode; + uint16 connHandle; + uint8 reason; + uint8 encEnable; +} hciEvt_EncryptChange_t; + +// LE Long Term Key Requested Event +typedef struct +{ + osal_event_hdr_t hdr; + uint8 BLEEventCode; + uint16 connHandle; + uint8 random[B_RANDOM_NUM_SIZE]; + uint16 encryptedDiversifier; +} hciEvt_BLELTKReq_t; + +// LE DATE LENGTH CHANGE Event +typedef struct +{ + osal_event_hdr_t hdr; + uint8 BLEEventCode; + uint16 connHandle; + uint16 MaxTxOctets; + uint16 MaxTxTime; + uint16 MaxRxOctets; + uint16 MaxRxTime; +} hciEvt_BLEDataLenChange_t; + +// LE PHY UPDATE Complete Event +typedef struct +{ + osal_event_hdr_t hdr; + uint8 BLEEventCode; + uint8 status; + uint16 connHandle; + uint8 txPhy; + uint8 rxPhy; +} hciEvt_BLEPhyUpdateComplete_t; + +// LE PHY UPDATE Complete Event +typedef struct +{ + osal_event_hdr_t hdr; + uint8 BLEEventCode; +} hciEvt_BLEEvent_Hdr_t; + +// Number of Completed Packets Event +typedef struct +{ + osal_event_hdr_t hdr; + uint8 numHandles; + uint16* pConnectionHandle; // pointer to the connection handle array + uint16* pNumCompletedPackets; // pointer to the number of completed packets array +} hciEvt_NumCompletedPkt_t; + +// Command Complete Event +typedef struct +{ + osal_event_hdr_t hdr; + uint8 numHciCmdPkt; // number of HCI Command Packet + uint16 cmdOpcode; + uint8* pReturnParam; // pointer to the return parameter +} hciEvt_CmdComplete_t; + +// Command Status Event +typedef struct +{ + osal_event_hdr_t hdr; + uint8 cmdStatus; + uint8 numHciCmdPkt; + uint16 cmdOpcode; +} hciEvt_CommandStatus_t; + +// Hardware Error Event +typedef struct +{ + osal_event_hdr_t hdr; + uint8 hardwareCode; +} hciEvt_HardwareError_t; + +// Disconnection Complete Event +typedef struct +{ + osal_event_hdr_t hdr; + uint8 status; + uint16 connHandle; // connection handle + uint8 reason; +} hciEvt_DisconnComplete_t; + +// Data Buffer Overflow Event +typedef struct +{ + osal_event_hdr_t hdr; + uint8 linkType; // synchronous or asynchronous buffer overflow +} hciEvt_BufferOverflow_t; + +// Data structure for HCI Command Complete Event Return Parameter +typedef struct +{ + uint8 status; + uint16 dataPktLen; + uint8 numDataPkts; +} hciRetParam_LeReadBufSize_t; + +typedef struct +{ + uint16 eventType; // advertisment or scan response event type + uint8 addrType; // public or random address type + uint8 addr[B_ADDR_LEN]; // device address + uint8 primaryPHY; + uint8 secondaryPHY; + uint8 advertisingSID; + uint8 txPower; + int8 rssi; // report RSSI + uint16 periodicAdvertisingInterval; + uint8 directAddrType; + uint8 directAddr[B_ADDR_LEN]; + uint8 dataLen; // length of report data + uint8 rptData[B_MAX_EXT_ADV_LEN]; // report data given by dataLen +} hciEvt_ExtAdvRptInfo_t; + +// Extended adv report +typedef struct +{ + osal_event_hdr_t hdr; + uint8 BLEEventCode; + uint8 numReports; + hciEvt_ExtAdvRptInfo_t* rptInfo; // pointer to the array of devInfo +} hciEvt_BLEExtAdvPktReport_t; + + +typedef struct +{ + osal_event_hdr_t hdr; + uint8 BLEEventCode; + uint8 status; + uint16 syncHandle; + uint8 advertisingSID; + uint8 advertiserAddressType; + uint8 advertiserAddress[B_ADDR_LEN]; + uint8 advertiserPHY; + uint16 periodicAdvertisingInterval; + uint8 advertiserClockAccuracy; +} hciEvt_BLEPrdAdvSyncEstabPkt_t; + +typedef struct +{ + osal_event_hdr_t hdr; + uint8 BLEEventCode; + uint16 syncHandle; +} hciEvt_BLEPrdAdvSyncLostPkt_t; + +// 2020-4-22 LE Advertising Set Terminated event +typedef struct +{ + osal_event_hdr_t hdr; + uint8 BLEEventCode; + uint8 status; + uint8 adv_handle; + uint16 connHandle; // connection handle + uint8 Num_Completed_Extended_Advertising_Events; +} hciEvt_AdvSetTerminated_t; + +// 2020-4-22 LE Channel Selection Algorithm event +typedef struct +{ + osal_event_hdr_t hdr; + uint8 BLEEventCode; + uint16 connHandle; // connection handle + uint8 chn_sel; +} hciEvt_ChannelSelAlgo_t; + +// 2020-01-14 LE IQ report event structure +typedef struct +{ + uint16 Handle; // syncHandle for connectionless handle , connection for connection Handle + uint8 chan_idx; + int16 rssi; + uint8 rssi_antID; + uint8 cte_type; + uint8 slot_duration; + uint8 packet_status; + uint16 EventCnt; // paEventcounter or connEventCounter + uint8 sampCnt; + uint8 ISample[B_MAX_IQ_LEN]; + uint8 QSample[B_MAX_IQ_LEN]; +} hciEvt_IQReportPkt_t; + +// 2020-01-14 LE Connectionless IQ report event structure +typedef struct +{ + osal_event_hdr_t hdr; + uint8 BLEEventCode; + hciEvt_IQReportPkt_t ConnectionlessIQ; +} hciEvt_BLEConnectionlessIQ_Pkt_t; + +// 2020-01-14 LE Connection IQ report event structure +typedef struct +{ + osal_event_hdr_t hdr; + uint8 BLEEventCode; + uint8 RX_PHY; + hciEvt_IQReportPkt_t ConnectionIQ; +} hciEvt_BLEConnectionIQ_Pkt_t; + +// 2020-01-14 LE Connection IQ report event structure +typedef struct +{ + osal_event_hdr_t hdr; + uint8 BLEEventCode; + uint8 status; + uint16 connHandle; +} hciEvt_BLE_CTEReport_Pkt_t; + + +typedef struct +{ + uint16 syncHandle; + uint8 txPower; + uint8 rssi; + uint8 cteType; + uint8 dataStatus; + uint8 dataLength; + uint8 data[B_MAX_PERIOD_ADV_LEN]; +} hciEvt_PrdAdvRptInfo_t; + + + +// Periodic adv report +typedef struct +{ + osal_event_hdr_t hdr; + uint8 BLEEventCode; + hciEvt_PrdAdvRptInfo_t* rptInfo; // pointer to the array of devInfo +} hciEvt_BLEPrdAdvPktReport_t; + +typedef struct +{ + osal_event_hdr_t hdr; + uint8* pData; +} hciPacket_t; + +typedef struct +{ + osal_event_hdr_t hdr; + uint8 pktType; + uint16 connHandle; + uint8 pbFlag; + uint16 pktLen; + uint8* pData; +} hciDataPacket_t; + +// OSAL HCI_DATA_EVENT message format. This message is used to forward incoming +// data messages up to an application +typedef struct +{ + osal_event_hdr_t hdr; // OSAL event header + uint16 connHandle; // connection handle + uint8 pbFlag; // data packet boundary flag + uint16 len; // length of data packet + uint8* pData; // data packet given by len +} hciDataEvent_t; + + + + +/******************************************************************************* + LOCAL VARIABLES +*/ + +/******************************************************************************* + GLOBAL VARIABLES +*/ + +/* +** HCI Support Functions +*/ + +/******************************************************************************* + @fn HCI_bm_alloc API + + @brief This API is used to allocate memory using buffer management. + + Note: This function should never be called by the application. + It is only used by HCI and L2CAP_bm_alloc. + + input parameters + + @param size - Number of bytes to allocate from the heap. + + output parameters + + @param None. + + @return Pointer to buffer, or NULL. +*/ +extern void* HCI_bm_alloc( uint16 size ); + + +/******************************************************************************* + @fn HCI_ValidConnTimeParams API + + @brief This API is used to check that the connection time parameter + ranges are valid, and that the connection time parameter + combination is valid. + + Note: Only connIntervalMax is used as part of the time parameter + combination check. + + input parameters + + @param connIntervalMin - Minimum connection interval. + @param connIntervalMax - Maximum connection interval. + @param connLatency - Connection slave latency. + @param connTimeout - Connection supervision timeout. + + output parameters + + @param None. + + @return TRUE: Connection time parameter check is valid. + FALSE: Connection time parameter check is invalid. +*/ +extern uint8 HCI_ValidConnTimeParams( uint16 connIntervalMin, + uint16 connIntervalMax, + uint16 connLatency, + uint16 connTimeout ); + + +/******************************************************************************* + @fn HCI_TestAppTaskRegister + + @brief HCI vendor specific registration for HCI Test Application. + + input parameters + + @param taskID - The HCI Test Application OSAL task identifer. + + output parameters + + @param None. + + @return None. +*/ +extern void HCI_TestAppTaskRegister( uint8 taskID ); + + +/******************************************************************************* + @fn HCI_GAPTaskRegister + + @brief HCI vendor specific registration for Host GAP. + + input parameters + + @param taskID - The Host GAP OSAL task identifer. + + output parameters + + @param None. + + @return None. +*/ +extern void HCI_GAPTaskRegister( uint8 taskID ); + + +/******************************************************************************* + + @fn HCI_L2CAPTaskRegister + + @brief HCI vendor specific registration for Host L2CAP. + + input parameters + + @param taskID - The Host L2CAP OSAL task identifer. + + output parameters + + @param None. + + @return None. + +*/ +extern void HCI_L2CAPTaskRegister( uint8 taskID ); + + +/******************************************************************************* + @fn HCI_SMPTaskRegister + + @brief HCI vendor specific registration for Host SMP. + + input parameters + + @param taskID - The Host SMP OSAL task identifer. + + output parameters + + @param None. + + @return None. +*/ +extern void HCI_SMPTaskRegister( uint8 taskID ); + + +/******************************************************************************* + @fn HCI_ExtTaskRegister + + @brief HCI vendor specific registration for Host extended commands. + + input parameters + + @param taskID - The Host Extended Command OSAL task identifer. + + output parameters + + @param None. + + @return None. +*/ +extern void HCI_ExtTaskRegister( uint8 taskID ); + + +/******************************************************************************* + @fn HCI_SendDataPkt API + + @brief This API is used to send a ACL data packet over a connection. + + Note: Empty packets are not sent. + + Related Events: HCI_NumOfCompletedPacketsEvent + + input parameters + + @param connHandle - Connection ID (handle). + @param pbFlag - Packet Boundary Flag. + @param pktLen - Number of bytes of data to transmit. + @param *pData - Pointer to data buffer to transmit. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_SendDataPkt( uint16 connHandle, + uint8 pbFlag, + uint16 pktLen, + uint8* pData ); + + + +/* +** HCI API +*/ + +/******************************************************************************* + @fn HCI_DisconnectCmd API + + @brief This BT API is used to terminate a connection. + + Related Events: HCI_CommandStatusEvent, + DisconnectEvent + + input parameters + + @param connHandle - Connection handle. + @param reason - Reason for disconnection: + HCI_DISCONNECT_AUTH_FAILURE, + HCI_DISCONNECT_REMOTE_USER_TERM, + HCI_DISCONNECT_REMOTE_DEV_POWER_OFF, + HCI_DISCONNECT_UNSUPPORTED_REMOTE_FEATURE, + HCI_DISCONNECT_KEY_PAIRING_NOT_SUPPORTED + HCI_DISCONNECT_UNACCEPTABLE_CONN_INTERVAL + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_DisconnectCmd( uint16 connHandle, + uint8 reason ); + + +/******************************************************************************* + @fn HCI_ReadRemoteVersionInfoCmd API + + @brief This BT API is used to request version information from the + the remote device in a connection. + + Related Events: HCI_CommandStatusEvent, + ReadRemoteVersionInfoEvent + + input parameters + + @param connHandle - Connection handle. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_ReadRemoteVersionInfoCmd( uint16 connHandle ); + + + +/******************************************************************************* + @fn HCI_SetEventMaskCmd API + + @brief This BT API is used to set the HCI event mask, which is used to + determine which events are supported. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param pMask - Pointer to an eight byte event mask. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_SetEventMaskCmd( uint8* pMask ); + + +/******************************************************************************* + @fn HCI_Reset API + + @brief This BT API is used to reset the Link Layer. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param None. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_ResetCmd( void ); + + + +/******************************************************************************* + @fn HCI_ReadTransmitPowerLevelCmd API + + @brief This BT API is used to read the transmit power level. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param connHandle - Connection handle. + @param txPwrType - HCI_READ_CURRENT_TX_POWER_LEVEL, + HCI_READ_MAXIMUM_TX_POWER_LEVEL + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_ReadTransmitPowerLevelCmd( uint16 connHandle, + uint8 txPwrType ); + + +/******************************************************************************* + @fn HCI_SetControllerToHostFlowCtrlCmd API + + @brief This BT API is used by the Host to turn flow control on or off + for data sent from the Controller to Host. + + Note: This command is currently not supported. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param flowControlEnable - HCI_CTRL_TO_HOST_FLOW_CTRL_OFF, + HCI_CTRL_TO_HOST_FLOW_CTRL_ACL_ON_SYNCH_OFF, + HCI_CTRL_TO_HOST_FLOW_CTRL_ACL_OFF_SYNCH_ON, + HCI_CTRL_TO_HOST_FLOW_CTRL_ACL_ON_SYNCH_ON + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_SetControllerToHostFlowCtrlCmd( uint8 flowControlEnable ); + + +/******************************************************************************* + @fn HCI_HostBufferSizeCmd API + + @brief This BT API is used by the Host to notify the Controller of the + maximum size ACL buffer size the Controller can send to the + Host. + + Note: This command is currently ignored by the Controller. It + is assumed that the Host can always handle the maximum + BLE data packet size. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param hostAclPktLen - Host ACL data packet length. + @param hostSyncPktLen - Host SCO data packet length . + @param hostTotalNumAclPkts - Host total number of ACL data packets. + @param hostTotalNumSyncPkts - Host total number of SCO data packets. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_HostBufferSizeCmd( uint16 hostAclPktLen, + uint8 hostSyncPktLen, + uint16 hostTotalNumAclPkts, + uint16 hostTotalNumSyncPkts ); + + +/******************************************************************************* + @fn HCI_HostNumCompletedPktCmd API + + @brief This BT API is used by the Host to notify the Controller of the + number of HCI data packets that have been completed for each + connection handle since this command was previously sent to the + controller. + + The Host_Number_Of_Conpleted_Packets command is a special + command. No event is normally generated after the command + has completed. The command should only be issued by the + Host if flow control in the direction from controller to + the host is on and there is at least one connection, or + if the controller is in local loopback mode. + + Note: It is assumed that there will be at most only one handle. + Even if more than one handle is provided, the Controller + does not track Host buffers as a function of connection + handles (and isn't required to do so). + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param numHandles - Number of connection handles. + @param connHandles - Array of connection handles. + @param numCompletedPkts - Array of number of completed packets. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_HostNumCompletedPktCmd( uint8 numHandles, + uint16* connHandles, + uint16* numCompletedPkts ); + + +/******************************************************************************* + @fn HCI_ReadLocalVersionInfoCmd API + + @brief This BT API is used to read the local version information. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param None. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_ReadLocalVersionInfoCmd( void ); + + +/******************************************************************************* + @fn HCI_ReadLocalSupportedCommandsCmd API + + @brief This BT API is used to read the locally supported commands. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param None. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_ReadLocalSupportedCommandsCmd( void ); + + +/******************************************************************************* + @fn HCI_ReadLocalSupportedFeaturesCmd API + + @brief This BT API is used to read the locally supported features. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param None. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_ReadLocalSupportedFeaturesCmd( void ); + + +/******************************************************************************* + @fn HCI_ReadBDADDRCmd API + + @brief This BT API is used to read this device's BLE address (BDADDR). + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param None. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_ReadBDADDRCmd( void ); + + +/******************************************************************************* + @fn HCI_ReadRssiCmd API + + @brief This BT API is used to read the RSSI of the last packet + received on a connection given by the connection handle. If + the Receiver Modem test is running (HCI_EXT_ModemTestRx), then + the RF RSSI for the last received data will be returned. If + there is no RSSI value, then HCI_RSSI_NOT_AVAILABLE will be + returned. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param connHandle - Connection handle. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_ReadRssiCmd( uint16 connHandle ); + +/* +** HCI Low Energy Commands +*/ + +/******************************************************************************* + @fn HCI_LE_SetEventMaskCmd API + + @brief This LE API is used to set the HCI LE event mask, which is used + to determine which LE events are supported. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param pEventMask - Pointer to LE event mask of 8 bytes. + + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_SetEventMaskCmd( uint8* pEventMask ); + + +/******************************************************************************* + @fn HCI_LE_ReadBufSizeCmd API + + @brief This LE API is used by the Host to determine the maximum ACL + data packet size allowed by the Controller. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param None. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_ReadBufSizeCmd( void ); + + +/******************************************************************************* + @fn HCI_LE_ReadLocalSupportedFeaturesCmd API + + @brief This LE API is used to read the LE locally supported features. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param None. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_ReadLocalSupportedFeaturesCmd( void ); + + +/******************************************************************************* + @fn HCI_LE_SetRandomAddressCmd API + + @brief This LE API is used to set this device's Random address. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param pRandAddr - Pointer to random address. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_SetRandomAddressCmd( uint8* pRandAddr ); + + + +/******************************************************************************* + @fn HCI_LE_SetAdvParamCmd API + + @brief This LE API is used to set the Advertising parameters. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param advIntervalMin - Minimum allowed advertising interval. + @param advIntervalMax - Maximum allowed advertising interval. + @param advType - HCI_CONNECTABLE_UNDIRECTED_ADV, + HCI_CONNECTABLE_DIRECTED_HDC_ADV, + HCI_SCANNABLE_UNDIRECTED, + HCI_NONCONNECTABLE_UNDIRECTED_ADV + HCI_CONNECTABLE_DIRECTED_LDC_ADV + @param ownAddrType - HCI_PUBLIC_DEVICE_ADDRESS, + HCI_RANDOM_DEVICE_ADDRESS + @param directAddrType - HCI_PUBLIC_DEVICE_ADDRESS, + HCI_RANDOM_DEVICE_ADDRESS + @param directAddr - Pointer to address of device when using + directed advertising. + @param advChannelMap - HCI_ADV_CHAN_37, + HCI_ADV_CHAN_38, + HCI_ADV_CHAN_39, + HCI_ADV_CHAN_37 | HCI_ADV_CHAN_38, + HCI_ADV_CHAN_37 | HCI_ADV_CHAN_39, + HCI_ADV_CHAN_38 | HCI_ADV_CHAN_39, + HCI_ADV_CHAN_ALL + @param advFilterPolicy - HCI_ADV_WL_POLICY_ANY_REQ, + HCI_ADV_WL_POLICY_WL_SCAN_REQ, + HCI_ADV_WL_POLICY_WL_CONNECT_REQ, + HCI_ADV_WL_POLICY_WL_ALL_REQ + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_SetAdvParamCmd( uint16 advIntervalMin, + uint16 advIntervalMax, + uint8 advType, + uint8 ownAddrType, + uint8 directAddrType, + uint8* directAddr, + uint8 advChannelMap, + uint8 advFilterPolicy ); + + +/******************************************************************************* + @fn HCI_LE_SetAdvDataCmd API + + @brief This LE API is used to set the Advertising data. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param dataLen - Length of Advertising data. + @param pData - Pointer to Advertising data. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_SetAdvDataCmd( uint8 dataLen, + uint8* pData ); + + +/******************************************************************************* + @fn HCI_LE_SetScanRspDataCmd API + + @brief This LE API is used to set the Advertising Scan Response data. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param dataLen - Length of Scan Response data. + @param pData - Pointer to Scan Response data. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_SetScanRspDataCmd( uint8 dataLen, + uint8* pData ); + + +/******************************************************************************* + @fn HCI_LE_SetAdvEnableCmd API + + @brief This LE API is used to turn Advertising on or off. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param advEnable - HCI_ENABLE_ADV, HCI_DISABLE_ADV + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_SetAdvEnableCmd( uint8 advEnable ); + + +/******************************************************************************* + @fn HCI_LE_ReadAdvChanTxPowerCmd API + + @brief This LE API is used to read transmit power when Advertising. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param None. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_ReadAdvChanTxPowerCmd( void ); + + +/******************************************************************************* + @fn HCI_LE_SetScanParamCmd API + + @brief This LE API is used to set the Scan parameters. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param scanType - HCI_SCAN_PASSIVE, HCI_SCAN_ACTIVE + @param scanInterval - Time between scan events. + @param scanWindow - Time of scan before scan event ends. + Note: When the scanWindow equals the scanInterval + then scanning is continuous. + @param ownAddrType - This device's address. + @param filterPolicy - HCI_SCAN_PASSIVE, HCI_SCAN_ACTIVE + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_SetScanParamCmd( uint8 scanType, + uint16 scanInterval, + uint16 scanWindow, + uint8 ownAddrType, + uint8 filterPolicy ); + + +/******************************************************************************* + @fn HCI_LE_SetScanEnableCmd API + + @brief This LE API is used to turn Scanning on or off. + + Related Events: HCI_CommandCompleteEvent, + AdvReportEvent + + input parameters + + @param scanEnable - HCI_SCAN_START, HCI_SCAN_STOP + @param filterDuplicates - HCI_FILTER_REPORTS_ENABLE, + HCI_FILTER_REPORTS_DISABLE + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_SetScanEnableCmd( uint8 scanEnable, + uint8 filterDuplicates ); + + +/******************************************************************************* + @fn HCI_LE_CreateConnCmd API + + @brief This LE API is used to create a connection. + + Related Events: HCI_CommandStatusEvent, + ConnectionCompleteEvent + + input parameters + + @param scanInterval - Time between Init scan events. + @param scanWindow - Time of scan before Init scan event ends. + Note: When the scanWindow equals the + scanInterval then scanning is + continuous. + @param initFilterPolicy - HCI_INIT_WL_POLICY_USE_PEER_ADDR, + HCI_INIT_WL_POLICY_USE_WHITE_LIST + @param addrTypePeer - HCI_PUBLIC_DEVICE_ADDRESS, + HCI_RANDOM_DEVICE_ADDRESS + @param peerAddr - Pointer to peer device's address. + @param ownAddrType - HCI_PUBLIC_DEVICE_ADDRESS, + HCI_RANDOM_DEVICE_ADDRESS + @param connIntervalMin - Minimum allowed connection interval. + @param connIntervalMax - Maximum allowed connection interval. + @param connLatency - Number of skipped events (slave latency). + @param connTimeout - Connection supervision timeout. + @param minLen - Info parameter about min length of conn. + @param maxLen - Info parameter about max length of conn. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_CreateConnCmd( uint16 scanInterval, + uint16 scanWindow, + uint8 initFilterPolicy, + uint8 addrTypePeer, + uint8* peerAddr, + uint8 ownAddrType, + uint16 connIntervalMin, + uint16 connIntervalMax, + uint16 connLatency, + uint16 connTimeout, + uint16 minLen, + uint16 maxLen ); + + +/******************************************************************************* + @fn HCI_LE_CreateConnCancelCmd API + + @brief This LE API is used to cancel a create connection. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param None. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_CreateConnCancelCmd( void ); + + +/******************************************************************************* + @fn HCI_LE_ReadWhiteListSizeCmd API + + @brief This LE API is used to read the white list. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param None. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_ReadWhiteListSizeCmd( void ); + + +/******************************************************************************* + @fn HCI_LE_ClearWhiteListCmd API + + @brief This LE API is used to clear the white list. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param None. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_ClearWhiteListCmd( void ); + + +/******************************************************************************* + @fn HCI_LE_AddWhiteListCmd API + + @brief This LE API is used to add a white list entry. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param addrType - HCI_PUBLIC_DEVICE_ADDRESS, HCI_RANDOM_DEVICE_ADDRESS + @param devAddr - Pointer to address of device to put in white list. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_AddWhiteListCmd( uint8 addrType, + uint8* devAddr ); + + +/******************************************************************************* + @fn HCI_LE_RemoveWhiteListCmd API + + @brief This LE API is used to remove a white list entry. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param addrType - HCI_PUBLIC_DEVICE_ADDRESS, HCI_RANDOM_DEVICE_ADDRESS + @param devAddr - Pointer to address of device to remove from the + white list. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_RemoveWhiteListCmd( uint8 addrType, + uint8* devAddr ); + + + +/******************************************************************************* + @fn HCI_LE_ConnUpdateCmd API + + @brief This LE API is used to update the connection parameters. + + Related Events: HCI_CommandStatusEvent, + ConnectionUpdateCompleteEvent + + input parameters + + @param connHandle - Time between Init scan events. + @param connIntervalMin - Minimum allowed connection interval. + @param connIntervalMax - Maximum allowed connection interval. + @param connLatency - Number of skipped events (slave latency). + @param connTimeout - Connection supervision timeout. + @param minLen - Info parameter about min length of conn. + @param maxLen - Info parameter about max length of conn. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_ConnUpdateCmd( uint16 connHandle, + uint16 connIntervalMin, + uint16 connIntervalMax, + uint16 connLatency, + uint16 connTimeout, + uint16 minLen, + uint16 maxLen ); + + +/******************************************************************************* + @fn HCI_LE_SetHostChanClassificationCmd API + + @brief This LE API is used to update the current data channel map. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param chanMap - Pointer to the new channel map. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_SetHostChanClassificationCmd( uint8* chanMap ); + + +/******************************************************************************* + @fn HCI_LE_ReadChannelMapCmd API + + @brief This LE API is used to read a connection's data channel map. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param connHandle - Connection handle. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_ReadChannelMapCmd( uint16 connHandle ); + +/******************************************************************************* + @fn HCI_LE_ReadRemoteUsedFeaturesCmd API + + @brief This LE API is used to read the remote device's used features. + + Related Events: HCI_CommandStatusEvent, + ReadRemoteUsedFeaturesCompleteEvent + + input parameters + + @param connHandle - Connection handle. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_ReadRemoteUsedFeaturesCmd( uint16 connHandle ); + + +/******************************************************************************* + @fn HCI_LE_EncryptCmd API + + @brief This LE API is used to perform an encryption using AES128. + + Note: Input parameters are ordered MSB..LSB. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param key - Pointer to 16 byte encryption key. + @param plainText - Pointer to 16 byte plaintext data. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_EncryptCmd( uint8* key, + uint8* plainText ); + + +/******************************************************************************* + @fn HCI_LE_RandCmd API + + @brief This LE API is used to generate a random number. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param None. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_RandCmd( void ); + + + +/******************************************************************************* + @fn HCI_LE_StartEncyptCmd API + + @brief This LE API is used to start encryption in a connection. + + Related Events: HCI_CommandStatusEvent, + EncChangeEvent or + EncKeyRefreshEvent + + input parameters + + @param connHandle - Connection handle. + @param random - Pointer to eight byte Random number. + @param encDiv - Pointer to two byte Encrypted Diversifier. + @param ltk - Pointer to 16 byte Long Term Key. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_StartEncyptCmd( uint16 connHandle, + uint8* random, + uint8* encDiv, + uint8* ltk ); + +/******************************************************************************* + @fn HCI_LE_LtkReqReplyCmd API + + @brief This LE API is used by the Host to send to the Controller a + positive LTK reply. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param connHandle - Connection handle. + @param ltk - Pointer to 16 byte Long Term Key. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_LtkReqReplyCmd( uint16 connHandle, + uint8* ltk ); + +/******************************************************************************* + @fn HCI_LE_LtkReqNegReplyCmd API + + @brief This LE API is used by the Host to send to the Controller a + negative LTK reply. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param connHandle - Connectin handle. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_LtkReqNegReplyCmd( uint16 connHandle ); + + +/******************************************************************************* + @fn HCI_LE_ReadSupportedStatesCmd API + + @brief This LE API is used to read the Controller's supported states. + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param None. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_ReadSupportedStatesCmd( void ); + + +/******************************************************************************* + @fn HCI_LE_ReceiverTestCmd API + + @brief This LE API is used to start the receiver Direct Test Mode test. + + Note: A HCI reset should be issued when done using DTM! + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param rxFreq - Rx RF frequency: + k=0..HCI_DTM_NUMBER_RF_CHANS-1, where: F=2402+(k*2MHz) + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_ReceiverTestCmd( uint8 rxFreq ); + + +/******************************************************************************* + @fn HCI_LE_TransmitterTestCmd API + + @brief This LE API is used to start the transmit Direct Test Mode test. + + Note: The BLE device is to transmit at maximum power! + + Note: A HCI reset should be issued when done using DTM! + + input parameters + + @param txFreq - Tx RF frequency: + k=0..HCI_DTM_NUMBER_RF_CHANS-1, where: + F=2402+(k*2MHz) + @param dataLen - Test data length in bytes: + 0..HCI_DIRECT_TEST_MAX_PAYLOAD_LEN + @param payloadType - Type of packet payload, per Direct Test Mode spec: + HCI_DIRECT_TEST_PAYLOAD_PRBS9, + HCI_DIRECT_TEST_PAYLOAD_0x0F, + HCI_DIRECT_TEST_PAYLOAD_0x55, + HCI_DIRECT_TEST_PAYLOAD_PRBS15, + HCI_DIRECT_TEST_PAYLOAD_0xFF, + HCI_DIRECT_TEST_PAYLOAD_0x00, + HCI_DIRECT_TEST_PAYLOAD_0xF0, + HCI_DIRECT_TEST_PAYLOAD_0xAA + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_TransmitterTestCmd( uint8 txFreq, + uint8 dataLen, + uint8 pktPayload ); + + +/******************************************************************************* + @fn HCI_LE_TestEndCmd API + + @brief This LE API is used to end the Direct Test Mode test. + + Note: A HCI reset should be issued when done using DTM! + + Related Events: HCI_CommandCompleteEvent + + input parameters + + @param None. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_LE_TestEndCmd( void ); + + +// BBB ROM code add +extern hciStatus_t HCI_LE_AddDevToResolvingListCmd( uint8 addrType, + uint8* devAddr, + uint8* peerIrk, + uint8* localIrk); + + +extern hciStatus_t HCI_LE_RemoveResolvingListCmd( uint8 addrType, + uint8* devAddr ); + +extern hciStatus_t HCI_LE_ClearResolvingListCmd( void ); + +extern hciStatus_t HCI_LE_ReadResolvingListSizeCmd( void ); + +extern hciStatus_t HCI_LE_SetAddressResolutionEnableCmd( uint8 enable ); + +extern hciStatus_t HCI_LE_SetResolvablePrivateAddressTimeoutCmd( uint16 rpaTimeout ); + + +/* +** HCI for Extended Adv +*/ +// +extern hciStatus_t HCI_LE_SetExtAdvSetRandomAddressCmd( uint8 adv_handle, + uint8* random_address); + +extern hciStatus_t HCI_LE_SetExtAdvParamCmd( uint8 adv_handle, + uint16 adv_event_properties, + uint32 primary_advertising_interval_Min, // 3 octets + uint32 primary_advertising_interval_Max, // 3 octets + uint8 primary_advertising_channel_map, + uint8 own_address_type, + uint8 peer_address_type, + uint8* peer_address, + uint8 advertising_filter_policy, + int8 advertising_tx_power, // update 2020-04-08 + uint8 primary_advertising_PHY, + uint8 secondary_advertising_max_skip, + uint8 secondary_advertising_PHY, + uint8 advertising_SID, + uint8 scan_request_notification_enable + ); + +// +extern hciStatus_t HCI_LE_SetExtAdvDataCmd( uint8 adv_handle, + uint8 operation, + uint8 fragment_preference, + uint8 advertising_data_length, + uint8* advertising_data + ); +// +extern hciStatus_t HCI_LE_SetExtScanRspDataCmd( uint8 adv_handle, + uint8 operation, + uint8 fragment_preference, + uint8 scan_rsp_data_length, + uint8* scan_rsp_data + ); + +// +extern hciStatus_t HCI_LE_SetExtAdvEnableCmd( uint8 enable, + uint8 number_of_sets, + uint8* advertising_handle, + uint16* duration, + uint8* max_extended_advertising_events); + +// +extern hciStatus_t HCI_LE_ReadMaximumAdvDataLengthCmd( void ); + +// +extern hciStatus_t HCI_LE_ReadNumberOfSupportAdvSetCmd( void ); + +// +extern hciStatus_t HCI_LE_RemoveAdvSetCmd( uint8 adv_handle); + +// +extern hciStatus_t HCI_LE_ClearAdvSetsCmd( void); + + +extern hciStatus_t HCI_LE_SetExtendedScanParametersCmd(uint8 own_address_type, + uint8 scanning_filter_policy, + uint8 scanning_PHYs, + uint8* scan_sype, + uint16* scan_interval, + uint16* scan_window); + +extern hciStatus_t HCI_LE_SetExtendedScanEnableCmd(uint8 enable, + uint8 filter_duplicates, + uint16 duration, + uint16 period); + +extern hciStatus_t HCI_LE_ExtendedCreateConnectionCmd(uint8 initiator_filter_policy, + uint8 own_address_type, + uint8 peer_address_type, + uint8* peer_address, + uint8 initiating_PHYs, + uint16* scan_interval, + uint16* scan_window, + uint16* conn_interval_min, + uint16* conn_interval_max, + uint16* conn_latency, + uint16* supervision_timeout, + uint16* minimum_CE_length, + uint16* maximum_CE_length); + +// +extern hciStatus_t HCI_LE_SetPeriodicAdvParameterCmd( uint8 adv_handle, + uint16 interval_min, + uint16 interval_max, + uint16 adv_event_properties + ); + +extern hciStatus_t HCI_LE_SetPeriodicAdvDataCmd( uint8 adv_handle, + uint8 operation, + uint8 advertising_data_length, + uint8* advertising_data + ); + +extern hciStatus_t HCI_LE_SetPeriodicAdvEnableCmd( uint8 enable, + uint8 advertising_handle); + + +extern hciStatus_t HCI_LE_PeriodicAdvertisingCreateSyncCmd(uint8 Options, + uint8 Advertising_SID, + uint8 Advertiser_Address_Type, + uint8* Advertiser_Address, + uint16 Skip, + uint16 Sync_Timeout, + uint8 Sync_CTE_Type); + +extern hciStatus_t HCI_LE_PeriodicAdvertisingCreateSyncCancelCmd(void); + +extern hciStatus_t HCI_LE_PeriodicAdvertisingTerminateSyncCmd(uint16 sync_handle); + +extern hciStatus_t HCI_LE_AddDevToPeriodicAdvListCmd( uint8 addrType, + uint8* devAddr, + uint8 sid); +extern hciStatus_t HCI_LE_RemovePeriodicAdvListCmd( uint8 addrType, + uint8* devAddr, + uint8 sid); +extern hciStatus_t HCI_LE_ClearPeriodicAdvListCmd( void ); +extern hciStatus_t HCI_LE_ReadPeriodicAdvListSizeCmd( void ); + + +/****************************************************************************** + fn: HCI_LE_ConnectionlessCTE_TransmitParamcmd + + brief: set CTE Parameters in any periodic advertising + 1ã€CTE Type + 2ã€CTE Length + 3ã€CTE antenna switching pattern + + input parameters: + advertising handle : Identify advertising set 0x0-0xEF + CTE_Length : CTE Length in 8us 0x2-0x14 + CTE_Type : 0:AOA CTE , 1:AoD CTE with 1us,2:AoD CTE with 2us, + CTE_Count : how many CTE packet in each PA event 0x1-0x10 + Switch_Pattern_LEN : number of Antenna IDs in the pattern + : AOD CTE, AOA shall be ignored + : 0x2-0x4B + Antenna_IDs[i] : List of Antenna IDs in the pattern + : AOD CTE, AOA shall be ignored + + output parameters: + Status :HCI_SUCCESS or other error codes + + + return hciStatus_t : HCI_SUCCESS + + ******************************************************************************/ +hciStatus_t HCI_LE_ConnectionlessCTE_TransmitParamCmd( uint8 advertising_handle, + uint8 len, + uint8 type, + uint8 count, + uint8 Pattern_LEN, + uint8* AnaIDs); + + +/****************************************************************************** + fn: HCI_LE_ConnectionlessCTE_TransmitEnableCmd + + brief: Controller enable or disable CTE in PA + + input parameters: + advertising handle : Identify advertising set in which CTE is enable or disable + : 0x0-0xEF + enable : 0 : disable , 1: enable + + + output parameters: + Status :HCI_SUCCESS or other error codes + + + return hciStatus_t : HCI_SUCCESS or other error codes + + ******************************************************************************/ +hciStatus_t HCI_LE_ConnectionlessCTE_TransmitEnableCmd( uint8 advertising_handle, + uint8 enable); + + + +/****************************************************************************** + fn: HCI_LE_ConnectionlessIQ_SampleEnableCmd + + brief: Controller enable or disable capturing IQ Samples from the CTE of PA pcakets + + input parameters: + sync_handle : periodic advertising handle + Range:0x0 - 0x0EFF + slot_Duration : switching and sampling slot 0x1:1us,0x2:2us,Other:RFU + enable : 0x0:IQ Sampling disable, 0x1:IQ Sampling enable + MaxSampledCTEs : max number of CTE in each PA event that the controller + should collect and report + Range : 0x0-0x10 + 0x0 : sample and report all available CTE + pattern_len : number of Antenna IDs in the pattern + Range:0x2 - 0x4B + AnaIDs : list of Antenna IDs in the pattern + + + output parameters: + status : HCI_SUCCESS or other error codes + sync_handle : Periodic advertising handle + + + return hciStatus_t : HCI_SUCCESS + + ******************************************************************************/ +hciStatus_t HCI_LE_ConnectionlessIQ_SampleEnableCmd( uint16 sync_handle, + uint8 enable, + uint8 slot_Duration, + uint8 MaxSampledCTEs, + uint8 pattern_len, + uint8* AnaIDs); + + +/****************************************************************************** + fn: HCI_LE_ConnectionCTE_ReceiveParamCmd + + brief: enable or disable sampling received CTE fields on the connection + set antenna switching pattern + set switching and sampling slot durations + + input parameters: + connHandle : connection handle Range 0x0 - 0x0EFF + enable : sampling enable 0:disable , 1:enable + slot_Duration : switching and sampling slot 0:1us, 1: 2us + pattern_len : the number of Antenna IDs in the pattern + Range: 0x2-0x4B + AnaIDs : list of Antenna IDs in the pattern + + + output parameters: + Status : HCI_SUCCESS or other error codes + connHandle : Connection Handle + + + return hciStatus_t + + ******************************************************************************/ +hciStatus_t HCI_LE_Set_ConnectionCTE_ReceiveParamCmd( uint16 connHandle, + uint8 enable, + uint8 slot_Duration, + uint8 pattern_len, + uint8* AnaIDs); + + + +/****************************************************************************** + fn: HCI_LE_Set_ConnectionCTE_TransmitParamCmd + + brief: used to set the antenna switching pattern and permitted CTE type + + input parameters: + connHandle : connection Handle, Range: 0x0 - 0x0EFF + type : bit set for CTE type , bit 0 : AOA CTE response, + bit 1 : AOD CTE response with 1us slots + bit 2 : AOD CTE response with 2us slots + pattern_len : the number of Antenna IDs in the pattern + AnaIDs : list of Antenna IDs in the pattern + + + output parameters: + Status : 0 : success, other error code + ConnHandle : connection handle + + + return hciStatus_t + + ******************************************************************************/ +hciStatus_t HCI_LE_Set_ConnectionCTE_TransmitParamCmd( uint16 connHandle, + uint8 type, + uint8 pattern_len, + uint8* AnaIDs); + + + + +/****************************************************************************** + fn: HCI_LE_Connection_CTE_Request_EnableCmd + + brief: request Controller to start or stop initiating the CTE request + procedure on connection + + input parameters: + connHandle : connection Handle + Range:0x0 - 0x0EFF + enable : Enable or disable CTE request for the connection + 0:disable,1:enable + Interval : define whether the CTE request procedure is initiated + only once or periodically. + Range:0x0 - 0xFFFF + 0x0 : Initiate the CTE request procedure once + 0x1 - 0xFFFF : Requested interval for initiating the CTE + procedure in number of connection events + Range: + len : minimum length of the CTE in 8us units + Range: 0x2 - 0x14 + type : indicate the type of CTE that the controller shall + request from the remote device + 0x0:AOA CTE + 0x1:AOD CTE with 1us + 0x2:AOD CTE with 2us + + + output parameters: + Status : 0x0 : command succeed , 0x1 - 0xff : other error code + connHandle : connection handle + + + return hciStatus_t + + ******************************************************************************/ +hciStatus_t HCI_LE_Connection_CTE_Request_EnableCmd( uint16 connHandle, + uint8 enable, + uint16 Interval, + uint8 len, + uint8 type); + + +/****************************************************************************** + fn: HCI_LE_Connection_CTE_Response_EnableCmd + + brief: request the controller to respond to LL_CTE_REQ with LL_CTE_RSP on the + specified connection + + input parameters: + connHandle : connection Handle + Range:0x0 - 0x0EFF + enable : enable or disable CTE response for the connection + + + output parameters: + status : 0x0 : command succeed , 0x1 - 0xff : other error code + connHandle : connection handle + + + + return hciStatus_t + + ******************************************************************************/ +hciStatus_t HCI_LE_Connection_CTE_Response_EnableCmd( uint16 connHandle, + uint8 enable); + + +/****************************************************************************** + fn: HCI_LE_READ_Anatenna_InfoCmd + + brief: Host read the switching rates, the sampling reate, the number of antennae, + and the maxumum length of a transmitted CTE supported by the controller + + input parameters: + None + + + output parameters: + status : 0x0 : command succeed , 0x1 - 0xff : other error code + switch_sample_rate : bit number indicate supported switching and sampling rate + bit 0 : 1us switching AOD transmission + bit 1 : 1us sampling AOD reception + bit 2 : 1us switching and sampling AOA reception + Antenna_len : number of Antennae supported by the controller + MAX_Pattern_len : MAX length of antenna switching pattern spooorted by the controller + MAX_CTE_LEN : MAX length or a transmitted CTE supported in 8us units + + + return hciStatus_t + + ******************************************************************************/ +hciStatus_t HCI_LE_READ_Anatenna_InfoCmd(void); + +#if (PHY_MCU_TYPE == MCU_BUMBEE_M0) +/* +** HCI Vendor Specific Comamnds: Link Layer Extensions +*/ + +/******************************************************************************* + @fn HCI_EXT_SetRxGainCmd API + + @brief This HCI Extension API is used to set the receiver gain. + + Related Events: HCI_VendorSpecifcCommandCompleteEvent + + input parameters + + @param rxGain - HCI_EXT_RX_GAIN_STD, HCI_EXT_RX_GAIN_HIGH + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_SetRxGainCmd( uint8 rxGain ); + + +/******************************************************************************* + @fn HCI_EXT_SetTxPowerCmd API + + @brief This HCI Extension API is used to set the transmit power. + + Related Events: HCI_VendorSpecifcCommandCompleteEvent + + input parameters + + @param txPower - LL_EXT_TX_POWER_MINUS_23_DBM, + LL_EXT_TX_POWER_MINUS_6_DBM, + LL_EXT_TX_POWER_0_DBM, + LL_EXT_TX_POWER_4_DBM + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_SetTxPowerCmd( uint8 txPower ); + + +/******************************************************************************* + @fn HCI_EXT_OnePktPerEvtCmd API + + @brief This HCI Extension API is used to set whether a connection will + be limited to one packet per event. + + Related Events: HCI_VendorSpecifcCommandCompleteEvent + + input parameters + + @param control - HCI_EXT_ENABLE_ONE_PKT_PER_EVT, + HCI_EXT_DISABLE_ONE_PKT_PER_EVT + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_OnePktPerEvtCmd( uint8 control ); + + +/******************************************************************************* + @fn HCI_EXT_ClkDivOnHaltCmd API + + @brief This HCI Extension API is used to set whether the system clock + will be divided when the MCU is halted. + + Related Events: HCI_VendorSpecifcCommandCompleteEvent + + input parameters + + @param control - HCI_EXT_ENABLE_CLK_DIVIDE_ON_HALT, + HCI_EXT_DISABLE_CLK_DIVIDE_ON_HALT + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_ClkDivOnHaltCmd( uint8 control ); + + +/******************************************************************************* + @fn HCI_EXT_DeclareNvUsageCmd API + + @brief This HCI Extension API is used to indicate to the Controller + whether or not the Host will be using the NV memory during BLE + operations. + + Related Events: HCI_VendorSpecifcCommandCompleteEvent + + input parameters + + @param mode - HCI_EXT_NV_IN_USE, HCI_EXT_NV_NOT_IN_USE + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_DeclareNvUsageCmd( uint8 mode ); + + +/******************************************************************************* + @fn HCI_EXT_DecryptCmd API + + @brief This HCI Extension API is used to decrypt encrypted data using + AES128. + + Related Events: HCI_VendorSpecifcCommandCompleteEvent + + input parameters + + @param key - Pointer to 16 byte encryption key. + @param encText - Pointer to 16 byte encrypted data. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_DecryptCmd( uint8* key, + uint8* encText ); + + +/******************************************************************************* + @fn HCI_EXT_SetLocalSupportedFeaturesCmd API + + @brief This HCI Extension API is used to write this devie's supported + features. + + Related Events: HCI_VendorSpecifcCommandCompleteEvent + + input parameters + + @param localFeatures - Pointer to eight bytes of local features. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_SetLocalSupportedFeaturesCmd( uint8* localFeatures ); + + +/******************************************************************************* + @fn HCI_EXT_SetFastTxResponseTimeCmd API + + @brief This HCI Extension API is used to set whether transmit data is + sent as soon as possible even when slave latency is used. + + Related Events: HCI_VendorSpecifcCommandCompleteEvent + + input parameters + + @param control - HCI_EXT_ENABLE_FAST_TX_RESP_TIME, + HCI_EXT_DISABLE_FAST_TX_RESP_TIME + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_SetFastTxResponseTimeCmd( uint8 control ); + +/******************************************************************************* + @fn HCI_EXT_SetSlaveLatencyOverrideCmd API + + @brief This HCI Extension API is used to to enable or disable + suspending slave latency. + + Related Events: HCI_VendorSpecifcCommandCompleteEvent + + input parameters + + @param control - HCI_EXT_ENABLE_SL_OVERRIDE, + HCI_EXT_DISABLE_SL_OVERRIDE + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_SetSlaveLatencyOverrideCmd( uint8 control ); + + +/******************************************************************************* + @fn HCI_EXT_ModemTestTxCmd + + @brief This API is used start a continuous transmitter modem test, + using either a modulated or unmodulated carrier wave tone, at + the frequency that corresponds to the specified RF channel. Use + HCI_EXT_EndModemTest command to end the test. + + Note: A Controller reset will be issued by HCI_EXT_EndModemTest! + Note: The BLE device will transmit at maximum power. + Note: This API can be used to verify this device meets Japan's + TELEC regulations. + + Related Events: HCI_VendorSpecifcCommandCompleteEvent + + input parameters + + @param cwMode - HCI_EXT_TX_MODULATED_CARRIER, + HCI_EXT_TX_UNMODULATED_CARRIER + txFreq - Transmit RF channel k=0..39, where BLE F=2402+(k*2MHz). + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_ModemTestTxCmd( uint8 cwMode, + uint8 txFreq ); + + +/******************************************************************************* + @fn HCI_EXT_ModemHopTestTxCmd + + @brief This API is used to start a continuous transmitter direct test + mode test using a modulated carrier wave and transmitting a + 37 byte packet of Pseudo-Random 9-bit data. A packet is + transmitted on a different frequency (linearly stepping through + all RF channels 0..39) every 625us. Use HCI_EXT_EndModemTest + command to end the test. + + Note: A Controller reset will be issued by HCI_EXT_EndModemTest! + Note: The BLE device will transmit at maximum power. + Note: This API can be used to verify this device meets Japan's + TELEC regulations. + + input parameters + + @param None. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_ModemHopTestTxCmd( void ); + + +/******************************************************************************* + @fn HCI_EXT_ModemTestRxCmd + + @brief This API is used to start a continuous receiver modem test + using a modulated carrier wave tone, at the frequency that + corresponds to the specific RF channel. Any received data is + discarded. Receiver gain may be adjusted using the + HCI_EXT_SetRxGain command. RSSI may be read during this test + by using the HCI_ReadRssi command. Use HCI_EXT_EndModemTest + command to end the test. + + Note: A Controller reset will be issued by HCI_EXT_EndModemTest! + Note: The BLE device will transmit at maximum power. + + input parameters + + @param rxFreq - Receiver RF channel k=0..39, where BLE F=2402+(k*2MHz). + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_ModemTestRxCmd( uint8 rxFreq ); + + +/******************************************************************************* + @fn HCI_EXT_EndModemTestCmd + + @brief This API is used to shutdown a modem test. A complete Controller + reset will take place. + + input parameters + + @param None. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_EndModemTestCmd( void ); + + +/******************************************************************************* + @fn HCI_EXT_SetBDADDRCmd + + @brief This API is used to set this device's BLE address (BDADDR). + + Note: This command is only allowed when the device's state is + Standby. + + Related Events: HCI_VendorSpecifcCommandCompleteEvent + + input parameters + + @param bdAddr - A pointer to a buffer to hold this device's address. + An invalid address (i.e. all FF's) will restore this + device's address to the address set at initialization. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_SetBDADDRCmd( uint8* bdAddr ); + + +/******************************************************************************* + @fn HCI_EXT_SetSCACmd + + @brief This API is used to set this device's Sleep Clock Accuracy. + + Note: For a slave device, this value is directly used, but only + if power management is enabled. For a master device, this + value is converted into one of eight ordinal values + representing a SCA range, as specified in Table 2.2, + Vol. 6, Part B, Section 2.3.3.1 of the Core specification. + + Note: This command is only allowed when the device is not in a + connection. + + Note: The device's SCA value remains unaffected by a HCI_Reset. + + input parameters + + @param scaInPPM - A SCA value in PPM from 0..500. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_SetSCACmd( uint16 scaInPPM ); + + +/******************************************************************************* + @fn HCI_EXT_EnablePTMCmd + + @brief This HCI Extension API is used to enable Production Test Mode. + + Note: This function can only be directly called from the + application and is not available via an external transport + interface such as RS232. Also, no vendor specific + command complete will be returned. + + input parameters + + @param None. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_EnablePTMCmd( void ); + + +/******************************************************************************* + @fn HCI_EXT_SetFreqTuneCmd + + @brief This HCI Extension API is used to set the frequency tuning up + or down. Setting the mode up/down decreases/increases the amount + of capacitance on the external crystal oscillator. + + Note: This is a Production Test Mode only command! + + input parameters + + @param step - HCI_PTM_SET_FREQ_TUNE_UP, HCI_PTM_SET_FREQ_TUNE_DOWN + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_SetFreqTuneCmd( uint8 step ); + + +/******************************************************************************* + @fn HCI_EXT_SaveFreqTuneCmd + + @brief This HCI Extension API is used to save the frequency tuning + value to flash. + + Note: This is a Production Test Mode only command! + + input parameters + + @param None. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_SaveFreqTuneCmd( void ); + + +/******************************************************************************* + @fn HCI_EXT_SetMaxDtmTxPowerCmd API + + @brief This HCI Extension API is used to set the maximum transmit + output power for Direct Test Mode. + + Related Events: HCI_VendorSpecifcCommandCompleteEvent + + input parameters + + @param txPower - LL_EXT_TX_POWER_MINUS_23_DBM, + LL_EXT_TX_POWER_MINUS_6_DBM, + LL_EXT_TX_POWER_0_DBM, + LL_EXT_TX_POWER_4_DBM + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_SetMaxDtmTxPowerCmd( uint8 txPower ); + + +/******************************************************************************* + +*/ +extern llStatus_t HCI_EXT_MapPmIoPortCmd( uint8 ioPort, uint8 ioPin ); + + +/******************************************************************************* + @fn HCI_EXT_DisconnectImmedCmd API + + @brief This HCI Extension API is used to disconnect the connection + immediately. + + Note: The connection (if valid) is immediately terminated + without notifying the remote device. The Host is still + notified. + + input parameters + + @param connHandle - Connection handle. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_DisconnectImmedCmd( uint16 connHandle ); + + +/******************************************************************************* + @fn HCI_EXT_PacketErrorRate Vendor Specific API + + @brief This function is used to Reset or Read the Packet Error Rate + counters for a connection. + + Note: The counters are only 16 bits. At the shortest connection + interval, this provides a bit over 8 minutes of data. + + input parameters + + @param connHandle - The LL connection ID on which to send this data. + @param command - HCI_EXT_PER_RESET, HCI_EXT_PER_READ + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_PacketErrorRateCmd( uint16 connHandle, uint8 command ); + + + +/******************************************************************************* + @fn HCI_EXT_PERbyChanCmd Vendor Specific API + + @brief This HCI Extension API is used to start or end Packet Error Rate + by Channel counter accumulation for a connection. If the + pointer is not NULL, it is assumed there is sufficient memory + for the PER data, per the type perByChan_t. If NULL, then + the operation is considered disabled. + + Note: It is the user's responsibility to make sure there is + sufficient memory for the data, and that the counters + are cleared prior to first use. + + Note: The counters are only 16 bits. At the shortest connection + interval, this provides a bit over 8 minutes of data. + + input parameters + + @param connHandle - The LL connection ID on which to send this data. + @param perByChan - Pointer to PER by Channel data, or NULL. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_PERbyChanCmd( uint16 connHandle, perByChan_t* perByChan ); + + +/******************************************************************************* +*/ +extern hciStatus_t HCI_EXT_ExtendRfRangeCmd( void ); + + +/******************************************************************************* + @fn HCI_EXT_HaltDuringRfCmd API + + @brief This HCI Extension API is used to enable or disable halting the + CPU during RF. The system defaults to enabled. + + Related Events: HCI_VendorSpecifcCommandCompleteEvent + + input parameters + + @param mode - HCI_EXT_HALT_DURING_RF_ENABLE, + HCI_EXT_HALT_DURING_RF_DISABLE + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_HaltDuringRfCmd( uint8 mode ); + + +/******************************************************************************* + @fn HCI_EXT_AdvEventNoticeCmd Vendor Specific API + + @brief This HCI Extension API is used to enable or disable a + notification to the specified task using the specified task + event whenever a Adv event ends. A non-zero taskEvent value is + taken to be "enable", while a zero valued taskEvent is taken + to be "disable". + + input parameters + + @param taskID - User's task ID. + @param taskEvent - User's task event. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_AdvEventNoticeCmd( uint8 taskID, uint16 taskEvent ); + + +/******************************************************************************* + @fn HCI_EXT_ConnEventNoticeCmd Vendor Specific API + + @brief This HCI Extension API is used to enable or disable a + notification to the specified task using the specified task + event whenever a Connection event ends. A non-zero taskEvent + value is taken to be "enable", while a zero valued taskEvent + taken to be "disable". + + Note: Currently, only a Slave connection is supported. + + input parameters + + @param taskID - User's task ID. + @param taskEvent - User's task event. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_ConnEventNoticeCmd( uint8 taskID, uint16 taskEvent ); + + +/******************************************************************************* + @fn HCI_EXT_BuildRevisionCmd Vendor Specific API + + @brief This HCI Extension API is used set a user revision number or + read the build revision number. + + input parameters + + @param mode - HCI_EXT_SET_USER_REVISION | HCI_EXT_READ_BUILD_REVISION + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_BuildRevisionCmd( uint8 mode, uint16 userRevNum ); + + +/******************************************************************************* + @fn HCI_EXT_DelaySleepCmd Vendor Specific API + + @brief This HCI Extension API is used set the sleep delay. + + input parameters + + @param delay - 0..1000, in milliseconds. + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_DelaySleepCmd( uint16 delay ); + + +/******************************************************************************* + @fn HCI_EXT_ResetSystemCmd Vendor Specific API + + @brief This HCI Extension API is used to issue a soft or hard + system reset. + + input parameters + + @param mode - HCI_EXT_RESET_SYSTEM_HARD | HCI_EXT_RESET_SYSTEM_SOFT + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_ResetSystemCmd( uint8 mode ); + + + +/******************************************************************************* + @fn HCI_EXT_OverlappedProcessingCmd Vendor Specific API + + @brief This HCI Extension API is used to enable or disable overlapped + processing. + + input parameters + + @param mode - HCI_EXT_ENABLE_OVERLAPPED_PROCESSING | + HCI_EXT_DISABLE_OVERLAPPED_PROCESSING + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_OverlappedProcessingCmd( uint8 mode ); + +/******************************************************************************* + @fn HCI_EXT_NumComplPktsLimitCmd Vendor Specific API + + @brief This HCI Extension API is used to set the minimum number of + completed packets which must be met before a Number of + Completed Packets event is returned. If the limit is not + reach by the end of the connection event, then a Number of + Completed Packets event will be returned (if non-zero) based + on the flushOnEvt flag. + + input parameters + + @param limit - From 1 to HCI_MAX_NUM_DATA_BUFFERS. + @param flushOnEvt - HCI_EXT_DISABLE_NUM_COMPL_PKTS_ON_EVENT | + HCI_EXT_ENABLE_NUM_COMPL_PKTS_ON_EVENT + + output parameters + + @param None. + + @return hciStatus_t +*/ +extern hciStatus_t HCI_EXT_NumComplPktsLimitCmd( uint8 limit, + uint8 flushOnEvt ); + + +/******************************************************************************* + @fn HCI_PPLUS_AdvEventDoneNoticeCmd Vendor Specific API + + @brief This HCI Extension API is used to enable or disable a notification to the + specified task using the specified task event whenever a Adv event ends. + A non-zero taskEvent value is taken to be "enable", while a zero valued + taskEvent is taken to be "disable". + + input parameters + + @param taskID - User's task ID. + @param taskEvent - User's task event. + + output parameters + + @param None. + + @return hciStatus_t +*/ +hciStatus_t HCI_PPLUS_AdvEventDoneNoticeCmd( uint8 taskID, uint16 taskEvent ); + +/******************************************************************************* + @fn HCI_PPLUS_ConnEventDoneNoticeCmd Vendor Specific API + + @brief This HCI Extension API is used to enable or disable a notification to the + specified task using the specified task event whenever a Connection event + ends. A non-zero taskEvent value is taken to be "enable", while a zero valued + taskEvent is taken to be "disable". + + input parameters + + @param taskID - User's task ID. + @param taskEvent - User's task event. + + output parameters + + @param None. + + @return hciStatus_t +*/ +hciStatus_t HCI_PPLUS_ConnEventDoneNoticeCmd( uint8 taskID, uint16 taskEvent ); + +/******************************************************************************* + This HCI Extension API is used to enable or disable a notification to the + specified task using the specified task event whenever a Connection event + ends. A non-zero taskEvent value is taken to be "enable", while a zero valued + taskEvent is taken to be "disable". + +*/ +hciStatus_t HCI_PPLUS_DateLengthChangedNoticeCmd( uint8 taskID, uint16 taskEvent ); + +/******************************************************************************* + This HCI Extension API is used to enable or disable a notification to the + specified task using the specified task event whenever a Connection event + ends. A non-zero taskEvent value is taken to be "enable", while a zero valued + taskEvent is taken to be "disable". + +*/ +hciStatus_t HCI_PPLUS_PhyUpdateNoticeCmd( uint8 taskID, uint16 taskEvent ); + + +/******************************************************************************* + @fn HCI_PPLUS_ExtendTRXCmd Vendor Specific API + + @brief This HCI Extension API is used to enable or disable Tx/Rx packets limit + per connection event to 8(default is 4). + + input parameters + + @param enable - TRUE: 8Tx/8Rx; FALSE: 4Tx/4Rx + + output parameters + + @param None. + + @return hciStatus_t +*/ +hciStatus_t HCI_PPLUS_ExtendTRXCmd( uint8 enable ); + +#endif /*#if (PHY_MCU_TYPE == MCU_BUMBEE_M0)*/ + +/******************************************************************************* +*/ +hciStatus_t HCI_LE_SetDataLengthCmd( uint16 connHandle, + uint16 TxOctets, + uint16 TxTime ); + + +/******************************************************************************* +*/ +hciStatus_t HCI_LE_ReadMaxDataLengthCmd(void); + +/******************************************************************************* + This LE API is used to read Suggested Default max Data length + + Public function defined in hci.h. +*/ +hciStatus_t HCI_LE_ReadSuggestedDefaultDataLengthCmd(void); + +/******************************************************************************* + This LE API is used to write Suggested Default Data length + + Public function defined in hci.h. +*/ +hciStatus_t HCI_LE_WriteSuggestedDefaultDataLengthCmd(uint16 suggestedMaxTxOctets,uint16 suggestedMaxTxTime); + + +/******************************************************************************* + This LE API is used to set DefaultPhyMode + + Public function defined in hci.h. +*/ +hciStatus_t HCI_LE_SetDefaultPhyMode( uint16 connId,uint8 allPhy,uint8 txPhy, uint8 rxPhy); + + +/******************************************************************************* + This LE API is used to Set PHY Mode + + Public function defined in hci.h. +*/ +hciStatus_t HCI_LE_SetPhyMode( uint16 connId,uint8 allPhy,uint8 txPhy, uint8 rxPhy,uint16 phyOptions); + +/******************************************************************************* + This LE API is used to Read PHY Mode + + Public function defined in hci.h. +*/ +hciStatus_t HCI_LE_ReadPhyMode( uint16 connId); + + + +#ifdef __cplusplus +} +#endif + +#endif /* HCI_H */ diff --git a/src/components/ble/include/l2cap.h b/src/components/ble/include/l2cap.h new file mode 100644 index 0000000..9d1e157 --- /dev/null +++ b/src/components/ble/include/l2cap.h @@ -0,0 +1,473 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +/************************************************************************************************** + Filename: l2cap.h + Revised: + Revision: + + Description: This file contains the L2CAP definitions. + + + **************************************************************************************************/ + +#ifndef L2CAP_H +#define L2CAP_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + * INCLUDES + */ +#include "bcomdef.h" +#include "OSAL.h" + +#include "log.h" +/********************************************************************* + CONSTANTS +*/ +#ifndef MTU_SIZE +#define MTU_SIZE 23 +#endif +#if( MTU_SIZE < 23 ) +#error "MTU_SIZE define error" +#endif + +// Minimum supported information payload for the Basic information frame (B-frame) +#define L2CAP_MTU_SIZE MTU_SIZE + +// Minimum supported information payload for the Control frame (C-frame) +#define L2CAP_SIG_MTU_SIZE 23 + +// Basic L2CAP header: Length (2 bytes) + Channel ID (2 bytes) +#define L2CAP_HDR_SIZE 4 + +// Minimum size of PDU received from lower layer protocol (incoming +// packet), or delivered to lower layer protocol (outgoing packet). +#define L2CAP_PDU_SIZE ( L2CAP_HDR_SIZE + L2CAP_MTU_SIZE ) + +// L2CAP Channel Identifiers. Identifiers from 0x0001 to 0x003F are +// reserved for specific L2CAP functions. Identifiers 0x0001-0x0003 +// are reserved by BR/EDR. +#define L2CAP_CID_NULL 0x0000 // Illegal Identifier +#define L2CAP_CID_ATT 0x0004 // Attribute Protocol +#define L2CAP_CID_SIG 0x0005 // L2CAP Signaling +#define L2CAP_CID_SMP 0x0006 // Security Management Protocol +#define L2CAP_CID_GENERIC 0x0007 // Generic Fixed Channel + +// L2CAP Dynamic Channel Identifiers +#define L2CAP_BASE_DYNAMIC_CID 0x0040 +#define L2CAP_LAST_DYNAMIC_CID ( BASE_DYNAMIC_CID + L2CAP_NUM_CHANNELS - 1 ) + +// Number of Fixed channels: one for each of ATT, Signaling, SMP channels and one Generic Channel +#define L2CAP_NUM_FIXED_CHANNELS 4 + +// Number of Protocols supported -- for future use +#define L2CAP_NUM_PROTOCOLS 0 + +// Number of Auxiliary channels: one for each of Echo Request, Information +// Request and Connection Parameter Update Request +#define L2CAP_NUM_AUX_CHANNELS 3 + +// Number of Dynamic channels: one per each protocol supported on each physical connection +#define L2CAP_NUM_DYNAMIC_CHANNELS ( L2CAP_NUM_PROTOCOLS * MAX_NUM_LL_CONN ) + +// Total number of L2CAP channels: Dynamic channels plus Auxiliary channels +#define L2CAP_NUM_CHANNELS ( L2CAP_NUM_DYNAMIC_CHANNELS + L2CAP_NUM_AUX_CHANNELS ) + +// L2CAP Response Timeout expired (RTX) value for Signaling commands (in seconds). +// The RTX timer is used for response timeout or to terminate a dynamic channel +// when the remote device is unresponsive to signaling requests. Its value may +// range from 1 to 60 seconds. +#define L2CAP_RTX_TIMEOUT 30 + +// L2CAP Signaling Codes (type of commands) +#define L2CAP_CMD_REJECT 0x01 +#define L2CAP_ECHO_REQ 0x08 // No longer supported +#define L2CAP_ECHO_RSP 0x09 // No longer supported +#define L2CAP_INFO_REQ 0x0a // No longer supported +#define L2CAP_INFO_RSP 0x0b // No longer supported +#define L2CAP_PARAM_UPDATE_REQ 0x12 +#define L2CAP_PARAM_UPDATE_RSP 0x13 + +/********************************************************************* + * Command Reject: Reason Codes + */ + // Command not understood +#define L2CAP_REJECT_CMD_NOT_UNDERSTOOD 0x0000 + + // Signaling MTU exceeded +#define L2CAP_REJECT_SIGNAL_MTU_EXCEED 0x0001 + + // Invalid CID in request +#define L2CAP_REJECT_INVALID_CID 0x0002 + +/********************************************************************* + * Information Request/Response: Info Type + */ + // Connectionless MTU +#define L2CAP_INFO_CONNLESS_MTU 0x0001 + + // Extended features supported +#define L2CAP_INFO_EXTENDED_FEATURES 0x0002 + + // Fixed channels supported +#define L2CAP_INFO_FIXED_CHANNELS 0x0003 + +/********************************************************************* + * Information Response: Extended Features Mask Values + */ + // Fixed channels are supported +#define L2CAP_FIXED_CHANNELS 0x00000080 + + // Length of Extended Features bit mask +#define L2CAP_EXTENDED_FEATURES_SIZE 4 + +/********************************************************************* + * Information Response: Fixed Channels Mask Values + */ + // Fixed Channel ATT is supported +#define L2CAP_FIXED_CHANNELS_ATT 0x10 + + // Fixed Channel L2CAP Signaling is supported +#define L2CAP_FIXED_CHANNELS_SIG 0x20 + + // Fixed Channel SMP is supported +#define L2CAP_FIXED_CHANNELS_SMP 0x40 + + // Length of Fixed Channels bit mask +#define L2CAP_FIXED_CHANNELS_SIZE 8 + +/********************************************************************* + * Information Response: Result Values + */ + // Success +#define L2CAP_INFO_SUCCESS 0x0000 + + // Not supported +#define L2CAP_INFO_NOT_SUPPORTED 0x0001 + +/********************************************************************* + * Connection Parameter Update Response: Result values + */ + // Connection Parameters accepted +#define L2CAP_CONN_PARAMS_ACCEPTED 0x0000 + + // Connection Parameters rejected +#define L2CAP_CONN_PARAMS_REJECTED 0x0001 + + +/********************************************************************* + * VARIABLES + */ + +/********************************************************************* + * MACROS + */ + +/********************************************************************* + * TYPEDEFS + */ + +// Invalid CID in Request format +typedef struct +{ + uint16 localCID; // Destination CID from the rejected command + uint16 remoteCID; // Source CID from the rejected command +} l2capInvalidCID_t; + +// Command Reject Reason Data format +typedef union +{ + uint16 signalMTU; // Maximum Signaling MTU + l2capInvalidCID_t invalidCID; // Invalid CID in Request +} l2capReasonData_t; + +// Command Reject format +typedef struct +{ + uint16 reason; // Reason + l2capReasonData_t reasonData; // Reason Data + + // Shorthand access for union members + #define maxSignalMTU reasonData.signalMTU + #define invalidLocalCID reasonData.invalidCID.localCID + #define invalidRemoteCID reasonData.invalidCID.remoteCID +} l2capCmdReject_t; + +// Echo Request format +typedef struct +{ + uint8 *pData; // Optional data field + uint16 len; // Length of data +} l2capEchoReq_t; + +// Echo Response format +typedef struct +{ + uint8 *pData; // Optional data field -- must be freed by the application + uint16 len; // Length of data +} l2capEchoRsp_t; + +// Information Request format +typedef struct +{ + uint16 infoType; // Information type +} l2capInfoReq_t; + +// Information Response Data field +typedef union +{ + uint16 connectionlessMTU; // Connectionless MTU + uint32 extendedFeatures; // Extended features supported + uint8 fixedChannels[L2CAP_FIXED_CHANNELS_SIZE]; // Fixed channels supported +} l2capInfo_t; + +// Information Response format +typedef struct +{ + uint16 result; // Result + uint16 infoType; // Information type + l2capInfo_t info; // Content of Info field depends on infoType +} l2capInfoRsp_t; + +// Connection Parameter Update Request format +typedef struct +{ + uint16 intervalMin; // Minimum Interval + uint16 intervalMax; // Maximum Interval + uint16 slaveLatency; // Slave Latency + uint16 timeoutMultiplier; // Timeout Multiplier +} l2capParamUpdateReq_t; + +// Connection Parameter Update Response format +typedef struct +{ + uint16 result; // Result +} l2capParamUpdateRsp_t; + +// Union of all L2CAP Signaling commands +typedef union +{ + // Requests + l2capEchoReq_t echoReq; + l2capInfoReq_t infoReq; + l2capParamUpdateReq_t updateReq; + + // Responses + l2capCmdReject_t cmdReject; + l2capEchoRsp_t echoRsp; + l2capInfoRsp_t infoRsp; + l2capParamUpdateRsp_t updateRsp; +} l2capSignalCmd_t; + +// OSAL L2CAP_SIGNAL_EVENT message format. This message is used to deliver an +// incoming Signaling command up to an upper layer application. +typedef struct +{ + osal_event_hdr_t hdr; // L2CAP_SIGNAL_EVENT and status + uint16 connHandle; // connection message was received on + uint8 id; // identifier to match responses with requests + uint8 opcode; // type of command + l2capSignalCmd_t cmd; // command data +} l2capSignalEvent_t; + +// L2CAP packet structure +typedef struct +{ + uint16 CID; // local channel id + uint8 *pPayload; // pointer to information payload. This contains the payload + // received from the upper layer protocol (outgoing packet), + // or delivered to the upper layer protocol (incoming packet). + uint16 len; // length of information payload +} l2capPacket_t; + +// OSAL L2CAP_DATA_EVENT message format. This message is used to forward an +// incoming data packet up to an upper layer application. +typedef struct +{ + osal_event_hdr_t hdr; // L2CAP_DATA_EVENT and status + uint16 connHandle; // connection packet was received on + l2capPacket_t pkt; // received packet +} l2capDataEvent_t; + + +typedef struct +{ + uint16 cIdx; // reassemble packet current idx + l2capPacket_t pkt; // received packet +} l2capReassemblePkt_t; + +typedef struct +{ + uint8 len; // pkt len + uint8* ptr ; // pkt point +} segmentBuff_t; + +typedef struct +{ + segmentBuff_t pkt[10];//251/27->9.2 + uint8 depth; + uint8 idx; + uint8* pBufScr; //source buffer ptr + uint8 fragment; +} l2capSegmentBuff_t; + + +typedef struct +{ + uint32 reassembleInCnt; + uint32 reassembleOutCnt; + uint32 reassembleErrIdx; + uint32 reassembleErrCID; + uint32 reassembleErrInComp; + uint32 reassembleErrMiss; + uint32 resssambleMemAlocErr; + + uint32 segmentInCnt; + uint32 segmentOutCnt; + uint32 segmentErrCnt; + uint32 fragmentSendCounter; + uint32 segmentMemAlocErr; + uint32 segmentSentToLinkLayerErr; + +} l2capSARDbugCnt_t; +//typedef enum +//{ +// DATA_IN_YBUF_FIRST = 0, // YBUF fisrt bufin fisrt shift out +// DATA_IN_XBUF_FIRST = 1 +//} SegmentBuffOrder_t; + +//typedef struct +//{ +// l2capSegmentBuff_t xBuf; +// l2capSegmentBuff_t yBuf; +// SegmentBuffOrder_t order; //which buffer +// +//}l2capSegmentPkt_t; + + + +/********************************************************************* + * VARIABLES + */ + +/********************************************************************* + * FUNCTIONS + */ + +/* + * Initialize L2CAP layer. + */ +extern void L2CAP_Init( uint8 taskId ); + +/* + * L2CAP Task event processing function. + */ +extern uint16 L2CAP_ProcessEvent( uint8 taskId, uint16 events ); + +/* + * Register a protocol/application with an L2CAP channel. + */ +extern bStatus_t L2CAP_RegisterApp( uint8 taskId, uint16 CID ); + +/* + * Send L2CAP Data Packet. + */ +extern bStatus_t L2CAP_SendData( uint16 connHandle, l2capPacket_t *pPkt ); + +/* + * Send Command Reject. + */ +extern bStatus_t L2CAP_CmdReject( uint16 connHandle, uint8 id, l2capCmdReject_t *pCmdReject ); + +/* + * Build Command Reject. + */ +extern uint16 L2CAP_BuildCmdReject( uint8 *pBuf, uint8 *pCmd ); + +/* + * Send L2CAP Echo Request. + */ +extern bStatus_t L2CAP_EchoReq( uint16 connHandle, l2capEchoReq_t *pEchoReq, uint8 taskId ); + +/* + * Send L2CAP Information Request. + */ +extern bStatus_t L2CAP_InfoReq( uint16 connHandle, l2capInfoReq_t *pInfoReq, uint8 taskId ); + +/* + * Build Information Response. + */ +extern uint16 L2CAP_BuildInfoRsp( uint8 *pBuf, uint8 *pCmd ); + +/* + * Parse Information Request. + */ +extern bStatus_t L2CAP_ParseInfoReq( l2capSignalCmd_t *pCmd, uint8 *pData, uint16 len ); + +/* + * Send L2CAP Connection Parameter Update Request. + */ +extern bStatus_t L2CAP_ConnParamUpdateReq( uint16 connHandle, l2capParamUpdateReq_t *pUpdateReq, uint8 taskId ); + +/* + * Parse Connection Parameter Update Request. + */ +extern bStatus_t L2CAP_ParseParamUpdateReq( l2capSignalCmd_t *pCmd, uint8 *pData, uint16 len ); + +/* + * Send L2CAP Connection Parameter Update Response. + */ +extern bStatus_t L2CAP_ConnParamUpdateRsp( uint16 connHandle, uint8 id, l2capParamUpdateRsp_t *pUpdateRsp ); + +/* + * Build Connection Parameter Update Response. + */ +extern uint16 L2CAP_BuildParamUpdateRsp( uint8 *pBuf, uint8 *pData ); + +/* + * Allocate a block of memory at the L2CAP layer. + */ +extern void *L2CAP_bm_alloc( uint16 size ); + +/* + * This API is used by the upper layer to turn flow control on + * or off for data packets sent from the Controller to the Host. + */ +extern void L2CAP_SetControllerToHostFlowCtrl( uint16 hostBuffSize, uint8 flowCtrlMode ); +/* + * This API is used by the upper layer to turn flow control on + * or off for data packets sent from the Controller to the Host. + * support DLE update + */ +extern void L2CAP_SetControllerToHostFlowCtrl_DLE( uint16 hostBuffSize, uint8 flowCtrlMode ); +/* + * This API is used by the upper layer to notify L2CAP of the + * number of data packets that have been completed for connection + * handle since this API was previously called. + */ +extern void L2CAP_HostNumCompletedPkts( uint16 connHandle, uint16 numCompletedPkts ); + + +extern uint8 l2capPktToSegmentBuff(uint16 connHandle,l2capSegmentBuff_t* pSegBuf, uint8 blen,uint8* pBuf); +extern uint8 l2capSegmentBuffToLinkLayer(uint16 connHandle, l2capSegmentBuff_t* pSegBuf); +extern void l2capPocessFragmentTxData(uint16 connHandle); +extern void l2capSarBufReset(void); +extern void L2CAP_ReassemblePkt_Reset(uint16 connHandle); +extern void L2CAP_SegmentPkt_Reset(uint16 connHandle); + +extern void L2CAP_ExtendFramgents_Config(uint8 flag); +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* L2CAP_H */ diff --git a/src/components/ble/include/sm.h b/src/components/ble/include/sm.h new file mode 100644 index 0000000..e3f7a95 --- /dev/null +++ b/src/components/ble/include/sm.h @@ -0,0 +1,362 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/** + @headerfile: sm.h + $Date: + $Revision: + + @mainpage BLE SM API + + This file contains the interface to the SM. + + + +*/ + +#ifndef SM_H +#define SM_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* ------------------------------------------------------------------- + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" + +/* ------------------------------------------------------------------- + MACROS +*/ + +/* ------------------------------------------------------------------- + CONSTANTS +*/ +/** @defgroup SM_IO_CAP_DEFINES SM I/O Capabilities + @{ +*/ +#define DISPLAY_ONLY 0x00 //!< Display Only Device +#define DISPLAY_YES_NO 0x01 //!< Display and Yes and No Capable +#define KEYBOARD_ONLY 0x02 //!< Keyboard Only +#define NO_INPUT_NO_OUTPUT 0x03 //!< No Display or Input Device +#define KEYBOARD_DISPLAY 0x04 //!< Both Keyboard and Display Capable +/** @} End SM_IO_CAP_DEFINES */ + +#define SM_AUTH_MITM_MASK(a) (((a) & 0x04) >> 2) + +/** @defgroup SM_PASSKEY_TYPE_DEFINES SM Passkey Types (Bit Masks) + @{ +*/ +#define SM_PASSKEY_TYPE_INPUT 0x01 //!< Input the passkey +#define SM_PASSKEY_TYPE_DISPLAY 0x02 //!< Display the passkey +/** @} End SM_PASSKEY_TYPE_DEFINES */ + +/** @defgroup SM_BONDING_FLAGS_DEFINES SM AuthReq Bonding Flags + Bonding flags 0x02 and 0x03 are reserved. + @{ +*/ +#define SM_AUTH_REQ_NO_BONDING 0x00 //!< No bonding +#define SM_AUTH_REQ_BONDING 0x01 //!< Bonding +/** @} End SM_BONDING_FLAGS_DEFINES */ + +#define PASSKEY_LEN 6 //! Passkey Character Length (ASCII Characters) + +#define SM_AUTH_STATE_CT2 0x20 +#define SM_AUTH_STATE_KEYPRESS 0x10 +#define SM_AUTH_STATE_SC 0x08 +#define SM_AUTH_STATE_AUTHENTICATED 0x04 //! Authenticate requested +#define SM_AUTH_STATE_BONDING 0x01 //! Bonding requested + +/* ------------------------------------------------------------------- + General TYPEDEFS +*/ + +/** + SM_NEW_RAND_KEY_EVENT message format. This message is sent to the + requesting task. +*/ +typedef struct +{ + osal_event_hdr_t hdr; //!< SM_NEW_RAND_KEY_EVENT and status + uint8 newKey[KEYLEN]; //!< New key value - if status is SUCCESS +} smNewRandKeyEvent_t; + +/** + Key Distribution field - True or False fields +*/ +typedef struct +{ + unsigned int sEncKey:1; //!< Set to distribute slave encryption key + unsigned int sIdKey:1; //!< Set to distribute slave identity key + unsigned int sSign:1; //!< Set to distribute slave signing key + unsigned int sReserved:5; // bug fixed 2018-11-26, reserved bits should be saved for upward compatibility + + unsigned int mEncKey:1; //!< Set to distribute master encryption key + unsigned int mIdKey:1; //!< Set to distribute master identity key + unsigned int mSign:1; //!< Set to distribute master signing key + unsigned int mReserved:5; // bug fixed 2018-11-26, reserved bits should be saved for upward compatibility +} keyDist_t; + +/** + Link Security Requirements +*/ +typedef struct +{ + uint8 ioCaps; //!< I/O Capabilities (ie. + uint8 oobAvailable; //!< True if Out-of-band key available + uint8 oob[KEYLEN]; //!< Out-Of-Bounds key + uint8 authReq; //!< Authentication Requirements + keyDist_t keyDist; //!< Key Distribution mask + uint8 maxEncKeySize; //!< Maximum Encryption Key size (7-16 bytes) +} smLinkSecurityReq_t; + +/** + Link Security Information +*/ +typedef struct +{ + uint8 ltk[KEYLEN]; //!< Long Term Key (LTK) + uint16 div; //!< LTK Diversifier + uint8 rand[B_RANDOM_NUM_SIZE]; //!< LTK random number + uint8 keySize; //!< LTK Key Size (7-16 bytes) +} smSecurityInfo_t; + +/** + Link Identity Information +*/ +typedef struct +{ + uint8 irk[KEYLEN]; //!< Identity Resolving Key (IRK) + uint8 bd_addr[B_ADDR_LEN]; //!< The advertiser may set this to zeroes to not disclose its BD_ADDR (public address). +} smIdentityInfo_t; + +/** + Signing Information +*/ +typedef struct +{ + uint8 srk[KEYLEN]; //!< Signature Resolving Key (CSRK) + uint32 signCounter; //!< Sign Counter +} smSigningInfo_t; + +/** + Pairing Request & Response - authReq field +*/ +typedef struct +{ + unsigned int bonding:2; //!< Bonding flags + unsigned int mitm:1; //!< Man-In-The-Middle (MITM) + unsigned int reserved:5; //!< Reserved - don't use +} authReq_t; + +/* ------------------------------------------------------------------- + GLOBAL VARIABLES +*/ + +/** + @defgroup SM_API Security Manager API Functions + + @{ +*/ + +/* ------------------------------------------------------------------- + FUNCTIONS - MASTER API - Only use these in a master device +*/ + +/** + @brief Initialize SM Initiator on a master device. + + @return SUCCESS +*/ +extern bStatus_t SM_InitiatorInit( void ); + +/** + @brief Start the pairing process. This function is also + called if the device is already bound. + + NOTE: Only one pairing process at a time per device. + + @param initiator - TRUE to start pairing as Initiator. + @param taskID - task ID to send results. + @param connectionHandle - Link's connection handle + @param pSecReqs - Security parameters for pairing + + @return SUCCESS,
+ INVALIDPARAMETER,
+ bleAlreadyInRequestedMode +*/ +extern bStatus_t SM_StartPairing( uint8 initiator, + uint8 taskID, + uint16 connectionHandle, + smLinkSecurityReq_t* pSecReqs ); + +/** + @brief Send Start Encrypt through HCI + + @param connHandle - Connection Handle + @param pLTK - pointer to 16 byte lkt + @param div - div or ediv + @param pRandNum - pointer to 8 byte random number + @param keyLen - length of LTK (bytes) + + @return SUCCESS,
+ INVALIDPARAMETER,
+ other from HCI/LL +*/ +extern bStatus_t SM_StartEncryption( uint16 connHandle, uint8* pLTK, + uint16 div, uint8* pRandNum, uint8 keyLen ); + + +/* ------------------------------------------------------------------- + FUNCTIONS - SLAVE API - Only use these in a slave device +*/ + +/** + @brief Initialize SM Responder on a slave device. + + @return SUCCESS +*/ +extern bStatus_t SM_ResponderInit( void ); + +/* ------------------------------------------------------------------- + FUNCTIONS - GENERAL API - both master and slave +*/ + +/** + @brief Generate a key with a random value. + + @param taskID - task ID to send results. + + @return SUCCESS,
+ bleNotReady,
+ bleMemAllocError,
+ FAILURE +*/ +extern bStatus_t SM_NewRandKey( uint8 taskID ); + +/** + @brief Calculate a new Private Resolvable address. + + @param pIRK - Identity Root Key. + @param pNewAddr - pointer to place to put new calc'd address + + @return SUCCESS - if started,
+ INVALIDPARAMETER +*/ +extern bStatus_t SM_CalcRandomAddr( uint8* pIRK, uint8* pNewAddr ); + +/** + @brief Resolve a Private Resolveable Address. + + @param pIRK - pointer to the IRK + @param pAddr - pointer to the random address + + @return SUCCESS - match,
+ FAILURE - don't match,
+ INVALIDPARAMETER - parameters invalid +*/ +extern bStatus_t SM_ResolveRandomAddrs( uint8* pIRK, uint8* pAddr ); + +/** + @brief Encrypt the plain text data with the key.. + + @param pKey - key data + @param pPlainText - Plain text data + @param pResult - place to put the encrypted result + + @return SUCCESS - if started,
+ INVALIDPARAMETER - one of the parameters are NULL,
+ bleAlreadyInRequestedMode,
+ bleMemAllocError +*/ +extern bStatus_t SM_Encrypt( uint8* pKey, uint8* pPlainText, uint8* pResult ); + +/** + @brief Generate an outgoing Authentication Signature. + + @param pData - message data + @param len - length of pData + @param pAuthenSig - place to put new signature + + @return SUCCESS - signature authentication generated,
+ INVALIDPARAMETER - pData or pAuthenSig is NULL,
+ bleMemAllocError +*/ +extern bStatus_t SM_GenerateAuthenSig( uint8* pData, uint8 len, uint8* pAuthenSig ); + +/** + @brief Verify an Authentication Signature. + + @param connHandle - connection to verify against. + @param authentication - TRUE if requires an authenticated CSRK, FALSE if not + @param pData - message data + @param len - length of pData + @param pAuthenSig - message signature to verify + + @return SUCCESS - signature authentication verified,
+ FAILURE - if not verified,
+ bleNotConnected - Connection not found,
+ INVALIDPARAMETER - pData or pAuthenSig is NULL, or signCounter is invalid,
+ bleMemAllocError +*/ +extern bStatus_t SM_VerifyAuthenSig( uint16 connHandle, + uint8 authentication, + uint8* pData, + uint16 len, + uint8* pAuthenSig ); + +/** + @brief Update the passkey for the pairing process. + + @param pPasskey - pointer to the 6 digit passkey + @param connectionHandle - connection handle to link. + + @return SUCCESS,
+ bleIncorrectMode - Not pairing,
+ INVALIDPARAMETER - link is incorrect +*/ +extern bStatus_t SM_PasskeyUpdate( uint8* pPasskey, uint16 connectionHandle ); + +/** + @} End SM_API +*/ + +/* ------------------------------------------------------------------- + TASK API - These functions must only be called OSAL. +*/ + +/** + @internal + + @brief SM Task Initialization Function. + + @param taskID - SM task ID. + + @return void +*/ +extern void SM_Init( uint8 task_id ); + +/** + @internal + + @brief SM Task event processing function. + + @param taskID - SM task ID + @param events - SM events. + + @return events not processed +*/ +extern uint16 SM_ProcessEvent( uint8 task_id, uint16 events ); + +/* ------------------------------------------------------------------- + -------------------------------------------------------------------*/ + +#ifdef __cplusplus +} +#endif + +#endif /* SM_H */ diff --git a/src/components/coremark/core_list_join.c b/src/components/coremark/core_list_join.c new file mode 100644 index 0000000..18c2e9c --- /dev/null +++ b/src/components/coremark/core_list_join.c @@ -0,0 +1,2506 @@ +/* + Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + + 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. + + Original Author: Shay Gal-on +*/ + +#include "coremark.h" +/* + Topic: Description + Benchmark using a linked list. + + Linked list is a common data structure used in many applications. + + For our purposes, this will excercise the memory units of the processor. + In particular, usage of the list pointers to find and alter data. + + We are not using Malloc since some platforms do not support this library. + + Instead, the memory block being passed in is used to create a list, + and the benchmark takes care not to add more items then can be + accomodated by the memory block. The porting layer will make sure + that we have a valid memory block. + + All operations are done in place, without using any extra memory. + + The list itself contains list pointers and pointers to data items. + Data items contain the following: + + idx - An index that captures the initial order of the list. + data - Variable data initialized based on the input parameters. The 16b are divided as follows: + o Upper 8b are backup of original data. + o Bit 7 indicates if the lower 7 bits are to be used as is or calculated. + o Bits 0-2 indicate type of operation to perform to get a 7b value. + o Bits 3-6 provide input for the operation. + +*/ + +/* local functions */ + +list_head* core_list_find(list_head* list,list_data* info); +list_head* core_list_reverse(list_head* list); +list_head* core_list_remove(list_head* item); +list_head* core_list_undo_remove(list_head* item_removed, list_head* item_modified); +list_head* core_list_insert_new(list_head* insert_point + , list_data* info, list_head** memblock, list_data** datablock + , list_head* memblock_end, list_data* datablock_end); +typedef ee_s32(*list_cmp)(list_data* a, list_data* b, core_results* res); +list_head* core_list_mergesort(list_head* list, list_cmp cmp, core_results* res); + + +ee_s16 calc_func_7(ee_s16* pdata, core_results* res) +{ + ee_s16 data=*pdata; + ee_s16 retval; + ee_u8 optype=(data>>7) & 1; /* bit 7 indicates if the function result has been cached */ + + if (optype) /* if cached, use cache */ + return (data & 0x007f); + else /* otherwise calculate and cache the result */ + { + ee_s16 flag=data & 0x7; /* bits 0-2 is type of function to perform */ + ee_s16 dtype=((data>>3) & 0xf); /* bits 3-6 is specific data for the operation */ + dtype |= dtype << 4; /* replicate the lower 4 bits to get an 8b value */ + + switch (flag) + { + case 0: + if (dtype<0x22) /* set min period for bit corruption */ + dtype=0x22; + + retval=core_bench_state(res->size,res->memblock[3],res->seed1,res->seed2,dtype,res->crc); + + if (res->crcstate==0) + res->crcstate=retval; + + break; + + case 1: + retval=core_bench_matrix(&(res->mat),dtype,res->crc); + + if (res->crcmatrix==0) + res->crcmatrix=retval; + + break; + + default: + retval=data; + break; + } + + res->crc=crcu16(retval,res->crc); + retval &= 0x007f; + *pdata = (data & 0xff00) | 0x0080 | retval; /* cache the result */ + return retval; + } +} + +ee_s16 calc_func_6(ee_s16* pdata, core_results* res) +{ + ee_s16 data=*pdata; + ee_s16 retval; + ee_u8 optype=(data>>7) & 1; /* bit 7 indicates if the function result has been cached */ + + if (optype) /* if cached, use cache */ + return (data & 0x007f); + else /* otherwise calculate and cache the result */ + { + ee_s16 flag=data & 0x7; /* bits 0-2 is type of function to perform */ + ee_s16 dtype=((data>>3) & 0xf); /* bits 3-6 is specific data for the operation */ + dtype |= dtype << 4; /* replicate the lower 4 bits to get an 8b value */ + + switch (flag) + { + case 0: + if (dtype<0x22) /* set min period for bit corruption */ + dtype=0x22; + + retval=core_bench_state(res->size,res->memblock[3],res->seed1,res->seed2,dtype,res->crc); + + if (res->crcstate==0) + res->crcstate=retval; + + break; + + case 1: + retval=core_bench_matrix(&(res->mat),dtype,res->crc); + + if (res->crcmatrix==0) + res->crcmatrix=retval; + + break; + + default: + retval=data; + break; + } + + res->crc=crcu16(retval,res->crc); + retval &= 0x007f; + *pdata = (data & 0xff00) | 0x0080 | retval; /* cache the result */ + return retval; + } +} + +ee_s16 calc_func_5(ee_s16* pdata, core_results* res) +{ + ee_s16 data=*pdata; + ee_s16 retval; + ee_u8 optype=(data>>7) & 1; /* bit 7 indicates if the function result has been cached */ + + if (optype) /* if cached, use cache */ + return (data & 0x007f); + else /* otherwise calculate and cache the result */ + { + ee_s16 flag=data & 0x7; /* bits 0-2 is type of function to perform */ + ee_s16 dtype=((data>>3) & 0xf); /* bits 3-6 is specific data for the operation */ + dtype |= dtype << 4; /* replicate the lower 4 bits to get an 8b value */ + + switch (flag) + { + case 0: + if (dtype<0x22) /* set min period for bit corruption */ + dtype=0x22; + + retval=core_bench_state(res->size,res->memblock[3],res->seed1,res->seed2,dtype,res->crc); + + if (res->crcstate==0) + res->crcstate=retval; + + break; + + case 1: + retval=core_bench_matrix(&(res->mat),dtype,res->crc); + + if (res->crcmatrix==0) + res->crcmatrix=retval; + + break; + + default: + retval=data; + break; + } + + res->crc=crcu16(retval,res->crc); + retval &= 0x007f; + *pdata = (data & 0xff00) | 0x0080 | retval; /* cache the result */ + return retval; + } +} + +ee_s16 calc_func_4(ee_s16* pdata, core_results* res) +{ + ee_s16 data=*pdata; + ee_s16 retval; + ee_u8 optype=(data>>7) & 1; /* bit 7 indicates if the function result has been cached */ + + if (optype) /* if cached, use cache */ + return (data & 0x007f); + else /* otherwise calculate and cache the result */ + { + ee_s16 flag=data & 0x7; /* bits 0-2 is type of function to perform */ + ee_s16 dtype=((data>>3) & 0xf); /* bits 3-6 is specific data for the operation */ + dtype |= dtype << 4; /* replicate the lower 4 bits to get an 8b value */ + + switch (flag) + { + case 0: + if (dtype<0x22) /* set min period for bit corruption */ + dtype=0x22; + + retval=core_bench_state(res->size,res->memblock[3],res->seed1,res->seed2,dtype,res->crc); + + if (res->crcstate==0) + res->crcstate=retval; + + break; + + case 1: + retval=core_bench_matrix(&(res->mat),dtype,res->crc); + + if (res->crcmatrix==0) + res->crcmatrix=retval; + + break; + + default: + retval=data; + break; + } + + res->crc=crcu16(retval,res->crc); + retval &= 0x007f; + *pdata = (data & 0xff00) | 0x0080 | retval; /* cache the result */ + return retval; + } +} + +ee_s16 calc_func_3(ee_s16* pdata, core_results* res) +{ + ee_s16 data=*pdata; + ee_s16 retval; + ee_u8 optype=(data>>7) & 1; /* bit 7 indicates if the function result has been cached */ + + if (optype) /* if cached, use cache */ + return (data & 0x007f); + else /* otherwise calculate and cache the result */ + { + ee_s16 flag=data & 0x7; /* bits 0-2 is type of function to perform */ + ee_s16 dtype=((data>>3) & 0xf); /* bits 3-6 is specific data for the operation */ + dtype |= dtype << 4; /* replicate the lower 4 bits to get an 8b value */ + + switch (flag) + { + case 0: + if (dtype<0x22) /* set min period for bit corruption */ + dtype=0x22; + + retval=core_bench_state(res->size,res->memblock[3],res->seed1,res->seed2,dtype,res->crc); + + if (res->crcstate==0) + res->crcstate=retval; + + break; + + case 1: + retval=core_bench_matrix(&(res->mat),dtype,res->crc); + + if (res->crcmatrix==0) + res->crcmatrix=retval; + + break; + + default: + retval=data; + break; + } + + res->crc=crcu16(retval,res->crc); + retval &= 0x007f; + *pdata = (data & 0xff00) | 0x0080 | retval; /* cache the result */ + return retval; + } +} + +ee_s16 calc_func_2(ee_s16* pdata, core_results* res) +{ + ee_s16 data=*pdata; + ee_s16 retval; + ee_u8 optype=(data>>7) & 1; /* bit 7 indicates if the function result has been cached */ + + if (optype) /* if cached, use cache */ + return (data & 0x007f); + else /* otherwise calculate and cache the result */ + { + ee_s16 flag=data & 0x7; /* bits 0-2 is type of function to perform */ + ee_s16 dtype=((data>>3) & 0xf); /* bits 3-6 is specific data for the operation */ + dtype |= dtype << 4; /* replicate the lower 4 bits to get an 8b value */ + + switch (flag) + { + case 0: + if (dtype<0x22) /* set min period for bit corruption */ + dtype=0x22; + + retval=core_bench_state(res->size,res->memblock[3],res->seed1,res->seed2,dtype,res->crc); + + if (res->crcstate==0) + res->crcstate=retval; + + break; + + case 1: + retval=core_bench_matrix(&(res->mat),dtype,res->crc); + + if (res->crcmatrix==0) + res->crcmatrix=retval; + + break; + + default: + retval=data; + break; + } + + res->crc=crcu16(retval,res->crc); + retval &= 0x007f; + *pdata = (data & 0xff00) | 0x0080 | retval; /* cache the result */ + return retval; + } +} + +ee_s16 calc_func_1(ee_s16* pdata, core_results* res) +{ + ee_s16 data=*pdata; + ee_s16 retval; + ee_u8 optype=(data>>7) & 1; /* bit 7 indicates if the function result has been cached */ + + if (optype) /* if cached, use cache */ + return (data & 0x007f); + else /* otherwise calculate and cache the result */ + { + ee_s16 flag=data & 0x7; /* bits 0-2 is type of function to perform */ + ee_s16 dtype=((data>>3) & 0xf); /* bits 3-6 is specific data for the operation */ + dtype |= dtype << 4; /* replicate the lower 4 bits to get an 8b value */ + + switch (flag) + { + case 0: + if (dtype<0x22) /* set min period for bit corruption */ + dtype=0x22; + + retval=core_bench_state(res->size,res->memblock[3],res->seed1,res->seed2,dtype,res->crc); + + if (res->crcstate==0) + res->crcstate=retval; + + break; + + case 1: + retval=core_bench_matrix(&(res->mat),dtype,res->crc); + + if (res->crcmatrix==0) + res->crcmatrix=retval; + + break; + + default: + retval=data; + break; + } + + res->crc=crcu16(retval,res->crc); + retval &= 0x007f; + *pdata = (data & 0xff00) | 0x0080 | retval; /* cache the result */ + return retval; + } +} + +ee_s16 calc_func_0(ee_s16* pdata, core_results* res) +{ + ee_s16 data=*pdata; + ee_s16 retval; + ee_u8 optype=(data>>7) & 1; /* bit 7 indicates if the function result has been cached */ + + if (optype) /* if cached, use cache */ + return (data & 0x007f); + else /* otherwise calculate and cache the result */ + { + ee_s16 flag=data & 0x7; /* bits 0-2 is type of function to perform */ + ee_s16 dtype=((data>>3) & 0xf); /* bits 3-6 is specific data for the operation */ + dtype |= dtype << 4; /* replicate the lower 4 bits to get an 8b value */ + + switch (flag) + { + case 0: + if (dtype<0x22) /* set min period for bit corruption */ + dtype=0x22; + + retval=core_bench_state(res->size,res->memblock[3],res->seed1,res->seed2,dtype,res->crc); + + if (res->crcstate==0) + res->crcstate=retval; + + break; + + case 1: + retval=core_bench_matrix(&(res->mat),dtype,res->crc); + + if (res->crcmatrix==0) + res->crcmatrix=retval; + + break; + + default: + retval=data; + break; + } + + res->crc=crcu16(retval,res->crc); + retval &= 0x007f; + *pdata = (data & 0xff00) | 0x0080 | retval; /* cache the result */ + return retval; + } +} + + + + + + +extern uint8 g_calc_func_cnt; +extern uint8 g_calc_func_entry[]; +ee_s16 calc_func(ee_s16* pdata, core_results* res) +{ + g_calc_func_cnt++; + + if(g_calc_func_entry[0x07&g_calc_func_cnt]==0) + { + return ( calc_func_0(pdata, res)); + } + else if(g_calc_func_entry[0x07&g_calc_func_cnt]==1) + { + return ( calc_func_1(pdata, res)); + } + else if(g_calc_func_entry[0x07&g_calc_func_cnt]==2) + { + return ( calc_func_2(pdata, res)); + } + else if(g_calc_func_entry[0x07&g_calc_func_cnt]==3) + { + return ( calc_func_3(pdata, res)); + } + else if(g_calc_func_entry[0x07&g_calc_func_cnt]==4) + { + return ( calc_func_4(pdata, res)); + } + else if(g_calc_func_entry[0x07&g_calc_func_cnt]==5) + { + return ( calc_func_5(pdata, res)); + } + else if(g_calc_func_entry[0x07&g_calc_func_cnt]==6) + { + return ( calc_func_6(pdata, res)); + } + else/* if(g_calc_func_entry[0x07&g_calc_func_cnt]==7)*/ + { + return ( calc_func_7(pdata, res)); + } +} +/* Function: cmp_complex + Compare the data item in a list cell. + + Can be used by mergesort. +*/ +ee_s32 cmp_complex(list_data* a, list_data* b, core_results* res) +{ + ee_s16 val1=calc_func(&(a->data16),res); + ee_s16 val2=calc_func(&(b->data16),res); + return val1 - val2; +} + +/* Function: cmp_idx + Compare the idx item in a list cell, and regen the data. + + Can be used by mergesort. +*/ +ee_s32 cmp_idx(list_data* a, list_data* b, core_results* res) +{ + if (res==NULL) + { + a->data16 = (a->data16 & 0xff00) | (0x00ff & (a->data16>>8)); + b->data16 = (b->data16 & 0xff00) | (0x00ff & (b->data16>>8)); + } + + return a->idx - b->idx; +} + +void copy_info(list_data* to,list_data* from) +{ + to->data16=from->data16; + to->idx=from->idx; +} + + +ee_u16 core_bench_list_7(core_results* res, ee_s16 finder_idx) +{ + ee_u16 retval=0; + ee_u16 found=0,missed=0; + list_head* list=res->list; + ee_s16 find_num=res->seed3; + list_head* this_find; + list_head* finder, *remover; + list_data info; + ee_s16 i; + info.idx=finder_idx; + + /* find values in the list, and change the list each time (reverse and cache if value found) */ + for (i=0; inext->info->data16 >> 8) & 1; + } + else + { + found++; + + if (this_find->info->data16 & 0x1) /* use found value */ + retval+=(this_find->info->data16 >> 9) & 1; + + /* and cache next item at the head of the list (if any) */ + if (this_find->next != NULL) + { + finder = this_find->next; + this_find->next = finder->next; + finder->next=list->next; + list->next=finder; + } + } + + if (info.idx>=0) + info.idx++; + + #if CORE_DEBUG + ee_printf("List find %d: [%d,%d,%d]\n",i,retval,missed,found); + #endif + } + + retval+=found*4-missed; + + /* sort the list by data content and remove one item*/ + if (finder_idx>0) + list=core_list_mergesort(list,cmp_complex,res); + + remover=core_list_remove(list->next); + /* CRC data content of list from location of index N forward, and then undo remove */ + finder=core_list_find(list,&info); + + if (!finder) + finder=list->next; + + while (finder) + { + retval=crc16(list->info->data16,retval); + finder=finder->next; + } + + #if CORE_DEBUG + ee_printf("List sort 1: %04x\n",retval); + #endif + remover=core_list_undo_remove(remover,list->next); + /* sort the list by index, in effect returning the list to original state */ + list=core_list_mergesort(list,cmp_idx,NULL); + /* CRC data content of list */ + finder=list->next; + + while (finder) + { + retval=crc16(list->info->data16,retval); + finder=finder->next; + } + + #if CORE_DEBUG + ee_printf("List sort 2: %04x\n",retval); + #endif + return retval; +} + +ee_u16 core_bench_list_6(core_results* res, ee_s16 finder_idx) +{ + ee_u16 retval=0; + ee_u16 found=0,missed=0; + list_head* list=res->list; + ee_s16 find_num=res->seed3; + list_head* this_find; + list_head* finder, *remover; + list_data info; + ee_s16 i; + info.idx=finder_idx; + + /* find values in the list, and change the list each time (reverse and cache if value found) */ + for (i=0; inext->info->data16 >> 8) & 1; + } + else + { + found++; + + if (this_find->info->data16 & 0x1) /* use found value */ + retval+=(this_find->info->data16 >> 9) & 1; + + /* and cache next item at the head of the list (if any) */ + if (this_find->next != NULL) + { + finder = this_find->next; + this_find->next = finder->next; + finder->next=list->next; + list->next=finder; + } + } + + if (info.idx>=0) + info.idx++; + + #if CORE_DEBUG + ee_printf("List find %d: [%d,%d,%d]\n",i,retval,missed,found); + #endif + } + + retval+=found*4-missed; + + /* sort the list by data content and remove one item*/ + if (finder_idx>0) + list=core_list_mergesort(list,cmp_complex,res); + + remover=core_list_remove(list->next); + /* CRC data content of list from location of index N forward, and then undo remove */ + finder=core_list_find(list,&info); + + if (!finder) + finder=list->next; + + while (finder) + { + retval=crc16(list->info->data16,retval); + finder=finder->next; + } + + #if CORE_DEBUG + ee_printf("List sort 1: %04x\n",retval); + #endif + remover=core_list_undo_remove(remover,list->next); + /* sort the list by index, in effect returning the list to original state */ + list=core_list_mergesort(list,cmp_idx,NULL); + /* CRC data content of list */ + finder=list->next; + + while (finder) + { + retval=crc16(list->info->data16,retval); + finder=finder->next; + } + + #if CORE_DEBUG + ee_printf("List sort 2: %04x\n",retval); + #endif + return retval; +} + +ee_u16 core_bench_list_5(core_results* res, ee_s16 finder_idx) +{ + ee_u16 retval=0; + ee_u16 found=0,missed=0; + list_head* list=res->list; + ee_s16 find_num=res->seed3; + list_head* this_find; + list_head* finder, *remover; + list_data info; + ee_s16 i; + info.idx=finder_idx; + + /* find values in the list, and change the list each time (reverse and cache if value found) */ + for (i=0; inext->info->data16 >> 8) & 1; + } + else + { + found++; + + if (this_find->info->data16 & 0x1) /* use found value */ + retval+=(this_find->info->data16 >> 9) & 1; + + /* and cache next item at the head of the list (if any) */ + if (this_find->next != NULL) + { + finder = this_find->next; + this_find->next = finder->next; + finder->next=list->next; + list->next=finder; + } + } + + if (info.idx>=0) + info.idx++; + + #if CORE_DEBUG + ee_printf("List find %d: [%d,%d,%d]\n",i,retval,missed,found); + #endif + } + + retval+=found*4-missed; + + /* sort the list by data content and remove one item*/ + if (finder_idx>0) + list=core_list_mergesort(list,cmp_complex,res); + + remover=core_list_remove(list->next); + /* CRC data content of list from location of index N forward, and then undo remove */ + finder=core_list_find(list,&info); + + if (!finder) + finder=list->next; + + while (finder) + { + retval=crc16(list->info->data16,retval); + finder=finder->next; + } + + #if CORE_DEBUG + ee_printf("List sort 1: %04x\n",retval); + #endif + remover=core_list_undo_remove(remover,list->next); + /* sort the list by index, in effect returning the list to original state */ + list=core_list_mergesort(list,cmp_idx,NULL); + /* CRC data content of list */ + finder=list->next; + + while (finder) + { + retval=crc16(list->info->data16,retval); + finder=finder->next; + } + + #if CORE_DEBUG + ee_printf("List sort 2: %04x\n",retval); + #endif + return retval; +} + +ee_u16 core_bench_list_4(core_results* res, ee_s16 finder_idx) +{ + ee_u16 retval=0; + ee_u16 found=0,missed=0; + list_head* list=res->list; + ee_s16 find_num=res->seed3; + list_head* this_find; + list_head* finder, *remover; + list_data info; + ee_s16 i; + info.idx=finder_idx; + + /* find values in the list, and change the list each time (reverse and cache if value found) */ + for (i=0; inext->info->data16 >> 8) & 1; + } + else + { + found++; + + if (this_find->info->data16 & 0x1) /* use found value */ + retval+=(this_find->info->data16 >> 9) & 1; + + /* and cache next item at the head of the list (if any) */ + if (this_find->next != NULL) + { + finder = this_find->next; + this_find->next = finder->next; + finder->next=list->next; + list->next=finder; + } + } + + if (info.idx>=0) + info.idx++; + + #if CORE_DEBUG + ee_printf("List find %d: [%d,%d,%d]\n",i,retval,missed,found); + #endif + } + + retval+=found*4-missed; + + /* sort the list by data content and remove one item*/ + if (finder_idx>0) + list=core_list_mergesort(list,cmp_complex,res); + + remover=core_list_remove(list->next); + /* CRC data content of list from location of index N forward, and then undo remove */ + finder=core_list_find(list,&info); + + if (!finder) + finder=list->next; + + while (finder) + { + retval=crc16(list->info->data16,retval); + finder=finder->next; + } + + #if CORE_DEBUG + ee_printf("List sort 1: %04x\n",retval); + #endif + remover=core_list_undo_remove(remover,list->next); + /* sort the list by index, in effect returning the list to original state */ + list=core_list_mergesort(list,cmp_idx,NULL); + /* CRC data content of list */ + finder=list->next; + + while (finder) + { + retval=crc16(list->info->data16,retval); + finder=finder->next; + } + + #if CORE_DEBUG + ee_printf("List sort 2: %04x\n",retval); + #endif + return retval; +} + +ee_u16 core_bench_list_3(core_results* res, ee_s16 finder_idx) +{ + ee_u16 retval=0; + ee_u16 found=0,missed=0; + list_head* list=res->list; + ee_s16 find_num=res->seed3; + list_head* this_find; + list_head* finder, *remover; + list_data info; + ee_s16 i; + info.idx=finder_idx; + + /* find values in the list, and change the list each time (reverse and cache if value found) */ + for (i=0; inext->info->data16 >> 8) & 1; + } + else + { + found++; + + if (this_find->info->data16 & 0x1) /* use found value */ + retval+=(this_find->info->data16 >> 9) & 1; + + /* and cache next item at the head of the list (if any) */ + if (this_find->next != NULL) + { + finder = this_find->next; + this_find->next = finder->next; + finder->next=list->next; + list->next=finder; + } + } + + if (info.idx>=0) + info.idx++; + + #if CORE_DEBUG + ee_printf("List find %d: [%d,%d,%d]\n",i,retval,missed,found); + #endif + } + + retval+=found*4-missed; + + /* sort the list by data content and remove one item*/ + if (finder_idx>0) + list=core_list_mergesort(list,cmp_complex,res); + + remover=core_list_remove(list->next); + /* CRC data content of list from location of index N forward, and then undo remove */ + finder=core_list_find(list,&info); + + if (!finder) + finder=list->next; + + while (finder) + { + retval=crc16(list->info->data16,retval); + finder=finder->next; + } + + #if CORE_DEBUG + ee_printf("List sort 1: %04x\n",retval); + #endif + remover=core_list_undo_remove(remover,list->next); + /* sort the list by index, in effect returning the list to original state */ + list=core_list_mergesort(list,cmp_idx,NULL); + /* CRC data content of list */ + finder=list->next; + + while (finder) + { + retval=crc16(list->info->data16,retval); + finder=finder->next; + } + + #if CORE_DEBUG + ee_printf("List sort 2: %04x\n",retval); + #endif + return retval; +} + +ee_u16 core_bench_list_2(core_results* res, ee_s16 finder_idx) +{ + ee_u16 retval=0; + ee_u16 found=0,missed=0; + list_head* list=res->list; + ee_s16 find_num=res->seed3; + list_head* this_find; + list_head* finder, *remover; + list_data info; + ee_s16 i; + info.idx=finder_idx; + + /* find values in the list, and change the list each time (reverse and cache if value found) */ + for (i=0; inext->info->data16 >> 8) & 1; + } + else + { + found++; + + if (this_find->info->data16 & 0x1) /* use found value */ + retval+=(this_find->info->data16 >> 9) & 1; + + /* and cache next item at the head of the list (if any) */ + if (this_find->next != NULL) + { + finder = this_find->next; + this_find->next = finder->next; + finder->next=list->next; + list->next=finder; + } + } + + if (info.idx>=0) + info.idx++; + + #if CORE_DEBUG + ee_printf("List find %d: [%d,%d,%d]\n",i,retval,missed,found); + #endif + } + + retval+=found*4-missed; + + /* sort the list by data content and remove one item*/ + if (finder_idx>0) + list=core_list_mergesort(list,cmp_complex,res); + + remover=core_list_remove(list->next); + /* CRC data content of list from location of index N forward, and then undo remove */ + finder=core_list_find(list,&info); + + if (!finder) + finder=list->next; + + while (finder) + { + retval=crc16(list->info->data16,retval); + finder=finder->next; + } + + #if CORE_DEBUG + ee_printf("List sort 1: %04x\n",retval); + #endif + remover=core_list_undo_remove(remover,list->next); + /* sort the list by index, in effect returning the list to original state */ + list=core_list_mergesort(list,cmp_idx,NULL); + /* CRC data content of list */ + finder=list->next; + + while (finder) + { + retval=crc16(list->info->data16,retval); + finder=finder->next; + } + + #if CORE_DEBUG + ee_printf("List sort 2: %04x\n",retval); + #endif + return retval; +} + +ee_u16 core_bench_list_1(core_results* res, ee_s16 finder_idx) +{ + ee_u16 retval=0; + ee_u16 found=0,missed=0; + list_head* list=res->list; + ee_s16 find_num=res->seed3; + list_head* this_find; + list_head* finder, *remover; + list_data info; + ee_s16 i; + info.idx=finder_idx; + + /* find values in the list, and change the list each time (reverse and cache if value found) */ + for (i=0; inext->info->data16 >> 8) & 1; + } + else + { + found++; + + if (this_find->info->data16 & 0x1) /* use found value */ + retval+=(this_find->info->data16 >> 9) & 1; + + /* and cache next item at the head of the list (if any) */ + if (this_find->next != NULL) + { + finder = this_find->next; + this_find->next = finder->next; + finder->next=list->next; + list->next=finder; + } + } + + if (info.idx>=0) + info.idx++; + + #if CORE_DEBUG + ee_printf("List find %d: [%d,%d,%d]\n",i,retval,missed,found); + #endif + } + + retval+=found*4-missed; + + /* sort the list by data content and remove one item*/ + if (finder_idx>0) + list=core_list_mergesort(list,cmp_complex,res); + + remover=core_list_remove(list->next); + /* CRC data content of list from location of index N forward, and then undo remove */ + finder=core_list_find(list,&info); + + if (!finder) + finder=list->next; + + while (finder) + { + retval=crc16(list->info->data16,retval); + finder=finder->next; + } + + #if CORE_DEBUG + ee_printf("List sort 1: %04x\n",retval); + #endif + remover=core_list_undo_remove(remover,list->next); + /* sort the list by index, in effect returning the list to original state */ + list=core_list_mergesort(list,cmp_idx,NULL); + /* CRC data content of list */ + finder=list->next; + + while (finder) + { + retval=crc16(list->info->data16,retval); + finder=finder->next; + } + + #if CORE_DEBUG + ee_printf("List sort 2: %04x\n",retval); + #endif + return retval; +} +ee_u16 core_bench_list_0(core_results* res, ee_s16 finder_idx) +{ + ee_u16 retval=0; + ee_u16 found=0,missed=0; + list_head* list=res->list; + ee_s16 find_num=res->seed3; + list_head* this_find; + list_head* finder, *remover; + list_data info; + ee_s16 i; + info.idx=finder_idx; + + /* find values in the list, and change the list each time (reverse and cache if value found) */ + for (i=0; inext->info->data16 >> 8) & 1; + } + else + { + found++; + + if (this_find->info->data16 & 0x1) /* use found value */ + retval+=(this_find->info->data16 >> 9) & 1; + + /* and cache next item at the head of the list (if any) */ + if (this_find->next != NULL) + { + finder = this_find->next; + this_find->next = finder->next; + finder->next=list->next; + list->next=finder; + } + } + + if (info.idx>=0) + info.idx++; + + #if CORE_DEBUG + ee_printf("List find %d: [%d,%d,%d]\n",i,retval,missed,found); + #endif + } + + retval+=found*4-missed; + + /* sort the list by data content and remove one item*/ + if (finder_idx>0) + list=core_list_mergesort(list,cmp_complex,res); + + remover=core_list_remove(list->next); + /* CRC data content of list from location of index N forward, and then undo remove */ + finder=core_list_find(list,&info); + + if (!finder) + finder=list->next; + + while (finder) + { + retval=crc16(list->info->data16,retval); + finder=finder->next; + } + + #if CORE_DEBUG + ee_printf("List sort 1: %04x\n",retval); + #endif + remover=core_list_undo_remove(remover,list->next); + /* sort the list by index, in effect returning the list to original state */ + list=core_list_mergesort(list,cmp_idx,NULL); + /* CRC data content of list */ + finder=list->next; + + while (finder) + { + retval=crc16(list->info->data16,retval); + finder=finder->next; + } + + #if CORE_DEBUG + ee_printf("List sort 2: %04x\n",retval); + #endif + return retval; +} + +/* Benchmark for linked list: + - Try to find multiple data items. + - List sort + - Operate on data from list (crc) + - Single remove/reinsert + At the end of this function, the list is back to original state +*/ +extern uint8 g_core_bench_list_cnt; +extern uint8 g_core_bench_list_entry[]; +ee_u16 core_bench_list(core_results* res, ee_s16 finder_idx) +{ + g_core_bench_list_cnt++; + + if(g_core_bench_list_entry[0x07&g_core_bench_list_cnt]==0) + { + return ( core_bench_list_0(res, finder_idx)); + } + else if(g_core_bench_list_entry[0x07&g_core_bench_list_cnt]==1) + { + return ( core_bench_list_1(res, finder_idx)); + } + else if(g_core_bench_list_entry[0x07&g_core_bench_list_cnt]==2) + { + return ( core_bench_list_2(res, finder_idx)); + } + else if(g_core_bench_list_entry[0x07&g_core_bench_list_cnt]==3) + { + return ( core_bench_list_3(res, finder_idx)); + } + else if(g_core_bench_list_entry[0x07&g_core_bench_list_cnt]==4) + { + return ( core_bench_list_4(res, finder_idx)); + } + else if(g_core_bench_list_entry[0x07&g_core_bench_list_cnt]==5) + { + return ( core_bench_list_5(res, finder_idx)); + } + else if(g_core_bench_list_entry[0x07&g_core_bench_list_cnt]==6) + { + return ( core_bench_list_6(res, finder_idx)); + } + else/* if(g_core_bench_list_entry[0x07&g_core_bench_list_cnt]==7)*/ + { + return ( core_bench_list_7(res, finder_idx)); + } +} +/* Function: core_list_init + Initialize list with data. + + Parameters: + blksize - Size of memory to be initialized. + memblock - Pointer to memory block. + seed - Actual values chosen depend on the seed parameter. + The seed parameter MUST be supplied from a source that cannot be determined at compile time + + Returns: + Pointer to the head of the list. + +*/ +list_head* core_list_init(ee_u32 blksize, list_head* memblock, ee_s16 seed) +{ + /* calculated pointers for the list */ + ee_u32 per_item=16+sizeof(struct list_data_s); + ee_u32 size=(blksize/per_item)-2; /* to accomodate systems with 64b pointers, and make sure same code is executed, set max list elements */ + list_head* memblock_end=memblock+size; + list_data* datablock=(list_data*)(memblock_end); + list_data* datablock_end=datablock+size; + /* some useful variables */ + ee_u32 i; + list_head* finder,*list=memblock; + list_data info; + /* create a fake items for the list head and tail */ + list->next=NULL; + list->info=datablock; + list->info->idx=0x0000; + list->info->data16=(ee_s16)0x8080; + memblock++; + datablock++; + info.idx=0x7fff; + info.data16=(ee_s16)0xffff; + core_list_insert_new(list,&info,&memblock,&datablock,memblock_end,datablock_end); + + /* then insert size items */ + for (i=0; inext; + i=1; + + while (finder->next!=NULL) + { + if (iinfo->idx=i++; + else + { + ee_u16 pat=(ee_u16)(i++ ^ seed); /* get a pseudo random number */ + finder->info->idx=0x3fff & (((i & 0x07) << 8) | pat); /* make sure the mixed items end up after the ones in sequence */ + } + + finder=finder->next; + } + + list = core_list_mergesort(list,cmp_idx,NULL); + #if CORE_DEBUG + ee_printf("Initialized list:\n"); + finder=list; + + while (finder) + { + ee_printf("[%04x,%04x]",finder->info->idx,(ee_u16)finder->info->data16); + finder=finder->next; + } + + ee_printf("\n"); + #endif + return list; +} + +/* Function: core_list_insert + Insert an item to the list + + Parameters: + insert_point - where to insert the item. + info - data for the cell. + memblock - pointer for the list header + datablock - pointer for the list data + memblock_end - end of region for list headers + datablock_end - end of region for list data + + Returns: + Pointer to new item. +*/ +list_head* core_list_insert_new(list_head* insert_point, list_data* info, list_head** memblock, list_data** datablock + , list_head* memblock_end, list_data* datablock_end) +{ + list_head* newitem; + + if ((*memblock+1) >= memblock_end) + return NULL; + + if ((*datablock+1) >= datablock_end) + return NULL; + + newitem=*memblock; + (*memblock)++; + newitem->next=insert_point->next; + insert_point->next=newitem; + newitem->info=*datablock; + (*datablock)++; + copy_info(newitem->info,info); + return newitem; +} + +/* Function: core_list_remove + Remove an item from the list. + + Operation: + For a singly linked list, remove by copying the data from the next item + over to the current cell, and unlinking the next item. + + Note: + since there is always a fake item at the end of the list, no need to check for NULL. + + Returns: + Removed item. +*/ +list_head* core_list_remove(list_head* item) +{ + list_data* tmp; + list_head* ret=item->next; + /* swap data pointers */ + tmp=item->info; + item->info=ret->info; + ret->info=tmp; + /* and eliminate item */ + item->next=item->next->next; + ret->next=NULL; + return ret; +} + +/* Function: core_list_undo_remove + Undo a remove operation. + + Operation: + Since we want each iteration of the benchmark to be exactly the same, + we need to be able to undo a remove. + Link the removed item back into the list, and switch the info items. + + Parameters: + item_removed - Return value from the + item_modified - List item that was modified during + + Returns: + The item that was linked back to the list. + +*/ +list_head* core_list_undo_remove(list_head* item_removed, list_head* item_modified) +{ + list_data* tmp; + /* swap data pointers */ + tmp=item_removed->info; + item_removed->info=item_modified->info; + item_modified->info=tmp; + /* and insert item */ + item_removed->next=item_modified->next; + item_modified->next=item_removed; + return item_removed; +} + +list_head* core_list_find_7(list_head* list,list_data* info) +{ + if (info->idx>=0) + { + while (list && (list->info->idx != info->idx)) + list=list->next; + + return list; + } + else + { + while (list && ((list->info->data16 & 0xff) != info->data16)) + list=list->next; + + return list; + } +} + +list_head* core_list_find_6(list_head* list,list_data* info) +{ + if (info->idx>=0) + { + while (list && (list->info->idx != info->idx)) + list=list->next; + + return list; + } + else + { + while (list && ((list->info->data16 & 0xff) != info->data16)) + list=list->next; + + return list; + } +} + +list_head* core_list_find_5(list_head* list,list_data* info) +{ + if (info->idx>=0) + { + while (list && (list->info->idx != info->idx)) + list=list->next; + + return list; + } + else + { + while (list && ((list->info->data16 & 0xff) != info->data16)) + list=list->next; + + return list; + } +} + +list_head* core_list_find_4(list_head* list,list_data* info) +{ + if (info->idx>=0) + { + while (list && (list->info->idx != info->idx)) + list=list->next; + + return list; + } + else + { + while (list && ((list->info->data16 & 0xff) != info->data16)) + list=list->next; + + return list; + } +} + +list_head* core_list_find_3(list_head* list,list_data* info) +{ + if (info->idx>=0) + { + while (list && (list->info->idx != info->idx)) + list=list->next; + + return list; + } + else + { + while (list && ((list->info->data16 & 0xff) != info->data16)) + list=list->next; + + return list; + } +} + +list_head* core_list_find_2(list_head* list,list_data* info) +{ + if (info->idx>=0) + { + while (list && (list->info->idx != info->idx)) + list=list->next; + + return list; + } + else + { + while (list && ((list->info->data16 & 0xff) != info->data16)) + list=list->next; + + return list; + } +} + +list_head* core_list_find_1(list_head* list,list_data* info) +{ + if (info->idx>=0) + { + while (list && (list->info->idx != info->idx)) + list=list->next; + + return list; + } + else + { + while (list && ((list->info->data16 & 0xff) != info->data16)) + list=list->next; + + return list; + } +} + + +list_head* core_list_find_0(list_head* list,list_data* info) +{ + if (info->idx>=0) + { + while (list && (list->info->idx != info->idx)) + list=list->next; + + return list; + } + else + { + while (list && ((list->info->data16 & 0xff) != info->data16)) + list=list->next; + + return list; + } +} + +/* Function: core_list_find + Find an item in the list + + Operation: + Find an item by idx (if not 0) or specific data value + + Parameters: + list - list head + info - idx or data to find + + Returns: + Found item, or NULL if not found. +*/ +extern uint8 g_core_list_find_cnt; +extern uint8 g_core_list_find_entry[]; +list_head* core_list_find(list_head* list,list_data* info) +{ + g_core_list_find_cnt++; + + if(g_core_list_find_entry[0x07&g_core_list_find_cnt]==0) + { + return ( core_list_find_0(list,info) ); + } + else if(g_core_list_find_entry[0x07&g_core_list_find_cnt]==1) + { + return ( core_list_find_1(list,info) ); + } + else if(g_core_list_find_entry[0x07&g_core_list_find_cnt]==2) + { + return ( core_list_find_2(list,info) ); + } + else if(g_core_list_find_entry[0x07&g_core_list_find_cnt]==3) + { + return ( core_list_find_3(list,info) ); + } + else if(g_core_list_find_entry[0x07&g_core_list_find_cnt]==4) + { + return ( core_list_find_4(list,info) ); + } + else if(g_core_list_find_entry[0x07&g_core_list_find_cnt]==5) + { + return ( core_list_find_5(list,info) ); + } + else if(g_core_list_find_entry[0x07&g_core_list_find_cnt]==6) + { + return ( core_list_find_6(list,info) ); + } + else/* if(g_core_list_find_entry[0x07&g_core_list_find_cnt]==7)*/ + { + return ( core_list_find_7(list,info) ); + } +} +/* Function: core_list_reverse + Reverse a list + + Operation: + Rearrange the pointers so the list is reversed. + + Parameters: + list - list head + info - idx or data to find + + Returns: + Found item, or NULL if not found. +*/ + +list_head* core_list_reverse(list_head* list) +{ + list_head* next=NULL, *tmp; + + while (list) + { + tmp=list->next; + list->next=next; + next=list; + list=tmp; + } + + return next; +} + +list_head* core_list_mergesort_7(list_head* list, list_cmp cmp, core_results* res) +{ + list_head* p, *q, *e, *tail; + ee_s32 insize, nmerges, psize, qsize, i; + insize = 1; + + while (1) + { + p = list; + list = NULL; + tail = NULL; + nmerges = 0; /* count number of merges we do in this pass */ + + while (p) + { + nmerges++; /* there exists a merge to be done */ + /* step `insize' places along from p */ + q = p; + psize = 0; + + for (i = 0; i < insize; i++) + { + psize++; + q = q->next; + + if (!q) break; + } + + /* if q hasn't fallen off end, we have two lists to merge */ + qsize = insize; + + /* now we have two lists; merge them */ + while (psize > 0 || (qsize > 0 && q)) + { + /* decide whether next element of merge comes from p or q */ + if (psize == 0) + { + /* p is empty; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + else if (qsize == 0 || !q) + { + /* q is empty; e must come from p. */ + e = p; + p = p->next; + psize--; + } + else if (cmp(p->info,q->info,res) <= 0) + { + /* First element of p is lower (or same); e must come from p. */ + e = p; + p = p->next; + psize--; + } + else + { + /* First element of q is lower; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + + /* add the next element to the merged list */ + if (tail) + { + tail->next = e; + } + else + { + list = e; + } + + tail = e; + } + + /* now p has stepped `insize' places along, and q has too */ + p = q; + } + + tail->next = NULL; + + /* If we have done only one merge, we're finished. */ + if (nmerges <= 1) /* allow for nmerges==0, the empty list case */ + return list; + + /* Otherwise repeat, merging lists twice the size */ + insize *= 2; + } + + #if COMPILER_REQUIRES_SORT_RETURN + return list; + #endif +} + + +list_head* core_list_mergesort_6(list_head* list, list_cmp cmp, core_results* res) +{ + list_head* p, *q, *e, *tail; + ee_s32 insize, nmerges, psize, qsize, i; + insize = 1; + + while (1) + { + p = list; + list = NULL; + tail = NULL; + nmerges = 0; /* count number of merges we do in this pass */ + + while (p) + { + nmerges++; /* there exists a merge to be done */ + /* step `insize' places along from p */ + q = p; + psize = 0; + + for (i = 0; i < insize; i++) + { + psize++; + q = q->next; + + if (!q) break; + } + + /* if q hasn't fallen off end, we have two lists to merge */ + qsize = insize; + + /* now we have two lists; merge them */ + while (psize > 0 || (qsize > 0 && q)) + { + /* decide whether next element of merge comes from p or q */ + if (psize == 0) + { + /* p is empty; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + else if (qsize == 0 || !q) + { + /* q is empty; e must come from p. */ + e = p; + p = p->next; + psize--; + } + else if (cmp(p->info,q->info,res) <= 0) + { + /* First element of p is lower (or same); e must come from p. */ + e = p; + p = p->next; + psize--; + } + else + { + /* First element of q is lower; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + + /* add the next element to the merged list */ + if (tail) + { + tail->next = e; + } + else + { + list = e; + } + + tail = e; + } + + /* now p has stepped `insize' places along, and q has too */ + p = q; + } + + tail->next = NULL; + + /* If we have done only one merge, we're finished. */ + if (nmerges <= 1) /* allow for nmerges==0, the empty list case */ + return list; + + /* Otherwise repeat, merging lists twice the size */ + insize *= 2; + } + + #if COMPILER_REQUIRES_SORT_RETURN + return list; + #endif +} + + +list_head* core_list_mergesort_5(list_head* list, list_cmp cmp, core_results* res) +{ + list_head* p, *q, *e, *tail; + ee_s32 insize, nmerges, psize, qsize, i; + insize = 1; + + while (1) + { + p = list; + list = NULL; + tail = NULL; + nmerges = 0; /* count number of merges we do in this pass */ + + while (p) + { + nmerges++; /* there exists a merge to be done */ + /* step `insize' places along from p */ + q = p; + psize = 0; + + for (i = 0; i < insize; i++) + { + psize++; + q = q->next; + + if (!q) break; + } + + /* if q hasn't fallen off end, we have two lists to merge */ + qsize = insize; + + /* now we have two lists; merge them */ + while (psize > 0 || (qsize > 0 && q)) + { + /* decide whether next element of merge comes from p or q */ + if (psize == 0) + { + /* p is empty; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + else if (qsize == 0 || !q) + { + /* q is empty; e must come from p. */ + e = p; + p = p->next; + psize--; + } + else if (cmp(p->info,q->info,res) <= 0) + { + /* First element of p is lower (or same); e must come from p. */ + e = p; + p = p->next; + psize--; + } + else + { + /* First element of q is lower; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + + /* add the next element to the merged list */ + if (tail) + { + tail->next = e; + } + else + { + list = e; + } + + tail = e; + } + + /* now p has stepped `insize' places along, and q has too */ + p = q; + } + + tail->next = NULL; + + /* If we have done only one merge, we're finished. */ + if (nmerges <= 1) /* allow for nmerges==0, the empty list case */ + return list; + + /* Otherwise repeat, merging lists twice the size */ + insize *= 2; + } + + #if COMPILER_REQUIRES_SORT_RETURN + return list; + #endif +} + + +list_head* core_list_mergesort_4(list_head* list, list_cmp cmp, core_results* res) +{ + list_head* p, *q, *e, *tail; + ee_s32 insize, nmerges, psize, qsize, i; + insize = 1; + + while (1) + { + p = list; + list = NULL; + tail = NULL; + nmerges = 0; /* count number of merges we do in this pass */ + + while (p) + { + nmerges++; /* there exists a merge to be done */ + /* step `insize' places along from p */ + q = p; + psize = 0; + + for (i = 0; i < insize; i++) + { + psize++; + q = q->next; + + if (!q) break; + } + + /* if q hasn't fallen off end, we have two lists to merge */ + qsize = insize; + + /* now we have two lists; merge them */ + while (psize > 0 || (qsize > 0 && q)) + { + /* decide whether next element of merge comes from p or q */ + if (psize == 0) + { + /* p is empty; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + else if (qsize == 0 || !q) + { + /* q is empty; e must come from p. */ + e = p; + p = p->next; + psize--; + } + else if (cmp(p->info,q->info,res) <= 0) + { + /* First element of p is lower (or same); e must come from p. */ + e = p; + p = p->next; + psize--; + } + else + { + /* First element of q is lower; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + + /* add the next element to the merged list */ + if (tail) + { + tail->next = e; + } + else + { + list = e; + } + + tail = e; + } + + /* now p has stepped `insize' places along, and q has too */ + p = q; + } + + tail->next = NULL; + + /* If we have done only one merge, we're finished. */ + if (nmerges <= 1) /* allow for nmerges==0, the empty list case */ + return list; + + /* Otherwise repeat, merging lists twice the size */ + insize *= 2; + } + + #if COMPILER_REQUIRES_SORT_RETURN + return list; + #endif +} + + +list_head* core_list_mergesort_3(list_head* list, list_cmp cmp, core_results* res) +{ + list_head* p, *q, *e, *tail; + ee_s32 insize, nmerges, psize, qsize, i; + insize = 1; + + while (1) + { + p = list; + list = NULL; + tail = NULL; + nmerges = 0; /* count number of merges we do in this pass */ + + while (p) + { + nmerges++; /* there exists a merge to be done */ + /* step `insize' places along from p */ + q = p; + psize = 0; + + for (i = 0; i < insize; i++) + { + psize++; + q = q->next; + + if (!q) break; + } + + /* if q hasn't fallen off end, we have two lists to merge */ + qsize = insize; + + /* now we have two lists; merge them */ + while (psize > 0 || (qsize > 0 && q)) + { + /* decide whether next element of merge comes from p or q */ + if (psize == 0) + { + /* p is empty; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + else if (qsize == 0 || !q) + { + /* q is empty; e must come from p. */ + e = p; + p = p->next; + psize--; + } + else if (cmp(p->info,q->info,res) <= 0) + { + /* First element of p is lower (or same); e must come from p. */ + e = p; + p = p->next; + psize--; + } + else + { + /* First element of q is lower; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + + /* add the next element to the merged list */ + if (tail) + { + tail->next = e; + } + else + { + list = e; + } + + tail = e; + } + + /* now p has stepped `insize' places along, and q has too */ + p = q; + } + + tail->next = NULL; + + /* If we have done only one merge, we're finished. */ + if (nmerges <= 1) /* allow for nmerges==0, the empty list case */ + return list; + + /* Otherwise repeat, merging lists twice the size */ + insize *= 2; + } + + #if COMPILER_REQUIRES_SORT_RETURN + return list; + #endif +} + + +list_head* core_list_mergesort_2(list_head* list, list_cmp cmp, core_results* res) +{ + list_head* p, *q, *e, *tail; + ee_s32 insize, nmerges, psize, qsize, i; + insize = 1; + + while (1) + { + p = list; + list = NULL; + tail = NULL; + nmerges = 0; /* count number of merges we do in this pass */ + + while (p) + { + nmerges++; /* there exists a merge to be done */ + /* step `insize' places along from p */ + q = p; + psize = 0; + + for (i = 0; i < insize; i++) + { + psize++; + q = q->next; + + if (!q) break; + } + + /* if q hasn't fallen off end, we have two lists to merge */ + qsize = insize; + + /* now we have two lists; merge them */ + while (psize > 0 || (qsize > 0 && q)) + { + /* decide whether next element of merge comes from p or q */ + if (psize == 0) + { + /* p is empty; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + else if (qsize == 0 || !q) + { + /* q is empty; e must come from p. */ + e = p; + p = p->next; + psize--; + } + else if (cmp(p->info,q->info,res) <= 0) + { + /* First element of p is lower (or same); e must come from p. */ + e = p; + p = p->next; + psize--; + } + else + { + /* First element of q is lower; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + + /* add the next element to the merged list */ + if (tail) + { + tail->next = e; + } + else + { + list = e; + } + + tail = e; + } + + /* now p has stepped `insize' places along, and q has too */ + p = q; + } + + tail->next = NULL; + + /* If we have done only one merge, we're finished. */ + if (nmerges <= 1) /* allow for nmerges==0, the empty list case */ + return list; + + /* Otherwise repeat, merging lists twice the size */ + insize *= 2; + } + + #if COMPILER_REQUIRES_SORT_RETURN + return list; + #endif +} + + +list_head* core_list_mergesort_1(list_head* list, list_cmp cmp, core_results* res) +{ + list_head* p, *q, *e, *tail; + ee_s32 insize, nmerges, psize, qsize, i; + insize = 1; + + while (1) + { + p = list; + list = NULL; + tail = NULL; + nmerges = 0; /* count number of merges we do in this pass */ + + while (p) + { + nmerges++; /* there exists a merge to be done */ + /* step `insize' places along from p */ + q = p; + psize = 0; + + for (i = 0; i < insize; i++) + { + psize++; + q = q->next; + + if (!q) break; + } + + /* if q hasn't fallen off end, we have two lists to merge */ + qsize = insize; + + /* now we have two lists; merge them */ + while (psize > 0 || (qsize > 0 && q)) + { + /* decide whether next element of merge comes from p or q */ + if (psize == 0) + { + /* p is empty; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + else if (qsize == 0 || !q) + { + /* q is empty; e must come from p. */ + e = p; + p = p->next; + psize--; + } + else if (cmp(p->info,q->info,res) <= 0) + { + /* First element of p is lower (or same); e must come from p. */ + e = p; + p = p->next; + psize--; + } + else + { + /* First element of q is lower; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + + /* add the next element to the merged list */ + if (tail) + { + tail->next = e; + } + else + { + list = e; + } + + tail = e; + } + + /* now p has stepped `insize' places along, and q has too */ + p = q; + } + + tail->next = NULL; + + /* If we have done only one merge, we're finished. */ + if (nmerges <= 1) /* allow for nmerges==0, the empty list case */ + return list; + + /* Otherwise repeat, merging lists twice the size */ + insize *= 2; + } + + #if COMPILER_REQUIRES_SORT_RETURN + return list; + #endif +} + + +list_head* core_list_mergesort_0(list_head* list, list_cmp cmp, core_results* res) +{ + list_head* p, *q, *e, *tail; + ee_s32 insize, nmerges, psize, qsize, i; + insize = 1; + + while (1) + { + p = list; + list = NULL; + tail = NULL; + nmerges = 0; /* count number of merges we do in this pass */ + + while (p) + { + nmerges++; /* there exists a merge to be done */ + /* step `insize' places along from p */ + q = p; + psize = 0; + + for (i = 0; i < insize; i++) + { + psize++; + q = q->next; + + if (!q) break; + } + + /* if q hasn't fallen off end, we have two lists to merge */ + qsize = insize; + + /* now we have two lists; merge them */ + while (psize > 0 || (qsize > 0 && q)) + { + /* decide whether next element of merge comes from p or q */ + if (psize == 0) + { + /* p is empty; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + else if (qsize == 0 || !q) + { + /* q is empty; e must come from p. */ + e = p; + p = p->next; + psize--; + } + else if (cmp(p->info,q->info,res) <= 0) + { + /* First element of p is lower (or same); e must come from p. */ + e = p; + p = p->next; + psize--; + } + else + { + /* First element of q is lower; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + + /* add the next element to the merged list */ + if (tail) + { + tail->next = e; + } + else + { + list = e; + } + + tail = e; + } + + /* now p has stepped `insize' places along, and q has too */ + p = q; + } + + tail->next = NULL; + + /* If we have done only one merge, we're finished. */ + if (nmerges <= 1) /* allow for nmerges==0, the empty list case */ + return list; + + /* Otherwise repeat, merging lists twice the size */ + insize *= 2; + } + + #if COMPILER_REQUIRES_SORT_RETURN + return list; + #endif +} + + +/* Function: core_list_mergesort + Sort the list in place without recursion. + + Description: + Use mergesort, as for linked list this is a realistic solution. + Also, since this is aimed at embedded, care was taken to use iterative rather then recursive algorithm. + The sort can either return the list to original order (by idx) , + or use the data item to invoke other other algorithms and change the order of the list. + + Parameters: + list - list to be sorted. + cmp - cmp function to use + + Returns: + New head of the list. + + Note: + We have a special header for the list that will always be first, + but the algorithm could theoretically modify where the list starts. + +*/ + +extern uint8 g_core_list_mergesort_cnt; +extern uint8 g_core_list_mergesort_entry[]; +list_head* core_list_mergesort(list_head* list, list_cmp cmp, core_results* res) +{ + g_core_list_mergesort_cnt++; + + if(g_core_list_mergesort_entry[0x07&g_core_list_mergesort_cnt]==0) + { + return ( core_list_mergesort_0(list, cmp, res)); + } + else if(g_core_list_mergesort_entry[0x07&g_core_list_mergesort_cnt]==1) + { + return ( core_list_mergesort_1(list, cmp, res)); + } + else if(g_core_list_mergesort_entry[0x07&g_core_list_mergesort_cnt]==2) + { + return ( core_list_mergesort_2(list, cmp, res)); + } + else if(g_core_list_mergesort_entry[0x07&g_core_list_mergesort_cnt]==3) + { + return ( core_list_mergesort_3(list, cmp, res)); + } + else if(g_core_list_mergesort_entry[0x07&g_core_list_mergesort_cnt]==4) + { + return ( core_list_mergesort_4(list, cmp, res)); + } + else if(g_core_list_mergesort_entry[0x07&g_core_list_mergesort_cnt]==5) + { + return ( core_list_mergesort_5(list, cmp, res)); + } + else if(g_core_list_mergesort_entry[0x07&g_core_list_mergesort_cnt]==6) + { + return ( core_list_mergesort_6(list, cmp, res)); + } + else/* if(g_core_list_mergesort_entry[0x07&g_core_list_mergesort_cnt]==7)*/ + { + return ( core_list_mergesort_7(list, cmp, res)); + } +} diff --git a/src/components/coremark/core_main.c b/src/components/coremark/core_main.c new file mode 100644 index 0000000..9e003af --- /dev/null +++ b/src/components/coremark/core_main.c @@ -0,0 +1,472 @@ +/* + Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + + 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. + + Original Author: Shay Gal-on +*/ + +/* File: core_main.c + This file contains the framework to acquire a block of memory, seed initial parameters, tun t he benchmark and report the results. +*/ +#include "coremark.h" + +uint8 g_crc_cnt = 0; +uint8 g_core_state_cnt= 0; +uint8 g_calc_func_cnt=0; +uint8 g_core_bench_list_cnt = 0; +uint8 g_core_list_mergesort_cnt=0; +uint8 g_core_list_find_cnt = 0; +uint8 g_matrix_sum_cnt=0; +uint8 g_matrix_mul_matrix_cnt=0; + + +uint8 g_crc_entry[8] = { 0, 1, 2, 3, 4, 5, 6, 7}; +uint8 g_core_state_entry[8] = { 0, 1, 2, 3, 4, 5, 6, 7}; +uint8 g_calc_func_entry[8] = { 0, 1, 2, 3, 4, 5, 6, 7}; +uint8 g_core_bench_list_entry[8] = { 0, 1, 2, 3, 4, 5, 6, 7}; +uint8 g_core_list_mergesort_entry[8] = { 0, 1, 2, 3, 4, 5, 6, 7}; +uint8 g_core_list_find_entry[8] = { 0, 1, 2, 3, 4, 5, 6, 7}; +uint8 g_matrix_sum_entry[8] = { 0, 1, 2, 3, 4, 5, 6, 7}; +uint8 g_matrix_mul_matrix_entry[8] = { 0, 1, 2, 3, 4, 5, 6, 7}; + +//----------------------------------------------------------------- +//core mark in cache 6K +//uint8 g_crc_entry[8] = { 0, 1, 2, 0, 1, 2, 0, 1}; +//uint8 g_core_state_entry[8] = { 0, 1, 2, 0, 1, 2, 0, 1}; +//uint8 g_calc_func_entry[8] = { 0, 1, 2, 0, 1, 2, 0, 1}; +//uint8 g_core_bench_list_entry[8] = { 0, 1, 2, 0, 1, 2, 0, 1}; +//uint8 g_core_list_mergesort_entry[8] = { 0, 1, 2, 0, 1, 2, 0, 1}; +//uint8 g_core_list_find_entry[8] = { 0, 1, 2, 0, 1, 2, 0, 1}; +//uint8 g_matrix_sum_entry[8] = { 0, 1, 2, 0, 1, 2, 0, 1}; +//uint8 g_matrix_mul_matrix_entry[8] = { 0, 1, 2, 0, 1, 2, 0, 1}; +/* Function: iterate + Run the benchmark for a specified number of iterations. + + Operation: + For each type of benchmarked algorithm: + a - Initialize the data block for the algorithm. + b - Execute the algorithm N times. + + Returns: + NULL. +*/ +static ee_u16 list_known_crc[] = {(ee_u16)0xd4b0,(ee_u16)0x3340,(ee_u16)0x6a79,(ee_u16)0xe714,(ee_u16)0xe3c1}; +static ee_u16 matrix_known_crc[] = {(ee_u16)0xbe52,(ee_u16)0x1199,(ee_u16)0x5608,(ee_u16)0x1fd7,(ee_u16)0x0747}; +static ee_u16 state_known_crc[] = {(ee_u16)0x5e47,(ee_u16)0x39bf,(ee_u16)0xe5a4,(ee_u16)0x8e3a,(ee_u16)0x8d84}; +void* iterate(void* pres) +{ + ee_u32 i; + ee_u16 crc; + core_results* res=(core_results*)pres; + ee_u32 iterations=res->iterations; + res->crc=0; + res->crclist=0; + res->crcmatrix=0; + res->crcstate=0; + + for (i=0; icrc=crcu16(crc,res->crc); + crc=core_bench_list(res,-1); + res->crc=crcu16(crc,res->crc); + + if (i==0) res->crclist=res->crc; + } + + return NULL; +} + +#if (SEED_METHOD==SEED_ARG) + ee_s32 get_seed_args(int i, int argc, char* argv[]); + #define get_seed(x) (ee_s16)get_seed_args(x,argc,argv) + #define get_seed_32(x) get_seed_args(x,argc,argv) +#else /* via function or volatile */ + ee_s32 get_seed_32(int i); + #define get_seed(x) (ee_s16)get_seed_32(x) +#endif + +#if (MEM_METHOD==MEM_STATIC) + ee_u8 static_memblk[TOTAL_DATA_SIZE]; +#endif +char* mem_name[3] = {"Static","Heap","Stack"}; +/* Function: main + Main entry routine for the benchmark. + This function is responsible for the following steps: + + 1 - Initialize input seeds from a source that cannot be determined at compile time. + 2 - Initialize memory block for use. + 3 - Run and time the benchmark. + 4 - Report results, testing the validity of the output if the seeds are known. + + Arguments: + 1 - first seed : Any value + 2 - second seed : Must be identical to first for iterations to be identical + 3 - third seed : Any value, should be at least an order of magnitude less then the input size, but bigger then 32. + 4 - Iterations : Special, if set to 0, iterations will be automatically determined such that the benchmark will run between 10 to 100 secs + +*/ + +#if MAIN_HAS_NOARGC +MAIN_RETURN_TYPE cm_main(void) +{ + int argc=0; + char* argv[1]; +#else +MAIN_RETURN_TYPE main(int argc, char* argv[]) +{ +#endif + ee_u16 i,j=0,num_algorithms=0; + ee_s16 known_id=-1,total_errors=0; + ee_u16 seedcrc=0; + CORE_TICKS total_time; + core_results results[MULTITHREAD]; + #if (MEM_METHOD==MEM_STACK) + ee_u8 stack_memblock[TOTAL_DATA_SIZE*MULTITHREAD]; + #endif + /* first call any initializations needed */ + portable_init(&(results[0].port), &argc, argv); + + /* First some checks to make sure benchmark will run ok */ + if (sizeof(struct list_head_s)>128) + { + ee_printf("list_head structure too big for comparable data!\n"); + return MAIN_RETURN_VAL; + } + + results[0].seed1=get_seed(1); + results[0].seed2=get_seed(2); + results[0].seed3=get_seed(3); + results[0].iterations=get_seed_32(4); + #if CORE_DEBUG + results[0].iterations=1; + #endif + results[0].execs=get_seed_32(5); + + if (results[0].execs==0) /* if not supplied, execute all algorithms */ + { + results[0].execs=ALL_ALGORITHMS_MASK; + } + + /* put in some default values based on one seed only for easy testing */ + if ((results[0].seed1==0) && (results[0].seed2==0) && (results[0].seed3==0)) /* validation run */ + { + results[0].seed1=0; + results[0].seed2=0; + results[0].seed3=0x66; + } + + if ((results[0].seed1==1) && (results[0].seed2==0) && (results[0].seed3==0)) /* perfromance run */ + { + results[0].seed1=0x3415; + results[0].seed2=0x3415; + results[0].seed3=0x66; + } + + #if (MEM_METHOD==MEM_STATIC) + results[0].memblock[0]=(void*)static_memblk; + results[0].size=TOTAL_DATA_SIZE; + results[0].err=0; + #if (MULTITHREAD>1) +#error "Cannot use a static data area with multiple contexts!" + #endif + #elif (MEM_METHOD==MEM_MALLOC) + + for (i=0 ; i1) + + if (default_num_contexts>MULTITHREAD) + { + default_num_contexts=MULTITHREAD; + } + + for (i=0 ; i=0) + { + for (i=0 ; i 0) + ee_printf("Iterations/Sec : %f\n",default_num_contexts*results[0].iterations/time_in_secs(total_time)); + + #else + ee_printf("Total time (secs): %d\n",time_in_secs(total_time)); + + if (time_in_secs(total_time) > 0) + ee_printf("Iterations/Sec : %d\n",default_num_contexts*results[0].iterations/time_in_secs(total_time)); + + #endif + + if (time_in_secs(total_time) < 10) + { + ee_printf("ERROR! Must execute for at least 10 secs for a valid result!\n"); + total_errors++; + } + + ee_printf("Iterations : %lu\n", (long unsigned) default_num_contexts*results[0].iterations); + ee_printf("Compiler version : %s\n",COMPILER_VERSION); + ee_printf("Compiler flags : %s\n",COMPILER_FLAGS); + #if (MULTITHREAD>1) + ee_printf("Parallel %s : %d\n",PARALLEL_METHOD,default_num_contexts); + #endif + ee_printf("Memory location : %s\n",MEM_LOCATION); + /* output for verification */ + ee_printf("seedcrc : 0x%04x\n",seedcrc); + + if (results[0].execs & ID_LIST) + for (i=0 ; i1) + ee_printf(" / %d:%s",default_num_contexts,PARALLEL_METHOD); + #endif + ee_printf("\n"); + } + + #endif + } + + if (total_errors>0) + ee_printf("Errors detected\n"); + + if (total_errors<0) + ee_printf("Cannot validate operation for these seed values, please compare with results on a known platform.\n"); + + #if (MEM_METHOD==MEM_MALLOC) + + for (i=0 ; i>(from)) & (~(0xffffffff << (to)))) + +#if CORE_DEBUG +void printmat(MATDAT* A, ee_u32 N, char* name) +{ + ee_u32 i,j; + ee_printf("Matrix %s [%dx%d]:\n",name,N,N); + + for (i=0; i N times, + changing the matrix values slightly by a constant amount each time. +*/ +ee_u16 core_bench_matrix(mat_params* p, ee_s16 seed, ee_u16 crc) +{ + ee_u32 N=p->N; + MATRES* C=p->C; + MATDAT* A=p->A; + MATDAT* B=p->B; + MATDAT val=(MATDAT)seed; + crc=crc16(matrix_test(N,C,A,B,val),crc); + return crc; +} + +/* Function: matrix_test + Perform matrix manipulation. + + Parameters: + N - Dimensions of the matrix. + C - memory for result matrix. + A - input matrix + B - operator matrix (not changed during operations) + + Returns: + A CRC value that captures all results calculated in the function. + In particular, crc of the value calculated on the result matrix + after each step by . + + Operation: + + 1 - Add a constant value to all elements of a matrix. + 2 - Multiply a matrix by a constant. + 3 - Multiply a matrix by a vector. + 4 - Multiply a matrix by a matrix. + 5 - Add a constant value to all elements of a matrix. + + After the last step, matrix A is back to original contents. +*/ +ee_s16 matrix_test(ee_u32 N, MATRES* C, MATDAT* A, MATDAT* B, MATDAT val) +{ + ee_u16 crc=0; + MATDAT clipval=matrix_big(val); + matrix_add_const(N,A,val); /* make sure data changes */ + #if CORE_DEBUG + printmat(A,N,"matrix_add_const"); + #endif + matrix_mul_const(N,C,A,val); + crc=crc16(matrix_sum(N,C,clipval),crc); + #if CORE_DEBUG + printmatC(C,N,"matrix_mul_const"); + #endif + matrix_mul_vect(N,C,A,B); + crc=crc16(matrix_sum(N,C,clipval),crc); + #if CORE_DEBUG + printmatC(C,N,"matrix_mul_vect"); + #endif + matrix_mul_matrix(N,C,A,B); + crc=crc16(matrix_sum(N,C,clipval),crc); + #if CORE_DEBUG + printmatC(C,N,"matrix_mul_matrix"); + #endif + matrix_mul_matrix_bitextract(N,C,A,B); + crc=crc16(matrix_sum(N,C,clipval),crc); + #if CORE_DEBUG + printmatC(C,N,"matrix_mul_matrix_bitextract"); + #endif + matrix_add_const(N,A,-val); /* return matrix to initial value */ + return crc; +} + +/* Function : matrix_init + Initialize the memory block for matrix benchmarking. + + Parameters: + blksize - Size of memory to be initialized. + memblk - Pointer to memory block. + seed - Actual values chosen depend on the seed parameter. + p - pointers to containing initialized matrixes. + + Returns: + Matrix dimensions. + + Note: + The seed parameter MUST be supplied from a source that cannot be determined at compile time +*/ +ee_u32 core_init_matrix(ee_u32 blksize, void* memblk, ee_s32 seed, mat_params* p) +{ + ee_u32 N=0; + MATDAT* A; + MATDAT* B; + ee_s32 order=1; + MATDAT val; + ee_u32 i=0,j=0; + + if (seed==0) + seed=1; + + while (jA=A; + p->B=B; + p->C=(MATRES*)align_mem(B+N*N); + p->N=N; + #if CORE_DEBUG + printmat(A,N,"A"); + printmat(B,N,"B"); + #endif + return N; +} + + +ee_s16 matrix_sum_7(ee_u32 N, MATRES* C, MATDAT clipval) +{ + MATRES tmp=0,prev=0,cur=0; + ee_s16 ret=0; + ee_u32 i,j; + + for (i=0; iclipval) + { + ret+=10; + tmp=0; + } + else + { + ret += (cur>prev) ? 1 : 0; + } + + prev=cur; + } + } + + return ret; +} + +ee_s16 matrix_sum_6(ee_u32 N, MATRES* C, MATDAT clipval) +{ + MATRES tmp=0,prev=0,cur=0; + ee_s16 ret=0; + ee_u32 i,j; + + for (i=0; iclipval) + { + ret+=10; + tmp=0; + } + else + { + ret += (cur>prev) ? 1 : 0; + } + + prev=cur; + } + } + + return ret; +} + +ee_s16 matrix_sum_5(ee_u32 N, MATRES* C, MATDAT clipval) +{ + MATRES tmp=0,prev=0,cur=0; + ee_s16 ret=0; + ee_u32 i,j; + + for (i=0; iclipval) + { + ret+=10; + tmp=0; + } + else + { + ret += (cur>prev) ? 1 : 0; + } + + prev=cur; + } + } + + return ret; +} + +ee_s16 matrix_sum_4(ee_u32 N, MATRES* C, MATDAT clipval) +{ + MATRES tmp=0,prev=0,cur=0; + ee_s16 ret=0; + ee_u32 i,j; + + for (i=0; iclipval) + { + ret+=10; + tmp=0; + } + else + { + ret += (cur>prev) ? 1 : 0; + } + + prev=cur; + } + } + + return ret; +} + +ee_s16 matrix_sum_3(ee_u32 N, MATRES* C, MATDAT clipval) +{ + MATRES tmp=0,prev=0,cur=0; + ee_s16 ret=0; + ee_u32 i,j; + + for (i=0; iclipval) + { + ret+=10; + tmp=0; + } + else + { + ret += (cur>prev) ? 1 : 0; + } + + prev=cur; + } + } + + return ret; +} + +ee_s16 matrix_sum_2(ee_u32 N, MATRES* C, MATDAT clipval) +{ + MATRES tmp=0,prev=0,cur=0; + ee_s16 ret=0; + ee_u32 i,j; + + for (i=0; iclipval) + { + ret+=10; + tmp=0; + } + else + { + ret += (cur>prev) ? 1 : 0; + } + + prev=cur; + } + } + + return ret; +} + +ee_s16 matrix_sum_1(ee_u32 N, MATRES* C, MATDAT clipval) +{ + MATRES tmp=0,prev=0,cur=0; + ee_s16 ret=0; + ee_u32 i,j; + + for (i=0; iclipval) + { + ret+=10; + tmp=0; + } + else + { + ret += (cur>prev) ? 1 : 0; + } + + prev=cur; + } + } + + return ret; +} + + +ee_s16 matrix_sum_0(ee_u32 N, MATRES* C, MATDAT clipval) +{ + MATRES tmp=0,prev=0,cur=0; + ee_s16 ret=0; + ee_u32 i,j; + + for (i=0; iclipval) + { + ret+=10; + tmp=0; + } + else + { + ret += (cur>prev) ? 1 : 0; + } + + prev=cur; + } + } + + return ret; +} + + +/* Function: matrix_sum + Calculate a function that depends on the values of elements in the matrix. + + For each element, accumulate into a temporary variable. + + As long as this value is under the parameter clipval, + add 1 to the result if the element is bigger then the previous. + + Otherwise, reset the accumulator and add 10 to the result. +*/ + +extern uint8 g_matrix_sum_cnt; +extern uint8 g_matrix_sum_entry[]; +ee_s16 matrix_sum(ee_u32 N, MATRES* C, MATDAT clipval) +{ + g_matrix_sum_cnt++; + + if(g_matrix_sum_entry[0x07&g_matrix_sum_cnt]==0) + { + return (matrix_sum_0(N, C, clipval)); + } + else if(g_matrix_sum_entry[0x07&g_matrix_sum_cnt]==1) + { + return (matrix_sum_1(N, C, clipval)); + } + else if(g_matrix_sum_entry[0x07&g_matrix_sum_cnt]==2) + { + return (matrix_sum_2(N, C, clipval)); + } + else if(g_matrix_sum_entry[0x07&g_matrix_sum_cnt]==3) + { + return (matrix_sum_3(N, C, clipval)); + } + else if(g_matrix_sum_entry[0x07&g_matrix_sum_cnt]==4) + { + return (matrix_sum_4(N, C, clipval)); + } + else if(g_matrix_sum_entry[0x07&g_matrix_sum_cnt]==5) + { + return (matrix_sum_5(N, C, clipval)); + } + else if(g_matrix_sum_entry[0x07&g_matrix_sum_cnt]==6) + { + return (matrix_sum_6(N, C, clipval)); + } + else/* if(g_matrix_sum_entry[0x07&g_matrix_sum_cnt]==7)*/ + { + return (matrix_sum_7(N, C, clipval)); + } +} + +/* Function: matrix_mul_const + Multiply a matrix by a constant. + This could be used as a scaler for instance. +*/ +void matrix_mul_const(ee_u32 N, MATRES* C, MATDAT* A, MATDAT val) +{ + ee_u32 i,j; + + for (i=0; i +#include +#include "coremark.h" + +#if VALIDATION_RUN + volatile ee_s32 seed1_volatile=0x3415; + volatile ee_s32 seed2_volatile=0x3415; + volatile ee_s32 seed3_volatile=0x66; +#endif +#if PERFORMANCE_RUN + volatile ee_s32 seed1_volatile=0x0; + volatile ee_s32 seed2_volatile=0x0; + volatile ee_s32 seed3_volatile=0x66; +#endif +#if PROFILE_RUN + volatile ee_s32 seed1_volatile=0x8; + volatile ee_s32 seed2_volatile=0x8 + volatile ee_s32 seed3_volatile=0x8; +#endif +//#define ITERATIONS 16 +#define ITERATIONS 256 +volatile ee_s32 seed4_volatile=ITERATIONS; +volatile ee_s32 seed5_volatile=0; +/* Porting : Timing functions + How to capture time and convert to seconds must be ported to whatever is supported by the platform. + e.g. Read value from on board RTC, read value from cpu clock cycles performance counter etc. + Sample implementation for standard time.h and windows.h definitions included. +*/ +/* Define : TIMER_RES_DIVIDER + Divider to trade off timer resolution and total time that can be measured. + + Use lower values to increase resolution, but make sure that overflow does not occur. + If there are issues with the return value overflowing, increase this value. +*/ +//#define NSECS_PER_SEC CLOCKS_PER_SEC + +uint32_t rtc_get_counter(void); +char s_tmpstr[2048]; +#define NSECS_PER_SEC 32768 +#define CORETIMETYPE clock_t +//#define GETMYTIME(_t) (*_t=clock()) +#define GETMYTIME(_t) (*_t=(clock_t)rtc_get_counter()) +#define MYTIMEDIFF(fin,ini) ((fin)-(ini)) +#define TIMER_RES_DIVIDER 1 +#define SAMPLE_TIME_IMPLEMENTATION 1 +#define EE_TICKS_PER_SEC (NSECS_PER_SEC / TIMER_RES_DIVIDER) + +/** Define Host specific (POSIX), or target specific global time variables. */ +static CORETIMETYPE start_time_val, stop_time_val; + +/* Function : start_time + This function will be called right before starting the timed portion of the benchmark. + + Implementation may be capturing a system timer (as implemented in the example code) + or zeroing some system parameters - e.g. setting the cpu clocks cycles to 0. +*/ +void start_time(void) +{ + GETMYTIME(&start_time_val ); +} +/* Function : stop_time + This function will be called right after ending the timed portion of the benchmark. + + Implementation may be capturing a system timer (as implemented in the example code) + or other system parameters - e.g. reading the current value of cpu cycles counter. +*/ +void stop_time(void) +{ + GETMYTIME(&stop_time_val ); + + if(stop_time_val < start_time_val ) + { + stop_time_val += 0x1000000; + } +} +/* Function : get_time + Return an abstract "ticks" number that signifies time on the system. + + Actual value returned may be cpu cycles, milliseconds or any other value, + as long as it can be converted to seconds by . + This methodology is taken to accomodate any hardware or simulated platform. + The sample implementation returns millisecs by default, + and the resolution is controlled by +*/ +CORE_TICKS get_time(void) +{ + CORE_TICKS elapsed=(CORE_TICKS)(MYTIMEDIFF(stop_time_val, start_time_val)); + return elapsed; +} +/* Function : time_in_secs + Convert the value returned by get_time to seconds. + + The type is used to accomodate systems with no support for floating point. + Default implementation implemented by the EE_TICKS_PER_SEC macro above. +*/ +secs_ret time_in_secs(CORE_TICKS ticks) +{ + secs_ret retval=((secs_ret)ticks) / (secs_ret)EE_TICKS_PER_SEC; + return retval; +} + +ee_u32 default_num_contexts=1; + +/* Function : portable_init + Target specific initialization code + Test for some common mistakes. +*/ +void portable_init(core_portable* p, int* argc, char* argv[]) +{ + if (sizeof(ee_ptr_int) != sizeof(ee_u8*)) + { + ee_printf("ERROR! Please define ee_ptr_int to a type that holds a pointer!\n"); + } + + if (sizeof(ee_u32) != 4) + { + ee_printf("ERROR! Please define ee_u32 to a 32b unsigned type!\n"); + } + + p->portable_id=1; +} +/* Function : portable_fini + Target specific final code +*/ +void portable_fini(core_portable* p) +{ + p->portable_id=0; +} + + diff --git a/src/components/coremark/core_portme.h b/src/components/coremark/core_portme.h new file mode 100644 index 0000000..4a68153 --- /dev/null +++ b/src/components/coremark/core_portme.h @@ -0,0 +1,199 @@ +/* + Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + + 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. + + Original Author: Shay Gal-on +*/ + +/* Topic : Description + This file contains configuration constants required to execute on different platforms +*/ +#ifndef CORE_PORTME_H +#define CORE_PORTME_H +/************************/ +/* Data types and settings */ +/************************/ +#define CORE_DEBUG 0 + +/* Configuration : HAS_FLOAT + Define to 1 if the platform supports floating point. +*/ +#ifndef HAS_FLOAT + #define HAS_FLOAT 1 +#endif +/* Configuration : HAS_TIME_H + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef HAS_TIME_H + #define HAS_TIME_H 1 +#endif +/* Configuration : USE_CLOCK + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef USE_CLOCK + #define USE_CLOCK 1 +#endif +/* Configuration : HAS_STDIO + Define to 1 if the platform has stdio.h. +*/ +#ifndef HAS_STDIO + #define HAS_STDIO 0 +#endif +/* Configuration : HAS_PRINTF + Define to 1 if the platform has stdio.h and implements the printf function. +*/ +#ifndef HAS_PRINTF + #define HAS_PRINTF 1 +#endif + +/* Configuration : CORE_TICKS + Define type of return from the timing functions. +*/ +#include +typedef clock_t CORE_TICKS; + +/* Definitions : COMPILER_VERSION, COMPILER_FLAGS, MEM_LOCATION + Initialize these strings per platform +*/ +#ifndef COMPILER_VERSION + #ifdef __GNUC__ + #define COMPILER_VERSION "GCC"__VERSION__ + #else + #define COMPILER_VERSION "Please put compiler version here (e.g. gcc 4.1)" + #endif +#endif +#ifndef COMPILER_FLAGS + #define COMPILER_FLAGS "-o0" /* "Please put compiler flags here (e.g. -o3)" */ +#endif +#ifndef MEM_LOCATION + #define MEM_LOCATION "STACK" +#endif + +/* Data Types : + To avoid compiler issues, define the data types that need ot be used for 8b, 16b and 32b in . + + Imprtant* : + ee_ptr_int needs to be the data type used to hold pointers, otherwise coremark may fail!!! +*/ +typedef signed short ee_s16; +typedef unsigned short ee_u16; +typedef signed int ee_s32; +typedef double ee_f32; +typedef unsigned char ee_u8; +typedef unsigned int ee_u32; +typedef ee_u32 ee_ptr_int; +typedef size_t ee_size_t; +/* align_mem : + This macro is used to align an offset to point to a 32b value. It is used in the Matrix algorithm to initialize the input memory blocks. +*/ +#define align_mem(x) (void *)(4 + (((ee_ptr_int)(x) - 1) & ~3)) + +/* Configuration : SEED_METHOD + Defines method to get seed values that cannot be computed at compile time. + + Valid values : + SEED_ARG - from command line. + SEED_FUNC - from a system function. + SEED_VOLATILE - from volatile variables. +*/ +#ifndef SEED_METHOD + #define SEED_METHOD SEED_VOLATILE +#endif + +/* Configuration : MEM_METHOD + Defines method to get a block of memry. + + Valid values : + MEM_MALLOC - for platforms that implement malloc and have malloc.h. + MEM_STATIC - to use a static memory array. + MEM_STACK - to allocate the data block on the stack (NYI). +*/ +#ifndef MEM_METHOD + #define MEM_METHOD MEM_STACK +#endif + +/* Configuration : MULTITHREAD + Define for parallel execution + + Valid values : + 1 - only one context (default). + N>1 - will execute N copies in parallel. + + Note : + If this flag is defined to more then 1, an implementation for launching parallel contexts must be defined. + + Two sample implementations are provided. Use or to enable them. + + It is valid to have a different implementation of and in , + to fit a particular architecture. +*/ +#ifndef MULTITHREAD + #define MULTITHREAD 1 + #define USE_PTHREAD 0 + #define USE_FORK 0 + #define USE_SOCKET 0 +#endif + +/* Configuration : MAIN_HAS_NOARGC + Needed if platform does not support getting arguments to main. + + Valid values : + 0 - argc/argv to main is supported + 1 - argc/argv to main is not supported + + Note : + This flag only matters if MULTITHREAD has been defined to a value greater then 1. +*/ +#ifndef MAIN_HAS_NOARGC + #define MAIN_HAS_NOARGC 0 +#endif + +/* Configuration : MAIN_HAS_NORETURN + Needed if platform does not support returning a value from main. + + Valid values : + 0 - main returns an int, and return value will be 0. + 1 - platform does not support returning a value from main +*/ +#ifndef MAIN_HAS_NORETURN + #define MAIN_HAS_NORETURN 0 +#endif + +/* Variable : default_num_contexts + Not used for this simple port, must cintain the value 1. +*/ +extern ee_u32 default_num_contexts; + +typedef struct CORE_PORTABLE_S +{ + ee_u8 portable_id; +} core_portable; + +/* target specific init/fini */ +void portable_init(core_portable* p, int* argc, char* argv[]); +void portable_fini(core_portable* p); + +#if !defined(PROFILE_RUN) && !defined(PERFORMANCE_RUN) && !defined(VALIDATION_RUN) + #if (TOTAL_DATA_SIZE==1200) + #define PROFILE_RUN 1 + #elif (TOTAL_DATA_SIZE==2000) + #define PERFORMANCE_RUN 1 + #else + #define VALIDATION_RUN 1 + #endif +#endif + +#endif /* CORE_PORTME_H */ diff --git a/src/components/coremark/core_state.c b/src/components/coremark/core_state.c new file mode 100644 index 0000000..975d0d7 --- /dev/null +++ b/src/components/coremark/core_state.c @@ -0,0 +1,1324 @@ +/* + Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + + 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. + + Original Author: Shay Gal-on +*/ + +#include "coremark.h" +/* local functions */ +enum CORE_STATE core_state_transition( ee_u8** instr, ee_u32* transition_count); + +/* + Topic: Description + Simple state machines like this one are used in many embedded products. + + For more complex state machines, sometimes a state transition table implementation is used instead, + trading speed of direct coding for ease of maintenance. + + Since the main goal of using a state machine in CoreMark is to excercise the switch/if behaviour, + we are using a small moore machine. + + In particular, this machine tests type of string input, + trying to determine whether the input is a number or something else. + (see core_state.png). +*/ + +/* Function: core_bench_state + Benchmark function + + Go over the input twice, once direct, and once after introducing some corruption. +*/ +ee_u16 core_bench_state(ee_u32 blksize, ee_u8* memblock, + ee_s16 seed1, ee_s16 seed2, ee_s16 step, ee_u16 crc) +{ + ee_u32 final_counts[NUM_CORE_STATES]; + ee_u32 track_counts[NUM_CORE_STATES]; + ee_u8* p=memblock; + ee_u32 i; + #if CORE_DEBUG + ee_printf("State Bench: %d,%d,%d,%04x\n",seed1,seed2,step,crc); + #endif + + for (i=0; i0) + { + for(i=0; i>3) & 0x3]; + next=4; + break; + + case 3: /* float */ + case 4: /* float */ + buf=floatpat[(seed>>3) & 0x3]; + next=8; + break; + + case 5: /* scientific */ + case 6: /* scientific */ + buf=scipat[(seed>>3) & 0x3]; + next=8; + break; + + case 7: /* invalid */ + buf=errpat[(seed>>3) & 0x3]; + next=8; + break; + + default: /* Never happen, just to make some compilers happy */ + break; + } + } + + size++; + + while (total='0') & (c<='9')) ? 1 : 0; + return retval; +} + +enum CORE_STATE core_state_transition_7( ee_u8** instr, ee_u32* transition_count) +{ + ee_u8* str=*instr; + ee_u8 NEXT_SYMBOL; + enum CORE_STATE state=CORE_START; + + for( ; *str && state != CORE_INVALID; str++ ) + { + NEXT_SYMBOL = *str; + + if (NEXT_SYMBOL==',') /* end of this input */ + { + str++; + break; + } + + switch(state) + { + case CORE_START: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + } + else if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) + { + state = CORE_S1; + } + else if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + } + else + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + + transition_count[CORE_START]++; + break; + + case CORE_S1: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + transition_count[CORE_S1]++; + } + else if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + transition_count[CORE_S1]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S1]++; + } + + break; + + case CORE_INT: + if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + transition_count[CORE_INT]++; + } + else if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INT]++; + } + + break; + + case CORE_FLOAT: + if( NEXT_SYMBOL == 'E' || NEXT_SYMBOL == 'e' ) + { + state = CORE_S2; + transition_count[CORE_FLOAT]++; + } + else if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_FLOAT]++; + } + + break; + + case CORE_S2: + if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) + { + state = CORE_EXPONENT; + transition_count[CORE_S2]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S2]++; + } + + break; + + case CORE_EXPONENT: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_SCIENTIFIC; + transition_count[CORE_EXPONENT]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_EXPONENT]++; + } + + break; + + case CORE_SCIENTIFIC: + if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + + break; + + default: + break; + } + } + + *instr=str; + return state; +} + + +enum CORE_STATE core_state_transition_6( ee_u8** instr, ee_u32* transition_count) +{ + ee_u8* str=*instr; + ee_u8 NEXT_SYMBOL; + enum CORE_STATE state=CORE_START; + + for( ; *str && state != CORE_INVALID; str++ ) + { + NEXT_SYMBOL = *str; + + if (NEXT_SYMBOL==',') /* end of this input */ + { + str++; + break; + } + + switch(state) + { + case CORE_START: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + } + else if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) + { + state = CORE_S1; + } + else if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + } + else + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + + transition_count[CORE_START]++; + break; + + case CORE_S1: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + transition_count[CORE_S1]++; + } + else if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + transition_count[CORE_S1]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S1]++; + } + + break; + + case CORE_INT: + if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + transition_count[CORE_INT]++; + } + else if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INT]++; + } + + break; + + case CORE_FLOAT: + if( NEXT_SYMBOL == 'E' || NEXT_SYMBOL == 'e' ) + { + state = CORE_S2; + transition_count[CORE_FLOAT]++; + } + else if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_FLOAT]++; + } + + break; + + case CORE_S2: + if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) + { + state = CORE_EXPONENT; + transition_count[CORE_S2]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S2]++; + } + + break; + + case CORE_EXPONENT: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_SCIENTIFIC; + transition_count[CORE_EXPONENT]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_EXPONENT]++; + } + + break; + + case CORE_SCIENTIFIC: + if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + + break; + + default: + break; + } + } + + *instr=str; + return state; +} + + +enum CORE_STATE core_state_transition_5( ee_u8** instr, ee_u32* transition_count) +{ + ee_u8* str=*instr; + ee_u8 NEXT_SYMBOL; + enum CORE_STATE state=CORE_START; + + for( ; *str && state != CORE_INVALID; str++ ) + { + NEXT_SYMBOL = *str; + + if (NEXT_SYMBOL==',') /* end of this input */ + { + str++; + break; + } + + switch(state) + { + case CORE_START: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + } + else if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) + { + state = CORE_S1; + } + else if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + } + else + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + + transition_count[CORE_START]++; + break; + + case CORE_S1: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + transition_count[CORE_S1]++; + } + else if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + transition_count[CORE_S1]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S1]++; + } + + break; + + case CORE_INT: + if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + transition_count[CORE_INT]++; + } + else if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INT]++; + } + + break; + + case CORE_FLOAT: + if( NEXT_SYMBOL == 'E' || NEXT_SYMBOL == 'e' ) + { + state = CORE_S2; + transition_count[CORE_FLOAT]++; + } + else if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_FLOAT]++; + } + + break; + + case CORE_S2: + if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) + { + state = CORE_EXPONENT; + transition_count[CORE_S2]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S2]++; + } + + break; + + case CORE_EXPONENT: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_SCIENTIFIC; + transition_count[CORE_EXPONENT]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_EXPONENT]++; + } + + break; + + case CORE_SCIENTIFIC: + if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + + break; + + default: + break; + } + } + + *instr=str; + return state; +} + + +enum CORE_STATE core_state_transition_4( ee_u8** instr, ee_u32* transition_count) +{ + ee_u8* str=*instr; + ee_u8 NEXT_SYMBOL; + enum CORE_STATE state=CORE_START; + + for( ; *str && state != CORE_INVALID; str++ ) + { + NEXT_SYMBOL = *str; + + if (NEXT_SYMBOL==',') /* end of this input */ + { + str++; + break; + } + + switch(state) + { + case CORE_START: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + } + else if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) + { + state = CORE_S1; + } + else if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + } + else + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + + transition_count[CORE_START]++; + break; + + case CORE_S1: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + transition_count[CORE_S1]++; + } + else if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + transition_count[CORE_S1]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S1]++; + } + + break; + + case CORE_INT: + if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + transition_count[CORE_INT]++; + } + else if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INT]++; + } + + break; + + case CORE_FLOAT: + if( NEXT_SYMBOL == 'E' || NEXT_SYMBOL == 'e' ) + { + state = CORE_S2; + transition_count[CORE_FLOAT]++; + } + else if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_FLOAT]++; + } + + break; + + case CORE_S2: + if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) + { + state = CORE_EXPONENT; + transition_count[CORE_S2]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S2]++; + } + + break; + + case CORE_EXPONENT: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_SCIENTIFIC; + transition_count[CORE_EXPONENT]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_EXPONENT]++; + } + + break; + + case CORE_SCIENTIFIC: + if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + + break; + + default: + break; + } + } + + *instr=str; + return state; +} + + +enum CORE_STATE core_state_transition_3( ee_u8** instr, ee_u32* transition_count) +{ + ee_u8* str=*instr; + ee_u8 NEXT_SYMBOL; + enum CORE_STATE state=CORE_START; + + for( ; *str && state != CORE_INVALID; str++ ) + { + NEXT_SYMBOL = *str; + + if (NEXT_SYMBOL==',') /* end of this input */ + { + str++; + break; + } + + switch(state) + { + case CORE_START: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + } + else if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) + { + state = CORE_S1; + } + else if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + } + else + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + + transition_count[CORE_START]++; + break; + + case CORE_S1: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + transition_count[CORE_S1]++; + } + else if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + transition_count[CORE_S1]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S1]++; + } + + break; + + case CORE_INT: + if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + transition_count[CORE_INT]++; + } + else if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INT]++; + } + + break; + + case CORE_FLOAT: + if( NEXT_SYMBOL == 'E' || NEXT_SYMBOL == 'e' ) + { + state = CORE_S2; + transition_count[CORE_FLOAT]++; + } + else if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_FLOAT]++; + } + + break; + + case CORE_S2: + if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) + { + state = CORE_EXPONENT; + transition_count[CORE_S2]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S2]++; + } + + break; + + case CORE_EXPONENT: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_SCIENTIFIC; + transition_count[CORE_EXPONENT]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_EXPONENT]++; + } + + break; + + case CORE_SCIENTIFIC: + if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + + break; + + default: + break; + } + } + + *instr=str; + return state; +} + +enum CORE_STATE core_state_transition_2( ee_u8** instr, ee_u32* transition_count) +{ + ee_u8* str=*instr; + ee_u8 NEXT_SYMBOL; + enum CORE_STATE state=CORE_START; + + for( ; *str && state != CORE_INVALID; str++ ) + { + NEXT_SYMBOL = *str; + + if (NEXT_SYMBOL==',') /* end of this input */ + { + str++; + break; + } + + switch(state) + { + case CORE_START: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + } + else if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) + { + state = CORE_S1; + } + else if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + } + else + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + + transition_count[CORE_START]++; + break; + + case CORE_S1: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + transition_count[CORE_S1]++; + } + else if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + transition_count[CORE_S1]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S1]++; + } + + break; + + case CORE_INT: + if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + transition_count[CORE_INT]++; + } + else if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INT]++; + } + + break; + + case CORE_FLOAT: + if( NEXT_SYMBOL == 'E' || NEXT_SYMBOL == 'e' ) + { + state = CORE_S2; + transition_count[CORE_FLOAT]++; + } + else if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_FLOAT]++; + } + + break; + + case CORE_S2: + if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) + { + state = CORE_EXPONENT; + transition_count[CORE_S2]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S2]++; + } + + break; + + case CORE_EXPONENT: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_SCIENTIFIC; + transition_count[CORE_EXPONENT]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_EXPONENT]++; + } + + break; + + case CORE_SCIENTIFIC: + if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + + break; + + default: + break; + } + } + + *instr=str; + return state; +} + +enum CORE_STATE core_state_transition_1( ee_u8** instr, ee_u32* transition_count) +{ + ee_u8* str=*instr; + ee_u8 NEXT_SYMBOL; + enum CORE_STATE state=CORE_START; + + for( ; *str && state != CORE_INVALID; str++ ) + { + NEXT_SYMBOL = *str; + + if (NEXT_SYMBOL==',') /* end of this input */ + { + str++; + break; + } + + switch(state) + { + case CORE_START: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + } + else if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) + { + state = CORE_S1; + } + else if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + } + else + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + + transition_count[CORE_START]++; + break; + + case CORE_S1: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + transition_count[CORE_S1]++; + } + else if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + transition_count[CORE_S1]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S1]++; + } + + break; + + case CORE_INT: + if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + transition_count[CORE_INT]++; + } + else if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INT]++; + } + + break; + + case CORE_FLOAT: + if( NEXT_SYMBOL == 'E' || NEXT_SYMBOL == 'e' ) + { + state = CORE_S2; + transition_count[CORE_FLOAT]++; + } + else if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_FLOAT]++; + } + + break; + + case CORE_S2: + if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) + { + state = CORE_EXPONENT; + transition_count[CORE_S2]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S2]++; + } + + break; + + case CORE_EXPONENT: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_SCIENTIFIC; + transition_count[CORE_EXPONENT]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_EXPONENT]++; + } + + break; + + case CORE_SCIENTIFIC: + if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + + break; + + default: + break; + } + } + + *instr=str; + return state; +} + + +enum CORE_STATE core_state_transition_0( ee_u8** instr, ee_u32* transition_count) +{ + ee_u8* str=*instr; + ee_u8 NEXT_SYMBOL; + enum CORE_STATE state=CORE_START; + + for( ; *str && state != CORE_INVALID; str++ ) + { + NEXT_SYMBOL = *str; + + if (NEXT_SYMBOL==',') /* end of this input */ + { + str++; + break; + } + + switch(state) + { + case CORE_START: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + } + else if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) + { + state = CORE_S1; + } + else if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + } + else + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + + transition_count[CORE_START]++; + break; + + case CORE_S1: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + transition_count[CORE_S1]++; + } + else if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + transition_count[CORE_S1]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S1]++; + } + + break; + + case CORE_INT: + if( NEXT_SYMBOL == '.' ) + { + state = CORE_FLOAT; + transition_count[CORE_INT]++; + } + else if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INT]++; + } + + break; + + case CORE_FLOAT: + if( NEXT_SYMBOL == 'E' || NEXT_SYMBOL == 'e' ) + { + state = CORE_S2; + transition_count[CORE_FLOAT]++; + } + else if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_FLOAT]++; + } + + break; + + case CORE_S2: + if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) + { + state = CORE_EXPONENT; + transition_count[CORE_S2]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S2]++; + } + + break; + + case CORE_EXPONENT: + if(ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_SCIENTIFIC; + transition_count[CORE_EXPONENT]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_EXPONENT]++; + } + + break; + + case CORE_SCIENTIFIC: + if(!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + + break; + + default: + break; + } + } + + *instr=str; + return state; +} + + +/* Function: core_state_transition + Actual state machine. + + The state machine will continue scanning until either: + 1 - an invalid input is detcted. + 2 - a valid number has been detected. + + The input pointer is updated to point to the end of the token, and the end state is returned (either specific format determined or invalid). +*/ + +extern uint8 g_core_state_cnt; +extern uint8 g_core_state_entry[]; +enum CORE_STATE core_state_transition( ee_u8** instr, ee_u32* transition_count) +{ + g_core_state_cnt++; + + if(g_core_state_entry[0x07&g_core_state_cnt]==0) + { + return (core_state_transition_0( instr, transition_count)); + } + else if(g_core_state_entry[0x07&g_core_state_cnt]==1) + { + return (core_state_transition_1( instr, transition_count)); + } + else if(g_core_state_entry[0x07&g_core_state_cnt]==2) + { + return (core_state_transition_2( instr, transition_count)); + } + else if(g_core_state_entry[0x07&g_core_state_cnt]==3) + { + return (core_state_transition_3( instr, transition_count)); + } + else if(g_core_state_entry[0x07&g_core_state_cnt]==4) + { + return (core_state_transition_4( instr, transition_count)); + } + else if(g_core_state_entry[0x07&g_core_state_cnt]==5) + { + return (core_state_transition_5( instr, transition_count)); + } + else if(g_core_state_entry[0x07&g_core_state_cnt]==6) + { + return (core_state_transition_6( instr, transition_count)); + } + else/* if(g_core_state_entry[0x07&g_core_state_cnt]==7)*/ + { + return (core_state_transition_7( instr, transition_count)); + } +} diff --git a/src/components/coremark/core_util.c b/src/components/coremark/core_util.c new file mode 100644 index 0000000..2ae469e --- /dev/null +++ b/src/components/coremark/core_util.c @@ -0,0 +1,507 @@ +/* + Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + + 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. + + Original Author: Shay Gal-on +*/ + +#include "coremark.h" +/* Function: get_seed + Get a values that cannot be determined at compile time. + + Since different embedded systems and compilers are used, 3 different methods are provided: + 1 - Using a volatile variable. This method is only valid if the compiler is forced to generate code that + reads the value of a volatile variable from memory at run time. + Please note, if using this method, you would need to modify core_portme.c to generate training profile. + 2 - Command line arguments. This is the preferred method if command line arguments are supported. + 3 - System function. If none of the first 2 methods is available on the platform, + a system function which is not a stub can be used. + + e.g. read the value on GPIO pins connected to switches, or invoke special simulator functions. +*/ +#if (SEED_METHOD==SEED_VOLATILE) +extern volatile ee_s32 seed1_volatile; +extern volatile ee_s32 seed2_volatile; +extern volatile ee_s32 seed3_volatile; +extern volatile ee_s32 seed4_volatile; +extern volatile ee_s32 seed5_volatile; +ee_s32 get_seed_32(int i) +{ + ee_s32 retval; + + switch (i) + { + case 1: + retval=seed1_volatile; + break; + + case 2: + retval=seed2_volatile; + break; + + case 3: + retval=seed3_volatile; + break; + + case 4: + retval=seed4_volatile; + break; + + case 5: + retval=seed5_volatile; + break; + + default: + retval=0; + break; + } + + return retval; +} +#elif (SEED_METHOD==SEED_ARG) +ee_s32 parseval(char* valstring) +{ + ee_s32 retval=0; + ee_s32 neg=1; + int hexmode=0; + + if (*valstring == '-') + { + neg=-1; + valstring++; + } + + if ((valstring[0] == '0') && (valstring[1] == 'x')) + { + hexmode=1; + valstring+=2; + } + + /* first look for digits */ + if (hexmode) + { + while (((*valstring >= '0') && (*valstring <= '9')) || ((*valstring >= 'a') && (*valstring <= 'f'))) + { + ee_s32 digit=*valstring-'0'; + + if (digit>9) + digit=10+*valstring-'a'; + + retval*=16; + retval+=digit; + valstring++; + } + } + else + { + while ((*valstring >= '0') && (*valstring <= '9')) + { + ee_s32 digit=*valstring-'0'; + retval*=10; + retval+=digit; + valstring++; + } + } + + /* now add qualifiers */ + if (*valstring=='K') + retval*=1024; + + if (*valstring=='M') + retval*=1024*1024; + + retval*=neg; + return retval; +} + +ee_s32 get_seed_args(int i, int argc, char* argv[]) +{ + if (argc>i) + return parseval(argv[i]); + + return 0; +} + +#elif (SEED_METHOD==SEED_FUNC) +/* If using OS based function, you must define and implement the functions below in core_portme.h and core_portme.c ! */ +ee_s32 get_seed_32(int i) +{ + ee_s32 retval; + + switch (i) + { + case 1: + retval=portme_sys1(); + break; + + case 2: + retval=portme_sys2(); + break; + + case 3: + retval=portme_sys3(); + break; + + case 4: + retval=portme_sys4(); + break; + + case 5: + retval=portme_sys5(); + break; + + default: + retval=0; + break; + } + + return retval; +} +#endif + +/* Function: crc* + Service functions to calculate 16b CRC code. + +*/ + + + +ee_u16 crcu8_1(ee_u8 data, ee_u16 crc ) +{ + ee_u8 i=0,x16=0,carry=0; + + for (i = 0; i < 8; i++) + { + x16 = (ee_u8)((data & 1) ^ ((ee_u8)crc & 1)); + data >>= 1; + + if (x16 == 1) + { + crc ^= 0x4002; + carry = 1; + } + else + carry = 0; + + crc >>= 1; + + if (carry) + crc |= 0x8000; + else + crc &= 0x7fff; + } + + return crc; +} + +ee_u16 crcu8_2(ee_u8 data, ee_u16 crc ) +{ + ee_u8 i=0,x16=0,carry=0; + + for (i = 0; i < 8; i++) + { + x16 = (ee_u8)((data & 1) ^ ((ee_u8)crc & 1)); + data >>= 1; + + if (x16 == 1) + { + crc ^= 0x4002; + carry = 1; + } + else + carry = 0; + + crc >>= 1; + + if (carry) + crc |= 0x8000; + else + crc &= 0x7fff; + } + + return crc; +} + +ee_u16 crcu8_3(ee_u8 data, ee_u16 crc ) +{ + ee_u8 i=0,x16=0,carry=0; + + for (i = 0; i < 8; i++) + { + x16 = (ee_u8)((data & 1) ^ ((ee_u8)crc & 1)); + data >>= 1; + + if (x16 == 1) + { + crc ^= 0x4002; + carry = 1; + } + else + carry = 0; + + crc >>= 1; + + if (carry) + crc |= 0x8000; + else + crc &= 0x7fff; + } + + return crc; +} + +ee_u16 crcu8_4(ee_u8 data, ee_u16 crc ) +{ + ee_u8 i=0,x16=0,carry=0; + + for (i = 0; i < 8; i++) + { + x16 = (ee_u8)((data & 1) ^ ((ee_u8)crc & 1)); + data >>= 1; + + if (x16 == 1) + { + crc ^= 0x4002; + carry = 1; + } + else + carry = 0; + + crc >>= 1; + + if (carry) + crc |= 0x8000; + else + crc &= 0x7fff; + } + + return crc; +} + +ee_u16 crcu8_5(ee_u8 data, ee_u16 crc ) +{ + ee_u8 i=0,x16=0,carry=0; + + for (i = 0; i < 8; i++) + { + x16 = (ee_u8)((data & 1) ^ ((ee_u8)crc & 1)); + data >>= 1; + + if (x16 == 1) + { + crc ^= 0x4002; + carry = 1; + } + else + carry = 0; + + crc >>= 1; + + if (carry) + crc |= 0x8000; + else + crc &= 0x7fff; + } + + return crc; +} + +ee_u16 crcu8_6(ee_u8 data, ee_u16 crc ) +{ + ee_u8 i=0,x16=0,carry=0; + + for (i = 0; i < 8; i++) + { + x16 = (ee_u8)((data & 1) ^ ((ee_u8)crc & 1)); + data >>= 1; + + if (x16 == 1) + { + crc ^= 0x4002; + carry = 1; + } + else + carry = 0; + + crc >>= 1; + + if (carry) + crc |= 0x8000; + else + crc &= 0x7fff; + } + + return crc; +} + +ee_u16 crcu8_7(ee_u8 data, ee_u16 crc ) +{ + ee_u8 i=0,x16=0,carry=0; + + for (i = 0; i < 8; i++) + { + x16 = (ee_u8)((data & 1) ^ ((ee_u8)crc & 1)); + data >>= 1; + + if (x16 == 1) + { + crc ^= 0x4002; + carry = 1; + } + else + carry = 0; + + crc >>= 1; + + if (carry) + crc |= 0x8000; + else + crc &= 0x7fff; + } + + return crc; +} + +ee_u16 crcu8_0(ee_u8 data, ee_u16 crc ) +{ + ee_u8 i=0,x16=0,carry=0; + + for (i = 0; i < 8; i++) + { + x16 = (ee_u8)((data & 1) ^ ((ee_u8)crc & 1)); + data >>= 1; + + if (x16 == 1) + { + crc ^= 0x4002; + carry = 1; + } + else + carry = 0; + + crc >>= 1; + + if (carry) + crc |= 0x8000; + else + crc &= 0x7fff; + } + + return crc; +} + +extern uint8 g_crc_cnt; +extern uint8 g_crc_entry[]; +ee_u16 crcu8(ee_u8 data, ee_u16 crc ) +{ + g_crc_cnt++; + + if(g_crc_entry[0x07&g_crc_cnt]==0) + { + return (crcu8_0( data, crc )); + } + else if(g_crc_entry[0x07&g_crc_cnt]==1) + { + return (crcu8_1( data, crc )); + } + else if(g_crc_entry[0x07&g_crc_cnt]==2) + { + return (crcu8_2( data, crc )); + } + else if(g_crc_entry[0x07&g_crc_cnt]==3) + { + return (crcu8_3( data, crc )); + } + else if(g_crc_entry[0x07&g_crc_cnt]==4) + { + return (crcu8_4( data, crc )); + } + else if(g_crc_entry[0x07&g_crc_cnt]==5) + { + return (crcu8_5( data, crc )); + } + else if(g_crc_entry[0x07&g_crc_cnt]==6) + { + return (crcu8_6( data, crc )); + } + else/* if(g_crc_entry[0x07&g_crc_cnt]==7)*/ + { + return (crcu8_7( data, crc )); + } +} + +ee_u16 crcu16(ee_u16 newval, ee_u16 crc) +{ + crc=crcu8( (ee_u8) (newval),crc); + crc=crcu8( (ee_u8) ((newval)>>8),crc); + return crc; +} +ee_u16 crcu32(ee_u32 newval, ee_u16 crc) +{ + crc=crc16((ee_s16) newval,crc); + crc=crc16((ee_s16) (newval>>16),crc); + return crc; +} +ee_u16 crc16(ee_s16 newval, ee_u16 crc) +{ + return crcu16((ee_u16)newval, crc); +} + +ee_u8 check_data_types() +{ + ee_u8 retval=0; + + if (sizeof(ee_u8) != 1) + { + ee_printf("ERROR: ee_u8 is not an 8b datatype!\n"); + retval++; + } + + if (sizeof(ee_u16) != 2) + { + ee_printf("ERROR: ee_u16 is not a 16b datatype!\n"); + retval++; + } + + if (sizeof(ee_s16) != 2) + { + ee_printf("ERROR: ee_s16 is not a 16b datatype!\n"); + retval++; + } + + if (sizeof(ee_s32) != 4) + { + ee_printf("ERROR: ee_s32 is not a 32b datatype!\n"); + retval++; + } + + if (sizeof(ee_u32) != 4) + { + ee_printf("ERROR: ee_u32 is not a 32b datatype!\n"); + retval++; + } + + if (sizeof(ee_ptr_int) != sizeof(int*)) + { + ee_printf("ERROR: ee_ptr_int is not a datatype that holds an int pointer!\n"); + retval++; + } + + if (retval>0) + { + ee_printf("ERROR: Please modify the datatypes in core_portme.h!\n"); + } + + return retval; +} diff --git a/src/components/coremark/coremark.h b/src/components/coremark/coremark.h new file mode 100644 index 0000000..8885b2a --- /dev/null +++ b/src/components/coremark/coremark.h @@ -0,0 +1,182 @@ +/* + Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + + 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. + + Original Author: Shay Gal-on +*/ + +/* Topic: Description + This file contains declarations of the various benchmark functions. +*/ + +/* Configuration: TOTAL_DATA_SIZE + Define total size for data algorithms will operate on +*/ +#ifndef TOTAL_DATA_SIZE + #define TOTAL_DATA_SIZE 2*1000 +#endif + +#define SEED_ARG 0 +#define SEED_FUNC 1 +#define SEED_VOLATILE 2 + +#define MEM_STATIC 0 +#define MEM_MALLOC 1 +#define MEM_STACK 2 + +#include "core_portme.h" +#include "log.h" +#include +#include +extern char s_tmpstr[]; +#if HAS_STDIO + #include +#endif +#if HAS_PRINTF + #define ee_printf(...) { sprintf(s_tmpstr, ##__VA_ARGS__);LOG(s_tmpstr);} +#endif + +/* Actual benchmark execution in iterate */ +void* iterate(void* pres); + +/* Typedef: secs_ret + For machines that have floating point support, get number of seconds as a double. + Otherwise an unsigned int. +*/ +#if HAS_FLOAT + typedef double secs_ret; +#else + typedef ee_u32 secs_ret; +#endif + +#if MAIN_HAS_NORETURN + #define MAIN_RETURN_VAL + #define MAIN_RETURN_TYPE void +#else + #define MAIN_RETURN_VAL 0 + #define MAIN_RETURN_TYPE int +#endif + +void start_time(void); +void stop_time(void); +CORE_TICKS get_time(void); +secs_ret time_in_secs(CORE_TICKS ticks); + +/* Misc useful functions */ +ee_u16 crcu8(ee_u8 data, ee_u16 crc); +ee_u16 crc16(ee_s16 newval, ee_u16 crc); +ee_u16 crcu16(ee_u16 newval, ee_u16 crc); +ee_u16 crcu32(ee_u32 newval, ee_u16 crc); +ee_u8 check_data_types(void); +void* portable_malloc(ee_size_t size); +void portable_free(void* p); +ee_s32 parseval(char* valstring); + +/* Algorithm IDS */ +#define ID_LIST (1<<0) +#define ID_MATRIX (1<<1) +#define ID_STATE (1<<2) +#define ALL_ALGORITHMS_MASK (ID_LIST|ID_MATRIX|ID_STATE) +#define NUM_ALGORITHMS 3 + +/* list data structures */ +typedef struct list_data_s +{ + ee_s16 data16; + ee_s16 idx; +} list_data; + +typedef struct list_head_s +{ + struct list_head_s* next; + struct list_data_s* info; +} list_head; + + +/*matrix benchmark related stuff */ +#define MATDAT_INT 1 +#if MATDAT_INT + typedef ee_s16 MATDAT; + typedef ee_s32 MATRES; +#else + typedef ee_f16 MATDAT; + typedef ee_f32 MATRES; +#endif + +typedef struct MAT_PARAMS_S +{ + int N; + MATDAT* A; + MATDAT* B; + MATRES* C; +} mat_params; + +/* state machine related stuff */ +/* List of all the possible states for the FSM */ +typedef enum CORE_STATE +{ + CORE_START=0, + CORE_INVALID, + CORE_S1, + CORE_S2, + CORE_INT, + CORE_FLOAT, + CORE_EXPONENT, + CORE_SCIENTIFIC, + NUM_CORE_STATES +} core_state_e ; + + +/* Helper structure to hold results */ +typedef struct RESULTS_S +{ + /* inputs */ + ee_s16 seed1; /* Initializing seed */ + ee_s16 seed2; /* Initializing seed */ + ee_s16 seed3; /* Initializing seed */ + void* memblock[4]; /* Pointer to safe memory location */ + ee_u32 size; /* Size of the data */ + ee_u32 iterations; /* Number of iterations to execute */ + ee_u32 execs; /* Bitmask of operations to execute */ + struct list_head_s* list; + mat_params mat; + /* outputs */ + ee_u16 crc; + ee_u16 crclist; + ee_u16 crcmatrix; + ee_u16 crcstate; + ee_s16 err; + /* ultithread specific */ + core_portable port; +} core_results; + +/* Multicore execution handling */ +#if (MULTITHREAD>1) + ee_u8 core_start_parallel(core_results* res); + ee_u8 core_stop_parallel(core_results* res); +#endif + +/* list benchmark functions */ +list_head* core_list_init(ee_u32 blksize, list_head* memblock, ee_s16 seed); +ee_u16 core_bench_list(core_results* res, ee_s16 finder_idx); + +/* state benchmark functions */ +void core_init_state(ee_u32 size, ee_s16 seed, ee_u8* p); +ee_u16 core_bench_state(ee_u32 blksize, ee_u8* memblock, + ee_s16 seed1, ee_s16 seed2, ee_s16 step, ee_u16 crc); + +/* matrix benchmark functions */ +ee_u32 core_init_matrix(ee_u32 blksize, void* memblk, ee_s32 seed, mat_params* p); +ee_u16 core_bench_matrix(mat_params* p, ee_s16 seed, ee_u16 crc); + diff --git a/src/components/driver/adc/adc.c b/src/components/driver/adc/adc.c new file mode 100644 index 0000000..9f8b8d2 --- /dev/null +++ b/src/components/driver/adc/adc.c @@ -0,0 +1,669 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file adc.c + @brief Contains all functions support for adc driver + @version 0.0 + @date 18. Oct. 2017 + @author qing.han + + + +*******************************************************************************/ +#include +#include "error.h" +#include "gpio.h" +#include "pwrmgr.h" +#include "clock.h" +#include "adc.h" +#include "log.h" +#include "jump_function.h" +#include "version.h" + +typedef struct _adc_Contex_t +{ + bool enable; + uint8_t all_channel; + uint8_t chs_en_shadow; + bool continue_mode; + + //sysclk_t clk_src; + uint16_t adc_cal_postive; + uint16_t adc_cal_negtive; + + adc_Hdl_t evt_handler; +} adc_Ctx_t; + +static adc_Ctx_t mAdc_Ctx = +{ + .enable = FALSE, + .all_channel = 0x00, + .chs_en_shadow = 0x00, + .continue_mode = FALSE, + .adc_cal_postive = 0xFFF, + .adc_cal_negtive = 0xFFF, + .evt_handler = NULL +}; + +gpio_pin_e s_pinmap[ADC_CH_NUM] = +{ + GPIO_DUMMY, //ADC_CH0 =0, + GPIO_DUMMY, //ADC_CH1 =1, + P11, //ADC_CH1N =2, + P23, //ADC_CH1P =3, ADC_CH1DIFF = 3, + P24, //ADC_CH2N =4, + P14, //ADC_CH2P =5, ADC_CH2DIFF = 5, + P15, //ADC_CH3N =6, + P20, //ADC_CH3P =7, ADC_CH3DIFF = 7, + GPIO_DUMMY, //ADC_CH_VOICE =8, +}; + +/************************************************************************************** + @fn hal_adc_value + + @brief This function process for get adc value + + input parameters + + @param ADC_CH_e adc_pin: adc pin select;ADC_CH0~ADC_CH7 and ADC_CH_VOICE + + output parameters + + @param None. + + @return ADC value + **************************************************************************************/ +static void hal_adc_load_calibration_value(void) +{ + uint32_t adc_cal = read_reg(SPIF_RSVD1_ADC_CALIBRATE); + mAdc_Ctx.adc_cal_negtive = (uint16_t)(adc_cal & 0x0fff); + mAdc_Ctx.adc_cal_postive = (uint16_t)((adc_cal >> 16) & 0x0fff); + LOG("AD_CAL[%x %x]\n", mAdc_Ctx.adc_cal_negtive, mAdc_Ctx.adc_cal_postive); + + if((mAdc_Ctx.adc_cal_negtive < 0x733) || (mAdc_Ctx.adc_cal_negtive > 0x8cc) || + (mAdc_Ctx.adc_cal_postive < 0x733) || (mAdc_Ctx.adc_cal_postive > 0x8cc)) + { + mAdc_Ctx.adc_cal_negtive = 0xfff; + mAdc_Ctx.adc_cal_postive = 0xfff; + LOG("->AD_CAL[%x %x]\n",mAdc_Ctx.adc_cal_negtive, mAdc_Ctx.adc_cal_postive); + } +} + +static void set_sampling_resolution(adc_CH_t channel, bool is_high_resolution,bool is_differential_mode) +{ + uint8_t aio = 0; + uint8_t diff_aio = 0; + + switch(channel) + { + case ADC_CH1N_P11: + aio = 0; + diff_aio = 1; + break; + + case ADC_CH1P_P23: + aio = 1; + diff_aio = 0; + break; + + case ADC_CH2N_P24: + aio = 2; + diff_aio = 3; + break; + + case ADC_CH2P_P14: + aio = 3; + diff_aio = 2; + break; + + case ADC_CH3N_P15: + aio = 4; + diff_aio = 7; + break; + + case ADC_CH3P_P20: + aio = 7; + diff_aio = 4; + break; + + default: + return; + } + + if(is_high_resolution) + { + if(is_differential_mode) + { + subWriteReg(&(AP_AON->PMCTL2_1),(diff_aio+8),(diff_aio+8),0); + subWriteReg(&(AP_AON->PMCTL2_1),diff_aio,diff_aio,1); + } + + subWriteReg(&(AP_AON->PMCTL2_1),(aio+8),(aio+8),0); + subWriteReg(&(AP_AON->PMCTL2_1),aio,aio,1); + } + else + { + if(is_differential_mode) + { + subWriteReg(&(AP_AON->PMCTL2_1),(diff_aio+8),(diff_aio+8),1); + subWriteReg(&(AP_AON->PMCTL2_1),diff_aio,diff_aio,0); + } + + subWriteReg(&(AP_AON->PMCTL2_1),(aio+8),(aio+8),1); + subWriteReg(&(AP_AON->PMCTL2_1),aio,aio,0); + } +} + +static void set_sampling_resolution_auto(uint8_t channel, uint8_t is_high_resolution,uint8_t is_differential_mode) +{ + uint8_t i_channel; + adc_CH_t a_channel; + AP_AON->PMCTL2_1 = 0x00; + + for(i_channel =MIN_ADC_CH; i_channel<=MAX_ADC_CH; i_channel++) + { + if(channel & BIT(i_channel)) + { + a_channel = (adc_CH_t)i_channel; + set_sampling_resolution(a_channel, + (is_high_resolution & BIT(i_channel)), + (is_differential_mode & BIT(i_channel))); + } + } +} + +static void set_differential_mode(void) +{ + subWriteReg(&( AP_PCRM->ANA_CTL),8,8,0); + subWriteReg(&( AP_PCRM->ANA_CTL),11,11,0); +} + +static void disable_analog_pin(adc_CH_t channel) +{ + int index = (int)channel; + gpio_pin_e pin = s_pinmap[index]; + + if(pin == GPIO_DUMMY) + return; + + hal_gpio_cfg_analog_io(pin,Bit_DISABLE); + hal_gpio_pin_init(pin,GPIO_INPUT); //ie=0,oen=1 set to imput + hal_gpio_pull_set(pin,GPIO_FLOATING); // +} + +static void clear_adcc_cfg(void) +{ + mAdc_Ctx.all_channel = 0x00; + mAdc_Ctx.chs_en_shadow = 0x00; + mAdc_Ctx.continue_mode = FALSE; + mAdc_Ctx.evt_handler = NULL; +} + +#if 0 +static void disable_channel(adc_CH_t ch) +{ + switch (ch) + { + case ADC_CH1N_P11: + AP_PCRM->ADC_CTL1 &= ~BIT(20); + break; + + case ADC_CH1P_P23: + AP_PCRM->ADC_CTL1 &= ~BIT(4); + break; + + case ADC_CH2N_P24: + AP_PCRM->ADC_CTL2 &= ~BIT(20); + break; + + case ADC_CH2P_P14: + AP_PCRM->ADC_CTL2 &= ~BIT(4); + break; + + case ADC_CH3N_P15: + AP_PCRM->ADC_CTL3 &= ~BIT(20); + break; + + case ADC_CH3P_P20: + AP_PCRM->ADC_CTL3 &= ~BIT(4); + break; + } +} +#endif +/////////////// adc //////////////////////////// +/************************************************************************************** + @fn hal_ADC_IRQHandler + + @brief This function process for adc interrupt + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +void __attribute__((used)) hal_ADC_IRQHandler(void) +{ + int ch,ch2,status =0,n; + uint16_t adc_data[MAX_ADC_SAMPLE_SIZE-2]; + + status = GET_IRQ_STATUS; + for (ch = MIN_ADC_CH; ch <= MAX_ADC_CH; ch++) + { + if ((mAdc_Ctx.all_channel & BIT(ch)) &&(status & BIT(ch))) + { + ch2=(ch%2)?(ch-1):(ch+1); + if(mAdc_Ctx.continue_mode == FALSE) + { + AP_ADCC->intr_mask &= ~ BIT(ch); //MASK coresponding channel + mAdc_Ctx.all_channel &= ~BIT(ch);//disable channel + } + + for (n = 0; n < (MAX_ADC_SAMPLE_SIZE-3); n++) + { + adc_data[n] = (uint16_t)(read_reg(ADC_CH_BASE + (ch * 0x80) + ((n+2) * 4))&0xfff); + adc_data[n+1] = (uint16_t)((read_reg(ADC_CH_BASE + (ch * 0x80) + ((n+2) * 4))>>16)&0xfff); + } + + AP_ADCC->intr_clear = BIT(ch); + + if(mAdc_Ctx.enable == FALSE) + continue; + + if (mAdc_Ctx.evt_handler) + { + adc_Evt_t evt; + evt.type = HAL_ADC_EVT_DATA; + evt.ch = (adc_CH_t)ch2; + evt.data = adc_data; + evt.size = MAX_ADC_SAMPLE_SIZE-3; + mAdc_Ctx.evt_handler(&evt); + } + } + } + + //LOG("> %x\n",mAdc_Ctx.all_channel); + if((mAdc_Ctx.all_channel == 0) && (mAdc_Ctx.continue_mode == FALSE))// + { + hal_adc_stop(); + } +} + +static void adc_wakeup_hdl(void) +{ + NVIC_SetPriority((IRQn_Type)ADCC_IRQn, IRQ_PRIO_HAL); +} + +/************************************************************************************** + @fn hal_adc_init + + @brief This function process for adc initial + + input parameters + + @param ADC_MODE_e mode: adc sample mode select;1:SAM_MANNUAL(mannual mode),0:SAM_AUTO(auto mode) + ADC_CH_e adc_pin: adc pin select;ADC_CH0~ADC_CH7 and ADC_CH_VOICE + ADC_SEMODE_e semode: signle-ended mode negative side enable; 1:SINGLE_END(single-ended mode) 0:DIFF(Differentail mode) + IO_CONTROL_e amplitude: input signal amplitude, 0:BELOW_1V,1:UP_1V + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +void hal_adc_init(void) +{ + hal_pwrmgr_register(MOD_ADCC,NULL,adc_wakeup_hdl); + clear_adcc_cfg(); + hal_adc_load_calibration_value(); + mAdc_Ctx.enable = TRUE; +} + +int hal_adc_clock_config(adc_CLOCK_SEL_t clk) +{ + if(mAdc_Ctx.enable == FALSE) + { + return PPlus_ERR_NOT_REGISTED; + } + subWriteReg(&(AP_PCRM->ADC_CTL4),2,1,clk); + return PPlus_SUCCESS; +} + +int hal_adc_start(void) +{ + uint8_t all_channel2 = (((mAdc_Ctx.chs_en_shadow&0x80)>>1)|\ + ((mAdc_Ctx.chs_en_shadow&0x40)<<1)|\ + ((mAdc_Ctx.chs_en_shadow&0x20)>>1)|\ + ((mAdc_Ctx.chs_en_shadow&0x10)<<1)|\ + ((mAdc_Ctx.chs_en_shadow&0x08)>>1)|\ + ((mAdc_Ctx.chs_en_shadow&0x04)<<1)); + + if(mAdc_Ctx.enable == FALSE) + { + return PPlus_ERR_NOT_REGISTED; + } + + //LOG("all_channel2:0x%x\n",all_channel2); + hal_pwrmgr_lock(MOD_ADCC); + JUMP_FUNCTION(ADCC_IRQ_HANDLER) = (uint32_t)&hal_ADC_IRQHandler; + + for(int i=MIN_ADC_CH; i<=MAX_ADC_CH; i++) + { + if(all_channel2 & (BIT(i))) + { + switch (i) + { + case ADC_CH1N_P11: + AP_PCRM->ADC_CTL1 |= BIT(20); + break; + + case ADC_CH1P_P23: + AP_PCRM->ADC_CTL1 |= BIT(4); + break; + + case ADC_CH2N_P24: + AP_PCRM->ADC_CTL2 |= BIT(20); + break; + + case ADC_CH2P_P14: + AP_PCRM->ADC_CTL2 |= BIT(4); + break; + + case ADC_CH3N_P15: + AP_PCRM->ADC_CTL3 |= BIT(20); + break; + + case ADC_CH3P_P20: + AP_PCRM->ADC_CTL3 |= BIT(4); + break; + } + } + } + + AP_PCRM->ANA_CTL |= BIT(3);//ENABLE_ADC; + AP_PCRM->ANA_CTL |= BIT(0);//new + + NVIC_EnableIRQ((IRQn_Type)ADCC_IRQn); //ADC_IRQ_ENABLE; + AP_ADCC->intr_mask = mAdc_Ctx.all_channel; //ENABLE_ADC_INT; + + //disableSleep(); + return PPlus_SUCCESS; +} + + +int hal_adc_config_channel(adc_Cfg_t cfg, adc_Hdl_t evt_handler) +{ + uint8_t i; + uint8_t chn_sel; + gpio_pin_e pin,pin_neg; + + if(mAdc_Ctx.enable == FALSE) + { + return PPlus_ERR_NOT_REGISTED; + } + + if(evt_handler == NULL) + { + return PPlus_ERR_INVALID_PARAM; + } + + if((cfg.channel & BIT(0)) || (cfg.channel & BIT(1))) + { + return PPlus_ERR_NOT_SUPPORTED; + } + + if((!cfg.channel & BIT(1))&&(cfg.is_differential_mode && (cfg.channel & BIT(1)))) + { + return PPlus_ERR_INVALID_PARAM; + } + + if(cfg.is_differential_mode != 0) + { + if((cfg.is_differential_mode != 0x80) && (cfg.is_differential_mode != 0x20) && (cfg.is_differential_mode != 0x08)) + { + return PPlus_ERR_INVALID_PARAM; + } + } + + clear_adcc_cfg(); + + AP_AON->PMCTL2_1 = 0x00; + AP_PCRM->ANA_CTL &= ~BIT(0); + AP_PCRM->ANA_CTL &= ~BIT(3); + hal_clk_gate_disable(MOD_ADCC); + hal_clk_reset(MOD_ADCC); + + mAdc_Ctx.continue_mode = cfg.is_continue_mode; + mAdc_Ctx.all_channel = cfg.channel & 0x03; + + for(i=2; i<8; i++) + { + if(cfg.channel & BIT(i)) + { + if(i%2) + { + mAdc_Ctx.all_channel |= BIT(i-1); + } + else + { + mAdc_Ctx.all_channel |= BIT(i+1); + } + } + } + mAdc_Ctx.chs_en_shadow = mAdc_Ctx.all_channel; + //LOG("cfg.channel:0x%x\n",cfg.channel); + LOG("mAdc_Ctx.all_channel:0x%x\n",mAdc_Ctx.all_channel); + + if((AP_PCR->SW_CLK & BIT(MOD_ADCC)) == 0) + { + hal_clk_gate_enable(MOD_ADCC); + } + + //CLK_1P28M_ENABLE; + AP_PCRM->CLKSEL |= BIT(6); + //ENABLE_XTAL_OUTPUT; //enable xtal 16M output,generate the 32M dll clock + AP_PCRM->CLKHF_CTL0 |= BIT(18); + //ENABLE_DLL; //enable DLL + AP_PCRM->CLKHF_CTL1 |= BIT(7); + //ADC_DBLE_CLOCK_DISABLE; //disable double 32M clock,we are now use 32M clock,should enable bit<13>, diable bit<21> + AP_PCRM->CLKHF_CTL1 &= ~BIT(21);//check + //subWriteReg(0x4000F044,21,20,3); + //ADC_CLOCK_ENABLE; //adc clock enbale,always use clk_32M + AP_PCRM->CLKHF_CTL1 |= BIT(13); + //subWriteReg(0x4000f07c,4,4,1); //set adc mode,1:mannual,0:auto mode + AP_PCRM->ADC_CTL4 |= BIT(4); + AP_PCRM->ADC_CTL4 |= BIT(0); + set_sampling_resolution_auto(cfg.channel, cfg.is_high_resolution,cfg.is_differential_mode); + AP_PCRM->ADC_CTL0 &= ~BIT(20); + AP_PCRM->ADC_CTL0 &= ~BIT(4); + AP_PCRM->ADC_CTL1 &= ~BIT(20); + AP_PCRM->ADC_CTL1 &= ~BIT(4); + AP_PCRM->ADC_CTL2 &= ~BIT(20); + AP_PCRM->ADC_CTL2 &= ~BIT(4); + AP_PCRM->ADC_CTL3 &= ~BIT(20); + AP_PCRM->ADC_CTL3 &= ~BIT(4); + AP_PCRM->ANA_CTL &= ~BIT(23);//disable micbias + + if(cfg.is_differential_mode == 0) + { + AP_PCRM->ADC_CTL4 &= ~BIT(4); //enable auto mode + mAdc_Ctx.evt_handler = evt_handler; + for(i=MIN_ADC_CH; i<=MAX_ADC_CH; i++) + { + if(cfg.channel & BIT(i)) + { + gpio_pin_e pin = s_pinmap[i]; + hal_gpio_pull_set(pin,GPIO_FLOATING); + hal_gpio_ds_control(pin, Bit_ENABLE); + hal_gpio_cfg_analog_io(pin, Bit_ENABLE); + } + } + } + else + { + switch(cfg.is_differential_mode) + { + case 0x80: + pin = P20; + pin_neg = P15; + chn_sel = 0x04; + break; + + case 0x20: + pin = P14; + pin_neg = P24; + chn_sel = 0x03; + break; + + case 0x08: + pin = P23; + pin_neg = P11; + chn_sel = 0x02; + break; + + case 0x02: + pin = P18; + pin_neg = P25; + chn_sel = 0x01; + *(volatile int*)(0x4000F020) = 0x0060; + break; + + default: + break; + } + + hal_gpio_ds_control(pin, Bit_ENABLE); + subWriteReg(&(AP_PCRM->ANA_CTL),7,5,chn_sel); + set_differential_mode(); + //LOG("%d %d %x\n",pin,pin_neg,*(volatile int*)0x40003800); + hal_gpio_pull_set(pin,GPIO_FLOATING); + hal_gpio_pull_set(pin_neg,GPIO_FLOATING); + hal_gpio_cfg_analog_io(pin,Bit_ENABLE); + hal_gpio_cfg_analog_io(pin_neg,Bit_ENABLE); + //LOG("%d %d %x\n",pin,pin_neg,*(volatile int*)0x40003800); + mAdc_Ctx.all_channel = (cfg.is_differential_mode >> 1); + mAdc_Ctx.evt_handler = evt_handler; + } + + return PPlus_SUCCESS; +} + +int hal_adc_stop(void) +{ + int i; + uint8_t all_channel2 = (((mAdc_Ctx.chs_en_shadow&0x80)>>1)|\ + ((mAdc_Ctx.chs_en_shadow&0x40)<<1)|\ + ((mAdc_Ctx.chs_en_shadow&0x20)>>1)|\ + ((mAdc_Ctx.chs_en_shadow&0x10)<<1)|\ + ((mAdc_Ctx.chs_en_shadow&0x08)>>1)|\ + ((mAdc_Ctx.chs_en_shadow&0x04)<<1)); + + if(mAdc_Ctx.enable == FALSE) + { + return PPlus_ERR_NOT_REGISTED; + } + + AP_AON->PMCTL2_1 = 0x00; + NVIC_DisableIRQ((IRQn_Type)ADCC_IRQn); + JUMP_FUNCTION(ADCC_IRQ_HANDLER) = 0; + AP_ADCC->intr_clear = 0x1FF; + + AP_PCRM->ANA_CTL &= ~BIT(3); + +#include "rf_phy_driver.h" + if(g_system_clk != SYS_CLK_DBL_32M) + { + AP_PCRM->CLKHF_CTL1 &= ~BIT(13); + } + + for(i = MIN_ADC_CH; i<= MAX_ADC_CH; i++) + { + if(all_channel2 & BIT(i)) + { + disable_analog_pin((adc_CH_t)i); + } + } + + AP_PCRM->ANA_CTL &= ~BIT(0);//Power down analog LDO + hal_clk_reset(MOD_ADCC); + hal_clk_gate_disable(MOD_ADCC); + clear_adcc_cfg(); + //enableSleep(); + hal_pwrmgr_unlock(MOD_ADCC); + return PPlus_SUCCESS; +} + + +#if(SDK_VER_CHIP==__DEF_CHIP_QFN32__) +const unsigned int adc_Lambda[MAX_ADC_CH - MIN_ADC_CH + 1] = +{ + 4519602,//P11 + 4308639,//P23 + 4263287,//P24 + 4482718,//P14 + 4180401,//P15 + 4072069,//P20 +}; + +#elif(SDK_VER_CHIP == __DEF_CHIP_TSOP16__) +const unsigned int adc_Lambda[MAX_ADC_CH - MIN_ADC_CH + 1] = +{ + 4488156,//P11 + 4308639,//P23, + 4263287,//P24, + 4467981,//P14 + 4142931,//P15 + 4054721,//P20 +}; +#endif + +float hal_adc_value_cal(adc_CH_t ch,uint16_t* buf, uint32_t size, uint8_t high_resol, uint8_t diff_mode) +{ + uint32_t i; + int adc_sum = 0; + volatile float result = 0.0; + uint16_t adc_cal_postive = mAdc_Ctx.adc_cal_postive; + uint16_t adc_cal_negtive = mAdc_Ctx.adc_cal_negtive; + + for (i = 0; i < size; i++) + { + adc_sum += (buf[i]&0xfff); + } + result = ((float)adc_sum)/size; + if((adc_cal_postive != 0xfff) && (adc_cal_negtive != 0xfff)) + { + float delta = ((int)(adc_cal_postive-adc_cal_negtive))/2.0; + + if(ch&0x01) + { + result = (diff_mode) ? ((result-2048-delta)*2/(adc_cal_postive+adc_cal_negtive)) + : ((result-delta) /(adc_cal_postive+adc_cal_negtive)); + } + else + { + result = (diff_mode) ? ((result-2048-delta)*2/(adc_cal_postive+adc_cal_negtive)) + : ((result+delta) /(adc_cal_postive+adc_cal_negtive)); + } + } + else + { + result = (diff_mode) ? (float)(result / 2048 -1) : (float)(result /4096); + } + + if(high_resol == TRUE) + { + result *= 800.0; + } + else + { + result = (float)result *(float)adc_Lambda[ch-2]*0.8/1000; + } + return result; +} diff --git a/src/components/driver/adc/adc.h b/src/components/driver/adc/adc.h new file mode 100644 index 0000000..8a862e7 --- /dev/null +++ b/src/components/driver/adc/adc.h @@ -0,0 +1,192 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file adc.h + @brief Contains all functions support for adc driver + @version 0.0 + @date 18. Oct. 2017 + @author qing.han + + + +*******************************************************************************/ +#ifndef __ADC__H__ +#define __ADC__H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +#include "types.h" +#include "bus_dev.h" +#include "gpio.h" + +#define MAX_ADC_SAMPLE_SIZE 32 +#define ADC_CH_BASE (0x40050400UL) + + + +#define CLEAR_ADC_INT(n) AP_ADC->intr_clear |= BIT(n) + +#define IS_CLAER_ADC_INT_VOICE (AP_ADC->intr_clear & BIT(8)) +#define IS_CLAER_ADC_INT(n) (AP_ADC->intr_clear & BIT(n)) + +#define GET_IRQ_STATUS (AP_ADCC->intr_status & 0x3ff) + +#define ENABLE_ADC (AP_PCRM->ANA_CTL |= BIT(3)) +#define DISABLE_ADC (AP_PCRM->ANA_CTL &= ~BIT(3)) + +#define ADC_CLOCK_ENABLE (AP_PCRM->CLKHF_CTL1 |= BIT(13)) +#define ADC_CLOCK_DISABLE (AP_PCRM->CLKHF_CTL1 &= ~BIT(13)) + + +#define SPIF_RSVD_AREA_1 (0x1000) +#define pSPIF_RSVD1_ADC_CALIBRATE ((volatile uint32_t*)(SPIF_BASE_ADDR + SPIF_RSVD_AREA_1)) +#define SPIF_RSVD1_ADC_CALIBRATE (SPIF_BASE_ADDR + SPIF_RSVD_AREA_1) + + + +/************************************************************************************** + @fn hal_get_adc_int_source + + @brief This function process for get adc interrupt source,such as adc channel NO + + input parameters + + @param None. + + output parameters + + @param None. + + @return adc interrupt source bit loaction(uint8_t) + **************************************************************************************/ +/* + ADC note: + There are ten pins which can config as analogy,there are some differences between them. + hardware analogy index: + gpio<11>/aio<0> + gpio<23>/aio<1>/micphone bias reference voltage + gpio<24>/aio<2> + gpio<14>/aio<3> + gpio<15>/aio<4>/micphone bias + gpio<16>/aio<5>/32K XTAL input + gpio<17>/aio<6>/32K XTAL output + gpio<18>/aio<7>/pga in+ + gpio<25>/aio<8> + gpio<20>/aio<9>/pga in- + + There are six pins which can work in adc single mode.Such as: + ADC_CH0 = 2,ADC_CH1N_P11 = 2, + ADC_CH1 = 3,ADC_CH1P_P23 = 3, + ADC_CH2 = 4,ADC_CH2N_P24 = 4, + ADC_CH3 = 5,ADC_CH2P_P14 = 5, + ADC_CH4 = 6,ADC_CH3N_P15 = 6, + ADC_CH9 = 7,ADC_CH3P_P20 = 7, + + There are four pair pins which can work in adc diff mode.Such as: + ADC_CH0DIFF = 1,p18(p) and P25(n) + ADC_CH1DIFF = 3,P23(p) and P11(n) + ADC_CH2DIFF = 5,P14(p) and P24(n) + ADC_CH3DIFF = 7,P20(p) and P15(n) + + There are two pins which uses with 32.768K crystal oscillator. + gpio<16>/aio<5>/32K XTAL input + gpio<17>/aio<6>/32K XTAL output + + There are four pins which uses as pga,voice and so on. + gpio<23>/aio<1>/micphone bias reference voltage,this pin is selected + gpio<15>/aio<4>/micphone bias + gpio<18>/aio<7>/pga in+ + gpio<20>/aio<9>/pga in- +*/ +typedef enum +{ + ADC_CH0DIFF = 1,/*p18(positive),p25(negative),only works in diff*/ + ADC_CH0 = 2,ADC_CH1N_P11 = 2,MIN_ADC_CH = 2, + ADC_CH1 = 3,ADC_CH1P_P23 = 3,ADC_CH1DIFF = 3,/*P23 and P11*/ + ADC_CH2 = 4,ADC_CH2N_P24 = 4, + ADC_CH3 = 5,ADC_CH2P_P14 = 5,ADC_CH2DIFF = 5,/*P14 and P24*/ + ADC_CH4 = 6,ADC_CH3N_P15 = 6, + ADC_CH9 = 7,ADC_CH3P_P20 = 7,MAX_ADC_CH = 7,ADC_CH3DIFF = 7,/*P20 and P15*/ + ADC_CH_VOICE = 8, + ADC_CH_NUM =9, +} adc_CH_t; + + +#define ADC_BIT(ch) (1<KeyConfig & BSP_BTN_CM_CFG; + uint32_t combine_temp; + + if(ComKeyFlag == 0) + { + if(g_btn_value[KEY_BUF_INDEX(index)] & BIT(KEY_BUF_MOD(index))) + { + return TRUE; + } + else + { + return FALSE; + } + } + else + { + combine_temp = g_combing_ptr[(index - g_combing_start)]; + + for(int i = 0; i < KEY_COMBINE_LEN; i++) + { + if(combine_temp & BIT(i)) + { + index = bsp_btn_map(BIT(i)); + + if((g_btn_value[KEY_BUF_INDEX(index)] & BIT(KEY_BUF_MOD(index))) == 0x00) + { + return FALSE; + } + } + } + + return TRUE; + } +} + +bool bsp_set_key_value_by_row_col(uint8_t cols_num,uint8_t row,uint8_t col,bool value) +{ + uint8_t m0; + uint32_t temp,combine_temp; + uint32_t index = row * cols_num + col; + + //LOG("----------->(%d) %d %d\n",__LINE__,index,value); + if(value) + { + g_btn_value[KEY_BUF_INDEX(index)] |= BIT(KEY_BUF_MOD(index)); + } + else + { + g_btn_value[KEY_BUF_INDEX(index)] &= ~BIT(KEY_BUF_MOD(index)); + } + + if((g_btn_ptr + index)->KeyConfig & BSP_BTN_CM_CFG) + { + combine_temp = g_combing_ptr[(index - g_combing_start)]; + + for(int i=0; i(%d) %d %d\n",__LINE__,index,value); + if(value) + { + g_btn_value[KEY_BUF_INDEX(index)] |= BIT(KEY_BUF_MOD(index)); + } + else + { + g_btn_value[KEY_BUF_INDEX(index)] &= ~BIT(KEY_BUF_MOD(index)); + } +} + +bool bsp_InitBtn(BTN_T* sum_btn_array,uint8_t sum_btn_num,uint8_t combine_btn_start,BTN_COMBINE_T* combine_btn_array) +{ + int i; + s_Key.Read = 0; + s_Key.Write = 0; + + if( (sum_btn_array == NULL) || (sum_btn_num == 0) || (sum_btn_num > BTN_NUMBER)) + { + return PPlus_ERR_INVALID_PARAM; + } + + g_btn_ptr = sum_btn_array; + g_btn_num = sum_btn_num; + + for(i=0; i= KEY_FIFO_SIZE) + { + s_Key.Write = 0; + } +} + +uint8_t bsp_GetKey(void) +{ + uint8_t ret; + + if (s_Key.Read == s_Key.Write) + { + return BTN_NONE; + } + else + { + ret = s_Key.Buf[s_Key.Read]; + + if (++s_Key.Read >= KEY_FIFO_SIZE) + { + s_Key.Read = 0; + } + + return ret; + } +} + +static void bsp_DetectBtn(uint8_t index) +{ + BTN_T* _pBtn = (g_btn_ptr + index); + + if (bsp_is_key_press(index)) + { + if (_pBtn->Count < _pBtn->FilterTime) + { + _pBtn->Count = _pBtn->FilterTime; + } + else if(_pBtn->Count < 2 * _pBtn->FilterTime) + { + _pBtn->Count++; + } + else + { + if (_pBtn->State == 0) + { + _pBtn->State = 1; + + if (_pBtn->KeyConfig & BSP_BTN_PD_CFG) + { + bsp_PutKey(BSP_BTN_PD_BASE + index); + } + } + + #ifdef BSP_BTN_LONG_PRESS_ENABLE + + if (_pBtn->LongTime > 0) + { + if (_pBtn->LongCount < _pBtn->LongTime) + { + if (++_pBtn->LongCount == _pBtn->LongTime) + { + if (_pBtn->KeyConfig & BSP_BTN_LPS_CFG) + { + bsp_PutKey(BSP_BTN_LPS_BASE + index); + } + } + } + else + { + if (_pBtn->RepeatSpeed > 0) + { + if (++_pBtn->RepeatCount >= _pBtn->RepeatSpeed) + { + _pBtn->RepeatCount = 0; + + if (_pBtn->KeyConfig & BSP_BTN_LPK_CFG) + { + bsp_PutKey(BSP_BTN_LPK_BASE + index); + } + } + } + } + } + + #endif + } + } + else + { + if(_pBtn->Count > _pBtn->FilterTime) + { + _pBtn->Count = _pBtn->FilterTime; + } + else if(_pBtn->Count != 0) + { + _pBtn->Count--; + } + else + { + if (_pBtn->State == 1) + { + _pBtn->State = 0; + + if (_pBtn->KeyConfig & BSP_BTN_UP_CFG ) + { + bsp_PutKey(BSP_BTN_UP_BASE + index); + } + } + } + + #ifdef BSP_BTN_LONG_PRESS_ENABLE + _pBtn->LongCount = 0; + _pBtn->RepeatCount = 0; + #endif + } +} + +uint8_t bsp_KeyPro(void) +{ + uint8_t ucKeyCode; + + for(int i = 0; i < g_btn_num; i++) + { + bsp_DetectBtn(i); + } + + ucKeyCode = bsp_GetKey(); + return ucKeyCode; +} + +bool bsp_KeyEmpty(void) +{ + for(int i = 0; i < g_btn_num; i++) + { + BTN_T* _pBtn = (g_btn_ptr + i); + #ifdef BSP_BTN_LONG_PRESS_ENABLE + + if ((_pBtn->State == 1) || (_pBtn->Count != 0) || (_pBtn->LongCount != 0) ||(_pBtn->RepeatCount != 0)) + #else + if ((_pBtn->State == 1) || (_pBtn->Count != 0) ) + #endif + { + return FALSE; + } + } + + if (s_Key.Read == s_Key.Write) + { + return TRUE; + } + else + { + return FALSE; + } +} + diff --git a/src/components/driver/bsp_button/bsp_button.h b/src/components/driver/bsp_button/bsp_button.h new file mode 100644 index 0000000..3e6faee --- /dev/null +++ b/src/components/driver/bsp_button/bsp_button.h @@ -0,0 +1,80 @@ +#ifndef __BSP_BUTTON_H__ +#define __BSP_BUTTON_H__ + +#include "types.h" + +//#define BSP_BTN_LONG_PRESS_ENABLE + +#define BTN_SYS_TICK 10 //unit:ms +#define BTN_FILTER_TICK_COUNT 5 //(BTN_SYS_TICK*BTN_FILTER_TICK_COUNT) ms +#define BTN_LONG_PRESS_START_TICK_COUNT 10 //(BTN_SYS_TICK*BTN_LONG_PRESS_START_TICK_COUNT) ms +#define BTN_LONG_PRESS_KEEP_TICK_COUNT 100 //(BTN_SYS_TICK*BTN_LONG_PRESS_KEEP_TICK_COUNT) ms + +#define BTN_NUMBER 32 //valid:[0,0x2F].reserved[0x30,0x3F] +#define BTN_NONE 0xFF + +#if (BTN_NUMBER > 48) + #error "error bsp button config,please check" +#endif + +/* + bit0:press down + bit1:press up + bit2:long press start + bit3:long press keep + bit4:combine or not +*/ +#define BSP_BTN_PD_CFG 0x01 +#define BSP_BTN_UP_CFG 0x02 +#define BSP_BTN_LPS_CFG 0x04 +#define BSP_BTN_LPK_CFG 0x08 +#define BSP_BTN_CM_CFG 0x10 + +#define BSP_BTN_PD_TYPE (0U<<6) +#define BSP_BTN_UP_TYPE (1U<<6) +#define BSP_BTN_LPS_TYPE (2U<<6) +#define BSP_BTN_LPK_TYPE (3U<<6) + +#define BSP_BTN_PD_BASE BSP_BTN_PD_TYPE +#define BSP_BTN_UP_BASE BSP_BTN_UP_TYPE +#define BSP_BTN_LPS_BASE BSP_BTN_LPS_TYPE +#define BSP_BTN_LPK_BASE BSP_BTN_LPK_TYPE + +#define BSP_BTN_TYPE(key) (key & 0xC0) +#define BSP_BTN_INDEX(key) (key & 0x3F) + +typedef uint32_t BTN_COMBINE_T; + +typedef struct +{ + uint8_t KeyConfig; + uint8_t State; + uint8_t Count; + uint8_t FilterTime; + + #ifdef BSP_BTN_LONG_PRESS_ENABLE + uint8_t LongCount; + uint8_t LongTime; + uint8_t RepeatSpeed; + uint8_t RepeatCount; + #endif +} BTN_T; + + +#define KEY_FIFO_SIZE 20 +typedef struct +{ + uint8_t Buf[KEY_FIFO_SIZE]; + uint8_t Read; + uint8_t Write; +} KEY_FIFO_T; + +bool bsp_InitBtn(BTN_T* sum_btn_array,uint8_t sum_btn_num,uint8_t combine_btn_start,BTN_COMBINE_T* combine_btn_array); + +uint8_t bsp_KeyPro(void); +uint8_t bsp_GetKey(void); +bool bsp_set_key_value_by_row_col(uint8_t cols_num,uint8_t row,uint8_t col,bool value); +void bsp_set_key_value_by_index(uint8_t index,bool value); +bool bsp_KeyEmpty(void); + +#endif diff --git a/src/components/driver/bsp_button/bsp_button_task.c b/src/components/driver/bsp_button/bsp_button_task.c new file mode 100644 index 0000000..cb7c442 --- /dev/null +++ b/src/components/driver/bsp_button/bsp_button_task.c @@ -0,0 +1,226 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: bsp_button_task.c + Revised: $Date $ + Revision: $Revision $ +**************************************************************************************************/ + +/********************************************************************* + INCLUDES +*/ +#include +#include "OSAL.h" +#include "OSAL_Timers.h" +#include "pwrmgr.h" +#include "bsp_button_task.h" + +uint8 Bsp_Btn_TaskID; + +bool bsp_btn_timer_flag = FALSE; +bool bsp_btn_gpio_flag = FALSE; +bool bsp_btn_kscan_flag = FALSE; +bsp_btn_callback_t bsp_btn_cb = NULL; + +//uint32_t bsp_btn_counter = 0; +//void wake_test(void) +//{ +// bsp_btn_counter++; +//} + +#if ((BSP_BTN_HARDWARE_CONFIG == BSP_BTN_JUST_KSCAN) || (BSP_BTN_HARDWARE_CONFIG ==BSP_BTN_GPIO_AND_KSCAN)) + +uint8 KscanMK_row[KSCAN_ALL_ROW_NUM]; +uint8 KscanMK_col[KSCAN_ALL_COL_NUM]; + +static void kscan_evt_handler(kscan_Evt_t* evt) +{ + bool ret; + + for(uint8_t i=0; inum; i++) + { + if(evt->keys[i].type == KEY_PRESSED) + { + ret = bsp_set_key_value_by_row_col(NUM_KEY_COLS,KscanMK_row[evt->keys[i].row],KscanMK_col[evt->keys[i].col],TRUE); + { + if(ret == TRUE) + { + bsp_btn_timer_flag = TRUE; + osal_start_reload_timer(Bsp_Btn_TaskID,BSP_BTN_EVT_SYSTICK,BTN_SYS_TICK); + } + } + } + else + { + bsp_set_key_value_by_row_col(NUM_KEY_COLS,KscanMK_row[evt->keys[i].row],KscanMK_col[evt->keys[i].col],FALSE); + } + } +} + +void kscan_button_init(uint8 task_id) +{ + kscan_Cfg_t cfg; + cfg.ghost_key_state = NOT_IGNORE_GHOST_KEY; + cfg.key_rows = rows; + cfg.key_cols = cols; + cfg.interval = 5; + cfg.evt_handler = kscan_evt_handler; + memset(KscanMK_row,0xff,KSCAN_ALL_ROW_NUM); + + for(int i=0; i 0) + + if(PPlus_SUCCESS != bsp_InitBtn(usr_sum_btn_array,BSP_TOTAL_BTN_NUM,BSP_SINGLE_BTN_NUM,usr_combine_btn_array)) + #else + if(PPlus_SUCCESS != bsp_InitBtn(usr_sum_btn_array,BSP_TOTAL_BTN_NUM,0,NULL)) + #endif + { + LOG("bsp button init error\n"); + } + + //hal_pwrmgr_register(MOD_USR8, NULL, wake_test); +} + +uint16 Bsp_Btn_ProcessEvent( uint8 task_id, uint16 events ) +{ + uint8_t ucKeyCode; + + if(Bsp_Btn_TaskID != task_id) + { + return 0; + } + + #if ((BSP_BTN_HARDWARE_CONFIG == BSP_BTN_JUST_KSCAN) || (BSP_BTN_HARDWARE_CONFIG == BSP_BTN_GPIO_AND_KSCAN)) + + if ( events & KSCAN_WAKEUP_TIMEOUT_EVT ) + { + hal_kscan_timeout_handler(); + return (events ^ KSCAN_WAKEUP_TIMEOUT_EVT); + } + + #endif + + if ( events & BSP_BTN_EVT_SYSTICK ) + { +// if((bsp_btn_counter%10)==0) +// LOG(".:%d ",bsp_btn_counter); + ucKeyCode = bsp_KeyPro(); + + if(ucKeyCode != BTN_NONE) + { + Bsp_Btn_Check(ucKeyCode); + } + + return (events ^ BSP_BTN_EVT_SYSTICK); + } + + return 0; +} diff --git a/src/components/driver/bsp_button/bsp_button_task.h b/src/components/driver/bsp_button/bsp_button_task.h new file mode 100644 index 0000000..59f0422 --- /dev/null +++ b/src/components/driver/bsp_button/bsp_button_task.h @@ -0,0 +1,101 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: bsp_button_task.h + Revised: $Date $ + Revision: $Revision $ + + +**************************************************************************************************/ +#ifndef __BSP_BUTTON_TASK_H__ +#define __BSP_BUTTON_TASK_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "bus_dev.h" +#include "bsp_gpio.h" +#include "kscan.h" +#include "bsp_button.h" +#include "log.h" + + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + CONSTANTS +*/ +#define BSP_BTN_JUST_GPIO (0x01) +#define BSP_BTN_JUST_KSCAN (0x02) +#define BSP_BTN_GPIO_AND_KSCAN (0x03) +#define BSP_BTN_HARDWARE_CONFIG BSP_BTN_JUST_GPIO + +#if (BSP_BTN_HARDWARE_CONFIG == BSP_BTN_JUST_GPIO) + +#define BSP_SINGLE_BTN_NUM (GPIO_SINGLE_BTN_NUM) +#define BSP_COMBINE_BTN_NUM (2) +#define BSP_TOTAL_BTN_NUM (BSP_SINGLE_BTN_NUM + BSP_COMBINE_BTN_NUM) + +#elif (BSP_BTN_HARDWARE_CONFIG == BSP_BTN_JUST_KSCAN) + +#define BSP_SINGLE_BTN_NUM (NUM_KEY_ROWS * NUM_KEY_COLS) +#define BSP_COMBINE_BTN_NUM (2) +#define BSP_TOTAL_BTN_NUM (BSP_SINGLE_BTN_NUM + BSP_COMBINE_BTN_NUM) + +#elif (BSP_BTN_HARDWARE_CONFIG == BSP_BTN_GPIO_AND_KSCAN) + +#define BSP_KSCAN_SINGLE_BTN_NUM (NUM_KEY_ROWS * NUM_KEY_COLS) +#define BSP_GPIO_SINGLE_BTN_NUM (GPIO_SINGLE_BTN_NUM) + +#define BSP_KSCAN_COMBINE_BTN_NUM (1) +#define BSP_GPIO_COMBINE_BTN_NUM (1) + +#define BSP_SINGLE_BTN_NUM (BSP_KSCAN_SINGLE_BTN_NUM + BSP_GPIO_SINGLE_BTN_NUM) +#define BSP_COMBINE_BTN_NUM (BSP_KSCAN_COMBINE_BTN_NUM + BSP_GPIO_COMBINE_BTN_NUM) +#define BSP_TOTAL_BTN_NUM (BSP_SINGLE_BTN_NUM + BSP_COMBINE_BTN_NUM) + +#else + +#error "error bsp button config,please check" + +#endif + + +extern BTN_T usr_sum_btn_array[BSP_TOTAL_BTN_NUM]; +#if (BSP_COMBINE_BTN_NUM > 0) +extern uint32_t usr_combine_btn_array[BSP_COMBINE_BTN_NUM]; +#endif + +extern bool bsp_btn_gpio_flag; +extern bool bsp_btn_kscan_flag; + +typedef void (*bsp_btn_callback_t)(uint8_t evt); +extern bsp_btn_callback_t bsp_btn_cb; + +#define BSP_BTN_EVT_SYSTICK (0x0010) +#define KSCAN_WAKEUP_TIMEOUT_EVT (0x0020) +#define BSP_BTN_EVT_DBG (0x0040) + +uint16 Bsp_Btn_ProcessEvent( uint8 task_id, uint16 events); +void Bsp_Btn_Init( uint8 task_id ); + +#if ((BSP_BTN_HARDWARE_CONFIG == BSP_BTN_JUST_KSCAN) || (BSP_BTN_HARDWARE_CONFIG ==BSP_BTN_GPIO_AND_KSCAN)) +extern KSCAN_ROWS_e rows[NUM_KEY_ROWS]; +extern KSCAN_COLS_e cols[NUM_KEY_COLS]; +#endif + + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* BSP_BUTTON_TASK_H */ diff --git a/src/components/driver/bsp_button/bsp_gpio.c b/src/components/driver/bsp_button/bsp_gpio.c new file mode 100644 index 0000000..d8b4a7e --- /dev/null +++ b/src/components/driver/bsp_button/bsp_gpio.c @@ -0,0 +1,80 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************** + + + Module Name: bsp_gpio + File name: bsp_gpio.c + Brief description: + key driver module + Data: 2020-06-30 + Revision:V0.01 +****************************************************************/ +#include "bsp_gpio.h" + +extern void gpio_btn_pin_event_handler(gpio_pin_e pin,IO_Wakeup_Pol_e type); + +static Gpio_Btn_Info* s_gpio_btn_ptr = NULL; +int hal_gpio_btn_init(Gpio_Btn_Info* gpio_btn_ptr) +{ + if((gpio_btn_ptr == NULL)||(GPIO_SINGLE_BTN_NUM == 0)) + { + return PPlus_ERR_INVALID_PARAM; + } + + if((gpio_btn_ptr->s_key == NULL) || (gpio_btn_ptr->cb == NULL)) + { + return PPlus_ERR_INVALID_PARAM; + } + + if(GPIO_SINGLE_BTN_NUM != sizeof(gpio_btn_ptr->s_key)/sizeof(gpio_btn_ptr->s_key[0])) + { + return PPlus_ERR_INVALID_PARAM; + } + + for(int i = 0; i < GPIO_SINGLE_BTN_NUM; i++) + { + if(GPIO_SINGLE_BTN_IDLE_LEVEL == 0) + { + hal_gpio_pull_set(*(gpio_btn_ptr->s_key+i),PULL_DOWN); + } + else + { + hal_gpio_pull_set(*(gpio_btn_ptr->s_key+i),WEAK_PULL_UP); + } + + hal_gpioin_register(*(gpio_btn_ptr->s_key+i),gpio_btn_pin_event_handler, gpio_btn_pin_event_handler); + } + + s_gpio_btn_ptr = gpio_btn_ptr; + return PPlus_SUCCESS; +} + +int hal_gpio_btn_get_index(gpio_pin_e pin,uint8_t* index) +{ + if(s_gpio_btn_ptr == NULL) + { + return PPlus_ERR_NOT_SUPPORTED; + } + + for(int i = 0; i < GPIO_SINGLE_BTN_NUM; i++) + { + if(pin == s_gpio_btn_ptr->s_key[i]) + { + *index = i; + return PPlus_SUCCESS; + } + } + + return PPlus_ERR_NOT_FOUND; +} + +void hal_gpio_btn_cb(uint8_t ucKeyCode) +{ + if(s_gpio_btn_ptr != NULL) + { + s_gpio_btn_ptr->cb(ucKeyCode); + } +} diff --git a/src/components/driver/bsp_button/bsp_gpio.h b/src/components/driver/bsp_button/bsp_gpio.h new file mode 100644 index 0000000..58760ac --- /dev/null +++ b/src/components/driver/bsp_button/bsp_gpio.h @@ -0,0 +1,46 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ +/************************************************************** + + + Module Name: bsp_gpio + File name: bsp_gpio.h + Brief description: + key driver module + Data: 2020-06-30 + Revision:V0.01 +****************************************************************/ + +#ifndef __KEY_H__ +#define __KEY_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "error.h" +#include "gpio.h" + +#define GPIO_SINGLE_BTN_NUM 3 +#define GPIO_SINGLE_BTN_IDLE_LEVEL 1 + +typedef void (*gpio_btn_callback_t)(uint8_t evt); + +typedef struct _Gpio_Btn_Info +{ + gpio_pin_e s_key[GPIO_SINGLE_BTN_NUM]; + gpio_btn_callback_t cb; +} Gpio_Btn_Info; + +int hal_gpio_btn_init(Gpio_Btn_Info* gpio_btn_ptr); + +int hal_gpio_btn_get_index(gpio_pin_e pin,uint8_t* index); + +void hal_gpio_btn_cb(uint8_t ucKeyCode); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/components/driver/clock/clock.c b/src/components/driver/clock/clock.c new file mode 100644 index 0000000..3459c6d --- /dev/null +++ b/src/components/driver/clock/clock.c @@ -0,0 +1,248 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ +#include "clock.h" +#include "gpio.h" +#include "global_config.h" +#include "error.h" +#include "rf_phy_driver.h" + + +extern uint32_t hclk,pclk; +extern uint32_t osal_sys_tick; + +void hal_clk_gate_enable(MODULE_e module) +{ + if(module < MOD_CP_CPU) + { + AP_PCR->SW_CLK |= BIT(module); + } + else if(module < MOD_PCLK_CACHE) + { + AP_PCR->SW_CLK1 |= BIT(module-MOD_CP_CPU); + } + else if(module < MOD_USR0) + { + AP_PCR->CACHE_CLOCK_GATE |= BIT(module-MOD_PCLK_CACHE); + } +} + +void hal_clk_gate_disable(MODULE_e module) +{ + if(module < MOD_CP_CPU) + { + AP_PCR->SW_CLK &= ~(BIT(module)); + } + else if(module < MOD_PCLK_CACHE) + { + AP_PCR->SW_CLK1 &= ~(BIT(module-MOD_CP_CPU)); + } + else if(module < MOD_USR0) + { + AP_PCR->CACHE_CLOCK_GATE &= ~(BIT(module-MOD_PCLK_CACHE)); + } +} + +int hal_clk_gate_get(MODULE_e module) +{ + if(module < MOD_CP_CPU) + { + return (AP_PCR->SW_CLK & BIT(module)); + } + else if(module < MOD_PCLK_CACHE) + { + return (AP_PCR->SW_CLK1 & BIT(module-MOD_CP_CPU)); + } + //else if(module < MOD_USR0) + else + { + return (AP_PCR->CACHE_CLOCK_GATE & BIT(module-MOD_PCLK_CACHE)); + } +} + +void hal_clk_get_modules_state(uint32_t* buff) +{ + *buff = AP_PCR->SW_CLK; + *(buff+1) = AP_PCR->SW_CLK1; + *(buff+2) = AP_PCR->CACHE_CLOCK_GATE; +} + +void hal_clk_reset(MODULE_e module) +{ + if(module < MOD_CP_CPU) + { + if((module >= MOD_TIMER5) &&(module <= MOD_TIMER6)) + { + AP_PCR->SW_RESET0 &= ~BIT(5); + AP_PCR->SW_RESET0 |= BIT(5); + } + else + { + AP_PCR->SW_RESET0 &= ~BIT(module); + AP_PCR->SW_RESET0 |= BIT(module); + } + } + else if(module < MOD_PCLK_CACHE) + { + if((module >= MOD_TIMER1) &&(module <= MOD_TIMER4)) + { + AP_PCR->SW_RESET2 &= ~BIT(4); + AP_PCR->SW_RESET2 |= BIT(4); + } + else + { + AP_PCR->SW_RESET2 &= ~BIT(module-MOD_CP_CPU); + AP_PCR->SW_RESET2 |= BIT(module-MOD_CP_CPU); + } + } + else if(module < MOD_USR0) + { + AP_PCR->CACHE_RST &= ~BIT(1-(module-MOD_HCLK_CACHE)); + AP_PCR->CACHE_RST |= BIT(1-(module-MOD_HCLK_CACHE)); + } +} + + +void hal_rtc_clock_config(CLK32K_e clk32Mode) +{ + if(clk32Mode == CLK_32K_RCOSC) + { + subWriteReg(&(AP_AON->PMCTL0),31,27,0x05); + subWriteReg(&(AP_AON->PMCTL2_0),16,7,0x3fb); + subWriteReg(&(AP_AON->PMCTL2_0),6,6,0x01); + //pGlobal_config[LL_SWITCH]|=RC32_TRACKINK_ALLOW|LL_RC32K_SEL; + } + else if(clk32Mode == CLK_32K_XTAL) + { + // P16 P17 for 32K XTAL input + hal_gpio_pull_set(P16,FLOATING); + hal_gpio_pull_set(P17,FLOATING); + subWriteReg(&(AP_AON->PMCTL2_0),9,8,0x03); //software control 32k_clk + subWriteReg(&(AP_AON->PMCTL2_0),6,6,0x00); //disable software control + subWriteReg(&(AP_AON->PMCTL0),31,27,0x16); + //pGlobal_config[LL_SWITCH]&=0xffffffee; + } + +// //ZQ 20200812 for rc32k wakeup +// subWriteReg(&(AP_AON->PMCTL0),28,28,0x1);//turn on 32kxtal +// subWriteReg(&(AP_AON->PMCTL1),18,17,0x0);// reduce 32kxtl bias current +} + + + +uint32_t hal_systick(void) +{ + return osal_sys_tick; +} + +uint32_t hal_ms_intv(uint32_t tick) +{ + uint32_t diff = 0; + + if(osal_sys_tick < tick) + { + diff = 0xffffffff- tick; + diff = osal_sys_tick + diff; + } + else + { + diff = osal_sys_tick - tick; + } + + return diff*625/1000; +} + +/************************************************************************************** + @fn WaitMs + + @brief This function process for wait program msecond,use RTC + + input parameters + + @param uint32_t msecond: the msecond value + + output parameters + + @param None. + + @return None. + **************************************************************************************/ + +void WaitMs(uint32_t msecond) +{ + WaitRTCCount((msecond << 15) / 1000); // step 32us +} + +void WaitUs(uint32_t wtTime) +{ + uint32_t T0,currTick,deltTick; + //T0 = read_current_time(); + T0 =(TIME_BASE - ((AP_TIM3->CurrentCount) >> 2)); + + while(1) + { + currTick = (TIME_BASE - ((AP_TIM3->CurrentCount) >> 2)); + deltTick = TIME_DELTA(currTick,T0); + + if(deltTick>wtTime) + break; + } +} +extern int m_in_critical_region ; +void hal_system_soft_reset(void) +{ + //HAL_ENTER_CRITICAL_SECTION(); + __disable_irq(); + m_in_critical_region++; + /** + config reset casue as RSTC_WARM_NDWC + reset path walkaround dwc + */ + AP_AON->SLEEP_R[0]=4; + + AON_CLEAR_XTAL_TRACKING_AND_CALIB; + + AP_PCR->SW_RESET1 = 0; + + while(1); +} + +void hal_rc32k_clk_tracking_init(void) +{ + extern uint32 counter_tracking; + extern uint32_t g_counter_traking_avg; + counter_tracking = g_counter_traking_avg = STD_RC32_16_CYCLE_16MHZ_CYCLE; + AON_CLEAR_XTAL_TRACKING_AND_CALIB; +} + +__ATTR_SECTION_XIP__ void hal_rfPhyFreqOff_Set(void) +{ + int32_t freqPpm=0; + freqPpm= *(volatile int32_t*) 0x11004008; + + if((freqPpm!=0xffffffff) && (freqPpm>=-50) && (freqPpm<=50)) + { + g_rfPhyFreqOffSet=(int8_t)freqPpm; + } + else + { + g_rfPhyFreqOffSet =RF_PHY_FREQ_FOFF_00KHZ; + } +} + +__ATTR_SECTION_XIP__ void hal_xtal16m_cap_Set(void) +{ + uint32_t cap=0; + cap= *(volatile int32_t*) 0x1100400c; + + if((cap!=0xffffffff) && (cap <= 0x1f)) + { + XTAL16M_CAP_SETTING(cap); + } + else + { + XTAL16M_CAP_SETTING(0x09); + } +} + + diff --git a/src/components/driver/clock/clock.h b/src/components/driver/clock/clock.h new file mode 100644 index 0000000..8b100cc --- /dev/null +++ b/src/components/driver/clock/clock.h @@ -0,0 +1,112 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ +#ifndef _HAL_CLOCK_H +#define _HAL_CLOCK_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "types.h" +#include "bus_dev.h" +//#include "common.h" + +typedef enum +{ + CLK_32K_XTAL = 0, + CLK_32K_RCOSC = 1, + +} CLK32K_e; + +typedef enum +{ + XTAL_16M = 0, + DBL_B_32M = 1, + DBL_32 = 2, + DLL_32M = 3, + +} ClkSrc_e; + +typedef enum _SYSCLK_SEL +{ + SYS_CLK_RC_32M = 0, + SYS_CLK_DBL_32M = 1, + SYS_CLK_XTAL_16M = 2, + SYS_CLK_DLL_48M = 3, + SYS_CLK_DLL_64M = 4, + SYS_CLK_DLL_96M = 5, + SYS_CLK_8M = 6, + SYS_CLK_4M = 7, + SYS_CLK_NUM = 8, +} sysclk_t; + +typedef enum +{ + HCLK_CHANGE = 0, + AP_CLK_CHANGE = 1, + CP_CLK_CHANGE = 2, +} clk_update_Type_t; + +typedef struct _clk_Evt_t +{ + uint8_t flag; + +} clk_Evt_t; + +typedef void (*clk_Hdl_t)(clk_Evt_t* pev); + +typedef struct _clk_Contex_t +{ + bool enable; + clk_Hdl_t evt_handler; +} clk_Ctx_t; + + +#define CLAER_RTC_COUNT AP_AON->RTCCTL |= BIT(1) +#define RUN_RTC AP_AON->RTCCTL |= BIT(0) +#define STOP_RTC AP_AON->RTCCTL &= ~BIT(0) + +#define hal_system_init clk_init +extern volatile uint32_t g_hclk; +#define clk_get_hclk() g_hclk +uint32_t clk_get_pclk(void); + +void hal_clk_gate_enable(MODULE_e module); +void hal_clk_gate_disable(MODULE_e module); +int hal_clk_gate_get(MODULE_e module); +void hal_clk_get_modules_state(uint32_t* buff); +void hal_clk_reset(MODULE_e module); +void hal_clk_rf_config(ClkSrc_e sel); +void hal_clk_rxadc_config(ClkSrc_e sel); + +bool hal_clk_set_pclk(uint32_t div); +int hal_clk_init(sysclk_t hclk_sel,clk_Hdl_t evt_handler); +void hal_rtc_clock_config(CLK32K_e clk32Mode); + +uint32_t hal_systick(void); +uint32_t hal_ms_intv(uint32_t tick); + +extern uint32_t rtc_get_counter(void); +void WaitMs(uint32_t msecond); +void WaitUs(uint32_t wtTime); +void hal_system_soft_reset(void); + + +extern int clk_init(sysclk_t h_system_clk_sel); +extern void WaitRTCCount(uint32_t rtcDelyCnt); +extern int clk_spif_ref_clk(sysclk_t spif_ref_sel); +extern uint32_t getMcuPrecisionCount(void); + +void hal_rfPhyFreqOff_Set(void); +void hal_xtal16m_cap_Set(void); + +void hal_rc32k_clk_tracking_init(void); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/src/components/driver/dma/dma.c b/src/components/driver/dma/dma.c new file mode 100644 index 0000000..e314c7e --- /dev/null +++ b/src/components/driver/dma/dma.c @@ -0,0 +1,370 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#include + +#include "clock.h" +#include "pwrmgr.h" +#include "error.h" +#include "log.h" +#include "jump_function.h" + +#include "dma.h" +#include "spi.h" +#include "uart.h" +#include "i2c.h" + +typedef struct +{ + bool init_flg; + DMA_CH_Ctx_t dma_ch_ctx[DMA_CH_NUM]; +} dma_ctx_t; + + +dma_ctx_t s_dma_ctx = +{ + .init_flg = FALSE, +}; + +static DMA_CONN_e get_src_conn(uint32_t addr) +{ + if(addr == (uint32_t)&(AP_SPI0->DataReg)) + return DMA_CONN_SPI0_Rx; + + if(addr == (uint32_t)&(AP_SPI1->DataReg)) + return DMA_CONN_SPI1_Rx; + + if(addr == (uint32_t)&(AP_I2C0->IC_DATA_CMD)) + return DMA_CONN_I2C0_Rx; + + if(addr == (uint32_t)&(AP_I2C1->IC_DATA_CMD)) + return DMA_CONN_I2C1_Rx; + + if(addr == (uint32_t)&(AP_UART0->RBR)) + return DMA_CONN_UART0_Rx; + + if(addr == (uint32_t)&(AP_UART1->RBR)) + return DMA_CONN_UART1_Rx; + + return DMA_CONN_MEM; +} + +static DMA_CONN_e get_dst_conn(uint32_t addr) +{ + if(addr == (uint32_t)&(AP_SPI0->DataReg)) + return DMA_CONN_SPI0_Tx; + + if(addr == (uint32_t)&(AP_SPI1->DataReg)) + return DMA_CONN_SPI1_Tx; + + if(addr == (uint32_t)&(AP_I2C0->IC_DATA_CMD)) + return DMA_CONN_I2C0_Tx; + + if(addr == (uint32_t)&(AP_I2C1->IC_DATA_CMD)) + return DMA_CONN_I2C1_Tx; + + if(addr == (uint32_t)&(AP_UART0->THR)) + return DMA_CONN_UART0_Tx; + + if(addr == (uint32_t)&(AP_UART1->THR)) + return DMA_CONN_UART1_Tx; + + return DMA_CONN_MEM; +} + +static void dma_wakeup_handler(void) +{ + hal_clk_gate_enable(MOD_DMA); + NVIC_SetPriority((IRQn_Type)DMAC_IRQn, IRQ_PRIO_HAL); + NVIC_EnableIRQ((IRQn_Type)DMAC_IRQn); + JUMP_FUNCTION(DMAC_IRQ_HANDLER) = (uint32_t)&hal_DMA_IRQHandler; + AP_DMA_MISC->DmaCfgReg = DMA_DMAC_E; +} + + +int hal_dma_init_channel(HAL_DMA_t cfg) +{ + DMA_CH_Ctx_t* pctx; + DMA_CH_t ch; + + if(!s_dma_ctx.init_flg) + return PPlus_ERR_NOT_REGISTED; + + ch = cfg.dma_channel; + + if(ch >= DMA_CH_NUM) + return PPlus_ERR_INVALID_PARAM; + + pctx = &s_dma_ctx.dma_ch_ctx[ch]; + + if(pctx ->init_ch) + return PPlus_ERR_INVALID_STATE; + + pctx->evt_handler = cfg.evt_handler; + pctx->init_ch = true; + return PPlus_SUCCESS; +} + + +int hal_dma_config_channel(DMA_CH_t ch, DMA_CH_CFG_t* cfg) +{ + DMA_CH_Ctx_t* pctx; + DMA_CONN_e src_conn,dst_conn; + uint32_t cctrl = 0; + uint32_t transf_type = DMA_TRANSFERTYPE_M2M; + uint32_t transf_per = 0; + uint32_t spif_protect = AP_SPIF->wr_protection; + uint32_t cache_bypass = AP_PCR->CACHE_BYPASS; + + if(!s_dma_ctx.init_flg) + return PPlus_ERR_NOT_REGISTED; + + if(ch >= DMA_CH_NUM) + { + return PPlus_ERR_INVALID_PARAM; + } + + pctx = &s_dma_ctx.dma_ch_ctx[ch]; + + if(!pctx->init_ch) + return PPlus_ERR_INVALID_STATE; + + if ((AP_DMA_MISC->ChEnReg & (DMA_DMACEnbldChns_Ch(ch))) || \ + (pctx->xmit_busy)) + { + // This channel is enabled, return ERROR, need to release this channel first + return PPlus_ERR_BUSY; + } + + // Reset the Interrupt status + AP_DMA_INT->ClearTfr = DMA_DMACIntTfrClr_Ch(ch); + // UnMask interrupt + AP_DMA_INT->MaskTfr = DMA_DMACCxIntMask_E(ch); + src_conn = get_src_conn(cfg->src_addr); + dst_conn = get_dst_conn(cfg->dst_addr); + + /* Assign Linker List Item value */ + if(src_conn && dst_conn) + { + transf_type = DMA_TRANSFERTYPE_P2P; + transf_per = DMA_DMACCxConfig_SrcPeripheral(src_conn-1)| \ + DMA_DMACCxConfig_DestPeripheral(dst_conn-1); + } + else if(src_conn) + { + transf_type = DMA_TRANSFERTYPE_P2M; + transf_per = DMA_DMACCxConfig_SrcPeripheral(src_conn-1); + } + else if(dst_conn) + { + transf_type = DMA_TRANSFERTYPE_M2P; + transf_per = DMA_DMACCxConfig_DestPeripheral(dst_conn-1); + } + + if((cfg->dst_addr > 0x11000000) && (cfg->dst_addr <= 0x11080000)) + { + pctx->xmit_flash = DMA_DST_XIMT_IS_FLASH; + + if(spif_protect) + { + AP_SPIF->wr_protection = 0; + } + + if(cache_bypass == 0) + { + AP_PCR->CACHE_BYPASS = 1; + } + } + else + { + pctx->xmit_flash = DMA_DST_XIMT_NOT_FLASH; + } + + AP_DMA_CH_CFG(ch)->SAR = cfg->src_addr; + AP_DMA_CH_CFG(ch)->DAR = cfg->dst_addr; + AP_DMA_CH_CFG(ch)->LLP = 0; + + if(DMA_GET_MAX_TRANSPORT_SIZE(ch) < cfg->transf_size) + { + return PPlus_ERR_INVALID_PARAM; + } + + AP_DMA_CH_CFG(ch)->CTL_H = DMA_DMACCxControl_TransferSize(cfg->transf_size); + subWriteReg(&(AP_DMA_CH_CFG(ch)->CFG_H),15,7,transf_per); + AP_DMA_CH_CFG(ch)->CFG = 0; + cctrl = DMA_DMACCxConfig_TransferType(transf_type)| \ + DMA_DMACCxControl_SMSize(cfg->src_msize)| \ + DMA_DMACCxControl_DMSize(cfg->dst_msize)| \ + DMA_DMACCxControl_SWidth(cfg->src_tr_width)| \ + DMA_DMACCxControl_DWidth(cfg->dst_tr_width)| \ + DMA_DMACCxControl_SInc(cfg->sinc)| \ + DMA_DMACCxControl_DInc(cfg->dinc)| \ + DMA_DMAC_INT_E; + AP_DMA_CH_CFG(ch)->CTL = cctrl; + + if(cfg->enable_int) + { + AP_DMA_INT->MaskTfr = DMA_DMACCxConfig_E(ch) | BIT(ch); + pctx->interrupt = true; + } + else + { + AP_DMA_INT->ClearTfr = DMA_DMACIntTfrClr_Ch(ch); + AP_DMA_INT->MaskTfr = DMA_DMACCxIntMask_E(ch); + pctx->interrupt = false; + } + + return PPlus_SUCCESS; +} + +int hal_dma_start_channel(DMA_CH_t ch) +{ + DMA_CH_Ctx_t* pctx; + + if(!s_dma_ctx.init_flg) + return PPlus_ERR_NOT_REGISTED; + + pctx = &s_dma_ctx.dma_ch_ctx[ch]; + AP_DMA_MISC->ChEnReg = DMA_DMACCxConfig_E(ch) | BIT(ch); + pctx->xmit_busy = TRUE; + hal_pwrmgr_lock(MOD_DMA); + return PPlus_SUCCESS; +} + +int hal_dma_stop_channel(DMA_CH_t ch) +{ + uint32_t spif_protect = AP_SPIF->wr_protection; + uint32_t cache_bypass = AP_PCR->CACHE_BYPASS; + DMA_CH_Ctx_t* pctx; + + if(!s_dma_ctx.init_flg) + return PPlus_ERR_NOT_REGISTED; + + if(ch >= DMA_CH_NUM) + { + return PPlus_ERR_INVALID_PARAM; + } + + pctx = &s_dma_ctx.dma_ch_ctx[ch]; + + if(pctx->xmit_flash == DMA_DST_XIMT_IS_FLASH) + { + if(spif_protect) + { + AP_SPIF->wr_protection = 2; + } + + if(cache_bypass == 0) + { + AP_PCR->CACHE_BYPASS = 0; + AP_CACHE->CTRL0 = 0x01; + } + } + + // Reset the Interrupt status + AP_DMA_INT->ClearTfr = DMA_DMACIntTfrClr_Ch(ch); + // UnMask interrupt +// AP_DMA_INT->MaskTfr = DMA_DMACCxIntMask_E(ch); + AP_DMA_MISC->ChEnReg = DMA_DMACCxConfig_E(ch); + pctx->xmit_busy = FALSE; + hal_pwrmgr_unlock(MOD_DMA); + return PPlus_SUCCESS; +} + +int hal_dma_status_control(DMA_CH_t ch) +{ + DMA_CH_Ctx_t* pctx; + + if(!s_dma_ctx.init_flg) + return PPlus_ERR_NOT_REGISTED; + + if(ch >= DMA_CH_NUM) + { + return PPlus_ERR_INVALID_PARAM; + } + + pctx = &s_dma_ctx.dma_ch_ctx[ch]; + + if(pctx->interrupt == false) + hal_dma_wait_channel_complete(ch); + + return PPlus_SUCCESS; +} + +int hal_dma_wait_channel_complete(DMA_CH_t ch) +{ + uint32_t Temp = 0; + + if(!s_dma_ctx.init_flg) + return PPlus_ERR_NOT_REGISTED; + + while(1) + { + Temp ++; + + if(AP_DMA_INT->RawTfr) + { + break; + } + } + + hal_dma_stop_channel(ch); + // LOG("wait count is %d\n",Temp); + return PPlus_SUCCESS; +} + +int hal_dma_init(void) +{ + uint8_t ret; + hal_clk_gate_enable(MOD_DMA); + hal_clk_reset(MOD_DMA); + NVIC_SetPriority((IRQn_Type)DMAC_IRQn, IRQ_PRIO_HAL); + NVIC_EnableIRQ((IRQn_Type)DMAC_IRQn); + JUMP_FUNCTION(DMAC_IRQ_HANDLER) = (uint32_t)&hal_DMA_IRQHandler; + ret = hal_pwrmgr_register(MOD_DMA,NULL, dma_wakeup_handler); + + if(ret == PPlus_SUCCESS) + { + s_dma_ctx.init_flg = TRUE; + memset(&(s_dma_ctx.dma_ch_ctx[0]), 0, sizeof(DMA_CH_Ctx_t)*DMA_CH_NUM); + //dmac controller enable + AP_DMA_MISC->DmaCfgReg = DMA_DMAC_E; + } + + return ret; +} + +int hal_dma_deinit(void) +{ + //dmac controller disable + AP_DMA_MISC->DmaCfgReg = DMA_DMAC_D; + s_dma_ctx.init_flg = FALSE; + memset(&(s_dma_ctx.dma_ch_ctx[0]), 0, sizeof(DMA_CH_Ctx_t)*DMA_CH_NUM); + hal_pwrmgr_unregister(MOD_DMA); + hal_clk_gate_disable(MOD_DMA); + return PPlus_SUCCESS; +} + +void __attribute__((used)) hal_DMA_IRQHandler(void) +{ + DMA_CH_t ch; + + for(ch = DMA_CH_0; ch < DMA_CH_NUM; ch++) + { + if(AP_DMA_INT->StatusTfr & BIT(ch)) + { + hal_dma_stop_channel(ch); + + if(s_dma_ctx.dma_ch_ctx[ch].evt_handler != NULL) + { + s_dma_ctx.dma_ch_ctx[ch].evt_handler(ch); + } + } + } +} + + + + diff --git a/src/components/driver/dma/dma.h b/src/components/driver/dma/dma.h new file mode 100644 index 0000000..485fae7 --- /dev/null +++ b/src/components/driver/dma/dma.h @@ -0,0 +1,367 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +/* Peripheral group ----------------------------------------------------------- */ +/** @defgroup GPDMA GPDMA (General Purpose Direct Memory Access) + @ingroup LPC177x_8xCMSIS_FwLib_Drivers + @{ +*/ + +#ifndef __DMA_H_ +#define __DMA_H_ + +/* Includes ------------------------------------------------------------------- */ +#include "bus_dev.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Public Macros -------------------------------------------------------------- */ +/** @defgroup GPDMA_Public_Macros GPDMA Public Macros + @{ +*/ + +/** DMAC Connection number definitions */ +typedef enum +{ + DMA_CONN_MEM=0,// ((0)) /*memory*/ + DMA_CONN_SPI0_Tx=1,// ((0UL)) /** SSP0 Tx */ + DMA_CONN_SPI0_Rx,// ((1UL)) /** SSP0 Rx */ + DMA_CONN_SPI1_Tx,// ((2UL)) /** SSP1 Tx */ + DMA_CONN_SPI1_Rx,// ((3UL)) /** SSP1 Rx */ + + DMA_CONN_I2C0_Tx=9,// ((8UL)) /** IIC0 Tx */ + DMA_CONN_I2C0_Rx,// ((9UL)) /** IIC0 Rx */ + DMA_CONN_I2C1_Tx,// ((10UL)) /** IIC1 Tx */ + DMA_CONN_I2C1_Rx,// ((11UL)) /** IIC1 Rx */ + + DMA_CONN_UART0_Tx,// ((10UL)) /** UART0 Tx */ + DMA_CONN_UART0_Rx,// ((11UL)) /** UART0 Rx */ + DMA_CONN_UART1_Tx,// ((12UL)) /** UART1 Tx */ + DMA_CONN_UART1_Rx,// ((13UL)) /** UART1 Rx */ +} DMA_CONN_e; + + +/** Burst size in Source and Destination definitions */ +#define DMA_BSIZE_1 ((0UL)) /**< Burst size = 1 */ +#define DMA_BSIZE_4 ((1UL)) /**< Burst size = 4 */ +#define DMA_BSIZE_8 ((2UL)) /**< Burst size = 8 */ +#define DMA_BSIZE_16 ((3UL)) /**< Burst size = 16 */ +#define DMA_BSIZE_32 ((4UL)) /**< Burst size = 32 */ +#define DMA_BSIZE_64 ((5UL)) /**< Burst size = 64 */ +#define DMA_BSIZE_128 ((6UL)) /**< Burst size = 128 */ +#define DMA_BSIZE_256 ((7UL)) /**< Burst size = 256 */ + +/** Width in Source transfer width and Destination transfer width definitions */ +#define DMA_WIDTH_BYTE ((0UL)) /**< Width = 1 byte */ +#define DMA_WIDTH_HALFWORD ((1UL)) /**< Width = 2 bytes */ +#define DMA_WIDTH_WORD ((2UL)) /**< Width = 4 bytes */ +#define DMA_WIDTH_2WORD ((3UL)) /**< Width = 8 bytes */ +#define DMA_WIDTH_4WORD ((4UL)) /**< Width = 16 bytes */ +#define DMA_WIDTH_8WORD ((5UL)) /**< Width = 32 bytes */ + + + + +/** DMAC Address Increment definitions */ +#define DMA_INC_INC ((0UL)) /**< Increment */ +#define DMA_INC_DEC ((1UL)) /**< Decrement */ +#define DMA_INC_NCHG ((2UL)) /**< No change */ + + +/** + @} +*/ + + +/* Private Macros ------------------------------------------------------------- */ +/** @defgroup GPDMA_Private_Macros GPDMA Private Macros + @{ +*/ + +/* --------------------- BIT DEFINITIONS -------------------------------------- */ +/*********************************************************************//** + Macro defines for DMA Interrupt Status register + **********************************************************************/ +#define DMA_DMACIntStat_Ch(n) (((1UL< +#include "types.h" +#include "flash.h" +#include "log.h" +#include "pwrmgr.h" +#include "error.h" + +#define SPIF_WAIT_IDLE_CYC (32) + +#define SPIF_STATUS_WAIT_IDLE(n) \ + do \ + { \ + while((AP_SPIF->fcmd &0x02)==0x02); \ + { \ + volatile int delay_cycle = n; \ + while (delay_cycle--){;} \ + } \ + while ((AP_SPIF->config & 0x80000000) == 0);\ + } while (0); + + +#define HAL_CACHE_ENTER_BYPASS_SECTION() do{ \ + HAL_ENTER_CRITICAL_SECTION();\ + AP_CACHE->CTRL0 = 0x02; \ + AP_PCR->CACHE_RST = 0x02;\ + AP_PCR->CACHE_BYPASS = 1; \ + HAL_EXIT_CRITICAL_SECTION();\ + }while(0); + + +#define HAL_CACHE_EXIT_BYPASS_SECTION() do{ \ + HAL_ENTER_CRITICAL_SECTION();\ + AP_CACHE->CTRL0 = 0x00;\ + AP_PCR->CACHE_RST = 0x03;\ + AP_PCR->CACHE_BYPASS = 0;\ + HAL_EXIT_CRITICAL_SECTION();\ + }while(0); + +#define spif_wait_nobusy(flg, tout_ns, return_val) {if(_spif_wait_nobusy_x(flg, tout_ns)){if(return_val){ return return_val;}}} + +static xflash_Ctx_t s_xflashCtx = {.spif_ref_clk=SYS_CLK_DLL_64M,.rd_instr=XFRD_FCMD_READ_DUAL}; + +chipMAddr_t g_chipMAddr; + +__ATTR_SECTION_SRAM__ static inline uint32_t spif_lock() +{ + HAL_ENTER_CRITICAL_SECTION(); + uint32_t vic_iser = NVIC->ISER[0]; + //mask all irq + NVIC->ICER[0] = 0xFFFFFFFF; + //enable ll irq and tim1 irq + NVIC->ISER[0] = 0x100010; + HAL_EXIT_CRITICAL_SECTION(); + return vic_iser; +} + +__ATTR_SECTION_SRAM__ static inline void spif_unlock(uint32_t vic_iser) +{ + HAL_ENTER_CRITICAL_SECTION(); + NVIC->ISER[0] = vic_iser; + HAL_EXIT_CRITICAL_SECTION(); +} + +static void hal_cache_tag_flush(void) +{ + HAL_ENTER_CRITICAL_SECTION(); + uint32_t cb = AP_PCR->CACHE_BYPASS; + volatile int dly = 8; + + if(cb==0) + { + AP_PCR->CACHE_BYPASS = 1; + } + + AP_CACHE->CTRL0 = 0x02; + + while (dly--) {;}; + + AP_CACHE->CTRL0 = 0x03; + + dly = 8; + + while (dly--) {;}; + + AP_CACHE->CTRL0 = 0x00; + + if(cb==0) + { + AP_PCR->CACHE_BYPASS = 0; + } + + HAL_EXIT_CRITICAL_SECTION(); +} + + +static uint8_t _spif_read_status_reg_x(void) +{ + uint8_t status; + spif_cmd(FCMD_RDST, 0, 2, 0, 0, 0); + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_rddata(&status, 1); + return status; +} + +static int _spif_wait_nobusy_x(uint8_t flg, uint32_t tout_ns) +{ + uint8_t status; + volatile int tout = (int )(tout_ns); + + for(; tout ; tout --) + { + status = _spif_read_status_reg_x(); + + if((status & flg) == 0) + return PPlus_SUCCESS; + + //insert polling interval + //5*32us + WaitRTCCount(5); + } + + return PPlus_ERR_BUSY; +} + +static void hal_cache_init(void) +{ + volatile int dly=100; + //clock gate + hal_clk_gate_enable(MOD_HCLK_CACHE); + hal_clk_gate_enable(MOD_PCLK_CACHE); + //cache rst ahp + AP_PCR->CACHE_RST=0x02; + + while(dly--) {}; + + AP_PCR->CACHE_RST=0x03; + + hal_cache_tag_flush(); + + //cache enable + AP_PCR->CACHE_BYPASS = 0; +} + +FLASH_CHIP_INFO phy_flash = +{ + .init_flag = FALSE, + .IdentificationID = 0x00, + .Capacity = 0x80000, +}; + + +int hal_get_flash_info(void) +{ + uint32_t cs; + uint8_t data[17]; + + if(phy_flash.init_flag == TRUE) + { + return PPlus_SUCCESS; + } + + cs = spif_lock(); + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + spif_cmd(FCMD_RDID, 0, 3, 0, 0, 0); + spif_rddata(data, 3); + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + spif_unlock(cs); + phy_flash.IdentificationID = (data[2]<<16) | (data[1]<<8) | data[0]; + + if((data[2] >= 0x11) && (data[2] <= 0x16))//most use:256K~2M.reserved:128K,4M + { + phy_flash.Capacity = (1ul << data[2]); + *(volatile int*)0x1fff0898 = phy_flash.Capacity; + } + else + { + phy_flash.Capacity = 512*1024; + *(volatile int*)0x1fff0898 = phy_flash.Capacity; + } + + phy_flash.init_flag = TRUE; + return PPlus_SUCCESS; +} + +#if(FLASH_PROTECT_FEATURE == 1) +int hal_flash_lock(void) +{ + uint32_t cs = spif_lock(); + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + AP_SPIF->fcmd = 0x6000001; + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + AP_SPIF->fcmd_wrdata[0] = 0x7c; + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + AP_SPIF->fcmd = 0x1008001; + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + spif_unlock(cs); + return PPlus_SUCCESS; +} + +int hal_flash_unlock(void) +{ + uint32_t cs = spif_lock(); + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + AP_SPIF->fcmd = 0x6000001; + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + AP_SPIF->fcmd_wrdata[0] = 0x00; + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + AP_SPIF->fcmd = 0x1008001; + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + spif_unlock(cs); + return PPlus_SUCCESS; +} + +uint8_t hal_flash_get_lock_state(void) +{ + uint32_t cs = spif_lock(); + uint8_t status; + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + status = _spif_read_status_reg_x(); + status = (status & 0x7c)>>2; + spif_unlock(cs); + return status; +} +#endif + +static void hw_spif_cache_config(void) +{ + spif_config(s_xflashCtx.spif_ref_clk,/*div*/1,s_xflashCtx.rd_instr,0,0); + AP_SPIF->wr_completion_ctrl=0xff010005;//set longest polling interval + NVIC_DisableIRQ(SPIF_IRQn); + NVIC_SetPriority((IRQn_Type)SPIF_IRQn, IRQ_PRIO_HAL); + hal_cache_init(); + hal_get_flash_info(); +} + +int hal_spif_cache_init(xflash_Ctx_t cfg) +{ + memset(&(s_xflashCtx), 0, sizeof(s_xflashCtx)); + memcpy(&(s_xflashCtx), &cfg, sizeof(s_xflashCtx)); + hw_spif_cache_config(); + hal_pwrmgr_register(MOD_SPIF, NULL, hw_spif_cache_config); + return PPlus_SUCCESS; +} + + +int hal_flash_read(uint32_t addr, uint8_t* data, uint32_t size) +{ + uint32_t cs = spif_lock(); + volatile uint8_t* u8_spif_addr = (volatile uint8_t*)((addr & 0x7ffff) | FLASH_BASE_ADDR); + uint32_t cb = AP_PCR->CACHE_BYPASS; + uint32_t remap; + + if(phy_flash.Capacity > 0x80000) + { + remap = addr & 0xf80000; + + if (remap) + { + AP_SPIF->remap = remap; + AP_SPIF->config |= 0x10000; + } + } + + //read flash addr direct access + //bypass cache + if(cb == 0) + { + HAL_CACHE_ENTER_BYPASS_SECTION(); + } + + for(int i=0; i 0x80000) + { + if (remap) + { + AP_SPIF->remap = 0; + AP_SPIF->config &= ~0x10000ul; + } + } + + spif_unlock(cs); + return PPlus_SUCCESS; +} + +int hal_flash_write(uint32_t addr, uint8_t* data, uint32_t size) +{ + uint8_t retval; + #if(FLASH_PROTECT_FEATURE == 1) + hal_flash_unlock(); + #endif + uint32_t cs = spif_lock(); + HAL_CACHE_ENTER_BYPASS_SECTION(); + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + retval = spif_write(addr,data,size); + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + HAL_CACHE_EXIT_BYPASS_SECTION(); + spif_unlock(cs); + #if(FLASH_PROTECT_FEATURE == 1) + hal_flash_lock(); + #endif + return retval; +} + +int hal_flash_write_by_dma(uint32_t addr, uint8_t* data, uint32_t size) +{ + uint8_t retval; + #if(FLASH_PROTECT_FEATURE == 1) + hal_flash_unlock(); + #endif + uint32_t cs = spif_lock(); + HAL_CACHE_ENTER_BYPASS_SECTION(); + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + retval = spif_write_dma(addr,data,size); + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + HAL_CACHE_EXIT_BYPASS_SECTION(); + spif_unlock(cs); + #if(FLASH_PROTECT_FEATURE == 1) + hal_flash_lock(); + #endif + return retval; +} + +int hal_flash_erase_sector(unsigned int addr) +{ + uint8_t retval; + #if(FLASH_PROTECT_FEATURE == 1) + hal_flash_unlock(); + #endif + uint32_t cs = spif_lock(); + uint32_t cb = AP_PCR->CACHE_BYPASS; + HAL_CACHE_ENTER_BYPASS_SECTION(); + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + retval = spif_erase_sector(addr); + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WELWIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + HAL_CACHE_EXIT_BYPASS_SECTION(); + + if(cb == 0) + { + hal_cache_tag_flush(); + } + + spif_unlock(cs); + #if(FLASH_PROTECT_FEATURE == 1) + hal_flash_lock(); + #endif + return retval; +} + +int hal_flash_erase_block64(unsigned int addr) +{ + uint8_t retval; + #if(FLASH_PROTECT_FEATURE == 1) + hal_flash_unlock(); + #endif + uint32_t cs = spif_lock(); + uint32_t cb = AP_PCR->CACHE_BYPASS; + HAL_CACHE_ENTER_BYPASS_SECTION(); + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + retval = spif_erase_block64(addr); + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WELWIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + HAL_CACHE_EXIT_BYPASS_SECTION(); + + if(cb == 0) + { + hal_cache_tag_flush(); + } + + spif_unlock(cs); + #if(FLASH_PROTECT_FEATURE == 1) + hal_flash_lock(); + #endif + return retval; +} + +int hal_flash_erase_all(void) +{ + uint8_t retval; + #if(FLASH_PROTECT_FEATURE == 1) + hal_flash_unlock(); + #endif + uint32_t cs = spif_lock(); + uint32_t cb = AP_PCR->CACHE_BYPASS; + HAL_CACHE_ENTER_BYPASS_SECTION(); + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + retval = spif_erase_all(); + SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC); + spif_wait_nobusy(SFLG_WELWIP, SPIF_TIMEOUT, PPlus_ERR_BUSY); + HAL_CACHE_EXIT_BYPASS_SECTION(); + + if(cb == 0) + { + hal_cache_tag_flush(); + } + + spif_unlock(cs); + #if(FLASH_PROTECT_FEATURE == 1) + hal_flash_lock(); + #endif + return retval; +} + +int flash_write_word(unsigned int offset, uint32_t value) +{ + uint32_t temp = value; + offset &= 0x00ffffff; + return (hal_flash_write (offset, (uint8_t*) &temp, 4)); +} + + +CHIP_ID_STATUS_e read_chip_mAddr(void) +{ + CHIP_ID_STATUS_e ret = CHIP_ID_UNCHECK; + uint8_t b; + for(int i=0;i0 && ret==CHIP_ID_EMPTY) + { + ret =CHIP_ID_INVALID; + } + + return ret; + } + } + + return ret; +} + +void check_chip_mAddr(void) +{ + //chip id check + for(int i=0;iintmask),pin,pin,1); + subWriteReg(&(AP_GPIO->inten),pin,pin,0); + return PPlus_SUCCESS; +} + +void hal_gpio_write(gpio_pin_e pin, uint8_t en) +{ +// hal_gpio_pin_init(pin,GPIO_OUTPUT); + if(en) + AP_GPIO->swporta_dr |= BIT(pin); + else + AP_GPIO->swporta_dr &= ~BIT(pin); + + hal_gpio_pin_init(pin,GPIO_OUTPUT); +} + +void hal_gpio_fast_write(gpio_pin_e pin, uint8_t en) +{ + if(en) + AP_GPIO->swporta_dr |= BIT(pin); + else + AP_GPIO->swporta_dr &= ~BIT(pin); +} + +bool hal_gpio_read(gpio_pin_e pin) +{ + uint32_t r; + + if(AP_GPIO->swporta_ddr & BIT(pin)) + r = AP_GPIO->swporta_dr; + else + r = AP_GPIO->ext_porta; + + return (int)((r>> pin) &1); +} + +void hal_gpio_fmux(gpio_pin_e pin, bit_action_e value) +{ + if(value) + { +// if((pin == P2) || (pin == P3)) +// hal_gpio_pin2pin3_control(pin,1); + AP_IOMUX->full_mux0_en |= BIT(pin); + } + else + AP_IOMUX->full_mux0_en &= ~BIT(pin); +} + +void hal_gpio_fmux_set(gpio_pin_e pin,gpio_fmux_e type) +{ + uint8_t h = 0,l = 0; + uint32_t reg_index; + uint32_t bit_index; + + if(pin != GPIO_DUMMY) + { + reg_index = pin / 4; + bit_index = pin % 4; + l = 8 * bit_index; + h = l + 5; + subWriteReg(&(AP_IOMUX->gpio_sel[reg_index]),h,l,type); + hal_gpio_fmux(pin, Bit_ENABLE); + } +} + +int hal_gpio_pin_init(gpio_pin_e pin,gpio_dir_t type) +{ + if((type == GPIO_INPUT)&&(m_gpioCtx.pin_assignments[pin] == GPIO_PIN_ASSI_OUT)) + { + return PPlus_ERR_INVALID_STATE; + } + + hal_gpio_fmux(pin,Bit_DISABLE); + + if((pin == P2) || (pin == P3)) + hal_gpio_pin2pin3_control(pin,1); + + hal_gpio_cfg_analog_io(pin,Bit_DISABLE); + + if(type == GPIO_OUTPUT) + { + AP_GPIO->swporta_ddr |= BIT(pin); + //m_gpioCtx.pin_assignments[pin] = GPIO_PIN_ASSI_OUT; + } + else + { + AP_GPIO->swporta_ddr &= ~BIT(pin); + m_gpioCtx.pin_assignments[pin] = GPIO_PIN_ASSI_IN; + } + + return PPlus_SUCCESS; +} + +static void hal_gpio_wakeup_control(gpio_pin_e pin, bit_action_e value) +{ + if(pin < P32) + { + if (value) + AP_AON->REG_S9 |= BIT(c_gpio_index[pin]); + else + AP_AON->REG_S9 &= ~BIT(c_gpio_index[pin]); + } + else + { + if (value) + AP_AON->REG_S10 |= BIT(c_gpio_index[pin] - 32); + else + AP_AON->REG_S10 &= ~BIT(c_gpio_index[pin] - 32); + } +} + +void hal_gpio_ds_control(gpio_pin_e pin, bit_action_e value) +{ + if(value) + AP_IOMUX->pad_ps0 |= BIT(pin); + else + AP_IOMUX->pad_ps0 &= ~BIT(pin); +} + +int hal_gpioretention_unregister(gpio_pin_e pin) +{ + if(m_gpioCtx.pin_assignments[pin] == GPIO_PIN_ASSI_IN) + return PPlus_ERR_INVALID_PARAM; + + m_gpioCtx.pin_assignments[pin] = GPIO_PIN_ASSI_NONE; + hal_gpio_pin_init(pin,GPIO_INPUT); + return PPlus_SUCCESS; +} + + +int hal_gpioin_unregister(gpio_pin_e pin) +{ + gpioin_Ctx_t* p_irq_ctx = &(m_gpioCtx.irq_ctx[0]); + + if (pin > (NUMBER_OF_PINS - 1)) + return PPlus_ERR_NOT_SUPPORTED; + + hal_gpioin_disable(pin); + p_irq_ctx[pin].negedgeHdl = NULL; + p_irq_ctx[pin].posedgeHdl = NULL; + return PPlus_SUCCESS; +} + +int hal_gpio_cfg_analog_io(gpio_pin_e pin, bit_action_e value) +{ + if((pin < P11) || (pin > P25)) + return PPlus_ERR_INVALID_PARAM; + + if(value) + { + hal_gpio_pull_set(pin,GPIO_FLOATING); + AP_IOMUX->Analog_IO_en |= BIT(pin - P11); + } + else + { + AP_IOMUX->Analog_IO_en &= ~BIT(pin - P11); + } + + return PPlus_SUCCESS; +} + + +void hal_gpio_pull_set(gpio_pin_e pin, gpio_pupd_e type) +{ + uint8_t i = c_gpio_pull[pin].reg_i; + uint8_t h = c_gpio_pull[pin].bit_h; + uint8_t l = c_gpio_pull[pin].bit_l; + + if(pin < P31) + subWriteReg(&(AP_AON->IOCTL[i]),h,l,type); + else + subWriteReg(&(AP_AON->PMCTL0),h,l,type); +} + +void hal_gpio_wakeup_set(gpio_pin_e pin, gpio_polarity_e type) +{ + uint8_t i = c_gpio_pull[pin].reg_i; + uint8_t p = c_gpio_pull[pin].bit_l-1; + + if (m_gpioCtx.pin_assignments[pin] != GPIO_PIN_ASSI_IN) + return; + + AP_GPIO->inttype_level |= BIT(pin);//edge sensitive + + if(pin < P31) + { + if(POL_FALLING == type) + AP_AON->IOCTL[i] |= BIT(p); + else + AP_AON->IOCTL[i] &= ~BIT(p); + } + else + { + if(POL_FALLING == type) + AP_AON->PMCTL0 |= BIT(p); + else + AP_AON->PMCTL0 &= ~BIT(p); + } + + hal_gpio_wakeup_control(pin,Bit_ENABLE);//enable wakeup function +} + +void hal_gpio_pin2pin3_control(gpio_pin_e pin, uint8_t en)//0:sw,1:other func +{ + if(en) + AP_IOMUX->gpio_pad_en |= BIT(pin-2); + else + AP_IOMUX->gpio_pad_en &= ~BIT(pin-2); +} + + +static void hal_gpio_retention_enable(gpio_pin_e pin,uint8_t en) +{ + if(en) + { + if((pin == P32)||(pin == P33)||(pin == P34)) + { + AP_AON->PMCTL0 |= BIT(retention_reg[pin][1]); + } + else + { + AP_AON->IOCTL[retention_reg[pin][0]] |= BIT(retention_reg[pin][1]); + } + } + else + { + if((pin == P32)||(pin == P33)||(pin == P34)) + { + AP_AON->PMCTL0 &= ~BIT(retention_reg[pin][1]); + } + else + { + AP_AON->IOCTL[retention_reg[pin][0]] &= ~BIT(retention_reg[pin][1]); + } + } +} + +int hal_gpioin_disable(gpio_pin_e pin) +{ + gpioin_Ctx_t* p_irq_ctx = &(m_gpioCtx.irq_ctx[0]); + + if (pin > (NUMBER_OF_PINS - 1)) + return PPlus_ERR_NOT_SUPPORTED; + + p_irq_ctx[pin].enable = FALSE; + m_gpioCtx.pin_assignments[pin] = GPIO_PIN_ASSI_NONE; + hal_gpio_pin_init(pin, GPIO_INPUT); + return hal_gpio_interrupt_disable(pin); +} + +static int hal_gpio_interrupt_enable(gpio_pin_e pin, gpio_polarity_e type) +{ + uint32_t gpio_tmp; + + if (pin >= NUMBER_OF_PINS) + return PPlus_ERR_NOT_SUPPORTED; + + gpio_tmp = AP_GPIO->inttype_level; + gpio_tmp |= (1 << pin); //edge sensitive + AP_GPIO->inttype_level = gpio_tmp; + gpio_tmp = AP_GPIO->intmask; + gpio_tmp &= ~(1 << pin); //unmask interrupt + AP_GPIO->intmask = gpio_tmp; + gpio_tmp = AP_GPIO->int_polarity; + + if (type == POL_RISING ) + gpio_tmp |= (1 << pin); + else + gpio_tmp &= ~(1 << pin); + + AP_GPIO->int_polarity = gpio_tmp; + gpio_tmp = AP_GPIO->inten; + gpio_tmp |= (1 << pin); //enable interrupt + AP_GPIO->inten = gpio_tmp; + return PPlus_SUCCESS; +} + +static void hal_gpioin_event_pin(gpio_pin_e pin, gpio_polarity_e type) +{ + gpioin_Ctx_t* p_irq_ctx = &(m_gpioCtx.irq_ctx[0]); + + if (p_irq_ctx[pin].posedgeHdl && (type == POL_RISING )) + { + p_irq_ctx[pin].posedgeHdl(pin,POL_RISING );//LOG("POS\n"); + } + else if (p_irq_ctx[pin].negedgeHdl && (type == POL_FALLING)) + { + p_irq_ctx[pin].negedgeHdl(pin,POL_FALLING);//LOG("NEG\n"); + } +} + +static void hal_gpioin_wakeup_trigger(gpio_pin_e pin) +{ + uint8_t pin_state = (uint8_t)hal_gpio_read(pin); + gpio_polarity_e type = pin_state ? POL_RISING : POL_FALLING; + + if (m_gpioCtx.irq_ctx[pin].pin_state != pin_state) + hal_gpioin_event_pin(pin, type); +} + +static void hal_gpioin_event(uint32 int_status, uint32 polarity) +{ + int i; + gpioin_Ctx_t* p_irq_ctx = &(m_gpioCtx.irq_ctx[0]); +// LOG("GI:%x,%x\n",int_status,polarity); + + for (i = 0; i < NUMBER_OF_PINS; i++) + { + if (int_status & (1ul << i)) + { + gpio_polarity_e type = (polarity & BIT(i)) ? POL_RISING : POL_FALLING; + hal_gpioin_event_pin((gpio_pin_e)i, type); + + //reconfig interrupt + if (p_irq_ctx[i].posedgeHdl && p_irq_ctx[i].negedgeHdl) //both raise and fall + { + type = (type == POL_RISING) ? POL_FALLING : POL_RISING ; + hal_gpio_interrupt_enable((gpio_pin_e)i, type); + } + else if (p_irq_ctx[i].posedgeHdl) //raise + { + hal_gpio_interrupt_enable((gpio_pin_e)i, POL_RISING ); + } + else if (p_irq_ctx[i].negedgeHdl) //fall + { + hal_gpio_interrupt_enable((gpio_pin_e)i, POL_FALLING); + } + } + } +} + +static void hal_gpio_sleep_handler(void) +{ + int i; + gpio_polarity_e pol; + + for (i = 0; i < NUMBER_OF_PINS; i++) + { + //config wakeup + if (m_gpioCtx.pin_assignments[i] == GPIO_PIN_ASSI_OUT) + { + hal_gpio_retention_enable((gpio_pin_e)i,Bit_ENABLE); + } + + if (m_gpioCtx.pin_assignments[i] == GPIO_PIN_ASSI_IN) + { + pol = hal_gpio_read((gpio_pin_e)i) ? POL_FALLING : POL_RISING ; + hal_gpio_wakeup_set((gpio_pin_e)i, pol); + m_gpioCtx.irq_ctx[i].pin_state = hal_gpio_read((gpio_pin_e)i); + } + } +} + +static void hal_gpio_wakeup_handler(void) +{ + int i; + NVIC_SetPriority(GPIO_IRQn, IRQ_PRIO_HAL); + NVIC_EnableIRQ(GPIO_IRQn); + + for (i = 0; i < NUMBER_OF_PINS; i++) + { + if((i == 2) || (i == 3)) + hal_gpio_pin2pin3_control((gpio_pin_e)i,1); + + if (m_gpioCtx.pin_assignments[i] == GPIO_PIN_ASSI_OUT) + { + bool pol = hal_gpio_read((gpio_pin_e)i); + hal_gpio_write((gpio_pin_e)i,pol); + hal_gpio_retention_enable((gpio_pin_e)i,Bit_DISABLE); + } + + if (m_gpioCtx.irq_ctx[i].enable) + { + hal_gpioin_enable((gpio_pin_e)i); //resume gpio irq + hal_gpioin_wakeup_trigger((gpio_pin_e)i);//trigger gpio irq manually + } + } +} + +void __attribute__((used)) hal_GPIO_IRQHandler(void) +{ + uint32 polarity = AP_GPIO->int_polarity; + uint32 st = AP_GPIO->int_status; + AP_GPIO->porta_eoi = st;//clear interrupt + hal_gpioin_event(st, polarity); +} + +int hal_gpioin_enable(gpio_pin_e pin) +{ + gpioin_Ctx_t* p_irq_ctx = &(m_gpioCtx.irq_ctx[0]); + gpio_polarity_e type = POL_FALLING; + uint32 pinVal = 0; + + if (p_irq_ctx[pin].posedgeHdl == NULL && p_irq_ctx[pin].negedgeHdl == NULL) + return PPlus_ERR_NOT_REGISTED; + + m_gpioCtx.pin_assignments[pin] = GPIO_PIN_ASSI_IN; + p_irq_ctx[pin].enable = TRUE; + hal_gpio_pin_init(pin, GPIO_INPUT); + + //hal_gpio_pull_set(pin, PULL_DOWN); //??need disccuss + if (p_irq_ctx[pin].posedgeHdl && p_irq_ctx[pin].negedgeHdl) //both raise and fall + { + pinVal = hal_gpio_read(pin); + type = pinVal ? POL_FALLING : POL_RISING ; + } + else if (p_irq_ctx[pin].posedgeHdl) //raise + { + type = POL_RISING ; + } + else if (p_irq_ctx[pin].negedgeHdl) //fall + { + type = POL_FALLING; + } + + hal_gpio_interrupt_enable(pin, type); + return PPlus_SUCCESS; +} + +int hal_gpioretention_register(gpio_pin_e pin) +{ + if(m_gpioCtx.pin_assignments[pin] == GPIO_PIN_ASSI_IN) + return PPlus_ERR_INVALID_PARAM; + + m_gpioCtx.pin_assignments[pin] = GPIO_PIN_ASSI_OUT; + hal_gpio_pin_init(pin,GPIO_OUTPUT); + return PPlus_SUCCESS; +} + + +int hal_gpioin_register(gpio_pin_e pin, gpioin_Hdl_t posedgeHdl, gpioin_Hdl_t negedgeHdl) +{ + int ret; + gpioin_Ctx_t* p_irq_ctx = &(m_gpioCtx.irq_ctx[0]); + hal_gpioin_disable(pin); + p_irq_ctx[pin].posedgeHdl = posedgeHdl; + p_irq_ctx[pin].negedgeHdl = negedgeHdl; + ret = hal_gpioin_enable(pin); + JUMP_FUNCTION(GPIO_IRQ_HANDLER) = (uint32_t)&hal_GPIO_IRQHandler; + + if (ret != PPlus_SUCCESS) + hal_gpioin_disable(pin); + + return ret; +} + +int hal_gpio_init(void) +{ + if (m_gpioCtx.state) + return PPlus_ERR_INVALID_STATE; + + memset(&m_gpioCtx, 0, sizeof(m_gpioCtx)); + m_gpioCtx.state = TRUE; + //disable all channel irq,unmask all channel + AP_GPIO->inten = 0; + AP_GPIO->intmask = 0; + //disable all wakeup pin + AP_WAKEUP->io_wu_mask_31_0 = 0; + AP_WAKEUP->io_wu_mask_34_32 = 0; + NVIC_SetPriority(GPIO_IRQn, IRQ_PRIO_HAL); + NVIC_EnableIRQ(GPIO_IRQn); + hal_pwrmgr_register(MOD_GPIO, hal_gpio_sleep_handler, hal_gpio_wakeup_handler); + return PPlus_SUCCESS; +} + +void hal_gpio_debug_mux(Freq_Type_e fre,bool en) +{ + if(en) + AP_IOMUX->debug_mux_en |= BIT(fre); + else + AP_IOMUX->debug_mux_en &= ~BIT(fre); +} + +void hal_gpioin_set_flag(gpio_pin_e pin) +{ + m_gpioCtx.pin_assignments[pin] = GPIO_PIN_ASSI_IN; +} diff --git a/src/components/driver/gpio/gpio.h b/src/components/driver/gpio/gpio.h new file mode 100644 index 0000000..f082995 --- /dev/null +++ b/src/components/driver/gpio/gpio.h @@ -0,0 +1,192 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file gpio.h + @brief Contains all functions support for gpio and iomux driver + @version 0.0 + @date 19. Oct. 2017 + @author qing.han + + + +*******************************************************************************/ +#ifndef __GPIO_H__ +#define __GPIO_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "bus_dev.h" +#include "error.h" + +#define NUMBER_OF_PINS 23 + +typedef enum +{ + GPIO_P00 = 0, P0 = GPIO_P00, + GPIO_P01 = 1, P1 = GPIO_P01, + GPIO_P02 = 2, P2 = GPIO_P02, + GPIO_P03 = 3, P3 = GPIO_P03, + GPIO_P07 = 4, P7 = GPIO_P07, + GPIO_P09 = 5, P9 = GPIO_P09, + GPIO_P10 = 6, P10 = GPIO_P10, + GPIO_P11 = 7, P11 = GPIO_P11, Analog_IO_0 = GPIO_P11, + GPIO_P14 = 8, P14 = GPIO_P14, Analog_IO_1 = GPIO_P14, + GPIO_P15 = 9, P15 = GPIO_P15, Analog_IO_2 = GPIO_P15, + GPIO_P16 = 10, P16 = GPIO_P16, Analog_IO_3 = GPIO_P16,XTALI = GPIO_P16, + GPIO_P17 = 11, P17 = GPIO_P17, Analog_IO_4 = GPIO_P17,XTALO = GPIO_P17, + GPIO_P18 = 12, P18 = GPIO_P18, Analog_IO_5 = GPIO_P18, + GPIO_P20 = 13, P20 = GPIO_P20, Analog_IO_6 = GPIO_P20, + GPIO_P23 = 14, P23 = GPIO_P23, Analog_IO_7 = GPIO_P23, + GPIO_P24 = 15, P24 = GPIO_P24, Analog_IO_8 = GPIO_P24, + GPIO_P25 = 16, P25 = GPIO_P25, Analog_IO_9 = GPIO_P25, + GPIO_P26 = 17, P26 = GPIO_P26, + GPIO_P27 = 18, P27 = GPIO_P27, + GPIO_P31 = 19, P31 = GPIO_P31, + GPIO_P32 = 20, P32 = GPIO_P32, + GPIO_P33 = 21, P33 = GPIO_P33, + GPIO_P34 = 22, P34 = GPIO_P34, + GPIO_NUM = 23, + GPIO_DUMMY = 0xff, +} gpio_pin_e; + +typedef enum +{ + FMUX_IIC0_SCL= 0, + FMUX_IIC0_SDA= 1, + FMUX_IIC1_SCL= 2, + FMUX_IIC1_SDA= 3, + FMUX_UART0_TX=4, FMUX_UART_TX=4, + FMUX_UART0_RX=5, FMUX_UART_RX=5, + FMUX_RF_RX_EN=6, + FMUX_RF_TX_EN=7, + FMUX_UART1_TX=8, + FMUX_UART1_RX=9, + FMUX_PWM0=10, + FMUX_PWM1=11, + FMUX_PWM2=12, + FMUX_PWM3=13, + FMUX_PWM4=14, + FMUX_PWM5=15, + FMUX_SPI_0_SCK=16, + FMUX_SPI_0_SSN=17, + FMUX_SPI_0_TX=18, + FMUX_SPI_0_RX=19, + FMUX_SPI_1_SCK=20, + FMUX_SPI_1_SSN=21, + FMUX_SPI_1_TX=22, + FMUX_SPI_1_RX=23, + FMUX_CHAX=24, + FMUX_CHBX=25, + FMUX_CHIX=26, + FMUX_CHAY=27, + FMUX_CHBY=28, + FMUX_CHIY=29, + FMUX_CHAZ=30, + FMUX_CHBZ=31, + FMUX_CHIZ=32, + FMUX_CLK1P28M=33, + FMUX_ADCC=34, + FMUX_ANT_SEL_0=35, + FMUX_ANT_SEL_1=36, + FMUX_ANT_SEL_2=37, + +} gpio_fmux_e; + +typedef enum +{ + FRE_HCLK_DIV8 = 0, + FRE_PCLK_DIV4 = 1, + FRE_CLK_1P28M = 2, + FRE_CLK_RC32K = 6, + FRE_XTAL_CLK32768 = 7, +} Freq_Type_e; + +typedef enum +{ + GPIO_INPUT = 0, + GPIO_OUTPUT = 1 +} gpio_dir_t; + +typedef enum +{ + POL_FALLING = 0, POL_ACT_LOW = 0, + POL_RISING = 1, POL_ACT_HIGH = 1 +} gpio_polarity_e; + +typedef enum +{ + Bit_DISABLE = 0, + Bit_ENABLE, +} bit_action_e; + +typedef enum +{ + GPIO_FLOATING = 0x00, //no pull + GPIO_PULL_UP_S = 0x01, //pull up strong + GPIO_PULL_UP = 0x02, //pull up weak + GPIO_PULL_DOWN = 0x03, +} gpio_pupd_e; + +typedef struct +{ + gpio_pin_e pin; + gpio_pupd_e type; +} ioinit_cfg_t; + + +#define NEGEDGE POL_FALLING +#define POSEDGE POL_RISING +#define IO_Wakeup_Pol_e gpio_polarity_e + +#define FLOATING GPIO_FLOATING +#define WEAK_PULL_UP GPIO_PULL_UP +#define STRONG_PULL_UP GPIO_PULL_UP_S +#define PULL_DOWN GPIO_PULL_DOWN +#define GPIO_Pin_e gpio_pin_e +#define OEN GPIO_OUTPUT +#define IE GPIO_INPUT +#define Fmux_Type_e gpio_fmux_e +#define GPIO_Wakeup_Pol_e gpio_polarity_e +#define BitAction_e bit_action_e +typedef void (*gpioin_Hdl_t)(gpio_pin_e pin,gpio_polarity_e type); + +void hal_gpio_write(gpio_pin_e pin, uint8_t en); +void hal_gpio_fast_write(gpio_pin_e pin, uint8_t en); +bool hal_gpio_read(gpio_pin_e pin); +void hal_gpio_fmux(gpio_pin_e pin, bit_action_e value); +void hal_gpio_fmux_set(gpio_pin_e pin,gpio_fmux_e type); + +int hal_gpio_pin_init(gpio_pin_e pin,gpio_dir_t type); +void hal_gpio_ds_control(gpio_pin_e pin, bit_action_e value); + +int hal_gpio_cfg_analog_io(gpio_pin_e pin, bit_action_e value) ; +void hal_gpio_pull_set(gpio_pin_e pin, gpio_pupd_e type) ; +void hal_gpio_wakeup_set(gpio_pin_e pin, gpio_polarity_e type); + +void hal_gpio_pin2pin3_control(gpio_pin_e pin, uint8_t en); +int hal_gpioin_disable(gpio_pin_e pin); + +void __attribute__((used)) hal_GPIO_IRQHandler(void); +int hal_gpioin_enable(gpio_pin_e pin); +int hal_gpioin_register(gpio_pin_e pin, gpioin_Hdl_t posedgeHdl, gpioin_Hdl_t negedgeHdl); +int hal_gpioretention_unregister(gpio_pin_e pin); +int hal_gpioretention_register(gpio_pin_e pin); +int hal_gpioin_unregister(gpio_pin_e pin); +int hal_gpio_init(void); +void hal_gpio_debug_mux(Freq_Type_e fre,bool en); + + +//rom api +extern int gpio_write(gpio_pin_e pin, uint8_t en); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/src/components/driver/i2c/i2c.c b/src/components/driver/i2c/i2c.c new file mode 100644 index 0000000..7a54b2f --- /dev/null +++ b/src/components/driver/i2c/i2c.c @@ -0,0 +1,443 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file i2c.c + @brief Contains all functions support for i2c driver + @version 0.0 + @date 25. Oct. 2017 + @author qing.han + + + +*******************************************************************************/ + +/******************************************************************************* + @ Module : pre-compiler + @ Description : NULL +*******************************************************************************/ +#define _I2C_CMD_ + +/******************************************************************************* + @ Module : Includes + @ Description : None +*******************************************************************************/ +#include "rom_sym_def.h" + +#include "types.h" + +#include "gpio.h" + +#include "i2c.h" + +#include "clock.h" +#include "log.h" +#include "error.h" +#include "OSAL.h" +#include "pwrmgr.h" + +#define I2C_OP_TIMEOUT 100 //100ms for an Byte operation +extern uint32_t pclk; + + +/************************************************************************************** + @fn hal_master_send_read_cmd + + @brief This function process for master send read command;It's vaild when the chip act as master + + input parameters + + @param uint8_t len: read length + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +static void hal_master_send_read_cmd(void* pi2c, uint8_t len) +{ + uint8_t i; + AP_I2C_TypeDef* pi2cdev = (AP_I2C_TypeDef*)pi2c; + + for(i=0; iIC_DATA_CMD = data; //data +} + +static void _hal_i2c_send_byte_x(void* pi2c, uint8_t data) +{ + AP_I2C_TypeDef* pi2cdev = (AP_I2C_TypeDef*)pi2c; + pi2cdev->IC_DATA_CMD = data; //data + + while(!(pi2cdev->IC_RAW_INTR_STAT&0x10)); +} + +/************************************************************************************** + @fn hal_i2c_send + + @brief This function process for send a serial(programe length) data by i2c interface + + input parameters + + @param unsigned char* str: send data(string) + uint32_t len: send length + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +int hal_i2c_send(void* pi2c, uint8_t* str,uint8_t len) +{ + uint8_t i; + AP_I2C_TypeDef* pi2cdev = (AP_I2C_TypeDef*)pi2c; + + if(pi2cdev != AP_I2C0 && pi2cdev != AP_I2C1) + { + return PPlus_ERR_INVALID_PARAM; + } + + for(i=0; iIC_INTR_STAT; + //st = pi2cdev->IC_RAW_INTR_STAT; + while(1) + { + cnt++; + + if(pi2cdev->IC_RAW_INTR_STAT&0x200)//check tx empty + break; + + I2C_CHECK_TOUT(to, I2C_OP_TIMEOUT, "hal_i2c_wait_tx_completed TO\n"); + } + + //LOG("I2c Tx empty:%x, %x\n", st0,st); + return PPlus_SUCCESS; +} + + +void* hal_i2c_init(i2c_dev_t dev, I2C_CLOCK_e i2c_clock_rate) +{ + int pclk = clk_get_pclk(); + AP_I2C_TypeDef* pi2cdev = NULL; + + if(dev == I2C_0) + { + pi2cdev = AP_I2C0; + hal_clk_gate_enable(MOD_I2C0); + } + else if(dev == I2C_1) + { + pi2cdev = AP_I2C1; + hal_clk_gate_enable(MOD_I2C1); + } + else + { + return NULL; + } + + pi2cdev->IC_ENABLE=0; + pi2cdev->IC_CON=0x61; + + if(i2c_clock_rate==I2C_CLOCK_100K) + { + pi2cdev->IC_CON= ((pi2cdev->IC_CON) & 0xfffffff9)|(0x01 << 1); + + if(pclk==16000000) + { + pi2cdev->IC_SS_SCL_HCNT=70; //16 + pi2cdev->IC_SS_SCL_LCNT=76; //32) + } + else if(pclk==32000000) + { + pi2cdev->IC_SS_SCL_HCNT=148; //16 + pi2cdev->IC_SS_SCL_LCNT=154; //32) + } + else if(pclk==48000000) + { + pi2cdev->IC_SS_SCL_HCNT=230; //16 + pi2cdev->IC_SS_SCL_LCNT=236; //32) + } + else if(pclk==64000000) + { + pi2cdev->IC_SS_SCL_HCNT=307; //16 + pi2cdev->IC_SS_SCL_LCNT=320; //32) + } + else if(pclk==96000000) + { + pi2cdev->IC_SS_SCL_HCNT=460; //16 + pi2cdev->IC_SS_SCL_LCNT=470; //32) + } + } + else if(i2c_clock_rate==I2C_CLOCK_400K) + { + pi2cdev->IC_CON= ((pi2cdev->IC_CON) & 0xfffffff9)|(0x02 << 1); + + if(pclk==16000000) + { + pi2cdev->IC_FS_SCL_HCNT=10; //16 + pi2cdev->IC_FS_SCL_LCNT=17; //32) + } + else if(pclk==32000000) + { + pi2cdev->IC_FS_SCL_HCNT=30; //16 + pi2cdev->IC_FS_SCL_LCNT=35; //32) + } + else if(pclk==48000000) + { + pi2cdev->IC_FS_SCL_HCNT=48; //16 + pi2cdev->IC_FS_SCL_LCNT=54; //32) + } + else if(pclk==64000000) + { + pi2cdev->IC_FS_SCL_HCNT=67; //16 + pi2cdev->IC_FS_SCL_LCNT=75; //32) + } + else if(pclk==96000000) + { + pi2cdev->IC_FS_SCL_HCNT=105; //16 + pi2cdev->IC_FS_SCL_LCNT=113; //32) + } + } + + pi2cdev->IC_TAR = I2C_MASTER_ADDR_DEF; + pi2cdev->IC_INTR_MASK=0; + pi2cdev->IC_RX_TL=0x0; + pi2cdev->IC_TX_TL=0x1; + pi2cdev->IC_ENABLE=1; + return (void*)pi2cdev; +} + + +int hal_i2c_deinit(void* pi2c) +{ + AP_I2C_TypeDef* pi2cdev = (AP_I2C_TypeDef*)pi2c; + + if(pi2cdev == AP_I2C0) + { + pi2cdev->IC_ENABLE=0; + hal_clk_gate_disable(MOD_I2C0); + } + else if(pi2cdev == AP_I2C1) + { + pi2cdev->IC_ENABLE=0; + hal_clk_gate_disable(MOD_I2C1); + } + else + { + return PPlus_ERR_INVALID_PARAM; + } + + return PPlus_SUCCESS; +} + + +/************************************************************************************** + @fn hal_i2c_pin_init + + @brief This function process for i2c pin initial(2 lines);You can use two i2c,i2c0 and i2c1,should programe by USE_AP_I2CX + + input parameters + + @param gpio_pin_e pin_sda: define sda_pin + gpio_pin_e pin_clk: define clk_pin + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +int hal_i2c_pin_init(i2c_dev_t dev, gpio_pin_e pin_sda, gpio_pin_e pin_clk) +{ + if(dev == I2C_0) + { + hal_gpio_fmux_set(pin_clk, FMUX_IIC0_SCL); + hal_gpio_fmux_set(pin_sda, FMUX_IIC0_SDA); + } + else if(dev == I2C_1) + { + hal_gpio_fmux_set(pin_clk, FMUX_IIC1_SCL); + hal_gpio_fmux_set(pin_sda, FMUX_IIC1_SDA); + } + else + { + return PPlus_ERR_INVALID_PARAM; + } + + hal_gpio_pull_set(pin_sda,GPIO_PULL_UP_S); + hal_gpio_pull_set(pin_clk,GPIO_PULL_UP_S); + + if(dev == I2C_0) + { + hal_clk_gate_enable(MOD_I2C0); + } + else if(dev == I2C_1) + { + hal_clk_gate_enable(MOD_I2C1); + } + + return PPlus_SUCCESS; +} + +int hal_i2c_tx_start(void* pi2c) +{ + AP_I2C_TypeDef* pi2cdev = (AP_I2C_TypeDef*)pi2c; + + if(pi2cdev != AP_I2C0 && pi2cdev != AP_I2C1) + { + return PPlus_ERR_INVALID_PARAM; + } + + pi2cdev->IC_ENABLE=1; + return PPlus_SUCCESS; +} + +/************************************************************************************** + @fn hal_i2c_addr_update + + @brief This function process for tar update + + input parameters + + @param uint8_t addr: address + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +int hal_i2c_addr_update(void* pi2c, uint8_t addr) +{ + AP_I2C_TypeDef* pi2cdev = (AP_I2C_TypeDef*)pi2c; + + if(pi2cdev != AP_I2C0 && pi2cdev != AP_I2C1) + { + return PPlus_ERR_INVALID_PARAM; + } + + pi2cdev->IC_ENABLE=0; + pi2cdev->IC_TAR = addr; + pi2cdev->IC_ENABLE=1; + return PPlus_SUCCESS; +} + + +int _hal_i2c_read_s(void* pi2c, uint8_t slave_addr, uint8_t reg, uint8_t* data, uint8_t size) +{ + I2C_INIT_TOUT(to); + AP_I2C_TypeDef* pi2cdev = (AP_I2C_TypeDef*)pi2c; + + if(pi2cdev != AP_I2C0 && pi2cdev != AP_I2C1) + { + return PPlus_ERR_INVALID_PARAM; + } + + hal_i2c_addr_update(pi2c, slave_addr); + HAL_ENTER_CRITICAL_SECTION(); + hal_i2c_tx_start(pi2c); + _hal_i2c_send_byte(pi2c, reg); + hal_master_send_read_cmd(pi2c, size); + HAL_EXIT_CRITICAL_SECTION(); + + while(1) + { + if(I2C_RX_FIFO_NOT_EMPTY(pi2cdev)) + { + *data = (pi2cdev->IC_DATA_CMD&0xff); + data++; + size --; + + if(size == 0) + break; + } + + I2C_CHECK_TOUT(to, I2C_OP_TIMEOUT*size, "I2C RD TO\n"); + } + + return PPlus_SUCCESS; +} + + + +int hal_i2c_read( + void* pi2c, + uint8_t slave_addr, + uint8_t reg, + uint8_t* data, + uint8_t size) +{ + uint8_t cnt; + int ret = PPlus_SUCCESS; + AP_I2C_TypeDef* pi2cdev = (AP_I2C_TypeDef*)pi2c; + + if(pi2cdev != AP_I2C0 && pi2cdev != AP_I2C1) + { + return PPlus_ERR_INVALID_PARAM; + } + + while(size) + { + cnt = (size >7) ? 7 : size; + size -= cnt; + ret = _hal_i2c_read_s(pi2c, slave_addr, reg, data, cnt); + + if(ret != PPlus_SUCCESS) + break; + + data += cnt; + } + + return ret; +} + + + diff --git a/src/components/driver/i2c/i2c.h b/src/components/driver/i2c/i2c.h new file mode 100644 index 0000000..16e4f1a --- /dev/null +++ b/src/components/driver/i2c/i2c.h @@ -0,0 +1,192 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file i2c.h + @brief Contains all functions support for i2c driver + @version 0.0 + @date 25. Oct. 2017 + @author qing.han + + + +*******************************************************************************/ +#ifndef __I2C__H__ +#define __I2C__H__ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/******************************************************************************* + @ Module : pre-compile + @ Description : NULL +*******************************************************************************/ +#ifdef _I2C_CMD_ +#define I2C_Ext +#else +#define I2C_Ext extern +#endif + +/******************************************************************************* + @ Module : Includes + @ Description : None +*******************************************************************************/ +#include "types.h" +#include "bus_dev.h" +#include "gpio.h" +#include "clock.h" + +#define I2C_USE_TIMEOUT 1 +#if(I2C_USE_TIMEOUT == 1) +#define I2C_INIT_TOUT(to) int to = hal_systick() +#define I2C_CHECK_TOUT(to, timeout, loginfo) {if(hal_ms_intv(to) > timeout){LOG(loginfo);return PPlus_ERR_TIMEOUT;}} +#else +#define I2C_INIT_TOUT(to) +#define I2C_CHECK_TOUT(to, timeout, loginfo) +#endif + + +/******************************************************************************* + @ Module : Macro Define + @ Description : None +*******************************************************************************/ +typedef enum +{ + I2C_0 =0, //define master mode,1:master mode,0:salve mode + I2C_1 =1 //define master mode,1:master mode,0:salve mode +} i2c_dev_t; + +/******************************************************************************* + @ Module : Macro Define + @ Description : I2C_SLAVE_ADDR_DEF ---- as slave mode + I2C_MASTER_ADDR_DEF --- as master mode addressing device +*******************************************************************************/ +#define I2C_SLAVE_ADDR_DEF 0x10 +#define I2C_MASTER_ADDR_DEF I2C_SLAVE_ADDR_DEF + +/******************************************************************************* + @ Module : I2C Buffer Length + @ Description : relate to RX FIFO & TX FIFO +*******************************************************************************/ +#define I2C_FIFO_DEPTH 8 +#define I2C_RX_TL_CNT I2C_FIFO_DEPTH +#define I2C_TX_TL_CNT I2C_FIFO_DEPTH + +/******************************************************************************* + @ Module : Macro Define + @ Description : Which IIC To be used +*******************************************************************************/ +#define USE_AP_I2CX I2C0 //define use i2c0 or i2c1,0:i2c0,1:i2c1 + +/******************************************************************************* + @ Module : Macro Define + @ Description : None +*******************************************************************************/ +#define I2C0_IRQ_ENABLE() *(volatile unsigned int *) 0xe000e100 |= BIT(12) +#define I2C0_IRQ_DISABLE() *(volatile unsigned int *) 0xe000e100 &= ~BIT(12) +#define I2C1_IRQ_ENABLE() *(volatile unsigned int *) 0xe000e100 |= BIT(13) +#define I2C1_IRQ_DISABLE() *(volatile unsigned int *) 0xe000e100 &= ~BIT(13) +#define I2C_READ_CMD(pi2cdev) (pi2cdev->IC_DATA_CMD = 0x100) //Read +#define I2C_RX_FIFO_FULL(pi2cdev) ((pi2cdev->IC_STATUS & 0x10)==0x10) +#define I2C_RX_FIFO_NOT_EMPTY(pi2cdev) ((pi2cdev->IC_STATUS & 0x08)==0x08) +#define I2C_TX_FIFO_EMPTY(pi2cdev) ((pi2cdev->IC_STATUS & 0x04)==0x04) +#define I2C_TX_FIFO_NOT_FULL(pi2cdev) ((pi2cdev->IC_STATUS & 0x02)==0x02) +#define I2C_WAIT_RD_REQ(pi2cdev) !((pi2cdev->IC_RAW_INTR_STAT & 0x20)==0x20) +#define I2C_RD_REQ(pi2cdev) ((pi2cdev->IC_RAW_INTR_STAT & 0x20)==0x20) +#define I2C_NUMBER_DATA_RX_FIFO(pi2cdev) (pi2cdev->IC_RXFLR) +#define I2C_NUMBER_DATA_TX_FIFO(pi2cdev) (pi2cdev->IC_TXFLR) +#define I2C_CLR_RD_REQ(pi2cdev) (pi2cdev->IC_CLR_RD_REG) +#define I2C_CLR_TX_ABRT(pi2cdev) (pi2cdev->IC_CLR_TX_ABRT) +#define I2C_ENABLE(pi2cdev) (pi2cdev->IC_ENABLE=1) +#define I2C_DISABLE(pi2cdev) (pi2cdev->IC_ENABLE=0) + +/******************************************************************************* + @ Module : I2C Interrupt Mask Register + @ Description : Interrupt MASK bit +*******************************************************************************/ +#define I2C_MASK_RX_UNDER 0x0001 +#define I2C_MASK_RX_OVER 0x0002 +#define I2C_MASK_RX_FULL 0x0004 +#define I2C_MASK_TX_OVER 0x0008 +#define I2C_MASK_TX_EMPTY 0x0010 +#define I2C_MASK_RD_REQ 0x0020 +#define I2C_MASK_TX_ABRT 0x0040 +#define I2C_MASK_RX_DONE 0x0080 +#define I2C_MASK_ACTIVITY 0x0100 +#define I2C_MASK_STOP_DET 0x0200 +#define I2C_MASK_START_DET 0x0400 +#define I2C_MASK_GEN_CALL 0x0800 + +/******************************************************************************* + @ Module : I2C Status Register + @ Description : Status Register BIT(Indicate transfer and FIFO Status) +*******************************************************************************/ +#define I2C_STATUS_ACTIVITY 0x0001 +#define I2C_STATUS_TFNF 0x0002 +#define I2C_STATUS_TFE 0x0004 +#define I2C_STATUS_RFNE 0x0008 +#define I2C_STATUS_RFF 0x0010 +#define I2C_STATUS_MST_ACTIVITY 0x0020 +#define I2C_STATUS_SLV_ACTIVITY 0x0040 + +#define I2C0_IRQ I2C0_IRQn +#define I2C1_IRQ I2C1_IRQn +/******************************************************************************* + @ Module : IIC Speed Mode + @ Description : None +*******************************************************************************/ +typedef enum +{ + SPEED_STANDARD = 1, //standard mode + SPEED_FAST, //fast mode +// SPEED_HIGH //high mode +} I2C_SPEED_e; + +/******************************************************************************* + @ Module : IIC Clock + @ Description : None +*******************************************************************************/ +typedef enum +{ + I2C_CLOCK_100K = 0x00, + I2C_CLOCK_400K, +} I2C_CLOCK_e; + +typedef struct _I2C_Evt_t +{ + uint16_t type; + uint8_t* data; + uint8_t len; +} I2C_Evt_t; + +typedef enum +{ + I2C_TX_STATE_UNINIT = 0, + I2C_TX_STATE_IDLE, + I2C_TX_STATE_TX, + I2C_TX_STATE_ERR +} I2C_STATE; + +/******************************************************************************* + @ Module : Function declaration + @ Description : None +*******************************************************************************/ +int hal_i2c_send(void* pi2c, uint8_t* str,uint8_t len); +void* hal_i2c_init(i2c_dev_t dev, I2C_CLOCK_e i2c_clock_rate); +int hal_i2c_deinit(void* pi2c); +int hal_i2c_pin_init(i2c_dev_t dev, gpio_pin_e pin_sda, gpio_pin_e pin_clk); +int hal_i2c_addr_update(void* pi2c, uint8_t addr); +int hal_i2c_wait_tx_completed(void* pi2c); +int hal_i2c_tx_start(void* pi2c); +int hal_i2c_read(void* pi2c,uint8_t slave_addr,uint8_t reg,uint8_t* data,uint8_t size); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/src/components/driver/i2c/i2c_common.c b/src/components/driver/i2c/i2c_common.c new file mode 100644 index 0000000..ae76c83 --- /dev/null +++ b/src/components/driver/i2c/i2c_common.c @@ -0,0 +1,298 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file i2c_comman.c + @brief i2c general Function + @version 1.0 + + +*******************************************************************************/ + +/******************************************************************************* + @ Module : Pre-Define + @ Description : None +*******************************************************************************/ +#define _I2C_Common_ + +/******************************************************************************* + @ Module : Includes + @ Description : None +*******************************************************************************/ +#include "i2c_common.h" +#include "error.h" +#include "log.h" + +/******************************************************************************* + @ Module : Macro Define + @ Description : None +*******************************************************************************/ +#define CONCAT_2(p1,p2) p1##p2 +#define CONCAT_3(p1,p2,p3) p1##p2##p3 +#define DRV_IIC_INSTANCE(id) CONCAT_2(AP_I2C,id) +#define DRV_GET_IIC_MOD_ID(id) CONCAT_2(MOD_I2C,id) +#define DRV_GET_IIC_IRQ_ID(id) CONCAT_3(I2C,id,_IRQ) + +/******************************************************************************* + @ Module : Typedef struct + @ Description : I2C Module +*******************************************************************************/ +typedef struct +{ + uint8_t busy; // busy +} I2C_Mode_t; + + +/******************************************************************************* + @ Module : Internal Variable + @ Description : None +*******************************************************************************/ +static I2C_Mode_t I2C_Mode[IIC_COUNT]; + +/******************************************************************************* + @ Module : I2C IRQ Handler + @ Description : None +*******************************************************************************/ +I2C_Hdl_t I2C0_IRQ_Handle = NULL; +I2C_Hdl_t I2C1_IRQ_Handle = NULL; + +/******************************************************************************* + @ Module : IIC Slave Address pre-Declare + @ Description : address , which can not be used +*******************************************************************************/ +const unsigned char I2C_INVALID_SLAVE_ADDR[I2C_NOT_USED_SLAVE_ADDRLEN] = {0x00,0x07,0x78,0x7f}; + + +/******************************************************************************* + @ Module : Get_IIC_Instance + @ Description : None +*******************************************************************************/ +AP_I2C_TypeDef* Hal_Get_IIC_Instance(uint8_t id) +{ + if(IIC_Module0 == id) + return (((AP_I2C_TypeDef*)DRV_IIC_INSTANCE(IIC_Module0))); + else + return (((AP_I2C_TypeDef*)DRV_IIC_INSTANCE(IIC_Module1))); +} + +/******************************************************************************* + @ Module : Hal_GetIIC_ModuleID + @ Description : Get IIC Module Index as MODULE_e type +*******************************************************************************/ +MODULE_e Hal_GetIIC_ModuleID(uint8_t id) +{ + if(IIC_Module0 == id) + return DRV_GET_IIC_MOD_ID(IIC_Module0); + else + return DRV_GET_IIC_MOD_ID(IIC_Module1); +} + +/******************************************************************************* + @ Module : Hal_GetIIC_IRQID + @ Description : Get IIC Interrupt Index +*******************************************************************************/ +uint8_t Hal_GetIIC_IRQID(uint8_t id) +{ + if(IIC_Module0 == id) + return DRV_GET_IIC_IRQ_ID(IIC_Module0); + else + return DRV_GET_IIC_IRQ_ID(IIC_Module1); +} + +/******************************************************************************* + @ Module : Hal_GetIIC_PIN_Fmux + @ Description : None +*******************************************************************************/ +void Hal_GetIIC_PIN_Fmux(uint8_t id,Fmux_Type_e* SCL_Fmux,Fmux_Type_e* SDA_Fmux) +{ + if(IIC_Module0 == id) + { + *SCL_Fmux = FMUX_IIC0_SCL; + *SDA_Fmux = FMUX_IIC0_SDA; + } + else + { + *SCL_Fmux = FMUX_IIC1_SCL; + *SDA_Fmux = FMUX_IIC1_SDA; + } +} + +/******************************************************************************* + @ Module : Register call back function + @ Description : None +*******************************************************************************/ +uint8_t Hal_IIC_Register_CallBack(uint8_t id,I2C_Hdl_t cb) +{ + if(id == IIC_Module0) + { + I2C_Mode[IIC_Module0].busy = TRUE; + I2C0_IRQ_Handle = cb; + return PPlus_IIC_SUCCESS; + } + else if( id == IIC_Module1 ) + { + I2C_Mode[IIC_Module1].busy = TRUE; + I2C1_IRQ_Handle = cb; + return PPlus_IIC_SUCCESS; + } + + return PPlus_ERR_IIC_ID; +} + +/******************************************************************************* + @ Module : unregister call back function + @ Description : None +*******************************************************************************/ +uint8_t Hal_IIC_unRegister_CallBack(uint8_t id) +{ + if(id == IIC_Module0) + { + I2C_Mode[IIC_Module0].busy = FALSE; + I2C0_IRQ_Handle = NULL; + return PPlus_IIC_SUCCESS; + } + else if( id == IIC_Module1 ) + { + I2C_Mode[IIC_Module1].busy = FALSE; + I2C1_IRQ_Handle = NULL; + return PPlus_IIC_SUCCESS; + } + + return PPlus_ERR_IIC_ID; +} + +/******************************************************************************* + @ Module : IIC Check IIC Valid + @ Description : [para in]:id,iic module 0,1 +*******************************************************************************/ +uint8_t Hal_IIC_Valid_Check(uint8_t id) +{ + if( id > (IIC_COUNT-1)) + return PPlus_ERR_IIC_ID; + else + return (I2C_Mode[id].busy); +} + +/******************************************************************************* + @ Module : IIC Check IIC Address Valid + @ Description : [para in]:Addr,usr set master or slave address +*******************************************************************************/ +uint8_t Hal_IIC_Addr_Valid(uint8_t Addr) +{ + for(unsigned char i=0; iIC_ENABLE_STATUS & 0x0001) + { + // IIC Already enabled + return PPLUS_ERR_IIC_ENABLE; + } + else + { + // IIC Closed Successed + return PPlus_IIC_SUCCESS; + } +} + +/******************************************************************************* + @ Module : IIC Receive data from RX FIFO + @ Description : [para in]:Ins,the instance wanted to READ Data +*******************************************************************************/ +uint8_t Hal_IIC_Read_RXFIFO(AP_I2C_TypeDef* Ins) +{ + return Ins->IC_DATA_CMD ; +} + +/******************************************************************************* + @ Module : Hal_INTR_SOURCE_Clear + @ Description : [para in]:Ins,the instance wanted to READ Data,irqs:interrupt source +*******************************************************************************/ +void Hal_INTR_SOURCE_Clear(AP_I2C_TypeDef* Ins,uint32_t irqs) +{ + switch( irqs ) + { + case I2C_MASK_RX_UNDER: + Ins->IC_CLR_UNDER; + break; + + case I2C_MASK_RX_OVER: + Ins->IC_CLR_RX_OVER; + break; + + case I2C_MASK_TX_OVER: + Ins->IC_CLR_TX_OVER; + break; + + case I2C_MASK_RD_REQ: + Ins->IC_CLR_RD_REG; + break; + + case I2C_MASK_TX_ABRT: + Ins->IC_CLR_TX_ABRT; + break; + + case I2C_MASK_RX_DONE: + Ins->IC_CLR_RX_DONE; + break; + + case I2C_MASK_ACTIVITY: + Ins->IC_CLR_ACTIVITY; + break; + + case I2C_MASK_STOP_DET: + Ins->IC_CLR_STOP_DET; + break; + + case I2C_MASK_START_DET: + Ins->IC_CLR_START_DET; + break; + + case I2C_MASK_GEN_CALL: + Ins->IC_CLR_GEN_CALL; + break; + } +} + +/******************************************************************************* + @ Module : Hal_IIC_Write_TXFIFO + @ Description : [para in]:Ins,the instance wanted to write, +*******************************************************************************/ +void Hal_IIC_Write_TXFIFO(AP_I2C_TypeDef* Ins,uint8_t data) +{ + Ins->IC_DATA_CMD = ((I2C_Data_WRITE << 8) | data); +} + +/******************************************************************************* + @ Module : hal_I2C0_IRQHandler + @ Description : This function process for i2c0 interrupt +*******************************************************************************/ +void __attribute__((used)) Hal_I2C0_IRQHandler(void) +{ + I2C_Evt_t irq_s; + irq_s.type= (I2C_EVT)(AP_I2C0->IC_INTR_STAT); + (*I2C0_IRQ_Handle)(&irq_s); +} + +/******************************************************************************* + @ Module : hal_I2C1_IRQHandler + @ Description : This function process for i2c1 interrupt +*******************************************************************************/ +void __attribute__((used)) Hal_I2C1_IRQHandler(void) +{ + I2C_Evt_t irq_s; + irq_s.type= (I2C_EVT)(AP_I2C1->IC_INTR_STAT); + (*I2C1_IRQ_Handle)(&irq_s); +} diff --git a/src/components/driver/i2c/i2c_common.h b/src/components/driver/i2c/i2c_common.h new file mode 100644 index 0000000..3ba0a41 --- /dev/null +++ b/src/components/driver/i2c/i2c_common.h @@ -0,0 +1,495 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file i2c_comman.h + @brief i2c General Configuration + @version 1.0 + +*******************************************************************************/ + +#ifndef __I2C_COMMON_H__ +#define __I2C_COMMON_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +/******************************************************************************* + @ Module : Includes + @ Description : NULL +*******************************************************************************/ +#include "bus_dev.h" +#include "gpio.h" + +/******************************************************************************* + @ Module : pre-compile + @ Description : NULL +*******************************************************************************/ + + +/******************************************************************************* + @ Module : Macro Define + @ Description : IIC Error Code +*******************************************************************************/ +#define PPlus_IIC_SUCCESS 0 +#define PPlus_ERR_IIC_ADDRESS 0xFE +#define PPlus_ERR_IIC_ID 0xFD +#define PPLUS_ERR_IIC_BUSY 0xFC +#define PPLUS_ERR_IIC_ENABLE 0xFB +#define PPlus_ERR_IIC_FAILURE 0xFF + +/******************************************************************************* + @ Module : Macro Define + @ Description : IIC InValid Handle +*******************************************************************************/ +#define PPlus_INVALID_HANDLE 0xFF + +/******************************************************************************* + @ Module : Macro Define + @ Description : The number of IIC Module(Two IIC:IIC0,IIC1) +*******************************************************************************/ +#define IIC_COUNT 2 + +/******************************************************************************* + @ Module : Macro Define + @ Description : Indicate IIC Module +*******************************************************************************/ +#define IIC_Module0 0 +#define IIC_Module1 1 + +/******************************************************************************* + @ Module : Macro Define + @ Description : IIC Bus Read or Wirte Device +*******************************************************************************/ +#define I2C_COMMAND_READ 0x01 +#define I2C_COMMAND_WRITE 0x00 + +/******************************************************************************* + @ Module : Macro Define + @ Description : IIC Bus Read or Write data from FIFO +*******************************************************************************/ +#define I2C_Data_READ 0x01 +#define I2C_Data_WRITE 0x00 + +/******************************************************************************* + @ Module : Macro Define + @ Description : Can not be used IIC Slave Address Length +*******************************************************************************/ +#define I2C_NOT_USED_SLAVE_ADDRLEN 4 + +/******************************************************************************* + @ Module : Macro Define + @ Description : None +*******************************************************************************/ +#define I2C_IC_DEFAULT_TAR_UPDATE 0 +#define I2C_IC_CLK_TYPE 1 + +/******************************************************************************* + @ Module : Macro Define + @ Description : IIC Default Master/Slave Address +*******************************************************************************/ +#define I2C_IC_DEFAULT_ADDR 0x0010 + +/******************************************************************************* + @ Module : I2C Buffer Length + @ Description : relate to RX FIFO & TX FIFO +*******************************************************************************/ +#define I2C_FIFO_DEPTH 8 +#define I2C_RX_TL_CNT I2C_FIFO_DEPTH +#define I2C_TX_TL_CNT I2C_FIFO_DEPTH + +/******************************************************************************* + @ Module : Macro Define + @ Description : IC_CON Bit Field Description +*******************************************************************************/ +// Determine IIC Slave enable or disable after reset(salve is enable in reset state) +// if slave enabled , MASTER_MODE should be disabled +#define IC_CON_IC_SLAVE_DISABLE 0x0040 + +// Determine whether restart conditions may be send when act as a master +// when act an a master , must enable this function +#define IC_CON_IC_RESTART_EN 0x0020 + +#define IC_CON_IC_10BITADDR_MASTER 0x0010 +// Determine the IIC Master Address Mode(10bit) + +// Determine the IIC Slave Address Mode(10bit) +#define IC_CON_IC_10BITADDR_SLAVE 0x0008 + +// Determine IIC Speed Mode +#define IC_CON_IC_SPEED_100K 0x0002 +#define IC_CON_IC_SPEED_400K 0x0004 +#define IC_CON_IC_SPEED_3_4M 0x0006 + +// Determine IIC Master Enable +#define IC_CON_MASTER_MODE 0x0001 + +/******************************************************************************* + @ Module : Macro Define + @ Description : IC_TAR Bit Field Description +*******************************************************************************/ +// this bit related to I2C_IC_DEFAULT_TAR_UPDATE Value +#define IC_TAR_IC_10BITADDR_MASTER 0x1000 + +// Indicate whether performance a Gengral call or start byte Command +// relate to IC_TAR_GC_OR_START +#define IC_TAR_SPECIAL_COMMAND_ENABLE 0x0800 + +// Dependency IC_TAR_SPECIAL_COMMAND_ENABLE +// if set, Start Byte,otherwise General Call +// General Call:only writes may be performed.when read resault TX_ABRT +// Start Byte:send Start Byte(0x01) to Synchronizate IIC Clock +#define IC_TAR_GC_OR_START 0x0400 + +// IC Default Slave Address +#define IC_TAR_DEFAULT_SLAVE_ADDRESS I2C_IC_DEFAULT_TAR_SLAVE_ADDR + +/******************************************************************************* + @ Module : Macro Define + @ Description : IC_SAR +*******************************************************************************/ +#define IC_SAR_DEFAUT_SLAVE_ADDRESS I2C_IC_DEFAULT_TAR_SLAVE_ADDR + +/******************************************************************************* + @ Module : I2C Interrupt Status Register + @ Description : Interrupt Status bit(cleared by reading the matching interrupt clear register.) +*******************************************************************************/ +#define I2C_INTR_STAT_RX_UNDER 0x0001 +#define I2C_INTR_STAT_RX_OVER 0x0002 +#define I2C_INTR_STAT_RX_FULL 0x0004 +#define I2C_INTR_STAT_TX_OVER 0x0008 +#define I2C_INTR_STAT_TX_EMPTY 0x0010 +#define I2C_INTR_STAT_RD_REQ 0x0020 +#define I2C_INTR_STAT_TX_ABRT 0x0040 +#define I2C_INTR_STAT_RX_DONE 0x0080 +#define I2C_INTR_STAT_ACTIVITY 0x0100 +#define I2C_INTR_STAT_STOP_DET 0x0200 +#define I2C_INTR_STAT_START_DET 0x0400 +#define I2C_INTR_STAT_GEN_CALL 0x0800 + +/******************************************************************************* + @ Module : I2C Interrupt Mask Register + @ Description : Interrupt MASK bit +*******************************************************************************/ +#define I2C_MASK_RX_UNDER 0x0001 +#define I2C_MASK_RX_OVER 0x0002 +#define I2C_MASK_RX_FULL 0x0004 +#define I2C_MASK_TX_OVER 0x0008 +#define I2C_MASK_TX_EMPTY 0x0010 +#define I2C_MASK_RD_REQ 0x0020 +#define I2C_MASK_TX_ABRT 0x0040 +#define I2C_MASK_RX_DONE 0x0080 +#define I2C_MASK_ACTIVITY 0x0100 +#define I2C_MASK_STOP_DET 0x0200 +#define I2C_MASK_START_DET 0x0400 +#define I2C_MASK_GEN_CALL 0x0800 +#define I2C_DISABLE_ALL_INTR 0 + +/******************************************************************************* + @ Module : I2C Raw Interrupt Register + @ Description : Interrupt MASK bit +*******************************************************************************/ +#define I2C_RAW_INTR_RX_UNDER 0x0001 +#define I2C_RAW_INTR_RX_OVER 0x0002 +#define I2C_RAW_INTR_RX_FULL 0x0004 +#define I2C_RAW_INTR_TX_OVER 0x0008 +#define I2C_RAW_INTR_TX_EMPTY 0x0010 +#define I2C_RAW_INTR_RD_REQ 0x0020 +#define I2C_RAW_INTR_TX_ABRT 0x0040 +#define I2C_RAW_INTR_RX_DONE 0x0080 +#define I2C_RAW_INTR_ACTIVITY 0x0100 +#define I2C_RAW_INTR_STOP_DET 0x0200 +#define I2C_RAW_INTR_START_DET 0x0400 +#define I2C_RAW_INTR_GEN_CALL 0x0800 + +/******************************************************************************* + @ Module : I2C ENABLE Status Register + @ Description : I2C ENABLE STATUS Bit +*******************************************************************************/ +#define I2C_ENSTA_IC_ENABLE_STATUS 0x0001 +#define I2C_ENSTA_SLV_RX_ABORT 0x0002 +#define I2C_ENSTA_SLV_RX_DATA_LOST 0x0004 + +/******************************************************************************* + @ Module : I2C Status Register + @ Description : Only read register ,indicate current transfer stauts and FIFO status +*******************************************************************************/ +#define I2C_STAT_SLV_ACTIVITY 0x0040 +#define I2C_STAT_MST_ACTIVITY 0x0020 +//Receive FIFO Completely Full +#define I2C_STAT_RFF 0x0010 +//Receive FIFO Not Empty +#define I2C_STAT_RFNF 0x0008 +// Transmit FIFO Completely Empty +#define I2C_STAT_TFE 0x0004 +// Transmit FIFO Not Full +#define I2C_STAT_TFNF 0x0002 +#define I2C_STAT_ACTIVITY 0x0001 + +/******************************************************************************* + @ Module : I2C Transmit Abort Source Register + @ Description : indicate the source of the TX_ABRT +*******************************************************************************/ +#define I2C_ABRT_7B_ADDR_NOACK 0x0001 +#define I2C_ABRT_10B_ADDR1_NOACK 0x0002 +#define I2C_ABRT_10B_ADDR2_NOACK 0x0004 +#define I2C_ABRT_TXDATA_NOACK 0x0008 +// master send a General Call , but no slave ACK +#define I2C_ABRT_GCALL_NOACK 0x0010 +// master send data to the bus , but user programmed the data direction is read +// from the bus(relate to IC_DATA_CMD[8]) +#define I2C_ABRT_GCALL_READ 0x0020 +// master in high speed mode ,and its code was ACK(Should not ACK) +#define I2C_ABRT_HS_ACKDET 0x0040 +// master send START Byte and detect ACK(Should not ACK) +#define I2C_ABRT_SBYTE_ACKDET 0x0080 +// the restart is diabled,and the user is trying to use the master to transmit +// data in high speed mode +#define I2C_ABRT_HS_NORTART 0x0100 + +// +#define I2C_ABRT_SBYTE_NORESTART 0x0200 + +#define I2C_ABRT_10B_RD_NORSTART 0x0400 +// user tries to initiate a master operation with the master mode disabled +#define I2C_ABRT_MASTER_DIS 0x0800 + +#define I2C_ABR_LOST 0x1000 + +// slave receive a read command ,but there's some data exists in TX FIFO, +// and issues interrupt to flush old TX FIFO +#define I2C_ABRT_SLVFLUSH_TXFIFO 0x2000 + +#define I2C_ABRT_SLV_ABRLOST 0x4000 + +// slave transmit data to the master , and use the read data command from the +// bus(relate to IC_DATA_CMD[8]) +#define I2C_ABRT_SLVRD_INTX 0x8000 + +#define I2C0_IRQ I2C0_IRQn +#define I2C1_IRQ I2C1_IRQn +/******************************************************************************* + @ Module : IIC Work Mode + @ Description : None +*******************************************************************************/ +typedef enum +{ + Slave = 0, + Master = IC_CON_IC_SLAVE_DISABLE | IC_CON_IC_RESTART_EN | IC_CON_MASTER_MODE, +} I2C_WorkMode; + +/******************************************************************************* + @ Module : IIC Speed Mode + @ Description : None +*******************************************************************************/ +typedef enum +{ + SPEED_STANDARD = 0x0002, //standard mode + SPEED_FAST = 0x0004, //fast mode + SPEED_HIGH = 0x0006, //high mode +} I2C_SPEED_e; + +/******************************************************************************* + @ Module : IIC Clock + @ Description : None +*******************************************************************************/ +typedef enum +{ + I2C_CLOCK_100K = 0x0002, + I2C_CLOCK_400K = 0x0004, + I2C_CLOCK_3_4M = 0x0006, +} I2C_CLOCK_e; + +/******************************************************************************* + @ Module : IIC Address Mode + @ Description : Only support 7 bit Address,be careful while using +*******************************************************************************/ +typedef enum +{ + I2C_ADDR_7bit = 0, + I2C_ADDR_10bit +} I2C_ADDRESS_e; + +/******************************************************************************* + @ Module : transfer mode + @ Description : + I2C_MODE_BLOCKING blocks task execution while an I2C transfer is in progress + I2C_MODE_CALLBACK does not block task execution; but calls a callback + function when the I2C transfer has completed +*******************************************************************************/ +typedef enum +{ + I2C_MODE_BLOCKING, /*!< I2C_transfer blocks execution*/ + I2C_MODE_CALLBACK /*!< I2C_transfer queues transactions and does not block */ +} I2C_TransferMode; + +/******************************************************************************* + @ Module : I2C Event enum + @ Description : None +*******************************************************************************/ +typedef enum +{ + // INTR SOURCE EVENT + I2C_RX_UNDER_Evt = 0x0001, + I2C_RX_OVER_Evt = 0x0002, + I2C_RX_FULL_Evt = 0x0004, + I2C_TX_OVER_Evt = 0x0008, + I2C_TX_EMPTY_Evt = 0x0010, + I2C_RD_REQ_Evt = 0x0020, + I2C_TX_ABRT_Evt = 0x0040, + I2C_RX_DONE_Evt = 0x0080, + I2C_ACTIVITY_Evt = 0x0100, + I2C_STOP_DET_Evt = 0x0200, + I2C_START_DET_Evt = 0x0400, + I2C_GEN_CALL_Evt = 0x0800, + // User Event + I2C_DINIT_SUCCESS = 0x1000 +} I2C_EVT; + +/******************************************************************************* + @ Module : I2C Event + @ Description : None +*******************************************************************************/ +typedef struct +{ + I2C_EVT type; + uint8_t len; +} I2C_Evt_t; + +/******************************************************************************* + @ Module : Function *p + @ Description : None +*******************************************************************************/ +typedef void (*I2C_Hdl_t)(I2C_Evt_t* pev); + + + +/******************************************************************************* + @ Module : I2C Master Paramter structure + @ Description : None +*******************************************************************************/ +typedef struct +{ + // General + uint8_t id; // set + I2C_WorkMode workmode; // init some Para ,according to workmode + I2C_CLOCK_e ClockMode; + I2C_ADDRESS_e AddressMode; + bool use_fifo; // check if use fifo,default used + uint8_t RX_FIFO_Len; // RX , TX FIFO SET + uint8_t Tx_FIFO_Len; + gpio_pin_e SDA_PIN; // I2C Pin + gpio_pin_e SCL_PIN; + I2C_TransferMode TransferMode; // according to TransferMode, that evt_handler can be + // enable or disable + I2C_Hdl_t evt_handler; + + uint8_t Master_Addressing; // TAR,when as master + uint32_t IC_xS_SCL_HCNT; + uint32_t IC_xS_SCL_LCNT; + +} I2C_Master_Parameter; + +/******************************************************************************* + @ Module : Master Default Init Parameter + @ Description : None +*******************************************************************************/ +//I2CCOM_Ext I2C_Parameter I2C_DefaultPara; + +/******************************************************************************* + @ Module : Function statement + @ Description : +*******************************************************************************/ +uint8_t Hal_Check_IIC_IsAlready_Closed(void); + +/******************************************************************************* + @ Module : Get_IIC_Instance + @ Description : + [para in]:id,iic module id 0 or 1 + [return]:instance address +*******************************************************************************/ +AP_I2C_TypeDef* Hal_Get_IIC_Instance(uint8_t id); + +/******************************************************************************* + @ Module : Hal_GetIIC_ModuleID + @ Description : None +*******************************************************************************/ +MODULE_e Hal_GetIIC_ModuleID(uint8_t id); + +/******************************************************************************* + @ Module : Hal_GetIIC_Interrupt ID + @ Description : None +*******************************************************************************/ +uint8_t Hal_GetIIC_IRQID(uint8_t id); + +/******************************************************************************* + @ Module : Hal_GetIIC_PIN_Fmux ID + @ Description : None +*******************************************************************************/ +void Hal_GetIIC_PIN_Fmux(uint8_t id,Fmux_Type_e* SCL_Fmux,Fmux_Type_e* SDA_Fmux); + +/******************************************************************************* + @ Module : IIC Register CallBack Function + @ Description : + [para in]:id,iic module 0,1;cb , call back function +*******************************************************************************/ +uint8_t Hal_IIC_Register_CallBack(uint8_t id,I2C_Hdl_t cb); + +/******************************************************************************* + @ Module : IIC unRegister CallBack Function + @ Description : [para in]:id,iic module 0,1 +*******************************************************************************/ +uint8_t Hal_IIC_unRegister_CallBack(uint8_t id); + +/******************************************************************************* + @ Module : IIC Check IIC Valid + @ Description : [para in]:id,iic module 0,1 +*******************************************************************************/ +uint8_t Hal_IIC_Valid_Check(uint8_t id); + +/******************************************************************************* + @ Module : IIC Check IIC Address Valid + @ Description : [para in]:Addr,usr set master or slave address +*******************************************************************************/ +uint8_t Hal_IIC_Addr_Valid(uint8_t Addr); + +/******************************************************************************* + @ Module : Check IIC Closed Success + @ Description : [para in]:Ins,the instance wanted to check +*******************************************************************************/ +uint8_t Hal_Check_IIC_Closed(AP_I2C_TypeDef* Ins); + +/******************************************************************************* + @ Module : IIC Receive data from RX FIFO + @ Description : [para in]:Ins,the instance wanted to READ Data +*******************************************************************************/ +uint8_t Hal_IIC_Read_RXFIFO(AP_I2C_TypeDef* Ins); + +/******************************************************************************* + @ Module : Hal_INTR_SOURCE_Clear + @ Description : [para in]:Ins,the instance wanted to READ Data,irqs:interrupt source +*******************************************************************************/ +void Hal_INTR_SOURCE_Clear(AP_I2C_TypeDef* Ins,uint32_t irqs); + +/******************************************************************************* + @ Module : Hal_IIC_Write_TXFIFO + @ Description : [para in]:Ins,the instance wanted to write, +*******************************************************************************/ +void Hal_IIC_Write_TXFIFO(AP_I2C_TypeDef* Ins,uint8_t data); + + + +void Hal_TRANS_ABRT_SourceCheck(void); + +void __attribute__((weak)) Hal_I2C0_IRQHandler(void); +void __attribute__((weak)) Hal_I2C1_IRQHandler(void); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/components/driver/i2c/i2c_io.c b/src/components/driver/i2c/i2c_io.c new file mode 100644 index 0000000..55aec64 --- /dev/null +++ b/src/components/driver/i2c/i2c_io.c @@ -0,0 +1,284 @@ +//#include "iic.h" +#include "bus_dev.h" +#include "gpio.h" +#include "error.h" + +//static gpio_pin_e s_pin_sda = GPIO_DUMMY; +//static gpio_pin_e s_pin_scl = GPIO_DUMMY; +//static bool s_dir_scl; +#define IIC_SDA_PIN GPIO_DUMMY +#define IIC_SCL_PIN GPIO_DUMMY + +#define TWI_SDA_LOW() hal_gpio_fast_write(IIC_SDA_PIN,0) +#define TWI_SDA_HIGH() hal_gpio_fast_write(IIC_SDA_PIN,1) + +#define TWI_SCL_LOW() hal_gpio_write(IIC_SCL_PIN,0) +#define TWI_SCL_HIGH() hal_gpio_write(IIC_SCL_PIN,1) + +#define TWI_SCL_READ() hal_gpio_read(IIC_SCL_PIN) +#define TWI_SDA_READ() hal_gpio_read(IIC_SDA_PIN) + +#define TWI_SDA_OUTPUT() hal_gpio_pin_init(IIC_SDA_PIN,OEN) +#define TWI_SDA_INPUT() hal_gpio_pin_init(IIC_SDA_PIN,IE); hal_gpio_pull_set(IIC_SDA_PIN, STRONG_PULL_UP) + +#define TWI_SCL_OUTPUT() hal_gpio_pin_init(IIC_SCL_PIN,OEN) +#define TWI_SCL_INPUT() hal_gpio_pin_init(IIC_SCL_PIN,IE); hal_gpio_pull_set(IIC_SCL_PIN, STRONG_PULL_UP) +/* + #define SCL_H GPIOC->BSRR = GPIO_Pin_12 + #define SCL_L GPIOC->BRR = GPIO_Pin_12 + + #define SDA_H GPIOC->BSRR = GPIO_Pin_11 + #define SDA_L GPIOC->BRR = GPIO_Pin_11 + + #define SCL_read GPIOC->IDR & GPIO_Pin_12 + #define SDA_read GPIOC->IDR & GPIO_Pin_11 +*/ +#define SCL_H TWI_SCL_HIGH() +#define SCL_L TWI_SCL_LOW() + +#define SDA_H TWI_SCL_HIGH() +#define SDA_L TWI_SCL_LOW() + +//#define SCL_read GPIOC->IDR & GPIO_Pin_12 +#define SDA_read TWI_SDA_READ() +//GPIOC->IDR & GPIO_Pin_11 + +#if 0 +static void scl_w(int value) +{ +} + +static int scl_r(void) +{ +} + +static void sda_w(int value) +{ +} + +static int sda_r(void) +{ +} +#endif + +void I2C_delay(void) +{ + uint8_t i=5; + + while(i) + { + i--; + } +} + +void I2C_delay_100us(uint32_t nCount) +{ + volatile int i = 450; + + while(nCount) + { + nCount--; + + for(; i; i--); + } +} + +bool i2c_start(void) +{ + SDA_H; + SCL_H; + I2C_delay(); + + if(!SDA_read) + { + return false; + } + + SDA_L; + I2C_delay(); + + if(SDA_read) + { + return false; + } + + SDA_L; + I2C_delay(); + return true; +} + +void i2c_stop(void) +{ + SCL_L; + I2C_delay(); + SDA_L; + I2C_delay(); + SCL_H; + I2C_delay(); + SDA_H; + I2C_delay(); +} + +void i2c_ack(void) +{ + SCL_L; + I2C_delay(); + SDA_L; + I2C_delay(); + SCL_H; + I2C_delay(); + SCL_L; + I2C_delay(); +} + +void i2c_nack(void) +{ + SCL_L; + I2C_delay(); + SDA_H; + I2C_delay(); + SCL_H; + I2C_delay(); + SCL_L; + I2C_delay(); +} + +bool i2c_wait_ack(void) +{ + SCL_L; + I2C_delay(); + SDA_H; + I2C_delay(); + SCL_H; + I2C_delay(); + + if(SDA_read) + { + SCL_L; + return false; + } + + SCL_L; + return true; +} + +void i2c_tx(uint8_t SendByte) +{ + uint8_t i=8; + + while(i--) + { + SCL_L; + I2C_delay(); + + if(SendByte&0x80) + SDA_H; + else + SDA_L; + + SendByte<<=1; + I2C_delay(); + SCL_H; + I2C_delay(); + } + + SCL_L; +} + +uint8_t i2c_rx(void) +{ + uint8_t i=8; + uint8_t ReceiveByte=0; + SDA_H; + + while(i--) + { + ReceiveByte<<=1; + SCL_L; + I2C_delay(); + SCL_H; + I2C_delay(); + + if(SDA_read) + { + ReceiveByte|=0x01; + } + } + + SCL_L; + return ReceiveByte; +} + +int i2c_io_pin_init(gpio_pin_e pin_sda, gpio_pin_e pin_clk) +{ + return PPlus_SUCCESS; +} +int i2c_io_pin_deinit(gpio_pin_e pin_sda, gpio_pin_e pin_clk) +{ + return PPlus_SUCCESS; +} + +bool i2c_io_read(uint8_t slave_addr, uint8_t reg, uint8_t* data, uint8_t size) +{ + if(!i2c_start()) + { + return false; + } + + i2c_tx(slave_addr); + + if(!i2c_wait_ack()) + { + i2c_stop(); + return false; + } + + i2c_tx(reg); + i2c_wait_ack(); + i2c_start(); + i2c_tx(slave_addr|0x01); + i2c_wait_ack(); + + while(size) + { + *data = i2c_rx(); + + if(size == 1) + { + i2c_nack(); + } + else + { + i2c_ack(); + } + + data++; + size--; + } + + i2c_stop(); + return true; +} + +bool i2c_io_write(uint8_t slave_addr, uint8_t reg, uint8_t value) +{ + if(!i2c_start())return false; + + i2c_tx(slave_addr); + + if(!i2c_wait_ack()) + { + i2c_stop(); + return false; + } + + i2c_tx(reg);//i2c_tx((uint8_t)(reg & 0x00FF)); + i2c_wait_ack(); + i2c_tx(value); + i2c_wait_ack(); + i2c_stop(); + return true; +} + + + diff --git a/src/components/driver/i2c/i2c_io.h b/src/components/driver/i2c/i2c_io.h new file mode 100644 index 0000000..22f9113 --- /dev/null +++ b/src/components/driver/i2c/i2c_io.h @@ -0,0 +1,49 @@ +#ifndef __IIC_H +#define __IIC_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#include "sys.h" +#include "delay.h" +#include "stdbool.h" + + + +void I2C_GPIO_Config(void); +void I2C_delay(void); +void I2C_delay_100us(u32 nCount); +bool I2C_Start(void); +void I2C_Stop(void); +void I2C_Ack(void); +void I2C_NoAck(void); +bool I2C_WaitAck(void); +void I2C_SendByte(u8 SendByte); +u8 I2C_ReceiveByte(void); +bool I2C_WriteByte(u8 SendByte, u16 WriteAddress, u8 DeviceAddress); +bool I2C_ReadByte(u8* pBuffer,u8 length,u16 ReadAddress,u8 DeviceAddress); + +#ifdef __cplusplus +} +#endif + + +#endif + + + + + + + + + + + + + + + + diff --git a/src/components/driver/i2c/i2c_s.c b/src/components/driver/i2c/i2c_s.c new file mode 100644 index 0000000..1b592a9 --- /dev/null +++ b/src/components/driver/i2c/i2c_s.c @@ -0,0 +1,156 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#include "bus_dev.h" +#include "gpio.h" +#include "clock.h" +#include "i2c_s.h" +#include "i2c.h" +#include "error.h" +#include "log.h" + +typedef struct +{ + uint8_t id; //0: uninit, 1: i2c0, 2:i2c1 + uint8_t mode; //(1)I2CS_MODE_REG_8BIT, (2)I2CS_MODE_REG_16BIT,(3)I2CS_MODE_RAW + uint8_t saddr; + gpio_pin_e cs; //cs pin, used to wakeup or release + gpio_pin_e sda; + gpio_pin_e scl; + AP_I2C_TypeDef* dev; + i2cs_hdl_t evt_handler; + uint8_t rxoffset; + uint8_t rxbuf[I2CS_RX_MAX_SIZE]; + uint8_t txoffset; + uint8_t txbuf[I2CS_TX_MAX_SIZE]; +} i2cs_ctx_t; + +static volatile uint8_t s_i2cs_state = I2CSST_IDLE; + +static i2cs_ctx_t s_i2cs_ctx; + +static void i2cs_irq_rx_handler(AP_I2C_TypeDef* pdev) +{ + uint32_t val; + + while(1) + { + if((pdev->IC_STATUS & BV(3)) == 0) + break; + + val = pdev->IC_DATA_CMD; + LOG("Rx %x\n",val); + } +} +static uint32_t tx_dummy = 0; +static void i2cs_irq_tx_handler(AP_I2C_TypeDef* pdev) +{ + pdev->IC_DATA_CMD = tx_dummy &0xff; + tx_dummy ++; + pdev->IC_DATA_CMD = tx_dummy &0xff; + tx_dummy ++; + //LOG("Tx\n"); +} +static void i2cs_irq_handler(AP_I2C_TypeDef* pdev) +{ + uint32_t int_status = pdev->IC_INTR_STAT; + uint32_t clr = pdev->IC_CLR_INTR; + + //LOG("i2cs_irq_handler %x\n",int_status); + if(int_status & I2C_MASK_START_DET) + { + } + + if(int_status & I2C_MASK_RX_FULL) + { + i2cs_irq_rx_handler(pdev); + } + + if(int_status & I2C_MASK_RD_REQ) + { + i2cs_irq_tx_handler(pdev); + } +} + +void __attribute__((used)) hal_I2C0_IRQHandler(void) +{ + i2cs_ctx_t* pctx = &s_i2cs_ctx; + + if(pctx->id == I2CS_0) + i2cs_irq_handler(AP_I2C0); +} +void __attribute__((used)) hal_I2C1_IRQHandler(void) +{ + i2cs_ctx_t* pctx = &s_i2cs_ctx; + + if(pctx->id == I2CS_1) + i2cs_irq_handler(AP_I2C1); +} + + + +int i2cs_init( + i2cs_channel_t ch_id, + i2cs_mode_t mode, + uint8_t saddr, //slave address + gpio_pin_e cs, //if need not cs, choose GPIO_DUMMY_PIN + gpio_pin_e sda, + gpio_pin_e scl, + i2cs_hdl_t evt_handler) +{ + i2cs_ctx_t* pctx = &s_i2cs_ctx; + Fmux_Type_e fmux; + MODULE_e module; + AP_I2C_TypeDef* pdev = NULL; + int irqid; + + if(pctx->id) + { + return PPlus_ERR_IO_CONFILCT; + } + + //parameter validate check + //set device + irqid = (ch_id == I2CS_0) ? I2C0_IRQ : I2C1_IRQ; + module = (ch_id == I2CS_0) ? MOD_I2C0 : MOD_I2C1; + hal_clk_gate_enable(module); + pdev = (ch_id == I2CS_0) ? AP_I2C0 : AP_I2C1; + pctx->id = ch_id; + pctx->dev = pdev; + pctx->saddr = saddr; + pctx->cs = cs; + pctx->scl = scl; + pctx->sda = sda; + pctx->evt_handler = evt_handler; + fmux = (ch_id == I2CS_0) ? IIC0_SCL : IIC1_SCL; + hal_gpio_fmux_set(scl, fmux); + fmux = (ch_id == I2CS_0) ? IIC0_SDA : IIC1_SDA; + hal_gpio_fmux_set(sda, fmux); + hal_gpio_pull_set(scl, STRONG_PULL_UP); + hal_gpio_pull_set(sda, STRONG_PULL_UP); + pdev->IC_ENABLE = 0; //disable + pdev->IC_CON = (SPEED_FAST) << 1; + pdev->IC_SAR = saddr; + pdev->IC_RX_TL = 1; + pdev->IC_TX_TL = 1; + pdev->IC_INTR_MASK = 0xfef;//(I2C_MASK_TX_ABRT | I2C_MASK_RD_REQ | I2C_MASK_RX_FULL | I2C_MASK_RX_DONE); + pdev->IC_ENABLE = 1; //disable + NVIC_EnableIRQ((IRQn_Type)irqid); + NVIC_SetPriority((IRQn_Type)irqid, IRQ_PRIO_HAL); + return PPlus_SUCCESS; +} + + +int i2cs_deinit(void) +{ + i2cs_ctx_t* pctx = &s_i2cs_ctx; + + if(pctx->id == 0) + return PPlus_ERR_IO_FAIL; + + //release io + return PPlus_SUCCESS; +} + diff --git a/src/components/driver/i2c/i2c_s.h b/src/components/driver/i2c/i2c_s.h new file mode 100644 index 0000000..07129d5 --- /dev/null +++ b/src/components/driver/i2c/i2c_s.h @@ -0,0 +1,82 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#ifndef _IIC_SLAVE_H +#define _IIC_SLAVE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "gpio.h" + +#define I2CS_RX_MAX_SIZE 64 +#define I2CS_TX_MAX_SIZE 64 + +#define IIC0_SCL FMUX_IIC0_SCL +#define IIC0_SDA FMUX_IIC0_SDA + +#define IIC1_SCL FMUX_IIC1_SCL +#define IIC1_SDA FMUX_IIC1_SDA + +//i2cs working state +enum +{ + I2CSST_IDLE = 0, + I2CSST_XMITING +}; + +typedef enum +{ + I2CS_0 = 1, + I2CS_1, +} i2cs_channel_t; + +typedef enum +{ + I2CS_MODE_REG_8BIT = 1, + I2CS_MODE_REG_16BIT, + I2CS_MODE_RAW +} i2cs_mode_t; + +enum +{ + I2CS_EVT_REG_REQ_READ = 1, //register mode read, master read request + I2CS_EVT_REG_REQ_READ_CMPL, //register mode read, read completed + I2CS_EVT_REG_RECV, //register mode write, recieved data + + I2CS_ET_RAW_RECV, //master write data to slave + I2CS_ET_RAW_TX_CMPL, //master read data from slave completed +};//event type + + +typedef struct +{ + uint8_t type; + uint8_t reg_u8; + uint16_t reg_u16; + uint8_t* dat; +} i2cs_evt_t; + +typedef void (*i2cs_hdl_t)(i2cs_evt_t* pev); +void __attribute__((weak)) hal_I2C0_IRQHandler(void); +void __attribute__((weak)) hal_I2C1_IRQHandler(void); +int i2cs_init( + i2cs_channel_t ch_id, + i2cs_mode_t mode, + uint8_t saddr, //slave address + gpio_pin_e cs, //if need not cs, choose GPIO_DUMMY_PIN + gpio_pin_e sda, + gpio_pin_e scl, + i2cs_hdl_t evt_handler); + + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/src/components/driver/i2c/i2c_slave.c b/src/components/driver/i2c/i2c_slave.c new file mode 100644 index 0000000..73c72f4 --- /dev/null +++ b/src/components/driver/i2c/i2c_slave.c @@ -0,0 +1,241 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file i2c_slave.c + @brief i2c slave function + @version 1.0 + +*******************************************************************************/ + +/******************************************************************************* + @ Module : Includes + @ Description : NULL +*******************************************************************************/ +#include "i2c_slave.h" +#include "gpio.h" +#include "error.h" +#include "osal.h" +#include "clock.h" +#include "log.h" + +/******************************************************************************* + @ Module : IIC_Slave status + @ Description : NULL +*******************************************************************************/ +typedef enum +{ + Slave_Closed = 0, + Slave_Opened, +} IIC_Slave_status; + +/******************************************************************************* + @ Module : IIC_Slave_cfg structure + @ Description : NULL +*******************************************************************************/ +typedef struct +{ + AP_I2C_TypeDef* addr; // get by software + MODULE_e module; // get by software + uint8_t INTR_ID; // get by software + gpio_pin_e SDA_PIN; // I2C Pin + gpio_pin_e SCL_PIN; + Fmux_Type_e Fmux_SCL; // get by software + Fmux_Type_e Fmux_SDA; // get by software + IIC_Slave_status state; +} IIC_Slave_cfg; + +/******************************************************************************* + @ Module : Global Variable + @ Description : NULL +*******************************************************************************/ +IIC_Slave_cfg Slave_cfg_g[IIC_COUNT]; + +/******************************************************************************* + @ Module : Internal Function statement + @ Description : NULL +*******************************************************************************/ +void I2C_Slave_Handler(I2C_Evt_t* pev); + +/******************************************************************************* + @ Module : Function Statement + @ Description : NULL +*******************************************************************************/ +uint8_t Hal_I2C_Slave_Init(I2C_Slave_Parameter* para,uint8_t* handle) +{ + uint8_t ret; + LOG("Hal_I2C_Slave_Init wakeup id:%02X \r\n",para->id); + ret = Hal_IIC_Valid_Check(para->id); + + if( ret == TRUE ) + { + return PPLUS_ERR_IIC_BUSY; + } + else if( ret == PPlus_ERR_IIC_ID) + { + return PPlus_ERR_IIC_ID; + } + else + { + if( Hal_IIC_Addr_Valid(para->Slave_Address) != PPlus_IIC_SUCCESS) + return PPlus_ERR_IIC_ADDRESS; + + osal_memset(&Slave_cfg_g[para->id],0,sizeof(IIC_Slave_cfg)); + // pre-para get + Slave_cfg_g[para->id].addr = Hal_Get_IIC_Instance(para->id); + Slave_cfg_g[para->id].module = Hal_GetIIC_ModuleID(para->id); + Slave_cfg_g[para->id].INTR_ID = Hal_GetIIC_IRQID(para->id); + Hal_GetIIC_PIN_Fmux(para->id,&(Slave_cfg_g[para->id].Fmux_SCL),&(Slave_cfg_g[para->id].Fmux_SDA)); + Slave_cfg_g[para->id].state = Slave_Closed; + // io init + Slave_cfg_g[para->id].SCL_PIN = para->SCL_PIN; + Slave_cfg_g[para->id].SDA_PIN = para->SDA_PIN; + hal_gpio_fmux_set(para->SCL_PIN, Slave_cfg_g[para->id].Fmux_SCL); + hal_gpio_fmux_set(para->SDA_PIN, Slave_cfg_g[para->id].Fmux_SDA); + hal_gpio_pull_set(para->SCL_PIN,STRONG_PULL_UP); + hal_gpio_pull_set(para->SDA_PIN,STRONG_PULL_UP); + // init + hal_clk_gate_enable(Slave_cfg_g[para->id].module); + Slave_cfg_g[para->id].addr->IC_ENABLE = FALSE; + Slave_cfg_g[para->id].addr->IC_CON = para->workmode | para->AddressMode; + Slave_cfg_g[para->id].addr->IC_SAR = para->Slave_Address; + Slave_cfg_g[para->id].addr->IC_RX_TL = para->RX_FIFO_Len - 1; + Slave_cfg_g[para->id].addr->IC_TX_TL = para->Tx_FIFO_Len - 1; + Slave_cfg_g[para->id].addr->IC_INTR_MASK = para->IRQ_Source; + Hal_IIC_Register_CallBack(para->id,para->evt_handler); + Hal_I2c_Slave_Open(para->id); + // NVIC Config + NVIC_EnableIRQ((IRQn_Type)(Slave_cfg_g[para->id].INTR_ID)); + NVIC_SetPriority((IRQn_Type)(Slave_cfg_g[para->id].INTR_ID), IRQ_PRIO_HAL); + *handle = para->id; + return PPlus_IIC_SUCCESS; + } +} + +/******************************************************************************* + @ Module : Open I2C Slave + @ Description : NULL +*******************************************************************************/ +uint8_t Hal_I2c_Slave_Open(uint8_t handle) +{ + if( Slave_cfg_g[handle].state == Slave_Closed ) + { + Slave_cfg_g[handle].state = Slave_Opened; + Slave_cfg_g[handle].addr->IC_ENABLE = TRUE; + return PPlus_IIC_SUCCESS; + } + else + return PPlus_ERR_IIC_FAILURE; +} + +/******************************************************************************* + @ Module : Close I2C Slave + @ Description : NULL +*******************************************************************************/ +void Hal_I2c_Slave_Close(uint8_t handle) +{ + Slave_cfg_g[handle].addr->IC_ENABLE = FALSE; +} + +/******************************************************************************* + @ Module : Close I2C Slave + @ Description : Should check close states,if closed completed + a delay occurs when IC_ENABLE is set to 0, because close iic module depends + on the iic bus activity +*******************************************************************************/ +uint8_t Hal_Check_I2C_Slave_Closed(uint8_t handle) +{ + if( Hal_Check_IIC_Closed(Slave_cfg_g[handle].addr) == PPlus_IIC_SUCCESS ) + { + Slave_cfg_g[handle].state = Slave_Closed; + return PPlus_IIC_SUCCESS; + } + else + return PPLUS_ERR_IIC_ENABLE; +} + +/******************************************************************************* + @ Module : Close I2C Slave + @ Description : NULL +*******************************************************************************/ +uint8_t Hal_I2C_Slave_Deinit(uint8_t* handle) +{ + LOG("HAL I2C SLAVE DINIT handle Value %d \n",*handle); + + if( Hal_IIC_unRegister_CallBack(*handle) != PPlus_IIC_SUCCESS ) + return PPlus_ERR_IIC_FAILURE; + + *handle = PPlus_INVALID_HANDLE; + return PPlus_IIC_SUCCESS; +} + +/******************************************************************************* + @ Module : Read data from rx fifo + @ Description : NULL +*******************************************************************************/ +void Hal_I2C_Slave_ReadRX_FIFO(uint8_t handle,uint8_t* p,uint8_t len) +{ + for(uint8_t i =0; i25us)(一个byte传输完æˆçš„æ—¶é—´ï¼‰ + 4ã€è¯»è¯·æ±‚触å‘å‰ï¼Œå¦‚æžœTXFIFO,总线触å‘TX_ABRTä¸­æ–­ï¼Œæ¸…é™¤æ—§æ•°æ® ï¼ˆé€šè¿‡è½¯ä»¶è¯»å– IC_CLR_TX_ABRT register,释放总线ï¼? + 5ã€å†™æ•°æ®åˆ?IC_DATA_CMD + 6ã€æ¸…除RD_REQ,TX_ABRT中断标志ä½ï¼ˆå¦‚果中断被å±è”½ï¼Œåˆ™éœ€è¦æ¸…除IC_RAW_INTR_STATï¼? + 7ã€æ€»çº¿é‡Šæ”¾SCL并传输数æ®ï¼ˆä¸?对应ï¼? + 8ã€MASTER 通过RESTART æˆ?STOP ç»§ç»­æ“作总线 +*/ +/******************************************************************************* + @ Module : I2C Slave å•字节接æ”? + @ Description : NULL +*******************************************************************************/ +/* + 1ã€IIC MASTER å¯»å€ + 2ã€IIC SLAVE ACK + 3ã€receives the transmitted byte and places it in the receive buffer + 如果RX FIFOå·²ç»æ»¡äº†ï¼Œå†æ¥æ•°æ®çš„æ—¶å€™ï¼Œå°†ä¼šè§¦å‘R_RX_OVERä¸­æ–­ï¼ŒäºŽæ­¤åŒæ—¶ï¼Œ + IICæ•°æ®å°†ä¼šç»§ç»­ä¼ è¾“(没有NACKä¿¡å·ï¼‰ï¼Œå¹¶æ— æ³•ä¿è¯åŽç»­æ•°æ®çš„完整 + 4ã€RX_FULL 中断 + 5ã€ä»ŽIC_DATA_CMD ä¸­è¯»å–æ•°æ? + 6ã€MASTER 通过RESTART æˆ?STOP ç»§ç»­æ“作总线 +*/ + diff --git a/src/components/driver/i2c/i2c_slave.h b/src/components/driver/i2c/i2c_slave.h new file mode 100644 index 0000000..5afdc9b --- /dev/null +++ b/src/components/driver/i2c/i2c_slave.h @@ -0,0 +1,64 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file i2c_slave.h + @brief i2c slave Configuration,API... + @version 1.0 + +*******************************************************************************/ + +#ifndef __I2C_SLAVE_H__ +#define __I2C_SLAVE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +/******************************************************************************* + @ Module : Includes + @ Description : NULL +*******************************************************************************/ +#include "types.h" +#include "i2c_common.h" + +/******************************************************************************* + @ Module : I2C Slave Paramter structure + @ Description : None +*******************************************************************************/ +typedef struct +{ + // General + uint8_t id; // set + I2C_WorkMode workmode; // init some Para ,according to workmode + I2C_ADDRESS_e AddressMode; + uint8_t RX_FIFO_Len; // RX , TX FIFO SET + uint8_t Tx_FIFO_Len; + gpio_pin_e SDA_PIN; // I2C Pin + gpio_pin_e SCL_PIN; + uint32_t IRQ_Source; + uint8_t Slave_Address; // SAR,when as Slave + I2C_Hdl_t evt_handler; +} I2C_Slave_Parameter; + + +/******************************************************************************* + @ Module : Function Statement + @ Description : NULL +*******************************************************************************/ +uint8_t Hal_I2C_Slave_Init(I2C_Slave_Parameter* para,uint8_t* handle); +uint8_t Hal_I2c_Slave_Open(uint8_t handle); +void Hal_I2c_Slave_Close(uint8_t handle); +uint8_t Hal_I2C_Slave_Deinit(uint8_t* handle); +uint8_t Hal_Check_I2C_Slave_Closed(uint8_t handle); +void Hal_I2C_Slave_ReadRX_FIFO(uint8_t handle,uint8_t* p,uint8_t len); +void Hal_I2C_Slave_CLR_IRQs(uint8_t handle,uint32_t irqs); +void Hal_I2C_Slave_WriteTX_FIFO(uint8_t handle,uint8_t* p,uint8_t len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/components/driver/key/key.c b/src/components/driver/key/key.c new file mode 100644 index 0000000..eccf229 --- /dev/null +++ b/src/components/driver/key/key.c @@ -0,0 +1,202 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************** + + + Module Name: key + File name: key.c + Brief description: + key driver module + Data: 2020-06-30 + Revision:V0.01 +****************************************************************/ +#include "rom_sym_def.h" +#include "key.h" +#include "log.h" +#include "OSAL.h" +#include "pwrmgr.h" +#include "error.h" + +key_contex_t key_state; + +extern uint32 getMcuPrecisionCount(void); + +static int key_timer_start(uint32 intval_ms) +{ + osal_start_timerEx(key_state.task_id, HAL_KEY_EVENT, intval_ms); + return 0; +} + +static void key_idle_handler(uint8 i,IO_Wakeup_Pol_e type) +{ + if(((type == NEGEDGE) && (key_state.key[i].idle_level == HAL_HIGH_IDLE)) || + ((type == POSEDGE) && (key_state.key[i].idle_level == HAL_LOW_IDLE))) + { + hal_pwrmgr_lock(MOD_USR1); + key_state.key[i].state = HAL_STATE_KEY_PRESS_DEBOUNCE; + key_state.temp[i].in_enable = TRUE; + key_timer_start(HAL_KEY_DEBOUNCD); + } +} + +static void key_press_debonce_handler(uint8 i,IO_Wakeup_Pol_e type) +{ + if(((type == NEGEDGE) && (key_state.key[i].idle_level == HAL_HIGH_IDLE)) || + ((type == POSEDGE) && (key_state.key[i].idle_level == HAL_LOW_IDLE))) + { + key_timer_start(HAL_KEY_DEBOUNCD); + } +} + +static void key_press_handler(uint8 i,IO_Wakeup_Pol_e type) +{ + if(((type == POSEDGE) && (key_state.key[i].idle_level == HAL_HIGH_IDLE)) || + ((type == NEGEDGE) && (key_state.key[i].idle_level == HAL_LOW_IDLE))) + { + hal_pwrmgr_lock(MOD_USR1); + key_state.key[i].state = HAL_STATE_KEY_RELEASE_DEBOUNCE; + key_timer_start(HAL_KEY_DEBOUNCD); + } +} + +static void key_release_debonce_handler(uint8 i,IO_Wakeup_Pol_e type) +{ + if(((type == POSEDGE) && (key_state.key[i].idle_level == HAL_HIGH_IDLE)) || + ((type == NEGEDGE) && (key_state.key[i].idle_level == HAL_LOW_IDLE))) + { + key_timer_start(HAL_KEY_DEBOUNCD); + } +} + +static void pin_event_handler(gpio_pin_e pin,IO_Wakeup_Pol_e type) +{ + uint8 i; + + for(i = 0; i < HAL_KEY_NUM; i++) + { + if(pin == key_state.key[i].pin) + break; + } + + if(i < HAL_KEY_NUM) + { + switch(key_state.key[i].state) + { + case HAL_STATE_KEY_IDLE: + key_idle_handler(i,type); + break; + + case HAL_STATE_KEY_PRESS_DEBOUNCE: + key_press_debonce_handler(i,type); + break; + + case HAL_STATE_KEY_PRESS: + key_press_handler(i,type); + break; + + case HAL_STATE_KEY_RELEASE_DEBOUNCE: + key_release_debonce_handler(i,type); + break; + + default: + break; + } + } +} + +void key_init(void) +{ + uint8 i; + + for(i = 0; i < HAL_KEY_NUM; ++i) + { + if(key_state.key[i].idle_level == HAL_LOW_IDLE) + { + hal_gpio_pull_set(key_state.key[i].pin,PULL_DOWN); + } + else + { + hal_gpio_pull_set(key_state.key[i].pin,WEAK_PULL_UP); + } + + key_state.temp[i].timer_tick = 0; + hal_gpioin_register(key_state.key[i].pin, pin_event_handler, pin_event_handler); + } + + hal_pwrmgr_register(MOD_USR1, NULL, NULL); +} + +static void key_press_debonce_timer_handler(uint8 i) +{ + if(((hal_gpio_read(key_state.key[i].pin) == FALSE) && (key_state.key[i].idle_level == HAL_HIGH_IDLE)) || + ((hal_gpio_read(key_state.key[i].pin) == TRUE) && (key_state.key[i].idle_level == HAL_LOW_IDLE))) + { + #ifdef HAL_KEY_SUPPORT_LONG_PRESS + osal_start_timerEx(key_state.task_id,KEY_DEMO_LONG_PRESS_EVT,HAL_KEY_LONG_PRESS_TIME); + #endif + hal_pwrmgr_unlock(MOD_USR1); + key_state.key[i].state = HAL_STATE_KEY_PRESS; + key_state.temp[i].timer_tick = getMcuPrecisionCount(); + + if(key_state.key_callbank != NULL) + { + key_state.key_callbank(i,HAL_KEY_EVT_PRESS); + } + } + else + { + key_state.key[i].state = HAL_STATE_KEY_IDLE; + key_state.temp[i].in_enable = FALSE; + } +} + +static void key_release_debonce_timer_handler(uint8 i) +{ + if(key_state.key[i].idle_level == hal_gpio_read(key_state.key[i].pin)) + { + osal_stop_timerEx(key_state.task_id,HAL_KEY_EVT_LONG_PRESS); + uint32_t hold_tick = (getMcuPrecisionCount() - key_state.temp[i].timer_tick)*625; + hal_pwrmgr_unlock(MOD_USR1); + + if(key_state.key_callbank != NULL) + { + #ifdef HAL_KEY_SUPPORT_LONG_PRESS + + if(hold_tick >= (HAL_KEY_LONG_PRESS_TIME * 1000))//2s + { + key_state.key_callbank(i,HAL_KEY_EVT_LONG_RELEASE); + key_state.key[i].state = HAL_STATE_KEY_IDLE; + } + else + #endif + { + key_state.key_callbank(i,HAL_KEY_EVT_RELEASE); + key_state.key[i].state = HAL_STATE_KEY_IDLE; + } + } + } + else + { + key_state.key[i].state = HAL_STATE_KEY_PRESS; + } +} + +void gpio_key_timer_handler(uint8 i) +{ + switch(key_state.key[i].state) + { + case HAL_STATE_KEY_PRESS_DEBOUNCE: + key_press_debonce_timer_handler(i); + break; + + case HAL_STATE_KEY_RELEASE_DEBOUNCE: + key_release_debonce_timer_handler(i); + break; + + default: + break; + } +} + diff --git a/src/components/driver/key/key.h b/src/components/driver/key/key.h new file mode 100644 index 0000000..f71cab2 --- /dev/null +++ b/src/components/driver/key/key.h @@ -0,0 +1,97 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ +/************************************************************** + + + Module Name: key + File name: key.h + Brief description: + key driver module + Data: 2020-06-30 + Revision:V0.01 +****************************************************************/ + +#ifndef __KEY_H__ +#define __KEY_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +#include "types.h" +#include "gpio.h" + +#define HAL_KEY_NUM 1 //config key's number +#define HAL_KEY_EVENT 0x4000 //assign short key event in your app event process + +#define HAL_KEY_SUPPORT_LONG_PRESS //if use long key,please enable it +#ifdef HAL_KEY_SUPPORT_LONG_PRESS +#define KEY_DEMO_LONG_PRESS_EVT 0x8000 //if use long key,assign long key event in your app process +#define HAL_KEY_LONG_PRESS_TIME 3000 //2s +#endif + +#define HAL_KEY_DEBOUNCD 20 //20ms + +typedef enum +{ + HAL_STATE_KEY_IDLE = 0x00, + HAL_STATE_KEY_PRESS_DEBOUNCE = 0x01, + HAL_STATE_KEY_PRESS = 0x02, + HAL_STATE_KEY_RELEASE_DEBOUNCE = 0x03, +} key_state_e; + +typedef enum +{ + HAL_KEY_EVT_IDLE = 0x0000, + HAL_KEY_EVT_PRESS = 0x0002, + HAL_KEY_EVT_RELEASE = 0x0004, + HAL_KEY_EVT_LONG_PRESS = 0x0010, + HAL_KEY_EVT_LONG_RELEASE = 0x0020, +} key_evt_t; + +typedef enum +{ + HAL_LOW_IDLE = 0x00, + HAL_HIGH_IDLE = 0x01, +} idle_level_e; + +typedef void (* key_callbank_hdl_t)(uint8_t,key_evt_t); + +typedef struct gpio_key_t +{ + gpio_pin_e pin; + key_state_e state; + idle_level_e idle_level; + +} gpio_key; + +typedef struct gpio_internal_t +{ + uint32_t timer_tick; + bool in_enable; + +} gpio_internal; + +typedef struct key_state +{ + gpio_key key[HAL_KEY_NUM]; + gpio_internal temp[HAL_KEY_NUM]; + uint8_t task_id; + key_callbank_hdl_t key_callbank; + +} key_contex_t; + + +void key_init(void); +void gpio_key_timer_handler(uint8 index); +extern key_contex_t key_state; + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/src/components/driver/kscan/kscan.c b/src/components/driver/kscan/kscan.c new file mode 100644 index 0000000..93e37fc --- /dev/null +++ b/src/components/driver/kscan/kscan.c @@ -0,0 +1,407 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file kscan.c + @brief Contains all functions support for key scan driver + @version 0.0 + @date 13. Nov. 2017 + @author Ding + + + +*******************************************************************************/ +#include "rom_sym_def.h" +#include +#include "clock.h" +#include "OSAL.h" +#include "kscan.h" +#include "pwrmgr.h" +#include "error.h" +#include "gpio.h" +#include "uart.h" +#include "bus_dev.h" +#include "log.h" +#include "jump_function.h" +typedef struct +{ + bool enable; + kscan_Cfg_t cfg; + uint16_t key_state[MULTI_KEY_NUM<<1]; + uint8_t pin_state[NUM_KEY_ROWS]; + uint8_t kscan_task_id; + uint16_t timeout_event; +} kscan_Ctx_t; + +static kscan_Ctx_t m_kscanCtx; +static kscan_Key_t m_keys[MAX_KEY_NUM]; + +static uint8_t reScan_flag=0; + + +//PRIVATE FUNCTIONS +static void kscan_hw_config(void); +static void hal_kscan_config_row(KSCAN_ROWS_e row); +static void hal_kscan_config_col(KSCAN_COLS_e col); +static void kscan_sleep_handler(void); +static void kscan_wakeup_handler(void); +static void get_key_matrix(uint16_t* key_matrix); +static void rmv_ghost_key(uint16_t* key_matrix); +static kscan_Evt_t kscan_compare_key(uint16_t* key_pre, uint16_t* key_nxt); +static void hal_kscan_clear_config(void); +extern void hal_gpioin_set_flag(gpio_pin_e pin); + +#define TIMEOUT_DELTA 10 +/************************************************************************************** + @fn hal_kscan_init + + @brief This function process for key scan initial + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +int hal_kscan_init(kscan_Cfg_t cfg, uint8 task_id, uint16 event) +{ + if(m_kscanCtx.enable) + return PPlus_ERR_INVALID_STATE; + + m_kscanCtx.cfg = cfg; + m_kscanCtx.kscan_task_id = task_id; + m_kscanCtx.timeout_event = event; + m_kscanCtx.enable = TRUE; + kscan_hw_config(); + JUMP_FUNCTION(KSCAN_IRQ_HANDLER) = (uint32_t)&hal_KSCAN_IRQHandler; + hal_pwrmgr_register(MOD_KSCAN, kscan_sleep_handler, kscan_wakeup_handler); + return PPlus_SUCCESS; +} + +/************************************************************************************** + @fn hal_kscan_clear_config + + @brief This function process for key scan clear config + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +void hal_kscan_clear_config() +{ + subWriteReg(&(AP_IOMUX->keyscan_in_en),10,0,0);//iomux:key_scan_in_en and key_scan_out_en + subWriteReg(&(AP_IOMUX->keyscan_out_en),11,0,0); + subWriteReg((&AP_KSCAN->ctrl0), 13, 2, 0);//kscan:mattrix scan outputs and mattrix scan inputs + subWriteReg((&AP_KSCAN->mk_in_en), 10, 0, 0); +} + + +void __attribute__((used)) hal_KSCAN_IRQHandler() +{ + uint16_t key_nxt[MULTI_KEY_NUM<<1]; + + if(reScan_flag==1) + reScan_flag=0; + + osal_stop_timerEx(m_kscanCtx.kscan_task_id, m_kscanCtx.timeout_event);//todo + get_key_matrix(key_nxt); + + if(m_kscanCtx.cfg.ghost_key_state == IGNORE_GHOST_KEY) + rmv_ghost_key(key_nxt); + + if(m_kscanCtx.cfg.evt_handler) + { + kscan_Evt_t evt = kscan_compare_key(m_kscanCtx.key_state, key_nxt); + + if(evt.num>0) + m_kscanCtx.cfg.evt_handler(&evt); + } + + memcpy(m_kscanCtx.key_state, key_nxt, sizeof(uint16_t)*(MULTI_KEY_NUM<<1)); + osal_start_timerEx(m_kscanCtx.kscan_task_id, m_kscanCtx.timeout_event, (2*m_kscanCtx.cfg.interval+TIMEOUT_DELTA));//todo +} + +void hal_kscan_timeout_handler() +{ + if(reScan_flag==0) + { + // LOG("kscan_reScan\n\r"); + hal_kscan_clear_config(); + reScan_flag=1; + kscan_hw_config(); + osal_start_timerEx(m_kscanCtx.kscan_task_id, m_kscanCtx.timeout_event, m_kscanCtx.cfg.interval+TIMEOUT_DELTA); + } + else if(reScan_flag==1) + { + //LOG("kscan_timeout_handler\n\r"); + osal_stop_timerEx(m_kscanCtx.kscan_task_id, m_kscanCtx.timeout_event); + uint16_t key_nxt[MULTI_KEY_NUM<<1]; + memset(&key_nxt[0],0,sizeof(uint16_t)*(MULTI_KEY_NUM<<1)); //all register must be 0.teedy add 2019/01/23 + + //get_key_matrix(key_nxt); //no need to read the register,because keyScan didn't update the register .teedy add 2019/01/23 + + if(m_kscanCtx.cfg.ghost_key_state == IGNORE_GHOST_KEY) + rmv_ghost_key(key_nxt); + + if(m_kscanCtx.cfg.evt_handler) + { + kscan_Evt_t evt = kscan_compare_key(m_kscanCtx.key_state, key_nxt); + m_kscanCtx.cfg.evt_handler(&evt); + } + + memcpy(m_kscanCtx.key_state, key_nxt, sizeof(uint16_t)*(MULTI_KEY_NUM<<1)); + reScan_flag=0; + hal_pwrmgr_unlock(MOD_KSCAN); + } +} + +static void kscan_hw_config(void) +{ + kscan_Cfg_t* cfg = &(m_kscanCtx.cfg); + hal_clk_gate_enable(MOD_KSCAN); + hal_kscan_clear_config(); + + for(uint8_t i=0; ikey_rows[i]); + + for(uint8_t i=0; ikey_cols[i]); + + subWriteReg((&AP_KSCAN->ctrl0),20,20,NOT_IGNORE_MULTI_KEY); + subWriteReg((&AP_KSCAN->ctrl0),23,23,SENCE_LOW);//SENCE_HIGH + subWriteReg((&AP_KSCAN->ctrl0),31,24,cfg->interval); + NVIC_SetPriority((IRQn_Type)KSCAN_IRQn, IRQ_PRIO_HAL); + NVIC_EnableIRQ((IRQn_Type)KSCAN_IRQn); + subWriteReg((&AP_KSCAN->ctrl0),1,1,1);//kscan int enable + subWriteReg((&AP_KSCAN->ctrl0),0,0,1);//kscan enable +} + +/************************************************************************************** + @fn hal_kscan_config_row + + @brief This function process for setting key row pin + + input parameters + + @param KSCAN_ROWS_e row + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +static void hal_kscan_config_row(KSCAN_ROWS_e row) +{ + gpio_pin_e row_pin = (gpio_pin_e)KSCAN_ROW_GPIO[row]; + hal_gpio_fmux(row_pin, Bit_DISABLE); + hal_gpio_pull_set(row_pin,GPIO_PULL_UP_S); + subWriteReg(&(AP_IOMUX->keyscan_in_en),row,row,1); + subWriteReg((&AP_KSCAN->mk_in_en),row,row, 1); +} + +/************************************************************************************** + @fn hal_kscan_config_col + + @brief This function process for setting key scan col pin + + input parameters + + @param KSCAN_COLS_e col + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +static void hal_kscan_config_col(KSCAN_COLS_e col) +{ + gpio_pin_e col_pin = (gpio_pin_e)KSCAN_COL_GPIO[col]; + hal_gpio_fmux(col_pin, Bit_DISABLE); + hal_gpio_pull_set(col_pin,GPIO_PULL_UP_S); + subWriteReg(&(AP_IOMUX->keyscan_out_en),col,col,1); + subWriteReg((&AP_KSCAN->ctrl0),(col+2),(col+2), 1); +} + +static void kscan_sleep_handler(void) +{ + gpio_polarity_e pol; + hal_kscan_clear_config(); + + for(uint8_t i=0; ikeyscan_out_en),m_kscanCtx.cfg.key_cols[i],m_kscanCtx.cfg.key_cols[i],0); + hal_gpioin_set_flag(col_pin); + hal_gpio_pull_set(col_pin, GPIO_PULL_DOWN); + hal_gpio_pin_init(col_pin, GPIO_INPUT); + } + + for(uint8_t i=0; ikeyscan_in_en),m_kscanCtx.cfg.key_rows[i],m_kscanCtx.cfg.key_rows[i],0); + hal_gpioin_set_flag(row_pin); + hal_gpio_pull_set(row_pin, GPIO_PULL_UP); + hal_gpio_pin_init(row_pin, GPIO_INPUT); + pol = hal_gpio_read(row_pin) ? POL_FALLING:POL_RISING; + hal_gpio_wakeup_set(row_pin, pol); + m_kscanCtx.pin_state[i] = pol; + } +} + +static void kscan_wakeup_handler(void) +{ + for(uint8_t i=0; ikeyscan_out_en),m_kscanCtx.cfg.key_cols[i],m_kscanCtx.cfg.key_cols[i],0); + hal_gpio_pull_set(col_pin, GPIO_PULL_DOWN); + hal_gpio_pin_init(col_pin, GPIO_INPUT); + } + + for(uint8_t i=0; ikeyscan_in_en),m_kscanCtx.cfg.key_rows[i],m_kscanCtx.cfg.key_rows[i],0); + hal_gpio_pull_set(row_pin, GPIO_PULL_UP);//teddy add 20190122 + hal_gpio_pin_init(row_pin, GPIO_INPUT); + } + + for(uint8_t i=0; imkc[i])) & 0x0000FFFF); + uint16_t high = (read_reg(&(AP_KSCAN->mkc[i])) & 0xFFFF0000) >> 16; + key_matrix[i*2] = low; + key_matrix[i*2+1] = high; + } +} + +/************************************************************************************** + @fn rmv_ghost_key + + @brief This function process for removing ghost key + + input parameters + + @param uint16_t* key_matrix + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +static void rmv_ghost_key(uint16_t* key_matrix) +{ + uint16_t mix_final = 0; + + for (uint8_t i=0; imkc[0]))//0x400240CCUL +//#define MULTI_KEY_READ_ADDR 0x4000d0CCUL//0x400240CCUL + + +const static uint8_t KSCAN_ROW_GPIO[11] = +{ + P0, + P2, + P15, + P25, + P10, + P18, + P23, + P32, + P34, + P27, + P7, +}; + +const static uint8_t KSCAN_COL_GPIO[12] = +{ + P1, + P3, + P14, + P24, + P9, + P20, + P33, + P31, + P26, + P17, + P16, + P11, +}; + +#define NUM_KEY_ROWS 4 +#define NUM_KEY_COLS 4 +#define MAX_KEY_NUM 10 +#define MAX_KEY_ROWS (sizeof(KSCAN_ROW_GPIO)/sizeof(uint8_t)) +#define MAX_KEY_COLS (sizeof(KSCAN_COL_GPIO)/sizeof(uint8_t)) + +#define KSCAN_ALL_ROW_NUM 11 +#define KSCAN_ALL_COL_NUM 12 +/************************************************************* + @brief enum variable used for setting rows + +*/ +typedef enum +{ + KEY_ROW_P00 = 0, + KEY_ROW_P02 = 1, + KEY_ROW_P15 = 2, + KEY_ROW_P25 = 3, + KEY_ROW_P10 = 4, + KEY_ROW_P18 = 5, + KEY_ROW_P23 = 6, + KEY_ROW_P32 = 7, + KEY_ROW_P34 = 8, + KEY_ROW_P27 = 9, + KEY_ROW_P07 = 10, + +} KSCAN_ROWS_e; + +/************************************************************* + @brief enum variable used for setting cols + +*/ +typedef enum +{ + KEY_COL_P01 = 0, + KEY_COL_P03 = 1, + KEY_COL_P14 = 2, + KEY_COL_P24 = 3, + KEY_COL_P09 = 4, + KEY_COL_P20 = 5, + KEY_COL_P33 = 6, + KEY_COL_P31 = 7, + KEY_COL_P26 = 8, + //KEY_COL_P17 = 9, + //KEY_COL_P16 = 10, + KEY_COL_P11 = 11, + +} KSCAN_COLS_e; + +/************************************************************* + @brief enum variable used for setting multiple key press + +*/ +typedef enum +{ + + NOT_IGNORE_MULTI_KEY = 0, + IGNORE_MULTI_KEY = 1 + +} KSCAN_MULTI_KEY_STATE_e; + +/************************************************************* + @brief enum variable used for setting whether ignore ghost key + +*/ +typedef enum +{ + + NOT_IGNORE_GHOST_KEY = 0, + IGNORE_GHOST_KEY = 1 + +} KSCAN_GHOST_KEY_STATE_e; + +/************************************************************* + @brief enum variable used for setting key press sense type + +*/ +typedef enum +{ + + SENCE_HIGH = 0, + SENCE_LOW = 1 + +} KSCAN_POLARITY_e; + +/************************************************************* + @brief enum variable used for setting key press sense type + +*/ +typedef enum +{ + + NO_KEY_PRESS = 0x00, + ONE_KEY_PRESS = 0x01, + MULTI_KEY_PRESS = 0x02 + +} KSCAN_KEY_PRESS_STATE_e; + +typedef enum +{ + KEY_RELEASED = 0, + KEY_PRESSED, +} kscan_Evt_Type_t; + +typedef struct +{ + uint8_t row; + uint8_t col; + kscan_Evt_Type_t type; +} kscan_Key_t; + +typedef struct kscan_Evt_t_ +{ + uint8_t num; + kscan_Key_t* keys; +} kscan_Evt_t; + +typedef void (*kscan_Hdl_t)(kscan_Evt_t* pev); + +typedef struct +{ + KSCAN_GHOST_KEY_STATE_e ghost_key_state; + KSCAN_ROWS_e* key_rows; + KSCAN_COLS_e* key_cols; + kscan_Hdl_t evt_handler; + uint8_t interval; +} kscan_Cfg_t; + + + +//PUBLIC FUNCTIONS +int hal_kscan_init(kscan_Cfg_t cfg, uint8 task_id, uint16 event); +void hal_kscan_timeout_handler(void); +void __attribute__((weak)) hal_KSCAN_IRQHandler(void); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/src/components/driver/led_light/led_light.c b/src/components/driver/led_light/led_light.c new file mode 100644 index 0000000..229d9bc --- /dev/null +++ b/src/components/driver/led_light/led_light.c @@ -0,0 +1,256 @@ + +#include "led_light.h" +#include "pwm.h" +#include "OSAL.h" +#include "gpio.h" +#include "error.h" + +static uint16_t s_light[3]; +static light_blink_cfg_t s_lightBlink; + +static pwm_ch_t pwm_ch[3]; +static gpio_pin_e* led_pin_ptr = NULL; +static uint16_t led_pin_num = 0; + +static void light_start_timer(void) +{ + //osal_start_timerEx(AppWrist_TaskID, TIMER_LIGHT_EVT, 30*1000); +} +static void light_stop_timer(void) +{ + //osal_stop_timerEx(AppWrist_TaskID, TIMER_LIGHT_EVT); +} + +void light_reflash(void) +{ + pwm_ch[0].cmpVal = s_light[0]; + pwm_ch[1].cmpVal = s_light[1]; + pwm_ch[2].cmpVal = s_light[2]; + hal_pwm_ch_start(pwm_ch[0]); + hal_pwm_ch_start(pwm_ch[1]); + hal_pwm_ch_start(pwm_ch[2]); + + if(s_light[LIGHT_RED] + s_light[LIGHT_GREEN] + s_light[LIGHT_BLUE]) + { + light_stop_timer(); + light_start_timer(); + } + else + { + light_stop_timer(); + } +} + +void light_timeout_handle(void) +{ +// s_light[0] = 0; +// s_light[1] = 0; +// s_light[2] = 0; +// hal_pwm_close_channel(PWM_CH0); +// hal_pwm_destroy(PWM_CH0); +// hal_pwm_close_channel(PWM_CH1); +// hal_pwm_destroy(PWM_CH1); +// hal_pwm_close_channel(PWM_CH2); +// hal_pwm_destroy(PWM_CH2); +// hal_pwm_stop(); +// hal_gpio_pin_init(GPIO_GREEN, IE); +// hal_gpio_pin_init(GPIO_RED, IE); +// hal_gpio_pin_init(GPIO_BLUE, IE); +// hal_gpio_pull_set(GPIO_GREEN, WEAK_PULL_UP); +// hal_gpio_pull_set(GPIO_RED, WEAK_PULL_UP); +// hal_gpio_pull_set(GPIO_BLUE, WEAK_PULL_UP); +} + +int light_config(uint8_t ch, uint16_t value) +{ + if(ch >2 || (value > LIGHT_TOP_VALUE)) + { + return PPlus_ERR_INVALID_PARAM; + } + + s_light[ch] = (uint16_t)value; + return PPlus_SUCCESS; +} + +int light_ctrl(uint8_t ch, uint16_t value) +{ + if(ch >2 || (value > LIGHT_TOP_VALUE)) + { + return PPlus_ERR_INVALID_PARAM; + } + + s_light[ch] = (uint16_t)value; + light_reflash(); + return PPlus_SUCCESS; +} + +static void led_init(gpio_pin_e* pin_ptr,uint16_t pin_num) +{ + gpio_pin_e pin; + + for(int i = 0; i < pin_num; i++) + { + pin = *(pin_ptr + i); + hal_gpio_pin_init(pin,IE); + hal_gpio_pull_set(pin,WEAK_PULL_UP); + } +} + +int light_init(gpio_pin_e* pin_ptr,uint16_t pin_num) +{ + if((pin_ptr == NULL) || (pin_num == 0)) + { + return PPlus_ERR_INVALID_PARAM; + } + else + { + led_pin_ptr = pin_ptr; + led_pin_num = pin_num; + } + + led_init(led_pin_ptr,led_pin_num); + s_light[LIGHT_GREEN] = 0; + s_light[LIGHT_BLUE] = 0; + s_light[LIGHT_RED] = 0; + osal_memset(&s_lightBlink, 0, sizeof(s_lightBlink)); + s_lightBlink.val0 = LIGHT_TURN_OFF; + s_lightBlink.val1 = LIGHT_TURN_ON; + light_pwm_init(); + return PPlus_SUCCESS; +} + +void light_pwm_init(void) +{ + hal_pwm_module_init(); + + for(int i = 0; i < sizeof(pwm_ch)/sizeof(pwm_ch[0]); i++) + { + pwm_ch[i].pwmN = (PWMN_e)(PWM_CH0 + (PWMN_e)i); + pwm_ch[i].pwmPin = GPIO_DUMMY; + pwm_ch[i].pwmDiv = PWM_CLK_NO_DIV; + pwm_ch[i].pwmMode = PWM_CNT_UP; + pwm_ch[i].pwmPolarity = PWM_POLARITY_RISING; + pwm_ch[i].cmpVal = 0; + pwm_ch[i].cntTopVal = LIGHT_TOP_VALUE; + } + + pwm_ch[0].pwmPin = *(led_pin_ptr + 0); + pwm_ch[1].pwmPin = *(led_pin_ptr + 1); + pwm_ch[2].pwmPin = *(led_pin_ptr + 2); +} + +void light_pwm_deinit(void) +{ + hal_pwm_ch_stop(pwm_ch[0]); + hal_pwm_ch_stop(pwm_ch[1]); + hal_pwm_ch_stop(pwm_ch[2]); + hal_pwm_module_deinit(); +} + +int light_blink_evt_cfg(uint8_t task_id,uint16_t event_id) +{ + if(s_lightBlink.status == 0) + { + s_lightBlink.task_id = task_id; + s_lightBlink.event_id = event_id; + return PPlus_SUCCESS; + } + else + { + return PPlus_ERR_BUSY; + } +} +int light_blink_set(uint8_t light,uint8 blinkIntv,uint8 blinkCnt) +{ + if(s_lightBlink.status == 0) + { + s_lightBlink.light = light; + s_lightBlink.tagCnt = blinkCnt; + s_lightBlink.intv = blinkIntv; + s_lightBlink.status = 1; + + if(s_lightBlink.task_id > 0 && s_lightBlink.event_id > 0) + { + light_ctrl(LIGHT_RED,0); + light_ctrl(LIGHT_GREEN,0); + light_ctrl(LIGHT_BLUE,0); + s_lightBlink.curCnt = 0; + osal_set_event(s_lightBlink.task_id, s_lightBlink.event_id); + } + else + { + return PPlus_ERR_NOT_FOUND; + } + + return PPlus_SUCCESS; + } + else + { + return PPlus_ERR_BUSY; + } +} +void light_blink_porcess_evt(void) +{ + if(s_lightBlink.curCnt == (s_lightBlink.tagCnt*2) ) + { + light_ctrl(LIGHT_RED,0); + light_ctrl(LIGHT_GREEN,0); + light_ctrl(LIGHT_BLUE,0); + osal_stop_timerEx( s_lightBlink.task_id, s_lightBlink.event_id); + s_lightBlink.status = 0; + } + else + { + if(s_lightBlink.curCnt&0x01) + { + light_ctrl(s_lightBlink.light,s_lightBlink.val1); + } + else + { + light_ctrl(s_lightBlink.light,s_lightBlink.val0); + } + + s_lightBlink.curCnt++; + osal_start_timerEx(s_lightBlink.task_id, s_lightBlink.event_id,s_lightBlink.intv*100); + } +} +void light_color_quickSet(light_color_t color) +{ + switch ( color ) + { + case LIGHT_COLOR_OFF: + LIGHT_ON_OFF(0,0,0); + break; + + case LIGHT_COLOR_RED: + LIGHT_ONLY_RED_ON; + break; + + case LIGHT_COLOR_GREEN: + LIGHT_ONLY_GREEN_ON; + break; + + case LIGHT_COLOR_BLUE: + LIGHT_ONLY_BLUE_ON; + break; + + case LIGHT_COLOR_CYAN: + LIGHT_ON_CYAN; + break; + + case LIGHT_COLOR_YELLOW: + LIGHT_ON_YELLOW; + break; + + case LIGHT_COLOR_MEGENTA: + LIGHT_ON_MEGENTA; + break; + + case LIGHT_COLOR_WHITE: + LIGHT_ON_WHITE; + break; + + default: + break; + } +} diff --git a/src/components/driver/led_light/led_light.h b/src/components/driver/led_light/led_light.h new file mode 100644 index 0000000..aa1620d --- /dev/null +++ b/src/components/driver/led_light/led_light.h @@ -0,0 +1,137 @@ + +#ifndef _LED_LIGHT_H +#define _LED_LIGHT_H + +#include "types.h" +#include "gpio.h" + +#define LIGHT_TOP_VALUE 256 +#define LIGHT_TURN_ON (LIGHT_TOP_VALUE-1) +#define LIGHT_TURN_OFF 0 + + +#define LIGHT_BLINK_EXTRA_FAST 1 +#define LIGHT_BLINK_FAST 3 +#define LIGHT_BLINK_SLOW 10 +#define LIGHT_BLINK_EXTRA_SLOW 30 + + +#define LIGHT_GREEN 0 +#define LIGHT_BLUE 1 +#define LIGHT_RED 2 + +typedef struct +{ + uint8_t light; + uint8_t curCnt; + uint8_t tagCnt; + uint8_t intv; + uint16_t val0; + uint16_t val1; + uint8_t status; + uint8_t task_id; + uint16_t event_id; +} light_blink_cfg_t; + +typedef enum +{ + LIGHT_COLOR_OFF = 0, + LIGHT_COLOR_RED=1, + LIGHT_COLOR_GREEN, + LIGHT_COLOR_BLUE, + LIGHT_COLOR_CYAN, + LIGHT_COLOR_YELLOW, + LIGHT_COLOR_MEGENTA, + LIGHT_COLOR_WHITE, + LIGHT_COLOR_NUM +} light_color_t; +static light_blink_cfg_t s_lightBlink; + +void light_timeout_handle(void); +int light_ctrl(uint8_t ch, uint16_t value); + +int light_config(uint8_t ch, uint16_t value); +int light_init(gpio_pin_e* pin_ptr,uint16_t pin_num); +void light_pwm_init(void); +void light_pwm_deinit(void); +void light_reflash(void); +int light_blink_evt_cfg(uint8_t task_id,uint16_t event_id); +int light_blink_set(uint8_t light,uint8 blinkIntv,uint8 blinkCnt); +void light_blink_porcess_evt(void); +void light_color_quickSet(light_color_t color); + + +#define LIGHT_ONLY_RED_ON \ + { \ + light_config(LIGHT_RED ,LIGHT_TURN_ON);\ + light_config(LIGHT_GREEN ,LIGHT_TURN_OFF);\ + light_config(LIGHT_BLUE ,LIGHT_TURN_OFF);\ + light_reflash();\ + \ + } + +#define LIGHT_ONLY_GREEN_ON \ + { \ + light_config(LIGHT_RED ,LIGHT_TURN_OFF);\ + light_config(LIGHT_GREEN ,LIGHT_TURN_ON);\ + light_config(LIGHT_BLUE ,LIGHT_TURN_OFF);\ + light_reflash();\ + \ + } + +#define LIGHT_ONLY_BLUE_ON \ + { \ + light_config(LIGHT_RED ,LIGHT_TURN_OFF);\ + light_config(LIGHT_GREEN ,LIGHT_TURN_OFF);\ + light_config(LIGHT_BLUE ,LIGHT_TURN_ON);\ + light_reflash();\ + \ + } + +#define LIGHT_ON_OFF(r,g,b) \ + { \ + light_config(LIGHT_RED ,r);\ + light_config(LIGHT_GREEN ,g);\ + light_config(LIGHT_BLUE ,b);\ + light_reflash();\ + \ + } + +#define LIGHT_ON_CYAN \ + { \ + light_config(LIGHT_RED ,0);\ + light_config(LIGHT_GREEN ,255);\ + light_config(LIGHT_BLUE ,255);\ + light_reflash();\ + \ + } + +#define LIGHT_ON_YELLOW \ + { \ + light_config(LIGHT_RED ,255);\ + light_config(LIGHT_GREEN ,255);\ + light_config(LIGHT_BLUE ,0);\ + light_reflash();\ + \ + } + +#define LIGHT_ON_MEGENTA \ + { \ + light_config(LIGHT_RED ,255);\ + light_config(LIGHT_GREEN ,0);\ + light_config(LIGHT_BLUE ,255);\ + light_reflash();\ + \ + } + + +#define LIGHT_ON_WHITE \ + { \ + light_config(LIGHT_RED ,255);\ + light_config(LIGHT_GREEN ,255);\ + light_config(LIGHT_BLUE ,255);\ + light_reflash();\ + \ + } +#endif + diff --git a/src/components/driver/log/log.h b/src/components/driver/log/log.h new file mode 100644 index 0000000..8c32b3c --- /dev/null +++ b/src/components/driver/log/log.h @@ -0,0 +1,116 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file log.h + @brief Contains all functions support for uart driver + @version 0.0 + @date 31. Jan. 2018 + @author eagle.han + + + +*******************************************************************************/ +#ifndef ENABLE_LOG_ROM +#ifndef __LOG_H__ +#define __LOG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "uart.h" +void dbg_printf(const char* format, ...); +void dbg_printf_init(void); +void my_dump_byte(uint8_t* pData, int dlen); +#ifndef DEBUG_INFO +#error "DEBUG_INFO undefined!" +#endif +typedef void(*std_putc)(char* data, uint16_t size); + + +#if(DEBUG_INFO == 1) +#define AT_LOG(...) +#define LOG_DEBUG(...) +#define LOG(...) dbg_printf(__VA_ARGS__) +#define LOG_INIT() dbg_printf_init() +#define LOG_DUMP_BYTE(a,b) my_dump_byte(a,b) +#elif(DEBUG_INFO == 2) +#define AT_LOG(...) dbg_printf(__VA_ARGS__) +#define LOG_DEBUG(...) +#define LOG(...) dbg_printf(__VA_ARGS__) +#define LOG_INIT() dbg_printf_init() +#define LOG_DUMP_BYTE(a,b) my_dump_byte(a,b) +#elif(DEBUG_INFO == 3) +#define LOG(...) dbg_printf(__VA_ARGS__) +#define AT_LOG(...) dbg_printf(__VA_ARGS__) +#define LOG_DEBUG(...) dbg_printf(__VA_ARGS__) +#define LOG_INIT() dbg_printf_init() +#define LOG_DUMP_BYTE(a,b) my_dump_byte(a,b) +#else +#define AT_LOG(...) +#define LOG_DEBUG(...) +#define LOG(...) +#define LOG_INIT() //{clk_gate_enable(MOD_UART);clk_reset(MOD_UART);clk_gate_disable(MOD_UART);} +#define LOG_DUMP_BYTE(a,b) +#endif + +#ifdef __cplusplus +} +#endif + +#endif //__LOG_H__ + +#else + +#ifndef __PHY_LOG_H +#define __PHY_LOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "types.h" +#include "uart.h" +#include +#include + +#define LOG_LEVEL_NONE 0 //no log output*/ +#define LOG_LEVEL_ERROR 1 //only log error*/ +#define LOG_LEVEL_DEBUG 2 //output debug info and error info*/ +#define LOG_LEVEL_LOG 3 //output all infomation*/ + +#define LOG_INIT() {hal_uart_init(115200,P9,P10,NULL);} + +#if 0//DEBUG_FPGA +#define LOG(...) do{;}while(0); +#else + +//conditional output +#define LOG(...) {if(s_rom_debug_level == LOG_LEVEL_LOG) log_printf(__VA_ARGS__);} +#define LOG_DEBUG(...) {if(s_rom_debug_level >= LOG_LEVEL_DEBUG) log_printf(__VA_ARGS__);} +#define LOG_ERROR(...) {if(s_rom_debug_level >= LOG_LEVEL_ERROR) log_printf(__VA_ARGS__);} + +//tx data anyway +#define PRINT(...) {SWU_TX(); log_printf(__VA_ARGS__);} +#endif + +extern volatile uint32_t s_rom_debug_level; + +typedef void(*std_putc)(char* data, int size); + +void log_vsprintf(std_putc putc, const char* fmt, va_list args); +void log_printf(const char* format, ...); +void log_set_putc(std_putc putc); +void log_clr_putc(std_putc putc); +int log_debug_level(uint8_t level); +uint32_t log_get_debug_level(void); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif diff --git a/src/components/driver/log/my_printf.c b/src/components/driver/log/my_printf.c new file mode 100644 index 0000000..b7ad225 --- /dev/null +++ b/src/components/driver/log/my_printf.c @@ -0,0 +1,439 @@ + +#include "rom_sym_def.h" +#include "types.h" +#include +#include +#include "uart.h" +#include "log.h" + + + +#define ZEROPAD 1 // Pad with zero +#define SIGN 2 // Unsigned/signed long +#define PLUS 4 // Show plus +#define SPACE 8 // Space if plus +#define LEFT 16 // Left justified +#define SPECIAL 32 // 0x +#define LARGE 64 // Use 'ABCDEF' instead of 'abcdef' +#define is_digit(c) ((c) >= '0' && (c) <= '9') +static const char* digits = "0123456789abcdefghijklmnopqrstuvwxyz"; +static const char* upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + +static size_t _strnlen(const char* s, size_t count) +{ + const char* sc; + + for (sc = s; *sc != '\0' && count--; ++sc); + + return sc - s; +} +static int skip_atoi(const char** s) +{ + int i = 0; + + while (is_digit(**s)) i = i * 10 + *((*s)++) - '0'; + + return i; +} +static void number(std_putc putc, long num, int base, int size, int precision, int type) +{ + char c, sign, tmp[66]; + const char* dig = digits; + int i; + char tmpch; + + if (type & LARGE) dig = upper_digits; + + if (type & LEFT) type &= ~ZEROPAD; + + if (base < 2 || base > 36) return; + + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + + if (type & SIGN) + { + if (num < 0) + { + sign = '-'; + num = -num; + size--; + } + else if (type & PLUS) + { + sign = '+'; + size--; + } + else if (type & SPACE) + { + sign = ' '; + size--; + } + } + + if (type & SPECIAL) + { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + + i = 0; + + if (num == 0) + tmp[i++] = '0'; + else + { + while (num != 0) + { + tmp[i++] = dig[((unsigned long)num) % (unsigned)base]; + num = ((unsigned long)num) / (unsigned)base; + } + } + + if (i > precision) precision = i; + + size -= precision; + + if (!(type & (ZEROPAD | LEFT))) + { + while (size-- > 0) + { + tmpch = ' '; + putc(&tmpch, 1); + } + } + + if (sign) + { + putc(&sign, 1); + } + + if (type & SPECIAL) + { + if (base == 8) + { + tmpch = '0'; + putc(&tmpch, 1); + } + else if (base == 16) + { + tmpch = '0'; + putc(&tmpch, 1); + tmpch = digits[33]; + putc(&tmpch, 1); + } + } + + if (!(type & LEFT)) + { + while (size-- > 0) + { + putc(&c, 1); + } + } + + while (i < precision--) + { + tmpch = '0'; + putc(&tmpch, 1); + } + + while (i-- > 0) + { + tmpch = tmp[i]; + putc(&tmpch, 1); + } + + while (size-- > 0) + { + tmpch = ' '; + putc(&tmpch, 1); + } +} + + + +static void log_vsprintf(std_putc putc, const char* fmt, va_list args) +{ + int len; + unsigned long num; + int base; + char* s; + int flags; // Flags to number() + int field_width; // Width of output field + int precision; // Min. # of digits for integers; max number of chars for from string + int qualifier; // 'h', 'l', or 'L' for integer fields + char* tmpstr = NULL; + int tmpstr_size = 0; + char tmpch; + + for (; *fmt; fmt++) + { + if (*fmt != '%') + { + if (tmpstr == NULL) + { + tmpstr = (char*)fmt; + tmpstr_size = 0; + } + + tmpstr_size ++; + continue; + } + else if (tmpstr_size) + { + putc(tmpstr, tmpstr_size); + tmpstr = NULL; + tmpstr_size = 0; + } + + // Process flags + flags = 0; +repeat: + fmt++; // This also skips first '%' + + switch (*fmt) + { + case '-': + flags |= LEFT; + goto repeat; + + case '+': + flags |= PLUS; + goto repeat; + + case ' ': + flags |= SPACE; + goto repeat; + + case '#': + flags |= SPECIAL; + goto repeat; + + case '0': + flags |= ZEROPAD; + goto repeat; + } + + // Get field width + field_width = -1; + + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') + { + fmt++; + field_width = va_arg(args, int); + + if (field_width < 0) + { + field_width = -field_width; + flags |= LEFT; + } + } + + // Get the precision + precision = -1; + + if (*fmt == '.') + { + ++fmt; + + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') + { + ++fmt; + precision = va_arg(args, int); + } + + if (precision < 0) precision = 0; + } + + // Get the conversion qualifier + qualifier = -1; + + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') + { + qualifier = *fmt; + fmt++; + } + + // Default base + base = 10; + + switch (*fmt) + { + case 'c': + if (!(flags & LEFT)) + { + while (--field_width > 0) + { + tmpch = ' '; + putc(&tmpch, 1); + } + } + + tmpch = (unsigned char)va_arg(args, int); + putc(&tmpch, 1); + + while (--field_width > 0) + { + tmpch = ' '; + putc(&tmpch, 1); + } + + continue; + + case 's': + s = va_arg(args, char*); + + if (!s) + s = ""; + + len = _strnlen(s, precision); + + if (!(flags & LEFT)) + { + while (len < field_width--) + { + tmpch = ' '; + putc(&tmpch, 1); + } + } + + putc(s, len); + + while (len < field_width--) + { + tmpch = ' '; + putc(&tmpch, 1); + } + + continue; + + case 'p': + if (field_width == -1) + { + field_width = 2 * sizeof(void*); + flags |= ZEROPAD; + } + + number(putc,(unsigned long)va_arg(args, void*), 16, field_width, precision, flags); + continue; + + case 'n': + continue; + + case 'A': + continue; + + // Integer number formats - set up the flags and "break" + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + + case 'u': + break; + + default: + if (*fmt != '%') + { + tmpch = '%'; + putc(&tmpch, 1); + } + + if (*fmt) + { + tmpch = *fmt; + putc(&tmpch, 1); + } + else + { + --fmt; + } + + continue; + } + + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (qualifier == 'h') + { + if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + } + else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + + number(putc, num, base, field_width, precision, flags); + } + + if (tmpstr_size) + { + putc(tmpstr, tmpstr_size); + tmpstr = NULL; + tmpstr_size = 0; + } +} + +static void _uart_putc(char* data, uint16_t size) +{ + hal_uart_send_buff(UART0, (uint8_t*)data, size); +} + +void dbg_printf(const char* format, ...) +{ + va_list args; + va_start(args, format); + log_vsprintf(_uart_putc, format, args); + va_end(args); +} + +void dbg_printf_init(void) +{ + uart_Cfg_t cfg = + { + .tx_pin = P9, + .rx_pin = P10, + .rts_pin = GPIO_DUMMY, + .cts_pin = GPIO_DUMMY, + .baudrate = 115200, + .use_fifo = TRUE, + .hw_fwctrl = FALSE, + .use_tx_buf = FALSE, + .parity = FALSE, + .evt_handler = NULL, + }; + hal_uart_init(cfg, UART0);//uart init +} + +void my_dump_byte(uint8_t* pData, int dlen) +{ + for(int i=0; i cntTopVal) + return; + + PWM_NO_LOAD_CH(pwmN); + PWM_SET_CMP_VAL(pwmN, cmpVal); + PWM_SET_TOP_VAL(pwmN, cntTopVal); + PWM_LOAD_CH(pwmN); +} + +static unsigned int pwm_en = 0; +void hal_pwm_start(void) +{ + if(pwm_en == 0) + { + hal_pwrmgr_lock(MOD_PWM); + PWM_ENABLE_ALL; + pwm_en = 1; + } +} + +void hal_pwm_stop(void) +{ + if(pwm_en == 1) + { + hal_pwrmgr_unlock(MOD_PWM); + PWM_DISABLE_ALL; + pwm_en = 0; + hal_clk_gate_disable(MOD_PWM); + } +} + +//------------------------------------------------------------ +//new api,make use easily +typedef struct +{ + bool enable; + bool ch_en[6]; + pwm_ch_t ch[6]; +} pwm_Ctx_t; + +static pwm_Ctx_t pwmCtx = +{ + .enable = FALSE, + .ch_en = {FALSE,FALSE,FALSE,FALSE,FALSE,FALSE}, +}; + +void hal_pwm_module_init(void) +{ + int i = 0; + + if(pwmCtx.enable == TRUE) + return; + + pwmCtx.enable = TRUE; + + for(i = 0; i < 6; i++) + { + pwmCtx.ch_en[i] = FALSE; + pwmCtx.ch[i].pwmN = (PWMN_e)i; + pwmCtx.ch[i].pwmPin = GPIO_DUMMY; + pwmCtx.ch[i].pwmDiv = PWM_CLK_NO_DIV; + pwmCtx.ch[i].pwmMode = PWM_CNT_UP; + pwmCtx.ch[i].pwmPolarity = PWM_POLARITY_RISING; + pwmCtx.ch[i].cmpVal = 0; + pwmCtx.ch[i].cntTopVal = 0; + hal_pwm_destroy((PWMN_e)i); + } + + hal_pwm_stop(); +} + +void hal_pwm_module_deinit(void) +{ + int i = 0; + + if(pwmCtx.enable == FALSE) + return; + + pwmCtx.enable = FALSE; + + for(i = 0; i < 6; i++) + { + pwmCtx.ch_en[i] = FALSE; + pwmCtx.ch[i].pwmN = (PWMN_e)i; + pwmCtx.ch[i].pwmPin = GPIO_DUMMY; + pwmCtx.ch[i].pwmDiv = PWM_CLK_NO_DIV; + pwmCtx.ch[i].pwmMode = PWM_CNT_UP; + pwmCtx.ch[i].pwmPolarity = PWM_POLARITY_RISING; + pwmCtx.ch[i].cmpVal = 0; + pwmCtx.ch[i].cntTopVal = 0; + hal_pwm_close_channel((PWMN_e)i); + hal_pwm_destroy((PWMN_e)i); + } + + hal_pwm_stop(); +} + +void hal_pwm_ch_start(pwm_ch_t ch) +{ + if(pwmCtx.enable == FALSE) + return; + + if(pwmCtx.ch_en[ch.pwmN] == TRUE) + { + hal_pwm_set_count_val(ch.pwmN,ch.cmpVal,ch.cntTopVal); + PWM_SET_DIV(ch.pwmN, ch.pwmDiv); + } + else + { + hal_pwm_init(ch.pwmN,ch.pwmDiv,ch.pwmMode,ch.pwmPolarity); + hal_pwm_set_count_val(ch.pwmN,ch.cmpVal,ch.cntTopVal); + hal_pwm_open_channel(ch.pwmN,ch.pwmPin); + pwmCtx.ch_en[ch.pwmN] = TRUE; + hal_pwm_start(); + } +} + +void hal_pwm_ch_stop(pwm_ch_t ch) +{ + if(pwmCtx.ch_en[ch.pwmN] == FALSE) + return; + else + { + pwmCtx.ch_en[ch.pwmN] = FALSE; + hal_pwm_destroy(ch.pwmN); + hal_pwm_close_channel(ch.pwmN); + } +} + +bool hal_pwm_ch_enable(PWMN_e pwmN) +{ + return pwmCtx.ch_en[pwmN]; +} + +pwm_ch_t hal_pwm_ch_reg(PWMN_e pwmN) +{ + return pwmCtx.ch[pwmN]; +} diff --git a/src/components/driver/pwm/pwm.h b/src/components/driver/pwm/pwm.h new file mode 100644 index 0000000..4aa637c --- /dev/null +++ b/src/components/driver/pwm/pwm.h @@ -0,0 +1,355 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file pwm.h + @brief Contains all functions support for pwm driver + @version 0.0 + @date 30. Oct. 2017 + @author Ding + + + +*******************************************************************************/ +#ifndef __PWM__H__ +#define __PWM__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "types.h" +#include "gpio.h" + + +#define PWM_ENABLE_ALL do{\ + AP_PWM->pwmen |= BIT(0);\ + AP_PWM->pwmen |= BIT(4);\ + }while(0) +#define PWM_DISABLE_ALL do{\ + AP_PWM->pwmen &= ~BIT(0);\ + AP_PWM->pwmen &= ~BIT(4);\ + }while(0) +#define PWM_ENABLE_CH_012 do{\ + AP_PWM->pwmen |= BIT(8);\ + AP_PWM->pwmen |= BIT(9);\ + }while(0) +#define PWM_DISABLE_CH_012 do{\ + AP_PWM->pwmen &= ~BIT(8);\ + AP_PWM->pwmen &= ~BIT(9);\ + }while(0) +#define PWM_ENABLE_CH_345 do{\ + AP_PWM->pwmen |= BIT(10);\ + AP_PWM->pwmen |= BIT(11);\ + }while(0) +#define PWM_DISABLE_CH_345 do{\ + AP_PWM->pwmen &= ~BIT(10);\ + AP_PWM->pwmen &= ~BIT(11);\ + }while(0) +#define PWM_ENABLE_CH_01 do{\ + AP_PWM->pwmen |= BIT(12);\ + AP_PWM->pwmen |= BIT(13);\ + }while(0) +#define PWM_DISABLE_CH_01 do{\ + AP_PWM->pwmen &= ~BIT(12);\ + AP_PWM->pwmen &= ~BIT(13);\ + }while(0) +#define PWM_ENABLE_CH_23 do{\ + AP_PWM->pwmen |= BIT(14);\ + AP_PWM->pwmen |= BIT(15);\ + }while(0) +#define PWM_DISABLE_CH_23 do{\ + AP_PWM->pwmen &= ~BIT(14);\ + AP_PWM->pwmen &= ~BIT(15);\ + }while(0) +#define PWM_ENABLE_CH_45 do{\ + AP_PWM->pwmen |= BIT(16);\ + AP_PWM->pwmen |= BIT(17);\ + }while(0) +#define PWM_DISABLE_CH_45 do{\ + AP_PWM->pwmen &= ~BIT(16);\ + AP_PWM->pwmen &= ~BIT(17);\ + }while(0) + +#define PWM_INSTANT_LOAD_CH(n) subWriteReg(&(AP_PWM_CTRL(n)->ctrl0),31,31,1) +#define PWM_NO_INSTANT_LOAD_CH(n) subWriteReg(&(AP_PWM_CTRL(n)->ctrl0),31,31,0) +#define PWM_LOAD_CH(n) subWriteReg(&(AP_PWM_CTRL(n)->ctrl0),16,16,1) +#define PWM_NO_LOAD_CH(n) subWriteReg(&(AP_PWM_CTRL(n)->ctrl0),16,16,0) +#define PWM_SET_DIV(n,v) subWriteReg(&(AP_PWM_CTRL(n)->ctrl0),14,12,v) +#define PWM_SET_MODE(n,v) subWriteReg(&(AP_PWM_CTRL(n)->ctrl0),8,8,v) +#define PWM_SET_POL(n,v) subWriteReg(&(AP_PWM_CTRL(n)->ctrl0),4,4,v) +#define PWM_ENABLE_CH(n) subWriteReg(&(AP_PWM_CTRL(n)->ctrl0),0,0,1) +#define PWM_DISABLE_CH(n) subWriteReg(&(AP_PWM_CTRL(n)->ctrl0),0,0,0) + +#define PWM_SET_CMP_VAL(n,v) subWriteReg(&(AP_PWM_CTRL(n)->ctrl1),31,16,v) +#define PWM_SET_TOP_VAL(n,v) subWriteReg(&(AP_PWM_CTRL(n)->ctrl1),15,0,v) +#define PWM_GET_CMP_VAL(n) ((AP_PWM_CTRL(n)->ctrl1 & 0xFFFF0000) >> 8) +#define PWM_GET_TOP_VAL(n) AP_PWM_CTRL(n)->ctrl1 & 0x0000FFFF + + +/************************************************************* + @brief enum variable, the number of PWM channels supported + +*/ +typedef enum +{ + PWM_CH0 = 0, + PWM_CH1 = 1, + PWM_CH2 = 2, + PWM_CH3 = 3, + PWM_CH4 = 4, + PWM_CH5 = 5 +} PWMN_e; + +/************************************************************* + @brief enum variable used for PWM clock prescaler + +*/ +typedef enum +{ + PWM_CLK_NO_DIV = 0, + PWM_CLK_DIV_2 = 1, + PWM_CLK_DIV_4 = 2, + PWM_CLK_DIV_8 = 3, + PWM_CLK_DIV_16 = 4, + PWM_CLK_DIV_32 = 5, + PWM_CLK_DIV_64 = 6, + PWM_CLK_DIV_128 = 7 +} PWM_CLK_DIV_e; + +/************************************************************* + @brief enum variable used for PWM work mode setting + +*/ +typedef enum +{ + PWM_CNT_UP = 0, + PWM_CNT_UP_AND_DOWN = 1 +} PWM_CNT_MODE_e; + +/************************************************************* + @brief enum variable used for PWM output polarity setting + +*/ +typedef enum +{ + PWM_POLARITY_RISING = 0, + PWM_POLARITY_FALLING = 1 +} PWM_POLARITY_e; + +/************************************************************************************** + @fn hal_pwm_init + + @brief This function process for pwm initial + + input parameters + + @param PWMN_e pwmN : pwm channel + PWM_CLK_DIV_e pwmDiv : clock prescaler of PWM channel + PWM_CNT_MODE_e pwmMode : count mode of PWM channel + PWM_POLARITY_e pwmPolarity : output polarity setting of PWM channel + unsigned short cmpVal : the compare value of PWM channel + unsigned short cntTopVal : the counter top value of PWM channel + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +void hal_pwm_init(PWMN_e pwmN, PWM_CLK_DIV_e pwmDiv, + PWM_CNT_MODE_e pwmMode, PWM_POLARITY_e pwmPolarity); + +/************************************************************************************** + @fn hal_pwm_open_channel + + @brief This function process for pwm start working + + input parameters + + @param PWMN_e pwmN : pwm channel + gpio_pin_e pwmPin : pwm pin number + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +void hal_pwm_open_channel(PWMN_e pwmN,gpio_pin_e pwmPin); + +/************************************************************************************** + @fn hal_pwm_close_channel + + @brief This function process for pwm stop working + + input parameters + + @param PWMN_e pwmN : pwm channel + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +void hal_pwm_close_channel(PWMN_e pwmN); + +/************************************************************************************** + @fn hal_pwm_destroy + + @brief This function process for pwm clear and disable + + input parameters + + @param PWMN_e pwmN : pwm channel + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +void hal_pwm_destroy(PWMN_e pwmN); + +/************************************************************************************** + @fn hal_pwm_set_count_val + + @brief This function process for change pwm count value + + input parameters + + @param PWMN_e pwmN : pwm channel + uint16_t cmpVal : the compare value of PWM channel + uint16_t cntTopVal : the counter top value of PWM channel + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +void hal_pwm_set_count_val(PWMN_e pwmN, uint16_t cmpVal, uint16_t cntTopVal); + +/************************************************************************************** + @fn hal_pwm_start + + @brief pwm start + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +void hal_pwm_start(void); + +/************************************************************************************** + @fn hal_pwm_stop + + @brief pwm stop + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +void hal_pwm_stop(void); + +//new api,make use easily +typedef struct +{ + PWMN_e pwmN; + gpio_pin_e pwmPin; + PWM_CLK_DIV_e pwmDiv; + PWM_CNT_MODE_e pwmMode; + PWM_POLARITY_e pwmPolarity; + uint16_t cmpVal; + uint16_t cntTopVal; + +} pwm_ch_t; + +/************************************************************************************** + @fn hal_pwm_module_init + + @brief init pwm global variables + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +void hal_pwm_module_init(void); + +/************************************************************************************** + @fn hal_pwm_module_deinit + + @brief deinit pwm global variables + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +void hal_pwm_module_deinit(void); + +/************************************************************************************** + @fn hal_pwm_ch_start + + @brief config and make a pwm start to work + + input parameters + + @param pwm_ch_t ch: pwm channel + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +void hal_pwm_ch_start(pwm_ch_t ch); + +/************************************************************************************** + @fn hal_pwm_ch_stop + + @brief make a pwm stop form working + + input parameters + + @param pwm_ch_t ch: pwm channel + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +void hal_pwm_ch_stop(pwm_ch_t ch); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/src/components/driver/pwrmgr/pwrmgr.c b/src/components/driver/pwrmgr/pwrmgr.c new file mode 100644 index 0000000..5e67706 --- /dev/null +++ b/src/components/driver/pwrmgr/pwrmgr.c @@ -0,0 +1,530 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ +#include "rom_sym_def.h" +#include "types.h" +#include "ll_sleep.h" +#include "bus_dev.h" +#include "string.h" + +#include "pwrmgr.h" +#include "error.h" +#include "gpio.h" +#include "log.h" +#include "clock.h" +#include "jump_function.h" +#include "flash.h" + +#include "rf_phy_driver.h" + +#if(CFG_SLEEP_MODE == PWR_MODE_NO_SLEEP) + static uint8_t mPwrMode = PWR_MODE_NO_SLEEP; + #elif(CFG_SLEEP_MODE == PWR_MODE_SLEEP) + static uint8_t mPwrMode = PWR_MODE_SLEEP; + #elif(CFG_SLEEP_MODE == PWR_MODE_PWROFF_NO_SLEEP) + static uint8_t mPwrMode = PWR_MODE_PWROFF_NO_SLEEP; +#else + #error "CFG_SLEEP_MODE define incorrect" +#endif + +//#define CFG_FLASH_ENABLE_DEEP_SLEEP +#ifdef CFG_FLASH_ENABLE_DEEP_SLEEP + #warning "CONFIG FLASH ENABLE DEEP SLEEP !!!" +#endif + +#define CFG_SRAM_RETENTION_LOW_CURRENT_LDO_ENABLE +#ifdef CFG_SRAM_RETENTION_LOW_CURRENT_LDO_ENABLE +// #warning "ENABLE LOW CURRENT LDO FOR SRAM RETENTION !!!" +#endif +typedef struct _pwrmgr_Context_t +{ + MODULE_e moudle_id; + bool lock; + pwrmgr_Hdl_t sleep_handler; + pwrmgr_Hdl_t wakeup_handler; +} pwrmgr_Ctx_t; + +static pwrmgr_Ctx_t mCtx[HAL_PWRMGR_TASK_MAX_NUM]; +static uint32_t sramRet_config; +static uint32_t s_config_swClk0 = DEF_CLKG_CONFIG_0; + +uint32_t s_config_swClk1 = DEF_CLKG_CONFIG_1; +uint32_t s_gpio_wakeup_src_group1,s_gpio_wakeup_src_group2; + +/* + osal_idle_task will be call +*/ +__ATTR_SECTION_SRAM__ void osal_idle_task (void) +{ + AP_WDT_FEED; + osal_pwrmgr_powerconserve0(); +} +int hal_pwrmgr_init(void) +{ + memset(&mCtx, 0, sizeof(mCtx)); + + switch(mPwrMode) + { + case PWR_MODE_NO_SLEEP: + case PWR_MODE_PWROFF_NO_SLEEP: + disableSleep(); + break; + + case PWR_MODE_SLEEP: + enableSleep(); + break; + } + + /* + if wdt enable, set osal idle task to feed wdt before powerconserve + */ + if(AP_WDT_ENABLE_STATE) + JUMP_FUNCTION(OSAL_POWER_CONSERVE)=(uint32_t)&osal_idle_task; + + return PPlus_SUCCESS; +} + +int hal_pwrmgr_clk_gate_config(MODULE_e module) +{ + if (module < MOD_CP_CPU) + { + s_config_swClk0 |= BIT(module); + } + else if (module < MOD_PCLK_CACHE) + { + s_config_swClk1 |= BIT(module - MOD_CP_CPU); + } + + return PPlus_SUCCESS; +} + +bool hal_pwrmgr_is_lock(MODULE_e mod) +{ + int i; + int ret = FALSE; + + if(mPwrMode == PWR_MODE_NO_SLEEP || mPwrMode == PWR_MODE_PWROFF_NO_SLEEP ) + { + return TRUE; + } + + HAL_ENTER_CRITICAL_SECTION(); + + for(i = 0; i< HAL_PWRMGR_TASK_MAX_NUM; i++) + { + if(mCtx[i].moudle_id == MOD_NONE) + break; + + if(mCtx[i].moudle_id == mod) + { + if(mCtx[i].lock == TRUE) + ret = TRUE; + + break; + } + } + + HAL_EXIT_CRITICAL_SECTION(); + return ret; +} + + +int hal_pwrmgr_lock(MODULE_e mod) +{ + int i; + int ret = PPlus_ERR_NOT_REGISTED; + + if(mPwrMode == PWR_MODE_NO_SLEEP || mPwrMode == PWR_MODE_PWROFF_NO_SLEEP ) + { + disableSleep(); + return PPlus_SUCCESS; + } + + HAL_ENTER_CRITICAL_SECTION(); + + for(i = 0; i< HAL_PWRMGR_TASK_MAX_NUM; i++) + { + if(mCtx[i].moudle_id == MOD_NONE) + break; + + if(mCtx[i].moudle_id == mod) + { + mCtx[i].lock = TRUE; + disableSleep(); + //LOG("LOCK\n"); + ret = PPlus_SUCCESS; + break; + } + } + + HAL_EXIT_CRITICAL_SECTION(); + return ret; +} + +int hal_pwrmgr_unlock(MODULE_e mod) +{ + int i, cnt = 0; + + if(mPwrMode == PWR_MODE_NO_SLEEP || mPwrMode == PWR_MODE_PWROFF_NO_SLEEP ) + { + disableSleep(); + return PPlus_SUCCESS; + } + + HAL_ENTER_CRITICAL_SECTION(); + + for(i = 0; i< HAL_PWRMGR_TASK_MAX_NUM; i++) + { + if(mCtx[i].moudle_id == MOD_NONE) + break; + + if(mCtx[i].moudle_id == mod) + { + mCtx[i].lock = FALSE; + } + + if(mCtx[i].lock) + cnt ++; + } + + if(cnt == 0) + enableSleep(); + else + disableSleep(); + + HAL_EXIT_CRITICAL_SECTION(); + //LOG("sleep mode:%d\n", isSleepAllow()); + return PPlus_SUCCESS; +} + +int hal_pwrmgr_register(MODULE_e mod, pwrmgr_Hdl_t sleepHandle, pwrmgr_Hdl_t wakeupHandle) +{ + int i; + pwrmgr_Ctx_t* pctx = NULL; + + for(i = 0; i< HAL_PWRMGR_TASK_MAX_NUM; i++) + { + if(mCtx[i].moudle_id == mod) + return PPlus_ERR_INVALID_STATE; + + if(mCtx[i].moudle_id == MOD_NONE) + { + pctx = &mCtx[i]; + break; + } + } + + if(pctx == NULL) + return PPlus_ERR_NO_MEM; + + pctx->lock = FALSE; + pctx->moudle_id = mod; + pctx->sleep_handler = sleepHandle; + pctx->wakeup_handler = wakeupHandle; + return PPlus_SUCCESS; +} + +int hal_pwrmgr_unregister(MODULE_e mod) +{ + int i; + pwrmgr_Ctx_t* pctx = NULL; + + for(i = 0; i< HAL_PWRMGR_TASK_MAX_NUM; i++) + { + if(mCtx[i].moudle_id == mod) + { + pctx = &mCtx[i]; + break; + } + + if(mCtx[i].moudle_id == MOD_NONE) + { + return PPlus_ERR_NOT_REGISTED; + } + } + + if(pctx == NULL) + return PPlus_ERR_NOT_REGISTED; + + HAL_ENTER_CRITICAL_SECTION(); + memcpy(pctx, pctx+1, sizeof(pwrmgr_Ctx_t)*(HAL_PWRMGR_TASK_MAX_NUM-i-1)); + HAL_EXIT_CRITICAL_SECTION(); + return PPlus_SUCCESS; +} + + +int __attribute__((used)) hal_pwrmgr_wakeup_process(void) +{ + int i; +#ifdef CFG_FLASH_ENABLE_DEEP_SLEEP + extern void spif_release_deep_sleep(void); + spif_release_deep_sleep(); + WaitRTCCount(8); // 8*32us +#endif + AP_PCR->SW_CLK = s_config_swClk0; + AP_PCR->SW_CLK1 = s_config_swClk1|0x01;//force set M0 CPU + s_gpio_wakeup_src_group1 = AP_AON->GPIO_WAKEUP_SRC[0]; + s_gpio_wakeup_src_group2 = AP_AON->GPIO_WAKEUP_SRC[1]; + //restore BB TIMER IRQ_PRIO + NVIC_SetPriority((IRQn_Type)BB_IRQn, IRQ_PRIO_REALTIME); + NVIC_SetPriority((IRQn_Type)TIM1_IRQn, IRQ_PRIO_HIGH); //ll_EVT + NVIC_SetPriority((IRQn_Type)TIM2_IRQn, IRQ_PRIO_HIGH); //OSAL_TICK + NVIC_SetPriority((IRQn_Type)TIM4_IRQn, IRQ_PRIO_HIGH); //LL_EXA_ADV + + for(i = 0; i< HAL_PWRMGR_TASK_MAX_NUM; i++) + { + if(mCtx[i].moudle_id == MOD_NONE) + { + return PPlus_ERR_NOT_REGISTED; + } + + if(mCtx[i].wakeup_handler) + mCtx[i].wakeup_handler(); + } + + return PPlus_SUCCESS; +} + +int __attribute__((used)) hal_pwrmgr_sleep_process(void) +{ + int i; + //20181013 ZQ : + hal_pwrmgr_RAM_retention_set(); + + //LOG("Sleep\n"); + for(i = 0; i< HAL_PWRMGR_TASK_MAX_NUM; i++) + { + if(mCtx[i].moudle_id == MOD_NONE) + { + //return PPlus_ERR_NOT_REGISTED; + //found last module + break; + } + + if(mCtx[i].sleep_handler) + mCtx[i].sleep_handler(); + } + +#ifdef CFG_FLASH_ENABLE_DEEP_SLEEP + extern void spif_set_deep_sleep(void); + spif_set_deep_sleep(); +#endif + return PPlus_SUCCESS; +} + +/************************************************************************************** + @fn hal_pwrmgr_RAM_retention + + @brief This function process for enable retention sram + + input parameters + + @param uint32_t sram: sram bit map + + output parameters + + @param None. + + @return refer error.h. + **************************************************************************************/ +int hal_pwrmgr_RAM_retention(uint32_t sram) +{ + if(sram & 0xffffffe0) + { + sramRet_config = 0x00; + return PPlus_ERR_INVALID_PARAM; + } + + sramRet_config = sram; + return PPlus_SUCCESS; +} + +int hal_pwrmgr_RAM_retention_clr(void) +{ + subWriteReg(0x4000f01c,21,17,0); + return PPlus_SUCCESS; +} + +int hal_pwrmgr_RAM_retention_set(void) +{ + subWriteReg(0x4000f01c,21,17,sramRet_config); + return PPlus_SUCCESS; +} + +int hal_pwrmgr_LowCurrentLdo_enable(void) +{ + #ifdef CFG_SRAM_RETENTION_LOW_CURRENT_LDO_ENABLE + uint32_t retention_flag; + hal_flash_read(0x1100181c,(uint8_t*)&retention_flag,4); + + if(retention_flag == 0xffffffff) + { + subWriteReg(0x4000f014,26,26, 1); + } + + return PPlus_SUCCESS; + #else + return PPlus_ERR_FORBIDDEN; + #endif +} + +int hal_pwrmgr_LowCurrentLdo_disable(void) +{ + subWriteReg(0x4000f014,26,26, 0); + return PPlus_SUCCESS; +} +extern void gpio_wakeup_set(gpio_pin_e pin, gpio_polarity_e type); +extern void gpio_pull_set(gpio_pin_e pin, gpio_pupd_e type); + +void hal_pwrmgr_poweroff(pwroff_cfg_t* pcfg, uint8_t wakeup_pin_num) +{ + HAL_ENTER_CRITICAL_SECTION(); + subWriteReg(0x4000f01c,6,6,0x00); //disable software control + //(void)(wakeup_pin_num); + + for(uint8_t i = 0; i < wakeup_pin_num; i++ ) + { + if(pcfg[i].type==POL_FALLING) + gpio_pull_set(pcfg[i].pin,GPIO_PULL_UP_S); + else + gpio_pull_set(pcfg[i].pin,GPIO_PULL_DOWN); + + gpio_wakeup_set(pcfg[i].pin, pcfg[i].type); + } + + /** + config reset casue as RSTC_OFF_MODE + reset path walkaround dwc + */ + + AON_CLEAR_XTAL_TRACKING_AND_CALIB; + + AP_AON->SLEEP_R[0] = 2; + write_reg(0x4000f000,0x5a5aa5a5); + + while(1); +} + +__ATTR_SECTION_SRAM__ void hal_pwrmgr_enter_sleep_rtc_reset(uint32_t sleepRtcTick) +{ + HAL_ENTER_CRITICAL_SECTION(); + subWriteReg(0x4000f01c,6,6,0x00); //disable software control + config_RTC(sleepRtcTick); + // clear sram retention + hal_pwrmgr_RAM_retention_clr(); + /** + config reset casue as RSTC_WARM_NDWC + reset path walkaround dwc + */ + + AON_CLEAR_XTAL_TRACKING_AND_CALIB; + + AP_AON->SLEEP_R[0]=4; + enter_sleep_off_mode(SYSTEM_SLEEP_MODE); + + while(1) {}; +} + + +#define STANDBY_WAIT_MS(a) WaitRTCCount((a)<<5) // 32us * 32 around 1ms +__attribute__((section("_section_standby_var_"))) pwroff_cfg_t s_pwroff_cfg[WAKEUP_PIN_MAX]; +__attribute__((section("_section_standby_var_"))) __attribute__((used)) uint8 pwroff_register_number=0; +__attribute__((section("_section_standby_code_"))) void wakeupProcess_standby(void) +{ + subWriteReg(0x4000f014,29,27,0x07); + STANDBY_WAIT_MS(5); +#ifdef CFG_FLASH_ENABLE_DEEP_SLEEP + extern void spif_release_deep_sleep(void); + spif_release_deep_sleep(); + STANDBY_WAIT_MS(15); +#endif + uint32_t volatile cnt=0; + uint8_t volatile find_flag=0; + uint8 pin_n=0; + extern bool gpio_read(gpio_pin_e pin); + + for(pin_n=0; pin_n(s_pwroff_cfg[pin_n].on_time>>5)) + { + write_reg(0x4000f030, 0x01); + break; + } + } + else + hal_pwrmgr_enter_standby(&s_pwroff_cfg[0],pwroff_register_number); + } + + set_sleep_flag(0); + AP_AON->SLEEP_R[0] = 4; + HAL_ENTER_CRITICAL_SECTION(); + AP_PCR->SW_RESET1 = 0; + + while(1); +} +extern void gpio_wakeup_set(gpio_pin_e pin, gpio_polarity_e type); +extern void gpio_pull_set(gpio_pin_e pin, gpio_pupd_e type); +__attribute__((section("_section_standby_code_"))) void hal_pwrmgr_enter_standby(pwroff_cfg_t* pcfg,uint8_t wakeup_pin_num) +{ + HAL_ENTER_CRITICAL_SECTION(); + subWriteReg(0x4000f01c,6,6,0x00); //disable software control + uint8_t i = 0; + + if(wakeup_pin_num>WAKEUP_PIN_MAX) + { + wakeup_pin_num=WAKEUP_PIN_MAX; + } + + for(i = 0; i < wakeup_pin_num; i++) + { + if(pcfg[i].type==POL_FALLING) + gpio_pull_set(pcfg[i].pin,GPIO_PULL_UP_S); + else + gpio_pull_set(pcfg[i].pin,GPIO_PULL_DOWN); + + gpio_wakeup_set(pcfg[i].pin, pcfg[i].type); + osal_memcpy(&s_pwroff_cfg[i],&(pcfg[i]),sizeof(pwroff_cfg_t)); + pwroff_register_number++; + } + + JUMP_FUNCTION(WAKEUP_PROCESS)= (uint32_t)&wakeupProcess_standby; +#ifdef CFG_FLASH_ENABLE_DEEP_SLEEP + extern void spif_set_deep_sleep(void); + spif_set_deep_sleep(); + WaitRTCCount(50); // 50*32us +#endif + subWriteReg(0x4000f014,29,27,0); + set_sleep_flag(1); + AP_AON->SLEEP_R[0] = 2; + subWriteReg(0x4000f01c,21,17,RET_SRAM0); + enter_sleep_off_mode(SYSTEM_SLEEP_MODE); + + while(1); +} + + + + + diff --git a/src/components/driver/pwrmgr/pwrmgr.h b/src/components/driver/pwrmgr/pwrmgr.h new file mode 100644 index 0000000..3d68907 --- /dev/null +++ b/src/components/driver/pwrmgr/pwrmgr.h @@ -0,0 +1,74 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + + +#ifndef _HAL_PWRMGR_HD +#define _HAL_PWRMGR_HD + +#ifdef __cplusplus +extern "C" { +#endif + + +#include "bus_dev.h" +#include "gpio.h" + +#define PWR_MODE_NO_SLEEP 1 +#define PWR_MODE_SLEEP 2 +#define PWR_MODE_PWROFF_NO_SLEEP 4 + +//WAKEUP FROM STANDBY MODE +#define WAKEUP_PIN_MAX 3 + +#define HAL_PWRMGR_TASK_MAX_NUM 10 + +#define RET_SRAM0 BIT(0) /*32K, 0x1fff0000~0x1fff7fff*/ +#define RET_SRAM1 BIT(1) /*16K, 0x1fff8000~0x1fffbfff*/ +#define RET_SRAM2 BIT(2) /*16K, 0x1fffc000~0x1fffffff*/ + +#define DEF_CLKG_CONFIG_0 (_CLK_IOMUX|_CLK_UART0|_CLK_GPIO|_CLK_SPIF|_CLK_DMA) + +#define DEF_CLKG_CONFIG_1 (_CLK_M0_CPU | _CLK_BB |_CLK_TIMER |_CLK_BBREG \ + |_CLK_TIMER1|_CLK_TIMER2|_CLK_TIMER3|_CLK_TIMER4|_CLK_COM) + +typedef struct +{ + gpio_pin_e pin; + gpio_polarity_e type; + uint16_t on_time; +} pwroff_cfg_t; + + +extern uint32_t g_system_reset_cause; + +typedef void (*pwrmgr_Hdl_t)(void); + +int hal_pwrmgr_init(void); +bool hal_pwrmgr_is_lock(MODULE_e mod); +int hal_pwrmgr_lock(MODULE_e mod); +int hal_pwrmgr_unlock(MODULE_e mod); +int hal_pwrmgr_register(MODULE_e mod, pwrmgr_Hdl_t sleepHandle, pwrmgr_Hdl_t wakeupHandle); +int hal_pwrmgr_unregister(MODULE_e mod); +int hal_pwrmgr_wakeup_process(void) __attribute__((weak)); +int hal_pwrmgr_sleep_process(void) __attribute__((weak)); +int hal_pwrmgr_RAM_retention(uint32_t sram); +int hal_pwrmgr_clk_gate_config(MODULE_e module); +int hal_pwrmgr_RAM_retention_clr(void); +int hal_pwrmgr_RAM_retention_set(void); +int hal_pwrmgr_LowCurrentLdo_enable(void); +int hal_pwrmgr_LowCurrentLdo_disable(void); + +void hal_pwrmgr_poweroff(pwroff_cfg_t* pcfg, uint8_t wakeup_pin_num); +__ATTR_SECTION_SRAM__ void hal_pwrmgr_enter_sleep_rtc_reset(uint32_t sleepRtcTick); +void hal_pwrmgr_enter_standby(pwroff_cfg_t* pcfg,uint8_t wakeup_pin_num) ; + +#ifdef __cplusplus +} +#endif + + +#endif + + diff --git a/src/components/driver/qdec/qdec.c b/src/components/driver/qdec/qdec.c new file mode 100644 index 0000000..9b532d6 --- /dev/null +++ b/src/components/driver/qdec/qdec.c @@ -0,0 +1,279 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file qdec.c + @brief Contains all functions support for key scan driver + @version 0.0 + @date 13. Nov. 2017 + @author Ding + + + +*******************************************************************************/ +#include "rom_sym_def.h" +#include +#include "bus_dev.h" + +#include "OSAL.h" +#include "qdec.h" +#include "gpio.h" +#include "uart.h" +#include "log.h" +#include "pwrmgr.h" +#include "error.h" +#include "clock.h" + + +qdec_Ctx_t m_qdecCtx; + + +void __attribute__((used)) hal_QDEC_IRQHandler() +{ + hal_gpio_pin_init(P20, OEN); + hal_gpio_write(P20,1); + osal_stop_timerEx(m_qdecCtx.qdec_task_id, m_qdecCtx.timeout_event); + WaitMs(1); + int32_t delta = GET_CNT_QUAN(m_qdecCtx.cfg.qdec_chn); + m_qdecCtx.count += delta; + + if(m_qdecCtx.cfg.evt_handler) + { + qdec_Evt_t evt; + evt.count = m_qdecCtx.count; + m_qdecCtx.cfg.evt_handler(&evt); + } + + CLR_INT_QUAN(m_qdecCtx.cfg.qdec_chn); + hal_pwrmgr_unlock(MOD_QDEC); + hal_gpio_pin_init(P20, OEN); + hal_gpio_write(P20,0); +} + +void hal_qdec_timeout_handler() +{ + osal_stop_timerEx(m_qdecCtx.qdec_task_id, m_qdecCtx.timeout_event); + hal_pwrmgr_unlock(MOD_QDEC); +} + +/************************************************************************************** + @fn hal_qdec_set_cha + + @brief This function process for qdec initial + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +static void hal_qdec_set_cha(QDEC_CHN_e qdecCHN,gpio_pin_e pin) +{ + hal_gpio_pull_set(pin, PULL_DOWN); + hal_gpio_fmux_set(pin, (Fmux_Type_e)(FMUX_CHAX + (qdecCHN*3))); +} + +/************************************************************************************** + @fn hal_qdec_set_chb + + @brief This function process for qdec initial + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +static void hal_qdec_set_chb(QDEC_CHN_e qdecCHN,gpio_pin_e pin) +{ + hal_gpio_pull_set(pin, PULL_DOWN); + hal_gpio_fmux_set(pin, (Fmux_Type_e)(FMUX_CHBX + (qdecCHN*3))); +} + +/************************************************************************************** + @fn hal_qdec_set_chi + + @brief This function process for qdec initial + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +static void hal_qdec_set_chi(QDEC_CHN_e qdecCHN,gpio_pin_e pin) +{ + hal_gpio_pull_set(pin, PULL_DOWN); + hal_gpio_fmux_set(pin, (Fmux_Type_e)(FMUX_CHIX + (qdecCHN*3))); +} + +/************************************************************************************** + @fn hal_qdec_init + + @brief This function process for qdec initial + + input parameters + + @param qdec_Cfg_t cfg + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +int hal_qdec_init(qdec_Cfg_t cfg, uint8 task_id, uint16 event) +{ + if(m_qdecCtx.enable) + return PPlus_ERR_INVALID_STATE; + + uint8_t pins[3] = {cfg.cha_pin, cfg.chb_pin, cfg.chi_pin}; + memcpy(m_qdecCtx.pin_arr, pins, sizeof(uint8_t)*3); + m_qdecCtx.cfg = cfg; + m_qdecCtx.qdec_task_id = task_id; + m_qdecCtx.timeout_event = event; + m_qdecCtx.enable = TRUE; + qdec_hw_config(); + hal_pwrmgr_register(MOD_QDEC, qdec_sleep_handler, qdec_wakeup_handler); + return PPlus_SUCCESS; +} + +void qdec_hw_config() +{ + qdec_Cfg_t* cfg = &(m_qdecCtx.cfg); + hal_clk_gate_enable(MOD_QDEC); + hal_qdec_set_cha(cfg->qdec_chn, cfg->cha_pin); + hal_qdec_set_chb(cfg->qdec_chn, cfg->chb_pin); + DIS_INT_INCN(cfg->qdec_chn); + DIS_INT_QUAN(cfg->qdec_chn); + DIS_INT_02F_QUAN(cfg->qdec_chn); + DIS_INT_F20_QUAN(cfg->qdec_chn); + SET_MODE_QUAN(cfg->qdec_chn, cfg->quaMode); + hal_qdec_set_qua_irq(cfg->qdec_chn, cfg->intMode); + + if(cfg->use_inc) + { + hal_qdec_set_chi(cfg->qdec_chn, cfg->chi_pin); + + if(cfg->use_inc_irq) + { + hal_qdec_set_inc_irq(cfg->qdec_chn, cfg->incMode, cfg->intMode); + } + } + + QDEC_IRQ_ENABLE; + ENABLE_CHN(cfg->qdec_chn); +} + +static void qdec_sleep_handler(void) +{ + uint8_t pin_num; + pin_num = m_qdecCtx.cfg.use_inc ? 3:2; + + for(uint8_t i=0; i +#include "pwrmgr.h" +#include "clock.h" +#include "log.h" +#include "jump_function.h" + +#if DMAC_USE + #include "dma.h" +#endif + +typedef struct _spi_Context +{ + spi_Cfg_t cfg; + hal_spi_t* spi_info; + bool is_slave_mode; + spi_xmit_t transmit; +} spi_Ctx_t; + +static spi_Ctx_t m_spiCtx[2]; + +#define SPI_HDL_VALIDATE(hdl) {if((hdl == NULL) || (hdl->spi_index > 1))\ + return PPlus_ERR_INVALID_PARAM;\ + if((hdl != m_spiCtx[0].spi_info) && (hdl != m_spiCtx[1].spi_info))\ + return PPlus_ERR_NOT_REGISTED;} + + +////////////////// SPI ///////////////////////////////////////// +static void hal_spi_write_fifo(AP_SSI_TypeDef* Ssix,uint8_t len,uint8_t* tx_rx_ptr) +{ + uint8_t i=0; + HAL_ENTER_CRITICAL_SECTION(); + + while(iDataReg = *(tx_rx_ptr+i); + i++; + } + + HAL_EXIT_CRITICAL_SECTION(); +} + + +void spi_int_enable(hal_spi_t* spi_ptr, uint32_t mask) +{ + AP_SSI_TypeDef* Ssix = NULL; + Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; + Ssix->IMR = mask & 0x11; + + if(Ssix == AP_SPI0) + { + JUMP_FUNCTION(SPI0_IRQ_HANDLER) = (uint32_t)&hal_SPI0_IRQHandler; + } + else + { + JUMP_FUNCTION(SPI1_IRQ_HANDLER) = (uint32_t)&hal_SPI1_IRQHandler; + } + + NVIC_EnableIRQ((IRQn_Type)(SPI0_IRQn + spi_ptr->spi_index)); + NVIC_SetPriority((IRQn_Type)(SPI0_IRQn + spi_ptr->spi_index), IRQ_PRIO_HAL); +} + +static void spi_int_disable(hal_spi_t* spi_ptr) +{ + AP_SSI_TypeDef* Ssix = NULL; + Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; + NVIC_DisableIRQ((IRQn_Type)(SPI0_IRQn + spi_ptr->spi_index)); + Ssix->IMR = 0x00; +} + +static void spi_int_handle(uint8_t id, spi_Ctx_t* pctx, AP_SSI_TypeDef* Ssix) +{ + volatile uint8_t spi_irs_status; + spi_evt_t evt; + uint8_t i, cnt; + spi_xmit_t* trans_ptr; + trans_ptr = &pctx->transmit; + spi_irs_status = Ssix->ISR; + + if(spi_irs_status & TRANSMIT_FIFO_EMPTY) + { + cnt = 8 - Ssix->TXFLR; + + for(i = 0; i< cnt; i++) + { + if(trans_ptr->tx_buf) + { + Ssix->DataReg = trans_ptr->tx_buf[trans_ptr->tx_offset ++]; + } + else + { + trans_ptr->tx_offset++; + Ssix->DataReg = 0; + } + + if(trans_ptr->tx_offset == trans_ptr->xmit_len) + { + Ssix->IMR = 0x10; + break; + } + } + } + + if(spi_irs_status & RECEIVE_FIFO_FULL) + { + cnt = Ssix->RXFTLR; + + for(i = 0; i< cnt; i++) + { + trans_ptr->rx_buf[trans_ptr->rx_offset++] = Ssix->DataReg; + } + + if(trans_ptr->rx_offset == trans_ptr->xmit_len) + { + if(pctx->cfg.force_cs == true) + hal_gpio_fmux(pctx->cfg.ssn_pin, Bit_ENABLE); + + trans_ptr->busy = false; + trans_ptr->rx_buf = NULL; + trans_ptr->rx_offset = 0; + evt.id = id; + evt.evt = SPI_RX_COMPLETED; + hal_pwrmgr_unlock((MODULE_e)(MOD_SPI0 + id)); + pctx->cfg.evt_handler(&evt); + evt.evt = SPI_TX_COMPLETED; + pctx->cfg.evt_handler(&evt); + } + } +} + +static void spis_int_handle(uint8_t id, spi_Ctx_t* pctx, AP_SSI_TypeDef* Ssix) +{ + volatile uint8_t spi_irs_status; + spi_xmit_t* trans_ptr; + spi_evt_t evt; + uint16_t i, cnt; + trans_ptr = &(pctx->transmit); + spi_irs_status = Ssix->ISR; + + if(spi_irs_status & TRANSMIT_FIFO_EMPTY) + { + cnt = 8 - Ssix->TXFLR; + + for(i = 0; i< cnt; i++) + { + if(trans_ptr->tx_offset == trans_ptr->xmit_len) + { + Ssix->IMR = 0x10; + break; + } + + if(trans_ptr->tx_buf) + { + Ssix->DataReg = trans_ptr->tx_buf[trans_ptr->tx_offset ++]; + } + else + { + trans_ptr->tx_offset ++; + Ssix->DataReg = 0; + } + } + } + + if(spi_irs_status & RECEIVE_FIFO_FULL) + { + volatile uint32_t garbage; + cnt = Ssix->RXFLR; + + if(trans_ptr->rx_buf) + { + for(i = 0; i< cnt; i++) + { + if(trans_ptr->xmit_len > trans_ptr->rx_offset) + trans_ptr->rx_buf[trans_ptr->rx_offset++] = Ssix->DataReg; + else + garbage = Ssix->DataReg; + } + } + else + { + uint8_t rxbuf[16]; + + if(trans_ptr->busy) + trans_ptr->rx_offset += cnt; + + for(i = 0; i< cnt; i++) + { + *(rxbuf+i) = Ssix->DataReg; + } + + evt.id = id; + evt.evt = SPI_RX_DATA_S; + evt.data = rxbuf; + evt.len = cnt; + pctx->cfg.evt_handler(&evt); + } + + if(trans_ptr->busy && trans_ptr->rx_offset >= trans_ptr->xmit_len) + { + memset(trans_ptr, 0, sizeof(spi_xmit_t)); + evt.id = id; + evt.evt = SPI_RX_COMPLETED; + evt.data = NULL; + evt.len = cnt; + pctx->cfg.evt_handler(&evt); + evt.evt = SPI_TX_COMPLETED; + pctx->cfg.evt_handler(&evt); + } + } +} + +/************************************************************************************** + @fn hal_SPI0_IRQHandler + + @brief This function process for spi0 interrupt,when use int please consummate its callbackfunction + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +void __attribute__((used)) hal_SPI0_IRQHandler(void) +{ + spi_Ctx_t* pctx = &m_spiCtx[0]; + + if(pctx->spi_info == NULL) + return; + + if(pctx->is_slave_mode) + spis_int_handle(0, pctx, AP_SPI0); + else + spi_int_handle(0, pctx, AP_SPI0); +} + +/************************************************************************************** + @fn hal_SPI1_IRQHandler + + @brief This function process for spi1 interrupt,when use int please consummate its callbackfunction + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +void __attribute__((used)) hal_SPI1_IRQHandler(void) +{ + spi_Ctx_t* pctx = &m_spiCtx[1]; + + if(pctx->spi_info == NULL) + return; + + if(pctx->is_slave_mode) + spis_int_handle(1, pctx, AP_SPI1); + else + spi_int_handle(1, pctx, AP_SPI1); +} + +/************************************************************************************** + @fn hal_spi_pin_init + + @brief This function process for spi pin initial(4 lines);You can use two spi,spi0 and spi1,should programe by USE_AP_SPIX + + input parameters + + @param GPIO_Pin_e sck_pin: define sclk pin + GPIO_Pin_e ssn_pin: define ssn pin + GPIO_Pin_e tx_pin: define transmit pin;when use as master,it's mosi pin;corresponding,use as slave,it's miso + GPIO_Pin_e rx_pin: define receive pin;when use as master,it's miso pin;corresponding,use as slave,it's mosi + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +static void hal_spi_pin_init(hal_spi_t* spi_ptr,GPIO_Pin_e sck_pin,GPIO_Pin_e ssn_pin,GPIO_Pin_e tx_pin,GPIO_Pin_e rx_pin) +{ + if(spi_ptr->spi_index == SPI0) + { + hal_gpio_fmux_set(sck_pin, FMUX_SPI_0_SCK); + hal_gpio_fmux_set(ssn_pin, FMUX_SPI_0_SSN); + hal_gpio_fmux_set(tx_pin, FMUX_SPI_0_TX); + hal_gpio_fmux_set(rx_pin, FMUX_SPI_0_RX); + } + else if(spi_ptr->spi_index == SPI1) + { + hal_gpio_fmux_set(sck_pin, FMUX_SPI_1_SCK); + hal_gpio_fmux_set(ssn_pin, FMUX_SPI_1_SSN); + hal_gpio_fmux_set(tx_pin, FMUX_SPI_1_TX); + hal_gpio_fmux_set(rx_pin, FMUX_SPI_1_RX); + } +} + +static void hal_spi_pin_deinit(GPIO_Pin_e sck_pin,GPIO_Pin_e ssn_pin,GPIO_Pin_e tx_pin,GPIO_Pin_e rx_pin) +{ + hal_gpio_fmux(sck_pin, Bit_DISABLE); + hal_gpio_fmux(ssn_pin, Bit_DISABLE); + hal_gpio_fmux(tx_pin, Bit_DISABLE); + hal_gpio_fmux(rx_pin, Bit_DISABLE); +} + +/************************************************************************************** + @fn hal_spi_master_init + + @brief This function process for spi master initial + + input parameters + + @param uint32_t baud: baudrate select + SPI_SCMOD_e scmod: Serial Clock Polarity and Phase select; SPI_MODE0, //SCPOL=0,SCPH=0(default) + SPI_MODE1, //SCPOL=0,SCPH=1 + SPI_MODE2, //SCPOL=1,SCPH=0 + SPI_MODE3, //SCPOL=1,SCPH=1 + SPI_TMOD_e tmod: Transfer Mode SPI_TRXD, //Transmit & Receive(default) + SPI_TXD, //Transmit Only + SPI_RXD, //Receive Only + SPI_EEPROM, //EEPROM Read + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +static void hal_spi_master_init(hal_spi_t* spi_ptr,uint32_t baud,SPI_SCMOD_e scmod,SPI_TMOD_e tmod) +{ + uint8_t shift = 0; + AP_SSI_TypeDef* Ssix = NULL; + AP_COM_TypeDef* apcom = AP_COM; + uint16_t baud_temp; + int pclk = clk_get_pclk(); + + if(spi_ptr->spi_index == SPI1) + { + shift = 1; + } + + Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; + Ssix->SSIEN = 0; //DISABLE_SPI; + apcom->PERI_MASTER_SELECT |= (BIT(shift)|BIT(shift+4)); + Ssix->CR0= ((Ssix->CR0) & 0xfffffc3f)|(scmod<<6)|(tmod<<8); + baud_temp = (pclk + (baud>>1)) / baud; + + if(baud_temp<2) + { + baud_temp = 2; + } + else if(baud_temp>65534) + { + baud_temp =65534; + } + + Ssix->BAUDR= baud_temp; // set clock(round) + Ssix->TXFTLR=4; // set fifo threshold to triggle interrupt + Ssix->RXFTLR=1; + Ssix->IMR = 0x00; + Ssix->SER=1; //enable slave device + Ssix->SSIEN = 1; //ENABLE_SPI; +} + +/************************************************************************************** + @fn hal_spi_slave_init + + @brief This function process for spi slave initial + + input parameters + + @param uint32_t baud: baudrate select + SPI_SCMOD_e scmod: Serial Clock Polarity and Phase select; SPI_MODE0, //SCPOL=0,SCPH=0(default) + SPI_MODE1, //SCPOL=0,SCPH=1 + SPI_MODE2, //SCPOL=1,SCPH=0 + SPI_MODE3, //SCPOL=1,SCPH=1 + SPI_TMOD_e tmod: Transfer Mode SPI_TRXD, //Transmit & Receive(default) + SPI_TXD, //Transmit Only + SPI_RXD, //Receive Only + SPI_EEPROM, //EEPROM Read + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +/*static*/ void hal_spi_slave_init(hal_spi_t* spi_ptr,uint32_t baud,SPI_SCMOD_e scmod,SPI_TMOD_e tmod) +{ + uint8_t shift = 0; + AP_SSI_TypeDef* Ssix = NULL; + AP_COM_TypeDef* apcom = AP_COM; + uint16_t baud_temp; + int pclk = clk_get_pclk(); + + if(spi_ptr->spi_index == SPI1) + { + shift = 1; + } + + Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; + Ssix->SSIEN = 0; //DISABLE_SPI; + apcom->PERI_MASTER_SELECT &= ~(BIT(shift)); + Ssix->CR0= ((Ssix->CR0) & 0xfffffc3f)|(scmod<<6)|(tmod<<8)|0x400; + baud_temp = (pclk + (baud>>1)) / baud; + + if(baud_temp<2) + { + baud_temp = 2; + } + else if(baud_temp>65534) + { + baud_temp =65534; + } + + Ssix->BAUDR= baud_temp; // set clock(round) + Ssix->TXFTLR=4; // set fifo threshold to triggle interrupt + Ssix->RXFTLR=1; //threshold is 1 + Ssix->IMR=0x11; //enable tx and rx + // Ssix->SER=1; //enable slave device + Ssix->SSIEN = 1; //ENABLE_SPI; +} +#if DMAC_USE +static void config_dma_channel4spitx(hal_spi_t* spi_ptr,uint8_t* tx_buf,uint16_t tx_len) +{ + DMA_CH_CFG_t cfgc; +// uint16_t* size16_tx_buf; + AP_SSI_TypeDef* Ssix = NULL; + Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; + Ssix->DMACR &= 0x01; + spi_Ctx_t* pctx; + pctx = &m_spiCtx[spi_ptr->spi_index]; +// if(pctx->cfg.spi_dfsmod == SPI_2BYTE) +// size16_tx_buf = (uint16_t *)tx_buf; + cfgc.transf_size = tx_len; + cfgc.sinc = DMA_INC_INC; + + if(pctx->cfg.spi_dfsmod == SPI_1BYTE) + { + cfgc.src_tr_width = DMA_WIDTH_BYTE; + cfgc.dst_tr_width = DMA_WIDTH_BYTE; + } + else + { + cfgc.src_tr_width = DMA_WIDTH_HALFWORD; + cfgc.dst_tr_width = DMA_WIDTH_HALFWORD; + } + + cfgc.src_msize = DMA_BSIZE_1; + cfgc.src_addr = (uint32_t)tx_buf; + cfgc.dinc = DMA_INC_NCHG; + cfgc.dst_msize = DMA_BSIZE_1; + cfgc.dst_addr = (uint32_t)&(Ssix->DataReg); + cfgc.enable_int = false; + hal_dma_config_channel(DMA_CH_0,&cfgc); + hal_dma_start_channel(DMA_CH_0); + Ssix->DMACR |= 0x02; + Ssix->DMATDLR = 0; +} + +static void config_dma_channel4spirx(hal_spi_t* spi_ptr,uint8_t* rx_buf,uint16_t rx_len) +{ + DMA_CH_CFG_t cfgc; + AP_SSI_TypeDef* Ssix = NULL; + Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; + Ssix->DMACR &= 0x02; + cfgc.transf_size = rx_len; + cfgc.sinc = DMA_INC_NCHG; + cfgc.src_tr_width = DMA_WIDTH_BYTE; + cfgc.src_msize = DMA_BSIZE_1; + cfgc.src_addr = (uint32_t)&(Ssix->DataReg); + cfgc.dinc = DMA_INC_INC; + cfgc.dst_tr_width = DMA_WIDTH_BYTE; + cfgc.dst_msize = DMA_BSIZE_1; + cfgc.dst_addr = (uint32_t)rx_buf; + cfgc.enable_int = false; + hal_dma_config_channel(DMA_CH_0,&cfgc); + hal_dma_start_channel(DMA_CH_0); + Ssix->DMACR |= 0x01; + Ssix->DMARDLR = 0; +} +#endif + +static int hal_spi_xmit_polling +( + hal_spi_t* spi_ptr, + uint8_t* tx_buf, + uint8_t* rx_buf, + uint16_t tx_len, + uint16_t rx_len +) +{ + uint32_t rx_size = rx_len, tx_size = tx_len; + uint32_t tmp_len,i; + AP_SSI_TypeDef* Ssix = NULL; + #if DMAC_USE + spi_Ctx_t* pctx; + pctx = &m_spiCtx[spi_ptr->spi_index]; + #endif + Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; + SPI_INIT_TOUT(to); + #if DMAC_USE + + if(rx_len && pctx->cfg.dma_rx_enable) + { + config_dma_channel4spirx(spi_ptr,rx_buf,rx_len); + } + else if(tx_len && pctx->cfg.dma_tx_enable) + { + config_dma_channel4spitx(spi_ptr,tx_buf,tx_len); + } + + #endif + + while(1) + { + if(Ssix->SR & TX_FIFO_NOT_FULL && tx_size + #if DMAC_USE + && !(pctx->cfg.dma_tx_enable) + #endif + ) +//#if DMAC_USE +// if(Ssix->SR & TX_FIFO_NOT_FULL && tx_size && !(pctx->cfg.dma_tx_enable)) +//#else +// if(Ssix->SR & TX_FIFO_NOT_FULL && tx_size) +//#endif + { + tmp_len = 8-Ssix->TXFLR; + + if(tmp_len > tx_size) + tmp_len = tx_size; + + if(tx_buf) + { + //support divider 2 + switch (tmp_len) + { + case 1: + Ssix->DataReg = *tx_buf; + break; + + case 2: + Ssix->DataReg = *tx_buf; + Ssix->DataReg = *(tx_buf+1); + break; + + case 3: + Ssix->DataReg = *tx_buf; + Ssix->DataReg = *(tx_buf+1); + Ssix->DataReg = *(tx_buf+2); + break; + + case 4: + Ssix->DataReg = *tx_buf; + Ssix->DataReg = *(tx_buf+1); + Ssix->DataReg = *(tx_buf+2); + Ssix->DataReg = *(tx_buf+3); + break; + + case 5: + Ssix->DataReg = *tx_buf; + Ssix->DataReg = *(tx_buf+1); + Ssix->DataReg = *(tx_buf+2); + Ssix->DataReg = *(tx_buf+3); + Ssix->DataReg = *(tx_buf+4); + break; + + case 6: + Ssix->DataReg = *tx_buf; + Ssix->DataReg = *(tx_buf+1); + Ssix->DataReg = *(tx_buf+2); + Ssix->DataReg = *(tx_buf+3); + Ssix->DataReg = *(tx_buf+4); + Ssix->DataReg = *(tx_buf+5); + break; + + case 7: + Ssix->DataReg = *tx_buf; + Ssix->DataReg = *(tx_buf+1); + Ssix->DataReg = *(tx_buf+2); + Ssix->DataReg = *(tx_buf+3); + Ssix->DataReg = *(tx_buf+4); + Ssix->DataReg = *(tx_buf+5); + Ssix->DataReg = *(tx_buf+6); + break; + + case 8: + Ssix->DataReg = *tx_buf; + Ssix->DataReg = *(tx_buf+1); + Ssix->DataReg = *(tx_buf+2); + Ssix->DataReg = *(tx_buf+3); + Ssix->DataReg = *(tx_buf+4); + Ssix->DataReg = *(tx_buf+5); + Ssix->DataReg = *(tx_buf+6); + Ssix->DataReg = *(tx_buf+7); + break; + + default: + break; + } + } + else + { + for(i = 0; i< tmp_len; i++) + { + Ssix->DataReg = 0; + } + } + + tx_size -= tmp_len; + } + + #if DMAC_USE + + if(((rx_len == 0) && ((tx_size == 0)||(tx_size && (pctx->cfg.dma_tx_enable)))) || + (rx_len && (tx_size == 0) && (pctx->cfg.dma_rx_enable))) + break; + else if(rx_len && !(pctx->cfg.dma_rx_enable)) + #else + if((rx_len == 0) && ((tx_size == 0))) + break; + else if(rx_len) + #endif + { + if(Ssix->RXFLR) + { + tmp_len = Ssix->RXFLR; + + for(i = 0; i< tmp_len; i++) + { + *rx_buf++= Ssix->DataReg; + } + + rx_size -= tmp_len; + } + + if(rx_size == 0) + break; + } + + SPI_CHECK_TOUT(to, SPI_OP_TIMEOUT, "hal_spi_xmit_polling TO\n"); + } + + #if DMAC_USE + + if((pctx->cfg.dma_rx_enable) || (pctx->cfg.dma_tx_enable)) + hal_dma_status_control(DMA_CH_0); + + #endif + + while(Ssix->SR & SPI_BUSY) + { + SPI_CHECK_TOUT(to, SPI_OP_TIMEOUT, "hal_spi_xmit_polling TO\n"); + } + + return PPlus_SUCCESS; +} + +static void spi0_sleep_handler(void) +{ + if(m_spiCtx[0].spi_info != NULL) + hal_spi_bus_deinit(m_spiCtx[0].spi_info); +} + +static void spi1_sleep_handler(void) +{ + if(m_spiCtx[1].spi_info != NULL) + hal_spi_bus_deinit(m_spiCtx[1].spi_info); +} + +static void spi0_wakeup_handler(void) +{ + NVIC_SetPriority((IRQn_Type)SPI0_IRQn, IRQ_PRIO_HAL); +} + +static void spi1_wakeup_handler(void) +{ + NVIC_SetPriority((IRQn_Type)SPI1_IRQn, IRQ_PRIO_HAL); +} + +void hal_spi_tmod_set(hal_spi_t* spi_ptr,SPI_TMOD_e mod) +{ + AP_SSI_TypeDef* Ssix = NULL; + Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; + Ssix->SSIEN = 0; + subWriteReg(&Ssix->CR0,9,8,mod); + Ssix->SSIEN = 1; +} + +void hal_spi_dfs_set(hal_spi_t* spi_ptr,SPI_DFS_e mod) +{ + AP_SSI_TypeDef* Ssix = NULL; + spi_Ctx_t* pctx; + Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; + pctx = &m_spiCtx[spi_ptr->spi_index]; + Ssix->SSIEN = 0; + subWriteReg(&Ssix->CR0,3,0,mod); + Ssix->SSIEN = 1; + pctx->cfg.spi_dfsmod = SPI_2BYTE; +} + + + +static void hal_spi_ndf_set(hal_spi_t* spi_ptr,uint16_t len) +{ + AP_SSI_TypeDef* Ssix = NULL; + + if(len == 0) + return; + + Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; + Ssix->SSIEN = 0; + Ssix->CR1 = len-1; + Ssix->SSIEN = 1; +} + +int hal_spi_transmit +( + hal_spi_t* spi_ptr, + SPI_TMOD_e mod, + uint8_t* tx_buf, + uint8_t* rx_buf, + uint16_t tx_len, + uint16_t rx_len +) +{ + int ret; + spi_Ctx_t* pctx; + AP_SSI_TypeDef* Ssix = NULL; + spi_xmit_t* trans_ptr; + SPI_HDL_VALIDATE(spi_ptr); + pctx = &m_spiCtx[spi_ptr->spi_index]; + trans_ptr = &(pctx->transmit); + + if(((tx_len == 0)&&(rx_len == 0))||(mod > SPI_EEPROM)||(tx_buf == NULL)) + return PPlus_ERR_INVALID_PARAM; + + if(pctx->transmit.busy == true) + return PPlus_ERR_BUSY; + + #if DMAC_USE + + if((pctx->cfg.dma_rx_enable && (rx_len==0)) || + (pctx->cfg.dma_tx_enable && (tx_len==0))) + { + return PPlus_ERR_INVALID_PARAM; + } + + #endif + Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; + hal_spi_tmod_set(spi_ptr,mod); + + if(mod > SPI_TXD) //spi receive only or eeprom read,should set read data len(ndf) + { + hal_spi_ndf_set(spi_ptr,rx_len); + } + + if(pctx->cfg.force_cs == true /*&& pctx->is_slave_mode == FALSE*/) + { + hal_gpio_fmux(pctx->cfg.ssn_pin,Bit_DISABLE); + hal_gpio_write(pctx->cfg.ssn_pin,0); + } + + if(pctx->cfg.int_mode == false) + { + ret = hal_spi_xmit_polling(spi_ptr,tx_buf, rx_buf, tx_len,rx_len); + + if(pctx->cfg.force_cs == true && pctx->is_slave_mode == FALSE) + hal_gpio_fmux(pctx->cfg.ssn_pin,Bit_ENABLE); + + if(ret) + return PPlus_ERR_TIMEOUT; + } + else + { + spi_int_disable(spi_ptr); + + if(trans_ptr->buf_len < tx_len) + return PPlus_ERR_NO_MEM; + + if(tx_buf) + { + if(!trans_ptr->tx_buf) + return PPlus_ERR_NO_MEM; + } + + trans_ptr->tx_offset = 0; + memcpy(trans_ptr->tx_buf,tx_buf,tx_len); + + if(Ssix->SR & TX_FIFO_NOT_FULL) + { + uint16_t _tx_len; + uint8_t dummy[8]; + + if(rx_buf) + { + trans_ptr->rx_buf = rx_buf; + } + + hal_pwrmgr_lock((MODULE_e)(MOD_SPI0 + spi_ptr->spi_index)); + _tx_len = (tx_len >= 8)?8:tx_len; + + if(trans_ptr->tx_buf) + { + trans_ptr->tx_offset += _tx_len; + hal_spi_write_fifo(Ssix,_tx_len,tx_buf); + } + else + { + hal_spi_write_fifo(Ssix,_tx_len,dummy); + } + + trans_ptr->xmit_len = tx_len; + } + + pctx->transmit.busy = true; + spi_int_enable(spi_ptr, 0x11); + } + + return PPlus_SUCCESS; +} + +int hal_spi_set_tx_buffer(hal_spi_t* spi_ptr,uint8_t* tx_buf,uint16_t len) +{ + SPI_HDL_VALIDATE(spi_ptr); + + if((tx_buf == NULL) || (len == 0)) + return PPlus_ERR_INVALID_PARAM; + + m_spiCtx[spi_ptr->spi_index].transmit.tx_buf = tx_buf;//used when tx int + m_spiCtx[spi_ptr->spi_index].transmit.buf_len = len; + return PPlus_SUCCESS; +} + +int hal_spi_set_int_mode(hal_spi_t* spi_ptr,bool en) +{ + SPI_HDL_VALIDATE(spi_ptr); + m_spiCtx[spi_ptr->spi_index].cfg.int_mode = en; + + if(en) + { + m_spiCtx[spi_ptr->spi_index].cfg.int_mode = true; + spi_int_enable(spi_ptr, 0x10); + } + else + { + m_spiCtx[spi_ptr->spi_index].cfg.int_mode = false; + spi_int_disable(spi_ptr); + } + + return PPlus_SUCCESS; +} + +int hal_spi_set_force_cs(hal_spi_t* spi_ptr,bool en) +{ + SPI_HDL_VALIDATE(spi_ptr); + m_spiCtx[spi_ptr->spi_index].cfg.force_cs = en; + return PPlus_SUCCESS; +} + +bool hal_spi_get_transmit_bus_state(hal_spi_t* spi_ptr) +{ + return m_spiCtx[spi_ptr->spi_index].transmit.busy; +} + + +int hal_spi_TxComplete(hal_spi_t* spi_ptr) +{ + AP_SSI_TypeDef* Ssix = NULL; + SPI_HDL_VALIDATE(spi_ptr); + Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; + SPI_INIT_TOUT(to); + + while(Ssix->SR & SPI_BUSY) + { + SPI_CHECK_TOUT(to, SPI_OP_TIMEOUT, "hal_spi_TxComplete TO\n"); + } + + return PPlus_SUCCESS; +} + +int hal_spi_send_byte(hal_spi_t* spi_ptr,uint8_t data) +{ + AP_SSI_TypeDef* Ssix = NULL; + SPI_HDL_VALIDATE(spi_ptr); + Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; + + if(Ssix->SR & TX_FIFO_NOT_FULL) + { + Ssix->DataReg = data & 0xff; + SPI_INIT_TOUT(to); + + while(Ssix->SR & SPI_BUSY) + { + SPI_CHECK_TOUT(to, SPI_OP_TIMEOUT,"hal_spi_send_byte TO\n"); + } + } + + return PPlus_SUCCESS; +} + + +int hal_spi_bus_init(hal_spi_t* spi_ptr,spi_Cfg_t cfg) +{ + spi_Ctx_t* pctx = NULL; + + if((spi_ptr == NULL) || (spi_ptr->spi_index > 1)) + return PPlus_ERR_INVALID_PARAM; + + pctx = &m_spiCtx[spi_ptr->spi_index]; + + if(pctx->spi_info != NULL) + return PPlus_ERR_BUSY; + + hal_clk_gate_enable((MODULE_e)(MOD_SPI0 + spi_ptr->spi_index)); + hal_spi_pin_init(spi_ptr,cfg.sclk_pin,cfg.ssn_pin,cfg.MOSI,cfg.MISO); + hal_spi_master_init(spi_ptr,cfg.baudrate, cfg.spi_scmod, cfg.spi_tmod); + pctx->cfg = cfg; + pctx->transmit.busy = false; + pctx->spi_info = spi_ptr; + + if(cfg.int_mode) + spi_int_enable(spi_ptr, 0x10); + else + spi_int_disable(spi_ptr); + + pctx->is_slave_mode = false; + return PPlus_SUCCESS; +} + +int hal_spis_clear_rx(hal_spi_t* spi_ptr) +{ + AP_SSI_TypeDef* Ssix = NULL; + volatile uint8_t rx; + SPI_HDL_VALIDATE(spi_ptr); + Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; + + while(Ssix->RXFLR) + { + rx = Ssix->DataReg; + } + + return (int)rx; +} + +uint32_t hal_spis_rx_len(hal_spi_t* spi_ptr) +{ + AP_SSI_TypeDef* Ssix = NULL; + Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; + return Ssix->RXFLR; +} + +int hal_spis_read_rxn(hal_spi_t* spi_ptr, uint8_t* pbuf, uint16_t len) +{ + AP_SSI_TypeDef* Ssix = NULL; + Ssix = (spi_ptr->spi_index == SPI0) ? AP_SPI0 : AP_SPI1; + + while(len) + { + *pbuf = Ssix->DataReg; + pbuf ++; + len --; + } + + return PPlus_SUCCESS; +} + +int hal_spis_bus_init(hal_spi_t* spi_ptr,spi_Cfg_t cfg) +{ + spi_Ctx_t* pctx = NULL; + + if((spi_ptr == NULL) || (spi_ptr->spi_index > 1)) + return PPlus_ERR_INVALID_PARAM; + + pctx = &m_spiCtx[spi_ptr->spi_index]; + + if(pctx->spi_info != NULL) + return PPlus_ERR_BUSY; + + hal_clk_gate_enable((MODULE_e)(MOD_SPI0 + spi_ptr->spi_index)); + hal_spi_pin_init(spi_ptr,cfg.sclk_pin,cfg.ssn_pin,cfg.MOSI,cfg.MISO); + hal_spi_slave_init(spi_ptr,cfg.baudrate, cfg.spi_scmod, cfg.spi_tmod); + pctx->cfg = cfg; + memset(&(pctx->transmit), 0, sizeof(spi_xmit_t)); + pctx->spi_info = spi_ptr; + pctx->is_slave_mode = true; + + if(cfg.int_mode) + spi_int_enable(spi_ptr, 0x10); + else + spi_int_disable(spi_ptr); + + return PPlus_SUCCESS; +} + +/************************************************************************************** + @fn hal_spi_deinit + + @brief This function will deinit the spi you select. + + input parameters + + @param hal_spi_t* spi_ptr: spi module handle. + + + output parameters + + @param None. + + @return + PPlus_SUCCESS + PPlus_ERR_INVALID_PARAM + **************************************************************************************/ +int hal_spi_bus_deinit(hal_spi_t* spi_ptr) +{ + SPI_HDL_VALIDATE(spi_ptr); + hal_clk_gate_disable((MODULE_e)(MOD_SPI0 + spi_ptr->spi_index)); + //spi_int_disable(spi_ptr); + hal_spi_pin_deinit(m_spiCtx[spi_ptr->spi_index].cfg.sclk_pin,m_spiCtx[spi_ptr->spi_index].cfg.ssn_pin,m_spiCtx[spi_ptr->spi_index].cfg.MOSI,m_spiCtx[spi_ptr->spi_index].cfg.MISO); + memset(&m_spiCtx,0,2*sizeof(spi_Ctx_t)); + return PPlus_SUCCESS; +} + + + +/************************************************************************************** + @fn hal_spi_init + + @brief it is used to init spi module. + + input parameters + @param None + + output parameters + @param None. + + @return None. + **************************************************************************************/ +int hal_spi_init(SPI_INDEX_e channel) +{ + int ret = 0; + + if(channel == SPI0) + { + ret = hal_pwrmgr_register(MOD_SPI0,spi0_sleep_handler, spi0_wakeup_handler); + + if(ret == PPlus_SUCCESS) + memset(&m_spiCtx[0],0,sizeof(spi_Ctx_t)); + + return ret; + } + else if(channel == SPI1) + { + ret = hal_pwrmgr_register(MOD_SPI0,spi1_sleep_handler, spi1_wakeup_handler); + + if(ret == PPlus_SUCCESS) + memset(&m_spiCtx[1],0,sizeof(spi_Ctx_t)); + + return ret; + } + + return PPlus_ERR_INVALID_PARAM; +} + +#if DMAC_USE +int hal_spi_dma_set(hal_spi_t* spi_ptr,bool ten,bool ren) +{ + spi_Ctx_t* pctx = NULL; + + if((spi_ptr == NULL) || (spi_ptr->spi_index > 1)) + return PPlus_ERR_INVALID_PARAM; + + pctx = &m_spiCtx[spi_ptr->spi_index]; + pctx->cfg.dma_rx_enable = ren; + pctx->cfg.dma_tx_enable = ten; + return PPlus_SUCCESS; +} +#endif + + diff --git a/src/components/driver/spi/spi.h b/src/components/driver/spi/spi.h new file mode 100644 index 0000000..98c6cf2 --- /dev/null +++ b/src/components/driver/spi/spi.h @@ -0,0 +1,177 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file spi.h + @brief Contains all functions support for spi driver + @version 0.0 + @date 18. Oct. 2017 + @author qing.han + + + +*******************************************************************************/ +#ifndef _SPI_H_ +#define _SPI_H_ + +#include "types.h" +#include "gpio.h" +#include "clock.h" +#include "bus_dev.h" + +#define SPI_MASTER_MODE 1 //define master mode,1:master mode,0:salve mode + +#define SPI_USE_TIMEOUT 1 +#define SPI_OP_TIMEOUT 1000 //100ms for an Byte operation +#if(SPI_USE_TIMEOUT == 1) + #define SPI_INIT_TOUT(to) int to = hal_systick() + #define SPI_CHECK_TOUT(to, timeout,loginfo) {if(hal_ms_intv(to) > timeout){LOG(loginfo);return PPlus_ERR_TIMEOUT;}} +#else + #define SPI_INIT_TOUT(to) + #define SPI_CHECK_TOUT(to, timeout,loginfo) +#endif + +#define ENABLE_SPI Ssix->SSIEN = 1 +#define DISABLE_SPI Ssix->SSIEN = 0 +#define NUMBER_DATA_RX_FIFO Ssix->RXFLR +#define NUMBER_DATA_TX_FIFO Ssix->TXFLR + +#define SPI_BUSY 0x1 +#define TX_FIFO_NOT_FULL 0x2 +#define TX_FIFO_EMPTY 0x4 +#define RX_FIFO_NOT_EMPTY 0x8 + +typedef enum +{ + SPI_MODE0=0, //SCPOL=0,SCPH=0 + SPI_MODE1, //SCPOL=0,SCPH=1 + SPI_MODE2, //SCPOL=1,SCPH=0 + SPI_MODE3, //SCPOL=1,SCPH=1 +} SPI_SCMOD_e; + +typedef enum +{ + SPI_1BYTE=0x07, //1byte + SPI_2BYTE=0x0f, //2byte +} SPI_DFS_e; + + +typedef enum +{ + SPI_TRXD=0, //Transmit & Receive + SPI_TXD, //Transmit Only + SPI_RXD, //Receive Only + SPI_EEPROM, //EEPROM Read +} SPI_TMOD_e; + +typedef enum +{ + SPI0=0, //use spi 0 + SPI1, //use spi 1 +} SPI_INDEX_e; + + +typedef enum +{ + SPI_TX_COMPLETED = 1, + SPI_RX_COMPLETED, + SPI_TX_REQ_S, //slave tx + SPI_RX_DATA_S, //slave rx +} SPI_EVT_e; + +typedef struct _spi_evt_t +{ + uint8_t id; + SPI_EVT_e evt; + uint8_t* data; + uint8_t len; +} spi_evt_t; + +typedef void (*spi_hdl_t)(spi_evt_t* pevt); + +typedef struct _spi_Cfg_t +{ + GPIO_Pin_e sclk_pin; + GPIO_Pin_e ssn_pin; + GPIO_Pin_e MOSI; + GPIO_Pin_e MISO; + uint32_t baudrate; + SPI_TMOD_e spi_tmod; + SPI_SCMOD_e spi_scmod; + SPI_DFS_e spi_dfsmod; + #if DMAC_USE + bool dma_tx_enable; + bool dma_rx_enable; + #endif + bool int_mode; + bool force_cs; + spi_hdl_t evt_handler; +} spi_Cfg_t; + +typedef enum +{ + TRANSMIT_FIFO_EMPTY = 0x01, + TRANSMIT_FIFO_OVERFLOW = 0x02, + RECEIVE_FIFO_UNDERFLOW = 0x04, + RECEIVE_FIFO_OVERFLOW = 0x08, + RECEIVE_FIFO_FULL = 0x10, +} SPI_INT_STATUS_e; + +typedef struct _hal_spi_t +{ + SPI_INDEX_e spi_index; +} hal_spi_t; + +typedef struct +{ + bool busy; + uint16_t xmit_len; + uint16_t buf_len; + uint8_t* tx_buf; + uint8_t* rx_buf; + uint16_t tx_offset; + uint16_t rx_offset; +} spi_xmit_t; + +void __attribute__((weak)) hal_SPI0_IRQHandler(void); + +void __attribute__((weak)) hal_SPI1_IRQHandler(void); + +void hal_spi_tmod_set(hal_spi_t* spi_ptr,SPI_TMOD_e mod); +void hal_spi_dfs_set(hal_spi_t* spi_ptr,SPI_DFS_e mod); + +int hal_spis_clear_rx(hal_spi_t* spi_ptr); +uint32_t hal_spis_rx_len(hal_spi_t* spi_ptr); +int hal_spis_read_rxn(hal_spi_t* spi_ptr, uint8_t* pbuf, uint16_t len); +int hal_spi_bus_init(hal_spi_t* spi_ptr,spi_Cfg_t cfg); +int hal_spis_bus_init(hal_spi_t* spi_ptr,spi_Cfg_t cfg); + +int hal_spi_bus_deinit(hal_spi_t* spi_ptr); + +int hal_spi_init(SPI_INDEX_e channel); + +int hal_spi_transmit +( + hal_spi_t* spi_ptr, + SPI_TMOD_e mod, + uint8_t* tx_buf, + uint8_t* rx_buf, + uint16_t tx_len, + uint16_t rx_len +); + +int hal_spi_set_tx_buffer(hal_spi_t* spi_ptr,uint8_t* tx_buf,uint16_t len); +int hal_spi_set_int_mode(hal_spi_t* spi_ptr,bool en); +int hal_spi_set_force_cs(hal_spi_t* spi_ptr,bool en); + +bool hal_spi_get_transmit_bus_state(hal_spi_t* spi_ptr); +int hal_spi_TxComplete(hal_spi_t* spi_ptr); +int hal_spi_send_byte(hal_spi_t* spi_ptr,uint8_t data); + +#if DMAC_USE + int hal_spi_dma_set(hal_spi_t* spi_ptr,bool ten,bool ren); +#endif + + +#endif diff --git a/src/components/driver/spiflash/spiflash.c b/src/components/driver/spiflash/spiflash.c new file mode 100644 index 0000000..da6cb0e --- /dev/null +++ b/src/components/driver/spiflash/spiflash.c @@ -0,0 +1,603 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ +#include "error.h" +#include "spiflash.h" +#include "log.h" +#include "string.h" +#include "dma.h" + + +uint32_t spiflash_space = 0x80000; + +hal_spi_t spiflash_spi = +{ + .spi_index = SPI0, +}; + +void spi_cb(spi_evt_t* evt) +{ +} + +void dma_cb(DMA_CH_t ch) +{ +} + + +spi_Cfg_t spi_cfg = +{ + .sclk_pin = GPIO_P02, + .ssn_pin = GPIO_P07, + .MOSI = GPIO_P00, + .MISO = GPIO_P03, + + .baudrate = 8000000, + .spi_tmod = SPI_TRXD, + .spi_scmod = SPI_MODE0, + .spi_dfsmod = SPI_1BYTE, + + #if DMAC_USE + .dma_tx_enable = false, + .dma_rx_enable = false, + #endif + + .int_mode = false, + .force_cs = true, + .evt_handler = spi_cb, +}; + +HAL_DMA_t dma_cfg = +{ + .dma_channel = DMA_CH_0, + .evt_handler = dma_cb, +}; + + +#define spiflash_cmd_tx_and_rx(mode,tx_buf,rx_buf,tx_len,rx_len) \ + hal_spi_transmit(&spiflash_spi,mode,tx_buf,rx_buf,tx_len,rx_len) + +//gd25q16 driver +uint32_t spiflash_read_identification(void)//check +{ + uint8_t buf_send[1] = {FLASH_RDID}; + uint8_t buf_rece[3] = {0x00,0x00,0x00}; + hal_spi_dma_set(&spiflash_spi,0,0); + + if(PPlus_SUCCESS == spiflash_cmd_tx_and_rx(SPI_EEPROM,buf_send,buf_rece,1,3)) + return (buf_rece[0] << 16)|(buf_rece[1] << 8) | (buf_rece[2]); + else + return 0xFFFFFF; +} + +uint16_t spiflash_read_status_register(uint8_t bitsSel)//0~low other~high +{ + uint8_t buf_send[1] = {0x00}; + uint8_t buf_rece[2] = {0x00,0x00}; + + if(bitsSel == 0) + buf_send[0] = FLASH_RDSR_LOW; + else + buf_send[0] = FLASH_RDSR_HIGH; + + hal_spi_dma_set(&spiflash_spi,0,0); + + if(PPlus_SUCCESS == spiflash_cmd_tx_and_rx(SPI_EEPROM,buf_send,buf_rece,1,2)) + return (buf_rece[0] << 8) | (buf_rece[1]); + else + return 0xFFFF; +} + +bool spiflash_bus_busy(void) +{ + return (spiflash_read_status_register(0) & 0x01); +} + + +void spiflash_program_erase_suspend(void) +{ + uint8_t buf_send[1] = {FLASH_PES}; + hal_spi_dma_set(&spiflash_spi,0,0); + + if(PPlus_SUCCESS == spiflash_cmd_tx_and_rx(SPI_TXD,buf_send,NULL,1,0)) + { + ; + } +} + +void spiflash_program_erase_resume(void) +{ + uint8_t buf_send[1] = {FLASH_PER}; + hal_spi_dma_set(&spiflash_spi,0,0); + + if(PPlus_SUCCESS == spiflash_cmd_tx_and_rx(SPI_TXD,buf_send,NULL,1,0)) + { + ; + } +} + +void spiflash_deep_powerdown(void) +{ + uint8_t buf_send[1] = {FLASH_DP}; + hal_spi_dma_set(&spiflash_spi,0,0); + + if(PPlus_SUCCESS == spiflash_cmd_tx_and_rx(SPI_TXD,buf_send,NULL,1,0)) + { + ; + } +} + +void spiflash_release_from_powerdown(void) +{ + uint8_t buf_send[1] = {FLASH_RDI}; + hal_spi_dma_set(&spiflash_spi,0,0); + + if(PPlus_SUCCESS == spiflash_cmd_tx_and_rx(SPI_TXD,buf_send,NULL,1,0)) + { + ; + } +} + +void spiflash_write_enable(void) +{ + uint8_t buf_send[1] = {FLASH_WREN}; + + while(spiflash_bus_busy()); + + hal_spi_dma_set(&spiflash_spi,0,0); + + if(PPlus_SUCCESS == spiflash_cmd_tx_and_rx(SPI_TXD,buf_send,NULL,1,0)) + { + ; + } +} + +void spiflash_write_disable(void) +{ + uint8_t buf_send[1] = {FLASH_WRDIS}; + //while(spiflash_bus_busy()); + hal_spi_dma_set(&spiflash_spi,0,0); + + if(PPlus_SUCCESS == spiflash_cmd_tx_and_rx(SPI_TXD,buf_send,NULL,1,0)) + { + ; + } +} + +void spiflash_chip_erase(void) +{ + uint8_t buf_send[1] = {FLASH_CE}; + buf_send[0] = FLASH_CE; + spiflash_write_enable(); + hal_spi_dma_set(&spiflash_spi,0,0); + + if(PPlus_SUCCESS == spiflash_cmd_tx_and_rx(SPI_TXD,buf_send,NULL,1,0)) + { + ; + } + + while(spiflash_bus_busy()); +} + +void spiflash_sector_erase(uint32_t addr) +{ + uint8_t buf_send[4] = {FLASH_SE,0x00,0x00,0x00}; + buf_send[1] = (addr>>16) & 0xff; + buf_send[2] = (addr>>8) & 0xff; + buf_send[3] = addr & 0xff; + spiflash_write_enable(); + hal_spi_dma_set(&spiflash_spi,0,0); + + if(PPlus_SUCCESS == spiflash_cmd_tx_and_rx(SPI_TXD,buf_send,NULL,4,0)) + { + ; + } + + while(spiflash_bus_busy()); +} + +void spiflash_block_erase_32KB(uint32_t addr) +{ + uint8_t buf_send[4] = {FLASH_BE_32KB,0x00,0x00,0x00}; + buf_send[1] = (addr>>16) & 0xff; + buf_send[2] = (addr>>8) & 0xff; + buf_send[3] = addr & 0xff; + spiflash_write_enable(); + hal_spi_dma_set(&spiflash_spi,0,0); + + if(PPlus_SUCCESS == spiflash_cmd_tx_and_rx(SPI_TXD,buf_send,NULL,4,0)) + { + ; + } + + while(spiflash_bus_busy()); +} + +void spiflash_block_erase_64KB(uint32_t addr) +{ + uint8_t buf_send[4] = {FLASH_BE_64KB,0x00,0x00,0x00}; + buf_send[1] = (addr>>16) & 0xff; + buf_send[2] = (addr>>8) & 0xff; + buf_send[3] = addr & 0xff; + spiflash_write_enable(); + hal_spi_dma_set(&spiflash_spi,0,0); + + if(PPlus_SUCCESS == spiflash_cmd_tx_and_rx(SPI_TXD,buf_send,NULL,4,0)) + { + ; + } + + while(spiflash_bus_busy()); +} + + +void spiflash_write_status_register(uint8_t data) +{ + uint8_t buf_send[2] = {FLASH_WRSR,0x00}; + buf_send[1] = data; + + while(spiflash_bus_busy()); + + spiflash_write_enable(); + hal_spi_dma_set(&spiflash_spi,0,0); + + if(PPlus_SUCCESS == spiflash_cmd_tx_and_rx(SPI_TXD,buf_send,NULL,2,0)) + { + ; + } +} + +static void spiflash_write_unit(uint32_t addr,uint8_t* tx_buf,uint8_t tx_len)//tx_len in [1,4] +{ + uint8_t buf_send[8] = {FLASH_PP,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + buf_send[1] = (addr>>16)&0xff; + buf_send[2] = (addr>>8)&0xff; + buf_send[3] = addr & 0xff; + + switch(tx_len) + { + case 1: + buf_send[4] = *tx_buf; + break; + + case 2: + buf_send[4] = *tx_buf; + buf_send[5] = *(tx_buf+1); + break; + + case 3: + buf_send[4] = *tx_buf; + buf_send[5] = *(tx_buf+1); + buf_send[6] = *(tx_buf+2); + break; + + case 4: + buf_send[4] = *tx_buf; + buf_send[5] = *(tx_buf+1); + buf_send[6] = *(tx_buf+2); + buf_send[7] = *(tx_buf+3); + break; + + default: + break; + } + + spiflash_write_enable(); + hal_spi_dma_set(&spiflash_spi,0,0); + + if(PPlus_SUCCESS == spiflash_cmd_tx_and_rx(SPI_TXD,buf_send,NULL,(tx_len + 4),0)) + { + ; + } +} + +void spiflash_write(uint32_t addr,uint8_t* tx_buf,uint16_t tx_len) +{ + uint16_t offset = 0,ret16; + ret16 = spiflash_read_status_register(0); + + if(ret16 != 0) + { + spiflash_write_status_register(0x00); + + while(spiflash_bus_busy()); + } + + while(tx_len > 0) + { + if(tx_len >= 4) + { + spiflash_write_unit((addr + offset),(tx_buf + offset),4); + offset += 4; + tx_len -= 4; + } + else + { + spiflash_write_unit((addr + offset),(tx_buf + offset),tx_len); + tx_len = 0; + } + + while(spiflash_bus_busy()); + } + +//you can process the protect with your requirenment +// if(ret16 != 0) +// { +// spiflash_write_status_register(ret16); +// } +} + +void spiflash_write_eeprom(uint32_t addr,uint8_t* tx_buf,uint16_t tx_len) +{ + uint8_t buf_send[256+4]; + uint16_t ret16; + buf_send[0] = FLASH_PP; + buf_send[1] = (addr>>16)&0xff; + buf_send[2] = (addr>>8)&0xff; + buf_send[3] = addr & 0xff; + memcpy(&buf_send[4],tx_buf,tx_len); + ret16 = spiflash_read_status_register(0); + + if(ret16 != 0) + { + spiflash_write_status_register(0x00); + + while(spiflash_bus_busy() == TRUE); + } + + spiflash_write_enable(); + hal_spi_dma_set(&spiflash_spi,1,0); + + if(PPlus_SUCCESS == spiflash_cmd_tx_and_rx(SPI_TXD,buf_send,NULL,(tx_len + 4),0)) + { + ; + } + + while(spiflash_bus_busy()); +} + + +static void spiflash_read_unit(uint32_t addr,uint8_t* rx_buf,uint8_t rx_len)//rx_len in [1,4] +{ + uint8_t buf_send[4] = {FLASH_READ,0x00,0x00,0x00}; + uint8_t buf_rece[4] = {0x00,0x00,0x00,0x00}; + buf_send[1] = (addr>>16)&0xff; + buf_send[2] = (addr>>8)&0xff; + buf_send[3] = addr & 0xff; + hal_spi_dma_set(&spiflash_spi,0,0); + + if(PPlus_SUCCESS == spiflash_cmd_tx_and_rx(SPI_EEPROM,buf_send,buf_rece,4,rx_len)) + { + switch(rx_len) + { + case 1: + *rx_buf = buf_rece[0]; + break; + + case 2: + *rx_buf = buf_rece[0]; + *(rx_buf+1) = buf_rece[1]; + break; + + case 3: + *rx_buf = buf_rece[0]; + *(rx_buf+1) = buf_rece[1]; + *(rx_buf+2) = buf_rece[2]; + break; + + case 4: + *rx_buf = buf_rece[0]; + *(rx_buf+1) = buf_rece[1]; + *(rx_buf+2) = buf_rece[2]; + *(rx_buf+3) = buf_rece[3]; + break; + + default: + break; + } + } +} + +static void spiflash_read_eeprom(uint32_t addr,uint8_t* rx_buf,uint16_t rx_len)//rx_len in [1,4] +{ + uint8_t buf_send[4] = {FLASH_READ,0x00,0x00,0x00}; + buf_send[1] = (addr>>16)&0xff; + buf_send[2] = (addr>>8)&0xff; + buf_send[3] = addr & 0xff; + hal_spi_dma_set(&spiflash_spi,0,1); + + if(PPlus_SUCCESS == spiflash_cmd_tx_and_rx(SPI_EEPROM,buf_send,rx_buf,4,rx_len)) + { + ; + } +} + +void spiflash_read(uint32_t addr,uint8_t* rx_buf,uint16_t rx_len) +{ +//polling mode=polling +//force_cs=0 + uint16_t offset = 0; + + while(rx_len > 0) + { + if(rx_len >= 4) + { + spiflash_read_unit((addr + offset),(rx_buf + offset),4); + offset += 4; + rx_len -= 4; + } + else + { + spiflash_read_unit((addr + offset),(rx_buf + offset),rx_len); + rx_len = 0; + } + } +} + +int spiflash_init(void) +{ + uint8_t retval = PPlus_SUCCESS; + retval = hal_spi_bus_init(&spiflash_spi,spi_cfg); + + if(retval != PPlus_SUCCESS) + { + LOG("spi init err!please check it!\n"); + return retval; + } + + retval = hal_dma_init_channel(dma_cfg); + + if(retval != PPlus_SUCCESS) + { + LOG("dma init err!please check it!\n"); + return retval; + } + + return retval; +} + +static void check_flash_space(uint8_t rev) +{ + if(rev == 0x11) //128k flash + { + spiflash_space = 0x20000; + } + else if(rev == 0x12) //256k flash + { + spiflash_space = 0x40000; + } + else if(rev == 0x13) //512k flash + { + spiflash_space = 0x80000; + } + else if(rev == 0x14) //1m flash + { + spiflash_space = 0x100000; + } + else if(rev == 0x15) //2m flash + { + spiflash_space = 0x200000; + } + else if(rev == 0x16) //4m flash + { + spiflash_space = 0x400000; + } + else + { + spiflash_space = 0x80000; //default value + } +} + + +//gd25q16 +int vendorflash_init(void) +{ + //if(hal_spi_bus_init(&spi,cfg) == PPlus_SUCCESS)//config and init spi first + // LOG("spi init success!\n"); + uint32_t dev = spiflash_read_identification(); + + if((!dev) || (dev==0xFFFFFF)) + { + LOG("read flash id error %X\n",dev); + return PPlus_ERR_INVALID_PARAM; + } + + LOG("flash id:0x%x\n",dev); + check_flash_space(dev&0xff); + return PPlus_SUCCESS; +} + +int vendorflash_read(uint32_t addr,uint8_t* data,uint16_t len) +{ + if((addr < spiflash_space) && (data != NULL) && (len > 0)) + { + spiflash_read_eeprom(addr,data,len); + return PPlus_SUCCESS; + } + + return PPlus_ERR_SPI_FLASH; +} + +int vendorflash_erase(uint32_t addr,uint32_t len) +{ + uint8_t lockinfo = 0; + uint32_t remainder = 0; + + if((addr >= spiflash_space) || (len == 0)) + return PPlus_ERR_INVALID_PARAM; + + lockinfo = spiflash_read_status_register(0); + spiflash_write_status_register(0x00); + + if((addr == 0) && (len == spiflash_space)) + spiflash_chip_erase(); + else + { + remainder = addr%0x1000;//4KB + + if(remainder) + { + addr -= remainder; + len += remainder; + } + + remainder = len%0x1000;//4KB + + if(remainder) + { + len = len + 0x1000 - remainder; + } + + addr = addr/0x1000; + len = len/0x1000; + + while(len > 0) + { + if(((addr %16) == 0) && (len >= 16)) + { + while(spiflash_bus_busy()); + + spiflash_block_erase_64KB(addr*0x1000); + addr += 16; + len -= 16; + continue; + } + + if(((addr %8) == 0) && (len >= 8)) + { + while(spiflash_bus_busy()); + + spiflash_block_erase_32KB(addr*0x1000); + addr += 8; + len -= 8; + continue; + } + + if(len >= 1) + { + while(spiflash_bus_busy()); + + spiflash_sector_erase(addr*0x1000); + addr += 1; + len -= 1; + continue; + } + } + } + + spiflash_write_status_register(lockinfo); + + while(spiflash_bus_busy()); + + return PPlus_SUCCESS; +} + +int vendorflash_write(uint32_t addr,const uint8_t* data,uint16_t len) +{ + if((addr < spiflash_space) && (data != NULL) && (len > 0)) + { + spiflash_write_eeprom(addr,(uint8_t*)data,len); + return PPlus_SUCCESS; + } + + return PPlus_ERR_SPI_FLASH; +} diff --git a/src/components/driver/spiflash/spiflash.h b/src/components/driver/spiflash/spiflash.h new file mode 100644 index 0000000..d641779 --- /dev/null +++ b/src/components/driver/spiflash/spiflash.h @@ -0,0 +1,83 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +#ifndef __SPIFLASH_H__ +#define __SPIFLASH_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "types.h" +#include "spi.h" + +/*gd25q16 cmd define*/ +#define FLASH_WREN 0x06 +#define FLASH_WRDIS 0x04 +#define FLASH_CE 0x60 +//#define FLASH_CE 0xC7 + +#define FLASH_DP 0xB9 +#define FLASH_RDI 0xAB +#define FLASH_SE 0x20 +#define FLASH_BE_32KB 0x52 +#define FLASH_BE_64KB 0xD8 +#define FLASH_WRSR 0x01 +#define FLASH_RDID 0x9F +#define FLASH_RDSR_LOW 0x05 +#define FLASH_RDSR_HIGH 0x35 +#define FLASH_PP 0x02 +#define FLASH_READ 0x03 + +#define FLASH_PES 0x75 +#define FLASH_PER 0x7A + +extern uint32_t spiflash_space; + +typedef enum +{ + FLASH_ERROR = 0, + FLASH_IDLE = 1, + FLASH_ERASING = 2, + FALSH_DATA_WRITING = 3, + FLASH_STATUS_WRITEING = 4, + FLASH_READING = 5 +} FLASH_STATUS_e; + +extern hal_spi_t spiflash_spi; + +/*gd25q16 api for hardware debug*/ +uint32_t spiflash_read_identification(void); +uint16_t spiflash_read_status_register(uint8_t bitsSel); +bool spiflash_bus_busy(void); +void spiflash_program_erase_suspend(void); +void spiflash_program_erase_resume(void); +void spiflash_deep_powerdown(void); +void spiflash_release_from_powerdown(void); + +void spiflash_write_enable(void); +void spiflash_write_disable(void); +void spiflash_chip_erase(void); +void spiflash_sector_erase(uint32_t addr); +void spiflash_block_erase_32KB(uint32_t addr); +void spiflash_block_erase_64KB(uint32_t addr); +void spiflash_write_status_register(uint8_t data); + +void spiflash_write(uint32_t addr,uint8_t* tx_buf,uint16_t tx_len); +void spiflash_read(uint32_t addr,uint8_t* rx_buf,uint16_t rx_len); + +int spiflash_init(void); + +/*gd25q16 api for user develop*/ +int vendorflash_init(void); +int vendorflash_read(uint32_t addr,uint8_t* data,uint16_t len); +int vendorflash_erase(uint32_t addr,uint32_t len); +int vendorflash_write(uint32_t addr,const uint8_t* data,uint16_t len); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/src/components/driver/timer/timer.c b/src/components/driver/timer/timer.c new file mode 100644 index 0000000..5b1eb5b --- /dev/null +++ b/src/components/driver/timer/timer.c @@ -0,0 +1,154 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ +#include "rom_sym_def.h" +#include "timer.h" +#include "error.h" +#include "clock.h" +#include "pwrmgr.h" +#include "jump_function.h" + +AP_TIM_TypeDef* const TimerIndex[FREE_TIMER_NUMBER]= {AP_TIM5,AP_TIM6}; +static ap_tm_hdl_t s_ap_callback = NULL; + +static int hal_timer_clear_int(AP_TIM_TypeDef* TIMx) +{ + return TIMx->EOI; +} + +static void hal_timer_stop_counter(AP_TIM_TypeDef* TIMx) +{ + TIMx->ControlReg = 0; + TIMx->LoadCount = 0; //0x0 + TIMx->CurrentCount = 0;//0x4 +} + +static void hal_timer_set_loadtimer(AP_TIM_TypeDef* TIMx, int time) +{ + if(time>0) + { + TIMx->ControlReg = 0x0; + TIMx->ControlReg = 0x2; + TIMx->LoadCount = 4*time;// 4MHz system timer, * 4 to convert to 1MHz timer + TIMx->ControlReg = 0x3; + } + else + { + TIMx->ControlReg = 0x0; + } +} + +void __attribute__((used)) hal_TIMER5_IRQHandler(void) +{ + if(AP_TIM5->status & 0x1) + { + hal_timer_clear_int(AP_TIM5); + + if(s_ap_callback) + s_ap_callback(HAL_EVT_TIMER_5); + } +} + +void __attribute__((used)) hal_TIMER6_IRQHandler(void) +{ + if(AP_TIM6->status & 0x1) + { + hal_timer_clear_int(AP_TIM6); + + if(s_ap_callback) + s_ap_callback(HAL_EVT_TIMER_6); + } +} + +static void hal_timer_wakeup_handler(void) +{ + if(s_ap_callback) + s_ap_callback(HAL_EVT_WAKEUP); +} + +void hal_timer_sleep_handler(void) +{ + if(s_ap_callback) + s_ap_callback(HAL_EVT_SLEEP); +} + +int hal_timer_mask_int(User_Timer_e timeId, bool en) +{ + volatile AP_TIM_TypeDef* TIMx; + TIMx = TimerIndex[timeId-AP_TIMER_ID_5]; + + if(en) + TIMx->ControlReg |= (1 << 2); + else + TIMx->ControlReg &= ~(1 << 2); + + return PPlus_SUCCESS; +} + +int hal_timer_set(User_Timer_e timeId, uint32_t us) +{ + uint32_t time = us; + + switch(timeId) + { + case AP_TIMER_ID_5: + JUMP_FUNCTION(TIM5_IRQ_HANDLER) = (uint32_t)&hal_TIMER5_IRQHandler; + NVIC_EnableIRQ((IRQn_Type)TIM5_IRQn); + NVIC_SetPriority((IRQn_Type)TIM5_IRQn, IRQ_PRIO_HAL); + hal_timer_set_loadtimer(AP_TIM5, time); + hal_clk_gate_enable(MOD_TIMER5); + break; + + case AP_TIMER_ID_6: + JUMP_FUNCTION(TIM6_IRQ_HANDLER) = (uint32_t)&hal_TIMER6_IRQHandler; + NVIC_EnableIRQ((IRQn_Type)TIM6_IRQn); + NVIC_SetPriority((IRQn_Type)TIM6_IRQn, IRQ_PRIO_HAL); + hal_timer_set_loadtimer(AP_TIM6, time); + hal_clk_gate_enable(MOD_TIMER6); + break; + + default: + return PPlus_ERR_INVALID_PARAM; + } + + return PPlus_SUCCESS; +} + +int hal_timer_stop(User_Timer_e timeId) +{ + switch(timeId) + { + case AP_TIMER_ID_5: + JUMP_FUNCTION(TIM5_IRQ_HANDLER) = 0; + hal_timer_stop_counter(AP_TIM5); + NVIC_DisableIRQ((IRQn_Type)TIM5_IRQn); + hal_clk_gate_disable(MOD_TIMER5); + break; + + case AP_TIMER_ID_6: + JUMP_FUNCTION(TIM6_IRQ_HANDLER) = 0; + hal_timer_stop_counter(AP_TIM6); + NVIC_DisableIRQ((IRQn_Type)TIM6_IRQn); + hal_clk_gate_disable(MOD_TIMER6); + break; + + default: + return PPlus_ERR_INVALID_PARAM; + } + + return PPlus_SUCCESS; +} + +int hal_timer_init(ap_tm_hdl_t callback) +{ + s_ap_callback = callback; + hal_timer_stop(AP_TIMER_ID_5); + hal_timer_stop(AP_TIMER_ID_6); + return hal_pwrmgr_register(MOD_TIMER, hal_timer_sleep_handler, hal_timer_wakeup_handler); +} + +int hal_timer_deinit(void) +{ + s_ap_callback = NULL; + return hal_pwrmgr_unregister(MOD_TIMER); +} diff --git a/src/components/driver/timer/timer.h b/src/components/driver/timer/timer.h new file mode 100644 index 0000000..5b8f7ec --- /dev/null +++ b/src/components/driver/timer/timer.h @@ -0,0 +1,60 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ +#ifndef __TIMER_H__ +#define __TIMER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "types.h" +#include "bus_dev.h" + +#define FREE_TIMER_NUMBER 2 + +typedef enum +{ + AP_TIMER_ID_5 = 5, + AP_TIMER_ID_6 = 6, + +} User_Timer_e; + +enum +{ + HAL_EVT_TIMER_5 = AP_TIMER_ID_5, + HAL_EVT_TIMER_6 = AP_TIMER_ID_6, + HAL_EVT_WAKEUP = 0x10, + HAL_EVT_SLEEP +}; + +typedef void(*ap_tm_hdl_t)(uint8_t evt); + +int hal_timer_init(ap_tm_hdl_t callback); + +int hal_timer_deinit(void); + +int hal_timer_set(User_Timer_e timeId, uint32_t us); + +int hal_timer_mask_int(User_Timer_e timeId, bool en); + +int hal_timer_stop(User_Timer_e timeId); + +void __attribute__((used)) hal_TIMER5_IRQHandler(void); +void __attribute__((used)) hal_TIMER6_IRQHandler(void); + +extern void set_timer(AP_TIM_TypeDef* TIMx, int time); + +extern uint32_t read_current_fine_time(void); + +extern uint32 read_LL_remainder_time(void); + +#ifndef BASE_TIME_UINTS +#define BASE_TIME_UNITS (0x3fffff) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/components/driver/uart/uart.c b/src/components/driver/uart/uart.c new file mode 100644 index 0000000..b929cd0 --- /dev/null +++ b/src/components/driver/uart/uart.c @@ -0,0 +1,508 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file uart.c + @brief Contains all functions support for uart driver + @version 0.0 + @date 19. Oct. 2017 + @author qing.han + + +*******************************************************************************/ +#include "rom_sym_def.h" +#include +#include "bus_dev.h" +#include "mcu.h" +#include "gpio.h" +#include "clock.h" +#include "uart.h" +#include "pwrmgr.h" +#include "error.h" +#include "jump_function.h" + +#define UART_TX_BUFFER_SIZE 256 + +typedef struct _uart_Context +{ + bool enable; + + uint8_t tx_state; + uart_Tx_Buf_t tx_buf; + uart_Cfg_t cfg; +} uart_Ctx_t; + +static uart_Ctx_t m_uartCtx[2] = +{ + {.enable = FALSE,}, + {.enable = FALSE,}, +}; + +static int txmit_buf_use_tx_buf(UART_INDEX_e uart_index,uint8_t* buf,uint16_t len) +{ + uart_Tx_Buf_t* p_txbuf = &(m_uartCtx[uart_index].tx_buf); + uint8_t* p_data; + AP_UART_TypeDef* cur_uart = (AP_UART_TypeDef*) AP_UART0_BASE; + + if(len == 0 || buf == NULL) + return PPlus_ERR_INVALID_PARAM; + + if(p_txbuf->tx_state == TX_STATE_UNINIT) + return PPlus_ERR_NO_MEM; + + if(p_txbuf->tx_buf_size < len) + return PPlus_ERR_NO_MEM; + + if(p_txbuf->tx_state != TX_STATE_IDLE) + { + if(p_txbuf->tx_data_size + len > p_txbuf->tx_buf_size) + return PPlus_ERR_NO_MEM; + + HAL_ENTER_CRITICAL_SECTION(); + memcpy(p_txbuf->tx_buf + p_txbuf->tx_data_size, buf, len); + p_txbuf->tx_data_size += len; + HAL_EXIT_CRITICAL_SECTION(); + return PPlus_SUCCESS; + } + + memcpy(p_txbuf->tx_buf, buf, len); + p_txbuf->tx_data_size = len; + p_txbuf->tx_data_offset = 0; + p_txbuf->tx_state = TX_STATE_TX; + p_data = p_txbuf->tx_buf; +// len = p_txbuf->tx_data_size; + len = len > UART_TX_FIFO_SIZE ? UART_TX_FIFO_SIZE : len; + + if(uart_index == UART1) + cur_uart = (AP_UART_TypeDef*) AP_UART1_BASE; + + cur_uart->IER &= ~(IER_ETBEI); + + while(len--) + { + cur_uart->THR = p_data[p_txbuf->tx_data_offset++]; + } + + if(uart_index == UART0) + hal_pwrmgr_lock(MOD_UART0); + else + hal_pwrmgr_lock(MOD_UART1); + + cur_uart->IER |= IER_ETBEI; + return PPlus_SUCCESS; +} + +static int txmit_buf_polling(UART_INDEX_e uart_index,uint8_t* buf,uint16_t len) +{ + //volatile int timeout = 0; + AP_UART_TypeDef* cur_uart = (AP_UART_TypeDef*) AP_UART0_BASE; + + if(uart_index == UART1) + cur_uart = (AP_UART_TypeDef*) AP_UART1_BASE; + + HAL_WAIT_CONDITION_TIMEOUT(!(cur_uart->USR & USR_BUSY), 100000); + + while(len--) + { + HAL_WAIT_CONDITION_TIMEOUT((cur_uart->LSR & LSR_THRE), 100000); + cur_uart->THR = *buf++; + //timeout=0; + } + + //wait shift register empty + HAL_WAIT_CONDITION_TIMEOUT((cur_uart->LSR & LSR_TEMT), 100000); + return PPlus_SUCCESS;; +} + +static void __ATTR_SECTION_SRAM__ irq_rx_handler(UART_INDEX_e uart_index,uint8_t flg) +{ + int i; + uint8_t data[UART_RX_FIFO_SIZE]; + uint8_t len; + AP_UART_TypeDef* cur_uart = (AP_UART_TypeDef*)AP_UART0_BASE; + + if(uart_index == UART1) + { + cur_uart = (AP_UART_TypeDef*) AP_UART1_BASE; + } + + if(m_uartCtx[uart_index].cfg.use_fifo) + { + len = cur_uart->RFL; + + for(i = 0; i< len; i++) + data[i] = (uint8_t)(cur_uart->RBR & 0xff); + } + else + { + len = 1; + cur_uart->LSR; //clear interrupt + data[0] = (uint8_t)(cur_uart->RBR & 0xff); + } + + if(m_uartCtx[uart_index].cfg.evt_handler) + { + uart_Evt_t evt; + evt.type = flg; + evt.data = data; + evt.len = len; + m_uartCtx[uart_index].cfg.evt_handler(&evt); + } +} + +static void __ATTR_SECTION_SRAM__ irq_tx_empty_handler(UART_INDEX_e uart_index) +{ + uart_Tx_Buf_t* p_txbuf = &(m_uartCtx[uart_index].tx_buf); + uint8_t* p_data; + uint16_t len; + AP_UART_TypeDef* cur_uart = (AP_UART_TypeDef*)AP_UART0_BASE; + + if(m_uartCtx[uart_index].enable == FALSE) + return; + + if(m_uartCtx[uart_index].cfg.use_fifo == FALSE) + return; + + if(m_uartCtx[uart_index].cfg.use_tx_buf == FALSE) + return; + + if(p_txbuf->tx_state != TX_STATE_TX) + return; + + p_data = p_txbuf->tx_buf; + len = p_txbuf->tx_data_size - p_txbuf->tx_data_offset; + len = len > UART_TX_FIFO_SIZE ? UART_TX_FIFO_SIZE : len; + + if(len == 0) + { + p_txbuf->tx_state = TX_STATE_IDLE; + p_txbuf->tx_data_offset = 0; + p_txbuf->tx_data_size = 0; + + if(m_uartCtx[uart_index].cfg.evt_handler) + { + uart_Evt_t evt = + { + .type = UART_EVT_TYPE_TX_COMPLETED, + .data = NULL, + .len = 0, + }; + m_uartCtx[uart_index].cfg.evt_handler(&evt); + } + + if(UART0 == uart_index) + hal_pwrmgr_unlock(MOD_UART0); + else + hal_pwrmgr_unlock(MOD_UART1); + + return; + } + + if(uart_index == UART1) + cur_uart = (AP_UART_TypeDef*) AP_UART1_BASE; + + while(len--) + { + cur_uart->THR = p_data[p_txbuf->tx_data_offset++]; + } +} + +static int uart_hw_deinit(UART_INDEX_e uart_index) +{ + MODULE_e mod = MOD_UART0; + IRQn_Type irq_type = UART0_IRQn; + AP_UART_TypeDef* cur_uart = AP_UART0; + + if(uart_index== UART1) + { + mod = MOD_UART1; + irq_type = UART1_IRQn; + cur_uart = AP_UART1; + } + + NVIC_DisableIRQ(irq_type); + hal_gpio_fmux(m_uartCtx[uart_index].cfg.tx_pin,Bit_DISABLE); + hal_gpio_fmux(m_uartCtx[uart_index].cfg.rx_pin,Bit_DISABLE); + cur_uart->LCR=0x80; + cur_uart->DLM=0; + cur_uart->DLL=0; + cur_uart->LCR =0; + cur_uart->FCR=0; + cur_uart->IER = 0; + //hal_clk_gate_enable(mod); + hal_clk_reset(mod); + hal_clk_gate_disable(mod); + + if(uart_index== UART0) + { + JUMP_FUNCTION(UART0_IRQ_HANDLER) = 0; + } + else + { + JUMP_FUNCTION(UART1_IRQ_HANDLER) = 0; + } + + return PPlus_SUCCESS; +} + + + +static int uart_hw_init(UART_INDEX_e uart_index) +{ + uart_Cfg_t* pcfg; + int pclk = clk_get_pclk(); + uint32_t dll; + AP_UART_TypeDef* cur_uart = AP_UART0; + MODULE_e mod = MOD_UART0; + IRQn_Type irq_type = UART0_IRQn; + gpio_fmux_e fmux_tx = FMUX_UART0_TX, fmux_rx = FMUX_UART0_RX; + uart_hw_deinit(uart_index); + + if(uart_index== UART1) + { + cur_uart = AP_UART1; + mod = MOD_UART1; + irq_type = UART1_IRQn; + fmux_tx = FMUX_UART1_TX; + fmux_rx = FMUX_UART1_RX; + } + + if((m_uartCtx[uart_index].cfg.tx_pin == GPIO_DUMMY) && (m_uartCtx[uart_index].cfg.rx_pin == GPIO_DUMMY)) + return PPlus_ERR_INVALID_PARAM; + + pcfg = &(m_uartCtx[uart_index].cfg); + hal_clk_gate_enable(mod); + hal_clk_reset(mod); +// if(m_uartCtx[uart_index].enable == FALSE){ +// hal_gpio_fmux(P9, Bit_DISABLE); +// hal_gpio_fmux(P10, Bit_DISABLE); +// } + hal_gpio_pull_set(pcfg->tx_pin, GPIO_PULL_UP); + hal_gpio_pull_set(pcfg->rx_pin, GPIO_PULL_UP); + hal_gpio_fmux_set(pcfg->tx_pin, fmux_tx); + hal_gpio_fmux_set(pcfg->rx_pin, fmux_rx); + cur_uart->LCR =0; + dll = ((pclk>>4)+(pcfg->baudrate>>1))/pcfg->baudrate; + cur_uart->MCR=0x0; + cur_uart->LCR=0x80; + cur_uart->DLM=(dll & 0xFF00) >> 8; + cur_uart->DLL=(dll & 0xFF); + + if(pcfg->parity) + cur_uart->LCR = 0x1b; //8bit, 1 stop even parity + else + cur_uart->LCR = 0x3; //8bit, 1 stop no parity + + if(pcfg->use_fifo)//set fifo, enable tx FIFO mode(empty trigger), rx FIFO mode(1/2 trigger) + cur_uart->FCR= FCR_TX_FIFO_RESET|FCR_RX_FIFO_RESET|FCR_FIFO_ENABLE|UART_FIFO_RX_TRIGGER|UART_FIFO_TX_TRIGGER; + else + cur_uart->FCR=0; + + //enable Received Data Available Interrupt + cur_uart->IER = IER_ERBFI; + + if(pcfg->use_fifo) + cur_uart->IER |= IER_PTIME; + + if(pcfg->use_tx_buf) + cur_uart->IER |= IER_ETBEI; + + if(uart_index== UART0) + { + JUMP_FUNCTION(UART0_IRQ_HANDLER) = (uint32_t)&hal_UART0_IRQHandler; + } + else + { + JUMP_FUNCTION(UART1_IRQ_HANDLER) = (uint32_t)&hal_UART1_IRQHandler; + } + + NVIC_SetPriority(irq_type, IRQ_PRIO_HAL); + NVIC_EnableIRQ(irq_type); + return PPlus_SUCCESS; +} +/************************************************************************************** + @fn hal_UART0_IRQHandler + + @brief This function process for uart interrupt + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +void __ATTR_SECTION_SRAM__ __attribute__((used)) hal_UART0_IRQHandler(void) +{ + uint8_t IRQ_ID= (AP_UART0->IIR & 0x0f); + + //if(m_uartCtx[UART0].enable == FALSE) + // return; + + switch(IRQ_ID) + { + case TIMEOUT_IRQ: + irq_rx_handler(UART0,UART_EVT_TYPE_RX_DATA_TO); + break; + + case RDA_IRQ: + irq_rx_handler(UART0,UART_EVT_TYPE_RX_DATA); + break; + + case THR_EMPTY: + irq_tx_empty_handler(UART0); + break; + + case RLS_IRQ: + break; + + case BUSY_IRQ: + (void)AP_UART0->USR; + break; + + default: + break; + } +} + +void __ATTR_SECTION_SRAM__ __attribute__((used)) hal_UART1_IRQHandler(void) +{ + uint8_t IRQ_ID= (AP_UART1->IIR & 0x0f); + + //if(m_uartCtx[UART1].enable == FALSE) + // return; + + switch(IRQ_ID) + { + case TIMEOUT_IRQ: + irq_rx_handler(UART1,UART_EVT_TYPE_RX_DATA_TO); + break; + + case RDA_IRQ: + irq_rx_handler(UART1,UART_EVT_TYPE_RX_DATA); + break; + + case THR_EMPTY: + irq_tx_empty_handler(UART1); + break; + + case RLS_IRQ: + break; + + case BUSY_IRQ: + (void)AP_UART1->USR; + break; + + default: + break; + } +} + + +static void uart_wakeup_process_0(void) +{ + uart_hw_init(UART0); +} + +static void uart_wakeup_process_1(void) +{ + uart_hw_init(UART1); +} + +int hal_uart_init(uart_Cfg_t cfg,UART_INDEX_e uart_index) +{ + if(m_uartCtx[uart_index].enable) + return PPlus_ERR_BUSY; + + //if(cfg.hw_fwctrl || cfg.parity) + // return PPlus_ERR_NOT_SUPPORTED; + if(cfg.hw_fwctrl) + return PPlus_ERR_NOT_SUPPORTED; + + memset(&(m_uartCtx[uart_index]), 0, sizeof(uart_Ctx_t)); + memcpy(&(m_uartCtx[uart_index].cfg), &cfg, sizeof(uart_Cfg_t)); + uart_hw_init(uart_index); + m_uartCtx[uart_index].enable = TRUE; + + if(uart_index == UART0) + hal_pwrmgr_register(MOD_UART0, NULL, uart_wakeup_process_0); + else + hal_pwrmgr_register(MOD_UART1, NULL, uart_wakeup_process_1); + + return PPlus_SUCCESS; +} + +int hal_uart_deinit(UART_INDEX_e uart_index) +{ + uart_hw_deinit(uart_index); + memset(&(m_uartCtx[uart_index]), 0, sizeof(uart_Ctx_t)); + m_uartCtx[uart_index].enable = FALSE; + + if(uart_index == UART0) + hal_pwrmgr_unregister(MOD_UART0); + else + hal_pwrmgr_unregister(MOD_UART1); + + return PPlus_SUCCESS; +} + +int hal_uart_set_tx_buf(UART_INDEX_e uart_index,uint8_t* buf, uint16_t size) +{ + uart_Tx_Buf_t* p_txbuf = &(m_uartCtx[uart_index].tx_buf); + + if(m_uartCtx[uart_index].enable == FALSE) + return PPlus_ERR_INVALID_STATE; + + if(m_uartCtx[uart_index].cfg.use_tx_buf == FALSE) + return PPlus_ERR_NOT_SUPPORTED; + + if(p_txbuf->tx_state != TX_STATE_UNINIT) + return PPlus_ERR_INVALID_STATE; + + HAL_ENTER_CRITICAL_SECTION(); + p_txbuf->tx_buf = buf; + p_txbuf->tx_buf_size = size; + p_txbuf->tx_data_offset = 0; + p_txbuf->tx_data_size= 0; + p_txbuf->tx_state = TX_STATE_IDLE; + HAL_EXIT_CRITICAL_SECTION(); + return PPlus_SUCCESS; +} + +int hal_uart_get_tx_ready(UART_INDEX_e uart_index) +{ + if(m_uartCtx[uart_index].cfg.use_tx_buf == FALSE) + return PPlus_SUCCESS; + + if(m_uartCtx[uart_index].tx_buf.tx_state == TX_STATE_IDLE) + return PPlus_SUCCESS; + + return PPlus_ERR_BUSY; +} + +int hal_uart_send_buff(UART_INDEX_e uart_index,uint8_t* buff,uint16_t len) +{ + if(m_uartCtx[uart_index].cfg.use_tx_buf) + { + return txmit_buf_use_tx_buf(uart_index,buff,len); + } + + return txmit_buf_polling(uart_index,buff,len); +} + +int hal_uart_send_byte(UART_INDEX_e uart_index,unsigned char data) +{ + AP_UART_TypeDef* cur_uart = (AP_UART_TypeDef*) AP_UART0_BASE; + + if(uart_index == UART1) + cur_uart = (AP_UART_TypeDef*) AP_UART1_BASE; + + HAL_WAIT_CONDITION_TIMEOUT((cur_uart->LSR & LSR_THRE), 10000); + cur_uart->THR=data; + HAL_WAIT_CONDITION_TIMEOUT((cur_uart->LSR & LSR_TEMT), 10000); + return PPlus_SUCCESS; +} diff --git a/src/components/driver/uart/uart.h b/src/components/driver/uart/uart.h new file mode 100644 index 0000000..f2a1513 --- /dev/null +++ b/src/components/driver/uart/uart.h @@ -0,0 +1,158 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file uart.h + @brief Contains all functions support for uart driver + @version 0.0 + @date 19. Oct. 2017 + @author qing.han + + + +*******************************************************************************/ +#ifndef __UART_H__ +#define __UART_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "types.h" +#include "gpio.h" + +#define UART_TX_FIFO_SIZE 16 +#define UART_RX_FIFO_SIZE 16 + +#define TX_FIFO_MODE 1 +#define RX_FIFO_MODE 2 +#define TX_RX_FIFO_MODE 3 + +#define FIFO_MODE 0//TX_RX_FIFO_MODE //0 + +#define FCR_RX_TRIGGER_00 0x00 +#define FCR_RX_TRIGGER_01 0x40 +#define FCR_RX_TRIGGER_10 0x80 +#define FCR_RX_TRIGGER_11 0xc0 +#define FCR_TX_TRIGGER_00 0x00 +#define FCR_TX_TRIGGER_01 0x10 +#define FCR_TX_TRIGGER_10 0x20 +#define FCR_TX_TRIGGER_11 0x30 +#define FCR_TX_FIFO_RESET 0x04 +#define FCR_RX_FIFO_RESET 0x02 +#define FCR_FIFO_ENABLE 0x01 + + +#define IER_PTIME 0x80 +#define IER_EDSSI 0x08 +#define IER_ELSI 0x04 +#define IER_ETBEI 0x02 +#define IER_ERBFI 0x01 + +/*LSR 0x14*/ +#define LSR_RFE 0x80 +#define LSR_TEMT 0x40 +#define LSR_THRE 0x20 +#define LSR_BI 0x10 +#define LSR_FE 0x08 +#define LSR_PE 0x04 +#define LSR_OE 0x02 +#define LSR_DR 0x01 + +/*USR 0x7c*/ +#define USR_RFF 0x10 +#define USR_RFNE 0x08 +#define USR_TFE 0x04 +#define USR_TFNF 0x02 +#define USR_BUSY 0x01 + +#define UART_FIFO_RX_TRIGGER FCR_RX_TRIGGER_10//FCR_RX_TRIGGER_10//FCR_RX_TRIGGER_11 +#define UART_FIFO_TX_TRIGGER FCR_TX_TRIGGER_00//FCR_TX_TRIGGER_00//FCR_TX_TRIGGER_01 + +typedef enum +{ + UART0=0, //use uart 0 + UART1=1, //use uart 1 +} UART_INDEX_e; + +enum UARTIRQID +{ + NONE_IRQ = 0, + NO_IRQ_PENDING_IRQ = 1, + THR_EMPTY = 2, + RDA_IRQ = 4, + RLS_IRQ = 6, + BUSY_IRQ = 7, + TIMEOUT_IRQ = 12, +}; + +enum +{ + TX_STATE_UNINIT = 0, + TX_STATE_IDLE, + TX_STATE_TX, + TX_STATE_ERR +}; + +typedef struct _uart_Evt_t +{ + uint8_t type; + uint8_t* data; + uint8_t len; +} uart_Evt_t; + + +typedef enum +{ + UART_EVT_TYPE_RX_DATA = 1, + UART_EVT_TYPE_RX_DATA_TO, //case rx data of uart RX timeout + UART_EVT_TYPE_TX_COMPLETED, +} uart_Evt_Type_t; + +typedef void (*uart_Hdl_t)(uart_Evt_t* pev); + +typedef struct _uart_Cfg_t +{ + gpio_pin_e tx_pin; + gpio_pin_e rx_pin; + gpio_pin_e rts_pin; + gpio_pin_e cts_pin; + uint32_t baudrate; + bool use_fifo; + bool hw_fwctrl; + bool use_tx_buf; + bool parity; + uart_Hdl_t evt_handler; +} uart_Cfg_t; + +typedef struct _uart_spi_t +{ + UART_INDEX_e uart_index; +} uart_t; + + +typedef struct _uart_Tx_Buf_t +{ + uint8_t tx_state; + uint16_t tx_data_offset; + uint16_t tx_data_size; + uint16_t tx_buf_size; + uint8_t* tx_buf; +} uart_Tx_Buf_t; + +int hal_uart_init(uart_Cfg_t cfg,UART_INDEX_e uart_index); +int hal_uart_deinit(UART_INDEX_e uart_index); +int hal_uart_set_tx_buf(UART_INDEX_e uart_index,uint8_t* buf, uint16_t size); +int hal_uart_get_tx_ready(UART_INDEX_e uart_index); +int hal_uart_send_buff(UART_INDEX_e uart_index,uint8_t* buff,uint16_t len); +int hal_uart_send_byte(UART_INDEX_e uart_index,unsigned char data); +void __attribute__((weak)) hal_UART0_IRQHandler(void); +void __attribute__((weak)) hal_UART1_IRQHandler(void); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/src/components/driver/voice/voice.c b/src/components/driver/voice/voice.c new file mode 100644 index 0000000..8d8b2d0 --- /dev/null +++ b/src/components/driver/voice/voice.c @@ -0,0 +1,396 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file voice.c + @brief Contains all functions support for adc driver + @version 0.0 + @date 16. Jun. 2018 + @author qing.han + + . + +*******************************************************************************/ +#include "rom_sym_def.h" +#include "error.h" +#include "bus_dev.h" +#include "gpio.h" +#include "pwrmgr.h" +#include "clock.h" +#include "adc.h" +#include +#include "log.h" +#include "voice.h" +#include "jump_function.h" + +static voice_Ctx_t mVoiceCtx; + +static uint32_t voice_data[HALF_VOICE_WORD_SIZE]; + +// Enable voice core +void hal_voice_enable(void) +{ + hal_clk_gate_enable(MOD_ADCC); + subWriteReg(0x40050000,0,0,1); +} + +// Disable voice core +void hal_voice_disable(void) +{ + hal_clk_gate_disable(MOD_ADCC); + subWriteReg(0x40050000,0,0,0); +} + +// Select DMIC +void hal_voice_dmic_mode(void) +{ + subWriteReg(0x4005000c,0,0,1); +} + +// Select AMIC +void hal_voice_amic_mode(void) +{ + subWriteReg(0x4005000c,0,0,0); + subWriteReg(0x4000f048,7,5,0); //Connect ADC to PGA + subWriteReg(0x4000f07c,4,4,1); + subWriteReg(0x4000f07c,0,0,1); + subWriteReg(0x4000F000 + 0x7c,2,1,HAL_ADC_CLOCK_320K); +} + +// Open a GPIO pin for DMIC +void hal_voice_dmic_open(gpio_pin_e dmicDataPin, gpio_pin_e dmicClkPin) +{ + hal_gpio_fmux_set(dmicDataPin, (Fmux_Type_e)FMUX_ADCC); + hal_gpio_fmux_set(dmicClkPin, (Fmux_Type_e)FMUX_CLK1P28M); +} + +// Set PGA gain for AMIC +/* + PGA second stage gain control bits + pga_1st_gain Gain (v/v) + 0 5 + 1 15 + + PGA second stage gain control bits + pga_2nd_gain<2:0> Gain (v/v) + 000 37/4 + 001 36/5 + 010 35/6 + 011 34/7 + 100 33/8 + 101 32/9 + 110 31/10 + 111 30/11 +*/ +void hal_voice_amic_gain(uint8_t amicGain) +{ + subWriteReg(0x4000F048, 22, 19,(amicGain&0x0F));//bit3:pga_1st_gain_t,bit2~0:pga_2nd_gain_t +} + +// Set voice process gain +void hal_voice_gain(uint8_t voiceGain) +{ + subWriteReg(0x4005000c,22,16,(uint32_t)voiceGain); +} + +// Set voice encoding mode +void hal_voice_encode(VOICE_ENCODE_t voiceEncodeMode) +{ + subWriteReg(0x4005000c,13,12,voiceEncodeMode); +} + +// Set voice data rate +void hal_voice_rate(VOICE_RATE_t voiceRate) +{ + subWriteReg(0x4005000c,9,8,voiceRate); +} + +// INTERNAL: Set voice notch filter config +static void set_voice_notch(VOICE_NOTCH_t voiceNotch) +{ + subWriteReg(0x4005000c,3,2,voiceNotch); +} + +// INTERNAL: Set voice data polarity +static void set_voice_polarity(VOICE_POLARITY_t voicePolarity) +{ + subWriteReg(0x4005000c,1,1,voicePolarity); +} + +// Enable voice auto-mute +void hal_voice_amute_on(void) +{ + subWriteReg(0x40050014,0,0,0); +} + +// Disable voice auto-mute +void hal_voice_amute_off(void) +{ + subWriteReg(0x40050014,0,0,1); +} + +// INTERNAL: Set voice auto-mute configurations +static void set_voice_amute_cfg( + uint16_t amutGainMax, + uint8_t amutGainBwMax, + uint8_t amutGdut, + uint8_t amutGst2, + uint8_t amutGst1, + uint16_t amutLvl2, + uint16_t amutLvl1, + uint8_t amutAlvl, + uint8_t amutBeta, + uint8_t amutWinl) +{ + subWriteReg(0x40050010,30,20,(uint32_t)amutGainMax); + subWriteReg(0x40050010,19,16,(uint32_t)amutGainBwMax); + subWriteReg(0x40050010,13,8,(uint32_t)amutGdut); + subWriteReg(0x40050010,7,4,(uint32_t)amutGst2); + subWriteReg(0x40050010,3,0,(uint32_t)amutGst1); + subWriteReg(0x40050014,30,20,(uint32_t)amutLvl2); + subWriteReg(0x40050014,18,8,(uint32_t)amutLvl1); + subWriteReg(0x40050018,15,8,(uint32_t)amutAlvl); + subWriteReg(0x40050018,6,4,(uint32_t)amutBeta); + subWriteReg(0x40050018,3,0,(uint32_t)amutWinl); +} + + + +/************************************************************************************** + @fn hal_VOICE_IRQHandler + + @brief This function process for adc interrupt + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +void __attribute__((used)) hal_ADC_IRQHandler(void) +{ +// uint32_t voice_data[HALF_VOICE_SAMPLE_SIZE]; + volatile uint32_t voice_int_status = GET_IRQ_STATUS; +// LOG("Voice interrupt processing\n"); + MASK_VOICE_INT; + + if (voice_int_status & BIT(8)) + { + int n; + + for (n = 0; n < HALF_VOICE_WORD_SIZE; n++) + { + voice_data[n] = (uint32_t)(read_reg(VOICE_BASE + n * 4)); + } + + CLEAR_VOICE_HALF_INT; + + while (IS_CLAER_VOICE_HALF_INT) {} + +// if(mVoiceCtx.enable == FALSE) +// continue; + if (mVoiceCtx.evt_handler) + { + voice_Evt_t evt; + evt.type = HAL_VOICE_EVT_DATA; + evt.data = voice_data; + evt.size = HALF_VOICE_WORD_SIZE; + mVoiceCtx.evt_handler(&evt); +// LOG("Voice memory half full interrupt processing completed\n"); + } + } + + if (voice_int_status & BIT(9)) + { + int n; + + for (n = 0; n < HALF_VOICE_WORD_SIZE; n++) + { + voice_data[n] = (uint32_t)(read_reg(VOICE_MID_BASE + n * 4)); + } + + CLEAR_VOICE_FULL_INT; + + while (IS_CLAER_VOICE_FULL_INT) {} + +// if(mVoiceCtx.enable == FALSE) +// continue; + if (mVoiceCtx.evt_handler) + { + voice_Evt_t evt; + evt.type = HAL_VOICE_EVT_DATA; + evt.data = voice_data; + evt.size = HALF_VOICE_WORD_SIZE; + mVoiceCtx.evt_handler(&evt); +// LOG("Voice memory full interrupt processing completed\n"); + } + } + + ENABLE_VOICE_INT; +} + +/************************************************************************************** + @fn hal_voice_init + + @brief This function process for adc initial + + input parameters + + @param ADC_MODE_e mode: adc sample mode select;1:SAM_MANNUAL(mannual mode),0:SAM_AUTO(auto mode) + ADC_CH_e adc_pin: adc pin select;ADC_CH0~ADC_CH7 and ADC_CH_VOICE + ADC_SEMODE_e semode: signle-ended mode negative side enable; 1:SINGLE_END(single-ended mode) 0:DIFF(Differentail mode) + IO_CONTROL_e amplitude: input signal amplitude, 0:BELOW_1V,1:UP_1V + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +void hal_voice_init(void) +{ + hal_pwrmgr_register(MOD_ADCC,NULL,NULL); + hal_pwrmgr_register(MOD_VOC,NULL,NULL); + memset(&mVoiceCtx, 0, sizeof(mVoiceCtx));; +} + +int hal_voice_config(voice_Cfg_t cfg, voice_Hdl_t evt_handler) +{ + if(mVoiceCtx.enable) + return PPlus_ERR_BUSY; + + if(evt_handler == NULL) + return PPlus_ERR_INVALID_PARAM; + + hal_clk_gate_enable(MOD_ADCC);//enable I2C clk gated + mVoiceCtx.evt_handler = evt_handler; //evt_handler; + + if(cfg.voiceSelAmicDmic) + { + hal_voice_dmic_mode(); + hal_voice_dmic_open(cfg.dmicDataPin, cfg.dmicClkPin); + } + else + { + hal_voice_amic_mode(); + hal_voice_amic_gain(cfg.amicGain); + hal_gpio_pull_set(P18,GPIO_FLOATING);//pga in+ + hal_gpio_pull_set(P20,GPIO_FLOATING);//pga in- + hal_gpio_pull_set(P15,GPIO_FLOATING);//micphone bias + //hal_gpio_pull_set(P23,GPIO_FLOATING);//micphone bias reference voltage + hal_gpio_cfg_analog_io(P15,Bit_ENABLE);//config micphone bias + } + + hal_voice_gain(cfg.voiceGain); + hal_voice_encode(cfg.voiceEncodeMode); + hal_voice_rate(cfg.voiceRate); + set_voice_notch(VOICE_NOTCH_1); + set_voice_polarity(VOICE_POLARITY_POS); + + if(cfg.voiceAutoMuteOnOff) + { + hal_voice_amute_off(); + } + else + { + hal_voice_amute_on(); + } + + set_voice_amute_cfg(64, 6, 9, 0, 1, 55, 10, 48, 3, 10); + mVoiceCtx.cfg = cfg; + //CLK_1P28M_ENABLE; + AP_PCRM->CLKSEL |= BIT(6); + //ENABLE_XTAL_OUTPUT; //enable xtal 16M output,generate the 32M dll clock + AP_PCRM->CLKHF_CTL0 |= BIT(18); + //ENABLE_DLL; //enable DLL + AP_PCRM->CLKHF_CTL1 |= BIT(7); + //ADC_DBLE_CLOCK_DISABLE; //disable double 32M clock,we are now use 32M clock,should enable bit<13>, diable bit<21> + AP_PCRM->CLKHF_CTL1 &= ~BIT(21); + //ADC_CLOCK_ENABLE; //adc clock enbale,always use clk_32M + AP_PCRM->CLKHF_CTL1 |= BIT(13); + //subWriteReg(0x4000f07c,4,4,1); //set adc mode,1:mannual,0:auto mode + AP_PCRM->ADC_CTL4 |= BIT(4); + //*(volatile unsigned int *) 0x4000f040=0x5014B820; + //*(volatile unsigned int *) 0x4000f044=0x019028b0; + //*(volatile unsigned int *) 0x4000f048=0x0000014b; +// hal_pwrmgr_register(MOD_ADCC,NULL,NULL); +// hal_pwrmgr_register(MOD_VOC,NULL,NULL); + return PPlus_SUCCESS; +} + +int hal_voice_start(void) +{ + hal_clk_gate_enable(MOD_ADCC); + mVoiceCtx.enable = TRUE; + hal_pwrmgr_lock(MOD_ADCC); + hal_pwrmgr_lock(MOD_VOC); + + if (mVoiceCtx.cfg.voiceSelAmicDmic) + { + } + else + { + AP_PCRM->ANA_CTL |= BIT(16); //Power on PGA + AP_PCRM->ANA_CTL |= BIT(3); //Power on ADC + AP_PCRM->ANA_CTL |= BIT(0); + AP_PCRM->ANA_CTL |= BIT(23); + } + + NVIC_SetPriority((IRQn_Type)ADCC_IRQn, IRQ_PRIO_HAL);//teddy add 20190121 + NVIC_EnableIRQ((IRQn_Type)ADCC_IRQn); + //Enable voice core + hal_voice_enable(); + JUMP_FUNCTION(ADCC_IRQ_HANDLER) = (uint32_t)&hal_ADC_IRQHandler; + //Enable VOICE IRQ + ENABLE_VOICE_INT; + return PPlus_SUCCESS; +} + +int hal_voice_stop(void) +{ + MASK_VOICE_INT; + //Disable voice core + hal_voice_disable(); + + if (mVoiceCtx.cfg.voiceSelAmicDmic) + { + } + else + { + AP_PCRM->ANA_CTL &= ~BIT(16); //Power off PGA + } + + //Enable sleep + hal_pwrmgr_unlock(MOD_VOC); + hal_pwrmgr_unlock(MOD_ADCC); + JUMP_FUNCTION(ADCC_IRQ_HANDLER) = 0; + mVoiceCtx.enable = FALSE; + return 0; +} + +int hal_voice_clear(void) +{ + //MASK_VOICE_INT; + MASK_VOICE_INT; + NVIC_DisableIRQ((IRQn_Type)ADCC_IRQn); + + if (mVoiceCtx.cfg.voiceSelAmicDmic) + { + hal_gpioin_disable(mVoiceCtx.cfg.dmicDataPin); + hal_gpioin_disable(mVoiceCtx.cfg.dmicClkPin); + } + else + { + } + + //clk_gate_disable(MOD_ADCC);//disable I2C clk gated + memset(&mVoiceCtx, 0, sizeof(mVoiceCtx)); + //enableSleep(); + hal_pwrmgr_unlock(MOD_VOC); + return 0; +} diff --git a/src/components/driver/voice/voice.h b/src/components/driver/voice/voice.h new file mode 100644 index 0000000..2d44ec1 --- /dev/null +++ b/src/components/driver/voice/voice.h @@ -0,0 +1,262 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file voice.h + @brief Contains all functions support for voice driver + @version 0.0 + @date 18. Jun. 2018 + @author qing.han + + + +*******************************************************************************/ +#ifndef __VOICE__H__ +#define __VOICE__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "types.h" +#include "gpio.h" + +#define MAX_VOICE_SAMPLE_SIZE 512 +#define MAX_VOICE_SAMPLE_ID (MAX_VOICE_SAMPLE_SIZE-1) +#define HALF_VOICE_SAMPLE_SIZE 256 +#define HALF_VOICE_SAMPLE_ID (HALF_VOICE_SAMPLE_SIZE-1) +#define MAX_VOICE_WORD_SIZE 256 +#define HALF_VOICE_WORD_SIZE 128 + +//#define BELOW_1V 0 +//#define UP_1V 1 +//#define ADC_INPUT_LEVEL BELOW_1V +//#define ADC_INPUT_LEVEL UP_1V + + +#define VOICE_BASE (0x40050800UL) +#define VOICE_MID_BASE (0x40050a00UL) +#define VOICE_SAMPLE_AUTO 0 +#define VOICE_SAMPLE_MANNUAL 1 +#define VOICE_SAMPLE_MODE SAMPLE_MANNUAL +//#define ADC_SAMPLE_MODE SAMPLE_AUTO + +#define ENABLE_VOICE_INT *(volatile unsigned int *)0x40050034 |= 0x00000300 +//#define ENABLE_VOICE_INT *(volatile unsigned int *)0x40050034 &= 0xfffffcff +#define MASK_VOICE_INT *(volatile unsigned int *)0x40050034 &= 0xfffffcff +//#define MASK_VOICE_INT *(volatile unsigned int *)0x40050034 |= 0x00000300 +/* #define ADC_IRQ_ENABLE *(volatile unsigned int *) 0xe000e100 = BIT(29) + #define ADC_IRQ_DISABLE *(volatile unsigned int *) 0xe000e100 = BIT(29) + #define CLEAR_ADC_INT_CH0 *(volatile unsigned int *)0x40050038 |= BIT(0) + #define CLEAR_ADC_INT_CH1 *(volatile unsigned int *)0x40050038 |= BIT(1) + #define CLEAR_ADC_INT_CH2 *(volatile unsigned int *)0x40050038 |= BIT(2) + #define CLEAR_ADC_INT_CH3 *(volatile unsigned int *)0x40050038 |= BIT(3) + #define CLEAR_ADC_INT_CH4 *(volatile unsigned int *)0x40050038 |= BIT(4) + #define CLEAR_ADC_INT_CH5 *(volatile unsigned int *)0x40050038 |= BIT(5) + #define CLEAR_ADC_INT_CH6 *(volatile unsigned int *)0x40050038 |= BIT(6) + #define CLEAR_ADC_INT_CH7 *(volatile unsigned int *)0x40050038 |= BIT(7)*/ +#define CLEAR_VOICE_HALF_INT *(volatile unsigned int *)0x40050038 |= BIT(8) +#define CLEAR_VOICE_FULL_INT *(volatile unsigned int *)0x40050038 |= BIT(9) +/* #define CLEAR_ADC_INT(n) *(volatile unsigned int *)0x40050038 |= BIT(n) + + #define IS_CLAER_ADC_INT_CH0 (*(volatile unsigned int *)0x4005003c) & BIT(0) + #define IS_CLAER_ADC_INT_CH1 (*(volatile unsigned int *)0x4005003c) & BIT(1) + #define IS_CLAER_ADC_INT_CH2 (*(volatile unsigned int *)0x4005003c) & BIT(2) + #define IS_CLAER_ADC_INT_CH3 (*(volatile unsigned int *)0x4005003c) & BIT(3) + #define IS_CLAER_ADC_INT_CH4 (*(volatile unsigned int *)0x4005003c) & BIT(4) + #define IS_CLAER_ADC_INT_CH5 (*(volatile unsigned int *)0x4005003c) & BIT(5) + #define IS_CLAER_ADC_INT_CH6 (*(volatile unsigned int *)0x4005003c) & BIT(6) + #define IS_CLAER_ADC_INT_CH7 (*(volatile unsigned int *)0x4005003c) & BIT(7)*/ +#define IS_CLAER_VOICE_HALF_INT (*(volatile unsigned int *)0x4005003c) & BIT(8) +#define IS_CLAER_VOICE_FULL_INT (*(volatile unsigned int *)0x4005003c) & BIT(9) +//#define IS_CLAER_ADC_INT(n) (*(volatile unsigned int *)0x4005003c) & BIT(n) + + + +#ifndef GET_IRQ_STATUS +#define GET_IRQ_STATUS (AP_ADCC->intr_status & 0x3ff) +#endif + +#ifndef ENABLE_ADC +#define ENABLE_ADC (AP_PCRM->ANA_CTL |= BIT(3)) +#endif + +#ifndef DISABLE_ADC +#define DISABLE_ADC (AP_PCRM->ANA_CTL &= ~BIT(3)) +#endif + +#ifndef ADC_CLOCK_ENABLE +#define ADC_CLOCK_ENABLE (AP_PCRM->CLKHF_CTL1 |= BIT(13)) +#endif + +#define ADC_DBLE_CLOCK_DISABLE (*(volatile unsigned int *)0x4000f044 &= ~BIT(21)) +#define POWER_DOWN_ADC (*(volatile unsigned int *)0x4000f048 &= ~BIT(3)) +#define POWER_UP_TEMPSENSOR (*(volatile unsigned int *)0x4000f048 |= BIT(29)) +#define REG_IO_CONTROL ((volatile unsigned int *)0x4000f020) + + + +#define ADCC_REG_BASE (0x4000F000) + +// Voice encode mode +typedef enum +{ + VOICE_ENCODE_PCMA = 0, + VOICE_ENCODE_PCMU = 1, + VOICE_ENCODE_CVSD = 2, + VOICE_ENCODE_BYP = 3 +} VOICE_ENCODE_t; + +// Voice sample rate +typedef enum +{ + VOICE_RATE_64K = 0, + VOICE_RATE_32K = 1, + VOICE_RATE_16K = 2, + VOICE_RATE_8K = 3 +} VOICE_RATE_t; + +// Voice notch filter configuration +typedef enum +{ + VOICE_NOTCH_BYP = 0, + VOICE_NOTCH_1 = 1, + VOICE_NOTCH_2 = 2, + VOICE_NOTCH_3 = 3 +} VOICE_NOTCH_t; + +// Voice polarity selection +typedef enum +{ + VOICE_POLARITY_POS = 0, + VOICE_POLARITY_NEG = 1 +} VOICE_POLARITY_t; + +enum +{ + HAL_VOICE_EVT_DATA = 1, + HAL_VOICE_EVT_FAIL = 0xff +}; + +// Voice configuration structure +typedef struct _voice_Cfg_t +{ + bool voiceSelAmicDmic; + gpio_pin_e dmicDataPin; + gpio_pin_e dmicClkPin; + uint8_t amicGain; + uint8_t voiceGain; + VOICE_ENCODE_t voiceEncodeMode; + VOICE_RATE_t voiceRate; + bool voiceAutoMuteOnOff; +} voice_Cfg_t; + +// Voice event structure +typedef struct _voice_Evt_t +{ + int type; + uint32_t* data; + uint32_t size; +} voice_Evt_t; + +typedef void (*voice_Hdl_t)(voice_Evt_t* pev); + +// Voice context structure +typedef struct _voice_Contex_t +{ + bool enable; + voice_Cfg_t cfg; + voice_Hdl_t evt_handler; +} voice_Ctx_t; + + +// Enable voice core +void hal_voice_enable(void); + +// Disable voice core +void hal_voice_disable(void); + +// Select DMIC +void hal_voice_dmic_mode(void); + +// Select AMIC +void hal_voice_amic_mode(void); + +// Open a GPIO pin for DMIC +void hal_voice_dmic_open(gpio_pin_e dmicDataPin, gpio_pin_e dmicClkPin); + +// Set PGA gain for AMIC +void hal_voice_amic_gain(uint8_t amicGain); + +// Set voice process gain +void hal_voice_gain(uint8_t voiceGain); + +// Set voice encoding mode +void hal_voice_encode(VOICE_ENCODE_t voiceEncodeMode); + +// Set voice data rate +void hal_voice_rate(VOICE_RATE_t voiceRate); + +// Enable voice auto-mute +void hal_voice_amute_on(void); + +// Disable voice auto-mute +void hal_voice_amute_off(void); + +/************************************************************************************** + @fn hal_VOICE_IRQHandler + + @brief This function process for adc interrupt + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +// Voice interrupt handler +void __attribute__((weak)) hal_ADC_IRQHandler(void); + +/************************************************************************************** + @fn hal_voice_init + + @brief This function process for adc initial + + input parameters + + @param ADC_MODE_e mode: adc sample mode select;1:SAM_MANNUAL(mannual mode),0:SAM_AUTO(auto mode) + ADC_CH_e adc_pin: adc pin select;ADC_CH0~ADC_CH7 and ADC_CH_VOICE + ADC_SEMODE_e semode: signle-ended mode negative side enable; 1:SINGLE_END(single-ended mode) 0:DIFF(Differentail mode) + IO_CONTROL_e amplitude: input signal amplitude, 0:BELOW_1V,1:UP_1V + + output parameters + + @param None. + + @return None. + **************************************************************************************/ +// Allocate memory and power manager for voice +void hal_voice_init(void); + +// Configure voice capture +int hal_voice_config(voice_Cfg_t cfg, voice_Hdl_t evt_handler); + +// Start voice capture +int hal_voice_start(void); + +// Stop voice capture +int hal_voice_stop(void); + +// Clear memory and power manager for voice +int hal_voice_clear(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/components/driver/watchdog/watchdog.c b/src/components/driver/watchdog/watchdog.c new file mode 100644 index 0000000..c0be726 --- /dev/null +++ b/src/components/driver/watchdog/watchdog.c @@ -0,0 +1,95 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ +#include "watchdog.h" +#include "error.h" +#include "clock.h" +#include "jump_function.h" + +extern volatile uint8 g_clk32K_config; +extern uint32_t s_config_swClk1; +uint8_t g_wdt_cycle = 0xFF;//valid value:0~7.0xFF:watchdog disable. + +void hal_WATCHDOG_IRQHandler(void) +{ + volatile uint32_t a; + a = AP_WDT->EOI; + AP_WDT->CRR = 0x76; + //LOG("WDT IRQ[%08x]\n",rtc_get_counter()); +} + +__ATTR_SECTION_SRAM__ void hal_watchdog_init(void) +{ + volatile uint32_t a; + uint8_t delay; + + if(g_wdt_cycle > 7) + return ; + + if(g_clk32K_config == CLK_32K_XTAL)//rtc use 32K XOSC,watchdog use the same + { + AP_PCRM->CLKSEL |= (1UL<<16); + } + else + { + AP_PCRM->CLKSEL &= ~(1UL<<16); //rtc use 32K RCOSC,watchdog use the same + } + + hal_clk_gate_enable(MOD_WDT); + s_config_swClk1|=_CLK_WDT; //add watchdog clk in pwrmg wakeup restore clk; + + if((AP_PCR->SW_RESET0 & 0x04)==0) + { + AP_PCR->SW_RESET0 |= 0x04; + delay = 20; + + while(delay-->0); + } + + if((AP_PCR->SW_RESET2 & 0x04)==0) + { + AP_PCR->SW_RESET2 |= 0x04; + delay=20; + + while(delay-->0); + } + + AP_PCR->SW_RESET2 &= ~0x20; + delay=20; + + while(delay-->0); + + AP_PCR->SW_RESET2 |= 0x20; + delay=20; + + while(delay-->0); + + a = AP_WDT->EOI; + AP_WDT->TORR = g_wdt_cycle; + #if (HAL_WDG_CFG_MODE==WDG_USE_INT_MODE) + NVIC_SetPriority((IRQn_Type)WDT_IRQn, IRQ_PRIO_HAL); + NVIC_EnableIRQ((IRQn_Type)WDT_IRQn); + JUMP_FUNCTION(WDT_IRQ_HANDLER) = (uint32_t)&hal_WATCHDOG_IRQHandler; + AP_WDT->CR = 0x1F;//use int + #else + AP_WDT->CR = 0x1D;//not use int + #endif + AP_WDT_FEED; +} + +void hal_watchdog_feed(void) +{ + AP_WDT_FEED; +} + +int watchdog_config(uint8 cycle) +{ + if(cycle > 7) + return PPlus_ERR_INVALID_PARAM; + else + g_wdt_cycle = cycle; + + hal_watchdog_init(); + JUMP_FUNCTION(HAL_WATCHDOG_INIT) = (uint32_t)&hal_watchdog_init; + return PPlus_SUCCESS; +} diff --git a/src/components/driver/watchdog/watchdog.h b/src/components/driver/watchdog/watchdog.h new file mode 100644 index 0000000..ba67647 --- /dev/null +++ b/src/components/driver/watchdog/watchdog.h @@ -0,0 +1,59 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ +#ifndef __WATCHDOG_H__ +#define __WATCHDOG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "types.h" +#include "bus_dev.h" + +#define WDG_2S 0 +#define WDG_4S 1 +#define WDG_8S 2 +#define WDG_16S 3 +#define WDG_32S 4 +#define WDG_64S 5 +#define WDG_128S 6 +#define WDG_256S 7 + +#define WDG_USE_POLLING_MODE 0//this mode is recommended +#define WDG_USE_INT_MODE 1 + +#define HAL_WDG_CFG_MODE WDG_USE_POLLING_MODE +/* + hal watchdog init function.it will be regist in wakeupinit . + watchdog will be restored in wakeup process +*/ +__ATTR_SECTION_SRAM__ void hal_watchdog_init(void); + +/* + watchdog interrupt function. + in this function,feed watchdog and clear int flag. +*/ +void hal_WATCHDOG_IRQHandler(void); + + +/* + watchdog feed function. + we also can feed watchdog in our code. + for example,if disable all int for a long time,but we want to avoid the watchdog reset. + in most case,it is not needed. +*/ +void hal_watchdog_feed(void); + +/* + watchdog init function.it runs in polling mode. + if use watchdog,please init it in main before system run,valid parameter 0~7. + if not,do not init in main. +*/ +int watchdog_config(uint8 cycle); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/components/ethermind/external/crypto/aes/README.txt b/src/components/ethermind/external/crypto/aes/README.txt new file mode 100644 index 0000000..d5713f6 --- /dev/null +++ b/src/components/ethermind/external/crypto/aes/README.txt @@ -0,0 +1,61 @@ +To realize the AES-CCM functionality using the aes.c interface herewith, pull the files aes-ccm.c and aes.h from the repo: https://github.com/wi-fi-analyzer/crackle, and make the following updates - + +** Update the 'xor_aes_block()' function implementation as below and use. + +static void xor_aes_block(u8 *dst, const u8 *src) +{ +#ifdef HAVE_ALIGNED_MEM_OPERATION + u32 *d = (u32 *) dst; + u32 *s = (u32 *) src; + *d++ ^= *s++; + *d++ ^= *s++; + *d++ ^= *s++; + *d++ ^= *s++; +#else /* HAVE_ALIGNED_MEM_OPERATION */ + u32 i; + + for (i = 0; i < 16; i++) + { + *dst++ ^= *src++; + } +#endif /* HAVE_ALIGNED_MEM_OPERATION */ +} + + +** Update the 'aes_ccm_encr()' function implementation as below and use. + +static void aes_ccm_encr(void *aes, size_t L, const u8 *in, size_t len, u8 *out, + u8 *a) +{ + size_t last = len % AES_BLOCK_SIZE; + size_t i; + + /* crypt = msg XOR (S_1 | S_2 | ... | S_n) */ + for (i = 1; i <= len / AES_BLOCK_SIZE; i++) { + PUT_BE16(&a[AES_BLOCK_SIZE - 2], i); + /* S_i = E(K, A_i) */ + aes_encrypt(aes, a, out); + xor_aes_block(out, in); + out += AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + } +#if 0 + if (last) { + PUT_BE16(&a[AES_BLOCK_SIZE - 2], i); + aes_encrypt(aes, a, out); + /* XOR zero-padded last block */ + for (i = 0; i < last; i++) + *out++ ^= *in++; + } +#else /* 0 */ + if (last) { + u8 tout[AES_BLOCK_SIZE]; + + PUT_BE16(&a[AES_BLOCK_SIZE - 2], i); + aes_encrypt(aes, a, tout); + /* XOR zero-padded last block */ + for (i = 0; i < last; i++) + *out++ = tout[i] ^ *in++; + } +#endif /* 0 */ +} diff --git a/src/components/ethermind/external/crypto/aes/aes-ccm.c b/src/components/ethermind/external/crypto/aes/aes-ccm.c new file mode 100644 index 0000000..a71b363 --- /dev/null +++ b/src/components/ethermind/external/crypto/aes/aes-ccm.c @@ -0,0 +1,240 @@ +/* + Counter with CBC-MAC (CCM) with AES + + Copyright (c) 2010-2012, Jouni Malinen + + This software may be distributed under the terms of the BSD license. + See README for more details. +*/ + +#include + +#include "aes.h" + +#define PUT_BE16(a, val) \ + do { \ + (a)[0] = ((u16) (val)) >> 8; \ + (a)[1] = ((u16) (val)) & 0xff; \ + } while (0) + + +static void xor_aes_block(u8* dst, const u8* src) +{ + #ifdef HAVE_ALIGNED_MEM_OPERATION + u32* d = (u32*) dst; + u32* s = (u32*) src; + *d++ ^= *s++; + *d++ ^= *s++; + *d++ ^= *s++; + *d++ ^= *s++; + #else /* HAVE_ALIGNED_MEM_OPERATION */ + u32 i; + + for (i = 0; i < 16; i++) + { + *dst++ ^= *src++; + } + + #endif /* HAVE_ALIGNED_MEM_OPERATION */ +} + + +static void aes_ccm_auth_start(void* aes, size_t M, size_t L, const u8* nonce, + const u8* aad, size_t aad_len, size_t plain_len, + u8* x) +{ + u8 aad_buf[2 * AES_BLOCK_SIZE]; + u8 b[AES_BLOCK_SIZE]; + /* Authentication */ + /* B_0: Flags | Nonce N | l(m) */ + b[0] = aad_len ? 0x40 : 0 /* Adata */; + b[0] |= (((M - 2) / 2) /* M' */ << 3); + b[0] |= (L - 1) /* L' */; + memcpy(&b[1], nonce, 15 - L); + PUT_BE16(&b[AES_BLOCK_SIZE - L], plain_len); + aes_encrypt(aes, b, x); /* X_1 = E(K, B_0) */ + + if (!aad_len) + return; + + PUT_BE16(aad_buf, aad_len); + memcpy(aad_buf + 2, aad, aad_len); + memset(aad_buf + 2 + aad_len, 0, sizeof(aad_buf) - 2 - aad_len); + xor_aes_block(aad_buf, x); + aes_encrypt(aes, aad_buf, x); /* X_2 = E(K, X_1 XOR B_1) */ + + if (aad_len > AES_BLOCK_SIZE - 2) + { + xor_aes_block(&aad_buf[AES_BLOCK_SIZE], x); + /* X_3 = E(K, X_2 XOR B_2) */ + aes_encrypt(aes, &aad_buf[AES_BLOCK_SIZE], x); + } +} + + +static void aes_ccm_auth(void* aes, const u8* data, size_t len, u8* x) +{ + size_t last = len % AES_BLOCK_SIZE; + size_t i; + + for (i = 0; i < len / AES_BLOCK_SIZE; i++) + { + /* X_i+1 = E(K, X_i XOR B_i) */ + xor_aes_block(x, data); + data += AES_BLOCK_SIZE; + aes_encrypt(aes, x, x); + } + + if (last) + { + /* XOR zero-padded last block */ + for (i = 0; i < last; i++) + x[i] ^= *data++; + + aes_encrypt(aes, x, x); + } +} + + +static void aes_ccm_encr_start(size_t L, const u8* nonce, u8* a) +{ + /* A_i = Flags | Nonce N | Counter i */ + a[0] = L - 1; /* Flags = L' */ + memcpy(&a[1], nonce, 15 - L); +} + + +static void aes_ccm_encr(void* aes, size_t L, const u8* in, size_t len, u8* out, + u8* a) +{ + size_t last = len % AES_BLOCK_SIZE; + size_t i; + + /* crypt = msg XOR (S_1 | S_2 | ... | S_n) */ + for (i = 1; i <= len / AES_BLOCK_SIZE; i++) + { + PUT_BE16(&a[AES_BLOCK_SIZE - 2], i); + /* S_i = E(K, A_i) */ + aes_encrypt(aes, a, out); + xor_aes_block(out, in); + out += AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + } + + #if 0 + + if (last) + { + PUT_BE16(&a[AES_BLOCK_SIZE - 2], i); + aes_encrypt(aes, a, out); + + /* XOR zero-padded last block */ + for (i = 0; i < last; i++) + *out++ ^= *in++; + } + + #else /* 0 */ + + if (last) + { + u8 tout[AES_BLOCK_SIZE]; + PUT_BE16(&a[AES_BLOCK_SIZE - 2], i); + aes_encrypt(aes, a, tout); + + /* XOR zero-padded last block */ + for (i = 0; i < last; i++) + *out++ = tout[i] ^ *in++; + } + + #endif /* 0 */ +} + + +static void aes_ccm_encr_auth(void* aes, size_t M, u8* x, u8* a, u8* auth) +{ + size_t i; + u8 tmp[AES_BLOCK_SIZE]; + /* U = T XOR S_0; S_0 = E(K, A_0) */ + PUT_BE16(&a[AES_BLOCK_SIZE - 2], 0); + aes_encrypt(aes, a, tmp); + + for (i = 0; i < M; i++) + auth[i] = x[i] ^ tmp[i]; +} + + +static void aes_ccm_decr_auth(void* aes, size_t M, u8* a, const u8* auth, u8* t) +{ + size_t i; + u8 tmp[AES_BLOCK_SIZE]; + /* U = T XOR S_0; S_0 = E(K, A_0) */ + PUT_BE16(&a[AES_BLOCK_SIZE - 2], 0); + aes_encrypt(aes, a, tmp); + + for (i = 0; i < M; i++) + t[i] = auth[i] ^ tmp[i]; +} + + +/* AES-CCM with fixed L=2 and aad_len <= 30 assumption */ +int aes_ccm_ae(const u8* key, size_t key_len, const u8* nonce, + size_t M, const u8* plain, size_t plain_len, + const u8* aad, size_t aad_len, u8* crypt, u8* auth) +{ + const size_t L = 2; + void* aes; + u8 x[AES_BLOCK_SIZE], a[AES_BLOCK_SIZE]; + + if (aad_len > 30 || M > AES_BLOCK_SIZE) + return -1; + + aes = aes_encrypt_init(key, key_len); + + if (aes == NULL) + return -1; + + aes_ccm_auth_start(aes, M, L, nonce, aad, aad_len, plain_len, x); + aes_ccm_auth(aes, plain, plain_len, x); + /* Encryption */ + aes_ccm_encr_start(L, nonce, a); + aes_ccm_encr(aes, L, plain, plain_len, crypt, a); + aes_ccm_encr_auth(aes, M, x, a, auth); + aes_encrypt_deinit(aes); + return 0; +} + + +/* AES-CCM with fixed L=2 and aad_len <= 30 assumption */ +int aes_ccm_ad(const u8* key, size_t key_len, const u8* nonce, + size_t M, const u8* crypt, size_t crypt_len, + const u8* aad, size_t aad_len, const u8* auth, u8* plain) +{ + const size_t L = 2; + void* aes; + u8 x[AES_BLOCK_SIZE], a[AES_BLOCK_SIZE]; + u8 t[AES_BLOCK_SIZE]; + + if (aad_len > 30 || M > AES_BLOCK_SIZE) + return -1; + + aes = aes_encrypt_init(key, key_len); + + if (aes == NULL) + return -1; + + /* Decryption */ + aes_ccm_encr_start(L, nonce, a); + aes_ccm_decr_auth(aes, M, a, auth, t); + /* plaintext = msg XOR (S_1 | S_2 | ... | S_n) */ + aes_ccm_encr(aes, L, crypt, crypt_len, plain, a); + aes_ccm_auth_start(aes, M, L, nonce, aad, aad_len, crypt_len, x); + aes_ccm_auth(aes, plain, crypt_len, x); + aes_encrypt_deinit(aes); + + if (memcmp(x, t, M) != 0) + { + return -1; + } + + return 0; +} diff --git a/src/components/ethermind/external/crypto/aes/aes.c b/src/components/ethermind/external/crypto/aes/aes.c new file mode 100644 index 0000000..fbceb3b --- /dev/null +++ b/src/components/ethermind/external/crypto/aes/aes.c @@ -0,0 +1,51 @@ + +/** + \file aes.c + + AES Interface file for the Open AES-CCM block. + +*/ + +/* + Copyright (C) 2013. Mindtree Limited. + All rights reserved. +*/ + +/* --------------------------------------------- Header File Inclusion */ +#include "aes.h" +#include "cry.h" + +/* --------------------------------------------- External Global Variables */ + +/* --------------------------------------------- Exported Global Variables */ + +/* --------------------------------------------- Static Global Variables */ + +/* --------------------------------------------- Functions */ + +void* aes_encrypt_init(const u8* key, size_t len) +{ + u8* ctx; + ctx = EM_alloc_mem (len); + + if (NULL != ctx) + { + memcpy (ctx, key, len); + } + + return (void*)ctx; +} + +void aes_encrypt(void* ctx, const u8* plain, u8* crypt) +{ + INT32 ret; + cry_aes_128_encrypt_be ((UCHAR*)plain, (UCHAR*)ctx, (UCHAR*)crypt, ret); + VOID ret; // resolve warning +} + +void aes_encrypt_deinit(void* ctx) +{ + EM_free_mem (ctx); +} + + diff --git a/src/components/ethermind/external/crypto/aes/aes.h b/src/components/ethermind/external/crypto/aes/aes.h new file mode 100644 index 0000000..6a9406a --- /dev/null +++ b/src/components/ethermind/external/crypto/aes/aes.h @@ -0,0 +1,36 @@ +/* + AES functions + Copyright (c) 2003-2006, Jouni Malinen + + This software may be distributed under the terms of the BSD license. + See README for more details. +*/ + +#ifndef AES_H +#define AES_H + +#include +#include + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; + +#define AES_BLOCK_SIZE 16 + +void* aes_encrypt_init(const u8* key, size_t len); +void aes_encrypt(void* ctx, const u8* plain, u8* crypt); +void aes_encrypt_deinit(void* ctx); +void* aes_decrypt_init(const u8* key, size_t len); +void aes_decrypt(void* ctx, const u8* crypt, u8* plain); +void aes_decrypt_deinit(void* ctx); + +int aes_ccm_ae(const u8* key, size_t key_len, const u8* nonce, + size_t M, const u8* plain, size_t plain_len, + const u8* aad, size_t aad_len, u8* crypt, u8* auth); +int aes_ccm_ad(const u8* key, size_t key_len, const u8* nonce, + size_t M, const u8* crypt, size_t crypt_len, + const u8* aad, size_t aad_len, const u8* auth, u8* plain); + +#endif /* AES_H */ + diff --git a/src/components/ethermind/external/crypto/asm_ecdh_p256/P256-cortex-ecdh.h b/src/components/ethermind/external/crypto/asm_ecdh_p256/P256-cortex-ecdh.h new file mode 100644 index 0000000..99454f6 --- /dev/null +++ b/src/components/ethermind/external/crypto/asm_ecdh_p256/P256-cortex-ecdh.h @@ -0,0 +1,80 @@ +/* Copyright 2018 Emil Lenngren. Licensed under the BSD 2-clause license. */ + +#ifndef P256_CORTEX_ECDH_H +#define P256_CORTEX_ECDH_H + +#include +#include + +/* + P-256 ECDH implementation + ========================= + + How to use + ---------- + Each part generates a key pair: + uint8_t my_public_point[64], my_private_key[32]; + do { + generate_random_bytes(my_private_key, 32); + } while (!P256_ecdh_keygen(my_public_point, my_private_key)); + The function generate_random_bytes is a placeholder for calling the system's cryptographically secure random generator. + With probability around 1/2^32, the loop will need more than one iteration. + + The public points are then exchanged, and the shared secret is computed: + uint8_t shared_secret[32]; + if (!P256_ecdh_shared_secret(shared_secret, others_public_point, my_private_key)) { + // The other part sent an invalid public point, so abort (it is important to handle this case) + } else { + // The shared_secret is now the same for both parts and may be used for cryptographic purposes + } + A safe alternative if one doesn't want to change the following parts of a protocol if the user sends an invalid key is to replace the + shared secret with the x coordinate of the own public key (same result as if the remote user sent the basepoint as public key) as follows: + uint8_t shared_secret[32]; + if (!P256_ecdh_shared_secret(shared_secret, others_public_point, my_private_key)) { + memcpy(shared_secret, my_public_point, 32); + } + // The shared_secret is now the same for both parts and may be used for cryptographic purposes + + About endianness + ---------------- + All parameters (coordinates, scalars/private keys, shared secret) are represented in little endian byte order. + Other libraries might use big endian convention, so if this should be used against such a library, make sure all 32-byte values exchanged are reversed. + + Security + -------- + The implementation runs in constant time (unless input values are invalid) and uses a constant memory access pattern, + regardless of the scalar/private key in order to protect against side channel attacks. + + Stack usage + ----------- + All functions need 1356 bytes available stack size on Cortex-M0 and 1.5 kB on Cortex-M4. + +*/ + +// Generic point multiplication +// Calculates scalar * point. +// If include_y_in_result == 0, result_point should be an array of size 32 bytes where the resulting x coordinate will be written. +// If include_y_in_result != 0, result_point should be an array of size 64 bytes where the resulting x coordinate concatenated with y will be written. +// Returns true on success and false on invalid input (see the functions below what defines invalid input). +// If false is returned, the result is not written. +bool P256_pointmult(uint8_t* result_point, const uint8_t point[64], const uint8_t scalar[32], bool include_y_in_result); + +// ECDH keygen +// Multiplies the scalar private_key with the curve-defined base point. +// The result should be an array of size 64 bytes where the x coordinate concatenated by the y coordinate will be written. +// Returns true on success and false if the private_key lies outside the allowed range [1..n-1], where n is the curve order. +// If false is returned, the result is not written. (At that point this function can be called again with a new randomized private_key.) +bool P256_ecdh_keygen(uint8_t result_my_public_point[64], const uint8_t private_key[32]); + +// ECDH shared secret +// Multiplies the scalar private_key with the other's public point. +// The result should be an array of size 32 bytes where the x coordinate of the result will be written (y is discarded). +// Returns true on success and false if any of the following occurs: +// - the scalar private_key lies outside the allowed range [1..n-1], where n is the curve order +// - a public point coordinate integer lies outside the allowed range [0..p-1], where p is the prime for the field used by the curve +// - the public point does not lie on the curve +// If false is returned, the result is not written. +// NOTE: the boolean return value MUST be checked in order to avoid different attacks. +bool P256_ecdh_shared_secret(uint8_t result_point_x[32], const uint8_t others_public_point[64], const uint8_t private_key[32]) __attribute__((warn_unused_result)); + +#endif diff --git a/src/components/ethermind/external/crypto/asm_ecdh_p256/P256-cortex-m0-ecdh-keil.s b/src/components/ethermind/external/crypto/asm_ecdh_p256/P256-cortex-m0-ecdh-keil.s new file mode 100644 index 0000000..2dd1e29 --- /dev/null +++ b/src/components/ethermind/external/crypto/asm_ecdh_p256/P256-cortex-m0-ecdh-keil.s @@ -0,0 +1,2954 @@ +; P-256 ECDH +; Author: Emil Lenngren +; Licensed under the BSD 2-clause license. +; The 256x256->512 multiplication/square code is based on public domain µNaCl by Ana Helena Sánchez and Björn Haase (https://munacl.cryptojedi.org/curve25519-cortexm0.shtml) + +; Note on calling conventions: some of the local functions in this file use custom calling conventions. +; Exported symbols use the standard C calling conventions for ARM, which means that r4-r11 and sp are preserved and the other registers are clobbered. + +; Stack usage is 1356 bytes. + +; Settings below for optimizing for speed vs size. +; When optimizing fully for speed, the run time is 4 456 738 cycles and code size is 3708 bytes. +; When optimizing fully for size, the run time is 5 764 182 cycles and code size is 2416 bytes. +; Get the time taken (in seconds) by dividing the number of cycles with the clock frequency (Hz) of the cpu. +; Different optimization levels can be done by setting some to 1 and some to 0. +; Optimizing all settings for size except use_mul_for_sqr and use_smaller_modinv gives a run time of 4 851 527 cycles and code size is 2968 bytes. + + gbla use_mul_for_sqr +use_mul_for_sqr seta 0 ; 1 to enable, 0 to disable (14% slower if enabled but saves 624/460 bytes (depending on use_noninlined_sqr64) of compiled code size) + + gbla use_noninlined_mul64 +use_noninlined_mul64 seta 1 ; 1 to enable, 0 to disable (2.6%/4.0% slower (depending on use_mul_for_sqr) if enabled but saves 308 bytes of compiled code size) + + gbla use_noninlined_sqr64 +use_noninlined_sqr64 seta 1 ; 1 to enable, 0 to disable (2.4% slower if enabled and use_mul_for_sqr=0 but saves 164 bytes of compiled code size) + + gbla use_interpreter +use_interpreter seta 1 ; 1 to enable, 0 to disable (3.6% slower if enabled but saves 268 bytes of compiled code size) + + gbla use_smaller_modinv +use_smaller_modinv seta 0 ; 1 to enable, 0 to disable (3.6% slower if enabled but saves 88 bytes of compiled code size) + + area |.text|,code,readonly + align 2 + + if use_noninlined_mul64 == 1 +; in: (r4,r5) = a[0..1], (r2,r3) = b[0..1] +; out: r0-r3 +; clobbers r4-r9 and lr +P256_mul64 proc + mov r6,r5 + mov r1,r2 + subs r5,r4 + sbcs r0,r0 + eors r5,r0 + subs r5,r0 + subs r1,r3 + sbcs r7,r7 + eors r1,r7 + subs r1,r7 + eors r7,r0 + mov r9,r1 + mov r8,r5 + lsrs r1,r4,#16 + uxth r4,r4 + mov r0,r4 + uxth r5,r2 + lsrs r2,#16 + muls r0,r5,r0;//00 + muls r5,r1,r5;//10 + muls r4,r2,r4;//01 + muls r1,r2,r1;//11 + lsls r2,r4,#16 + lsrs r4,r4,#16 + adds r0,r2 + adcs r1,r4 + lsls r2,r5,#16 + lsrs r4,r5,#16 + adds r0,r2 + adcs r1,r4 + lsrs r4,r6,#16 + uxth r6,r6 + uxth r5,r3 + lsrs r3,r3,#16 + mov r2,r6 + muls r2,r5,r2 + muls r5,r4,r5 + muls r6,r3,r6 + muls r3,r4,r3 + lsls r4,r5,#16 + lsrs r5,r5,#16 + adds r2,r4 + adcs r3,r5 + lsls r4,r6,#16 + lsrs r5,r6,#16 + adds r2,r4 + adcs r3,r5 + eors r6,r6 + adds r2,r1 + adcs r3,r6 + mov r1,r9 + mov r5,r8 + mov r8,r0 + lsrs r0,r1,#16 + uxth r1,r1 + mov r4,r1 + lsrs r6,r5,#16 + uxth r5,r5 + muls r1,r5,r1 + muls r4,r6,r4 + muls r5,r0,r5 + muls r0,r6,r0 + lsls r6,r4,#16 + lsrs r4,#16 + adds r1,r6 + adcs r0,r4 + lsls r6,r5,#16 + lsrs r5,#16 + adds r1,r6 + adcs r0,r5 + eors r1,r7 + eors r0,r7 + eors r4,r4 + asrs r7,r7,#1 + adcs r1,r2 + adcs r2,r0 + adcs r7,r4 + mov r0,r8 + adds r1,r0 + adcs r2,r3 + adcs r3,r7 + bx lr + endp + endif + +; in: *r10 = a, *r11 = b, (r4,r5) = a[0..1], (r2,r3) = b[0..1] +; out: r8,r9,r2-r7 +; clobbers all other registers +P256_mul128 proc + if use_noninlined_mul64 == 1 + push {lr} + frame push {lr} + endif + ;///////MUL128///////////// + ;MUL64 + if use_noninlined_mul64 == 0 + mov r6,r5 + mov r1,r2 + subs r5,r4 + sbcs r0,r0 + eors r5,r0 + subs r5,r0 + subs r1,r3 + sbcs r7,r7 + eors r1,r7 + subs r1,r7 + eors r7,r0 + mov r9,r1 + mov r8,r5 + lsrs r1,r4,#16 + uxth r4,r4 + mov r0,r4 + uxth r5,r2 + lsrs r2,#16 + muls r0,r5,r0;//00 + muls r5,r1,r5;//10 + muls r4,r2,r4;//01 + muls r1,r2,r1;//11 + lsls r2,r4,#16 + lsrs r4,r4,#16 + adds r0,r2 + adcs r1,r4 + lsls r2,r5,#16 + lsrs r4,r5,#16 + adds r0,r2 + adcs r1,r4 + lsrs r4,r6,#16 + uxth r6,r6 + uxth r5,r3 + lsrs r3,r3,#16 + mov r2,r6 + muls r2,r5,r2 + muls r5,r4,r5 + muls r6,r3,r6 + muls r3,r4,r3 + lsls r4,r5,#16 + lsrs r5,r5,#16 + adds r2,r4 + adcs r3,r5 + lsls r4,r6,#16 + lsrs r5,r6,#16 + adds r2,r4 + adcs r3,r5 + eors r6,r6 + adds r2,r1 + adcs r3,r6 + mov r1,r9 + mov r5,r8 + mov r8,r0 + lsrs r0,r1,#16 + uxth r1,r1 + mov r4,r1 + lsrs r6,r5,#16 + uxth r5,r5 + muls r1,r5,r1 + muls r4,r6,r4 + muls r5,r0,r5 + muls r0,r6,r0 + lsls r6,r4,#16 + lsrs r4,#16 + adds r1,r6 + adcs r0,r4 + lsls r6,r5,#16 + lsrs r5,#16 + adds r1,r6 + adcs r0,r5 + eors r1,r7 + eors r0,r7 + eors r4,r4 + asrs r7,r7,#1 + adcs r1,r2 + adcs r2,r0 + adcs r7,r4 + mov r0,r8 + adds r1,r0 + adcs r2,r3 + adcs r3,r7 + else + bl P256_mul64 + endif + push {r0,r1} + frame address sp,8+use_noninlined_mul64*4 + mov r1,r10 + mov r10,r2 + ldm r1,{r0,r1,r4,r5} + mov r2,r4 + mov r7,r5 + subs r2,r0 + sbcs r7,r1 + sbcs r6,r6 + eors r2,r6 + eors r7,r6 + subs r2,r6 + sbcs r7,r6 + push {r2,r7} + frame address sp,16+use_noninlined_mul64*4 + mov r2,r11 + mov r11,r3 + ldm r2,{r0,r1,r2,r3} + subs r0,r2 + sbcs r1,r3 + sbcs r7,r7 + eors r0,r7 + eors r1,r7 + subs r0,r7 + sbcs r1,r7 + eors r7,r6 + mov r12,r7 + push {r0,r1} + frame address sp,24+use_noninlined_mul64*4 + ;MUL64 + if use_noninlined_mul64 == 0 + mov r6,r5 + mov r1,r2 + subs r5,r4 + sbcs r0,r0 + eors r5,r0 + subs r5,r0 + subs r1,r3 + sbcs r7,r7 + eors r1,r7 + subs r1,r7 + eors r7,r0 + mov r9,r1 + mov r8,r5 + lsrs r1,r4,#16 + uxth r4,r4 + mov r0,r4 + uxth r5,r2 + lsrs r2,#16 + muls r0,r5,r0;//00 + muls r5,r1,r5;//10 + muls r4,r2,r4;//01 + muls r1,r2,r1;//11 + lsls r2,r4,#16 + lsrs r4,r4,#16 + adds r0,r2 + adcs r1,r4 + lsls r2,r5,#16 + lsrs r4,r5,#16 + adds r0,r2 + adcs r1,r4 + lsrs r4,r6,#16 + uxth r6,r6 + uxth r5,r3 + lsrs r3,r3,#16 + mov r2,r6 + muls r2,r5,r2 + muls r5,r4,r5 + muls r6,r3,r6 + muls r3,r4,r3 + lsls r4,r5,#16 + lsrs r5,r5,#16 + adds r2,r4 + adcs r3,r5 + lsls r4,r6,#16 + lsrs r5,r6,#16 + adds r2,r4 + adcs r3,r5 + eors r6,r6 + adds r2,r1 + adcs r3,r6 + mov r1,r9 + mov r5,r8 + mov r8,r0 + lsrs r0,r1,#16 + uxth r1,r1 + mov r4,r1 + lsrs r6,r5,#16 + uxth r5,r5 + muls r1,r5,r1 + muls r4,r6,r4 + muls r5,r0,r5 + muls r0,r6,r0 + lsls r6,r4,#16 + lsrs r4,#16 + adds r1,r6 + adcs r0,r4 + lsls r6,r5,#16 + lsrs r5,#16 + adds r1,r6 + adcs r0,r5 + eors r1,r7 + eors r0,r7 + eors r4,r4 + asrs r7,r7,#1 + adcs r1,r2 + adcs r2,r0 + adcs r7,r4 + mov r0,r8 + adds r1,r0 + adcs r2,r3 + adcs r3,r7 + else + bl P256_mul64 + endif + mov r4,r10 + mov r5,r11 + eors r6,r6 + adds r0,r4 + adcs r1,r5 + adcs r2,r6 + adcs r3,r6 + mov r10,r2 + mov r11,r3 + pop {r2-r5} + frame address sp,8+use_noninlined_mul64*4 + push {r0,r1} + frame address sp,16+use_noninlined_mul64*4 + if use_noninlined_mul64 == 0 + mov r6,r5 + mov r1,r2 + subs r5,r4 + sbcs r0,r0 + eors r5,r0 + subs r5,r0 + subs r1,r3 + sbcs r7,r7 + eors r1,r7 + subs r1,r7 + eors r7,r0 + mov r9,r1 + mov r8,r5 + lsrs r1,r4,#16 + uxth r4,r4 + mov r0,r4 + uxth r5,r2 + lsrs r2,#16 + muls r0,r5,r0;//00 + muls r5,r1,r5;//10 + muls r4,r2,r4;//01 + muls r1,r2,r1;//11 + lsls r2,r4,#16 + lsrs r4,r4,#16 + adds r0,r2 + adcs r1,r4 + lsls r2,r5,#16 + lsrs r4,r5,#16 + adds r0,r2 + adcs r1,r4 + lsrs r4,r6,#16 + uxth r6,r6 + uxth r5,r3 + lsrs r3,r3,#16 + mov r2,r6 + muls r2,r5,r2 + muls r5,r4,r5 + muls r6,r3,r6 + muls r3,r4,r3 + lsls r4,r5,#16 + lsrs r5,r5,#16 + adds r2,r4 + adcs r3,r5 + lsls r4,r6,#16 + lsrs r5,r6,#16 + adds r2,r4 + adcs r3,r5 + eors r6,r6 + adds r2,r1 + adcs r3,r6 + mov r1,r9 + mov r5,r8 + mov r8,r0 + lsrs r0,r1,#16 + uxth r1,r1 + mov r4,r1 + lsrs r6,r5,#16 + uxth r5,r5 + muls r1,r5,r1 + muls r4,r6,r4 + muls r5,r0,r5 + muls r0,r6,r0 + lsls r6,r4,#16 + lsrs r4,#16 + adds r1,r6 + adcs r0,r4 + lsls r6,r5,#16 + lsrs r5,#16 + adds r1,r6 + adcs r0,r5 + eors r1,r7 + eors r0,r7 + eors r4,r4 + asrs r7,r7,#1 + adcs r1,r2 + adcs r2,r0 + adcs r7,r4 + mov r0,r8 + adds r1,r0 + adcs r2,r3 + adcs r3,r7 + else + bl P256_mul64 + endif + pop {r4,r5} + frame address sp,8+use_noninlined_mul64*4 + mov r6,r12 + mov r7,r12 + eors r0,r6 + eors r1,r6 + eors r2,r6 + eors r3,r6 + asrs r6,r6,#1 + adcs r0,r4 + adcs r1,r5 + adcs r4,r2 + adcs r5,r3 + eors r2,r2 + adcs r6,r2 ;//0,1 + adcs r7,r2 + pop {r2,r3} + frame address sp,0+use_noninlined_mul64*4 + mov r8,r2 + mov r9,r3 + adds r2,r0 + adcs r3,r1 + mov r0,r10 + mov r1,r11 + adcs r4,r0 + adcs r5,r1 + adcs r6,r0 + adcs r7,r1 + if use_noninlined_mul64 == 1 + pop {pc} + else + bx lr + endif + endp + + if use_mul_for_sqr == 1 +;thumb_func +P256_sqrmod ;label definition + mov r2,r1 + ; fallthrough + endif + +; *r0 = out, *r1 = a, *r2 = b +P256_mulmod proc + push {r0,lr} + frame push {lr} + frame address sp,8 + sub sp,#64 + frame address sp,72 + push {r1-r2} + frame address sp,80 + mov r10,r2 + mov r11,r1 + mov r0,r2 + ldm r0!,{r4,r5} + adds r0,#8 + ldm r1!,{r2,r3} + adds r1,#8 + push {r0,r1} + frame address sp,88 + + bl P256_mul128 + add r0,sp,#24 + stm r0!,{r2,r3} + add r0,sp,#16 + mov r2,r8 + mov r3,r9 + stm r0!,{r2,r3} + + ;pop {r0} ;result+8 + ;stm r0!,{r2,r3} + pop {r1,r2} ;a+16 b+16 + frame address sp,80 + ;push {r0} + push {r4-r7} + frame address sp,96 + mov r10,r1 + mov r11,r2 + ldm r1!,{r4,r5} + ldm r2,{r2,r3} + + bl P256_mul128 + + mov r0,r8 + mov r1,r9 + mov r8,r6 + mov r9,r7 + pop {r6,r7} + frame address sp,88 + adds r0,r6 + adcs r1,r7 + pop {r6,r7} + frame address sp,80 + adcs r2,r6 + adcs r3,r7 + ;pop {r7} ;result+16 + add r7,sp,#24 + stm r7!,{r0-r3} + mov r10,r7 + eors r0,r0 + mov r6,r8 + mov r7,r9 + adcs r4,r0 + adcs r5,r0 + adcs r6,r0 + adcs r7,r0 + pop {r1,r2} ;b a + frame address sp,72 + mov r12,r2 + push {r4-r7} + frame address sp,88 + ldm r1,{r0-r7} + subs r0,r4 + sbcs r1,r5 + sbcs r2,r6 + sbcs r3,r7 + eors r4,r4 + sbcs r4,r4 + eors r0,r4 + eors r1,r4 + eors r2,r4 + eors r3,r4 + subs r0,r4 + sbcs r1,r4 + sbcs r2,r4 + sbcs r3,r4 + mov r6,r12 + mov r12,r4 ;//carry + mov r5,r10 + stm r5!,{r0-r3} + mov r11,r5 + mov r8,r0 + mov r9,r1 + ldm r6,{r0-r7} + subs r4,r0 + sbcs r5,r1 + sbcs r6,r2 + sbcs r7,r3 + eors r0,r0 + sbcs r0,r0 + eors r4,r0 + eors r5,r0 + eors r6,r0 + eors r7,r0 + subs r4,r0 + sbcs r5,r0 + sbcs r6,r0 + sbcs r7,r0 + mov r1,r12 + eors r0,r1 + mov r1,r11 + stm r1!,{r4-r7} + push {r0} + frame address sp,92 + mov r2,r8 + mov r3,r9 + + bl P256_mul128 + + pop {r0} ;//r0,r1 + frame address sp,88 + mov r12,r0 ;//negative + eors r2,r0 + eors r3,r0 + eors r4,r0 + eors r5,r0 + eors r6,r0 + eors r7,r0 + push {r4-r7} + frame address sp,104 + add r1,sp,#32 ;result + ldm r1!,{r4-r7} + ;mov r11,r1 ;//reference + mov r1,r9 + eors r1,r0 + mov r10,r4 + mov r4,r8 + asrs r0,#1 + eors r0,r4 + mov r4,r10 + adcs r0,r4 + adcs r1,r5 + adcs r2,r6 + adcs r3,r7 + eors r4,r4 + adcs r4,r4 + mov r10,r4 ;//carry + ;mov r4,r11 + add r4,sp,#32+16 + ldm r4,{r4-r7} + adds r0,r4 + adcs r1,r5 + adcs r2,r6 + adcs r3,r7 + mov r9,r4 + ;mov r4,r11 + add r4,sp,#32+16 + stm r4!,{r0-r3} + ;mov r11,r4 + pop {r0-r3} + frame address sp,88 + mov r4,r9 + adcs r4,r0 + adcs r5,r1 + adcs r6,r2 + adcs r7,r3 + movs r1,#0 + adcs r1,r1 + mov r0,r10 + mov r10,r1 ;//carry + asrs r0,#1 + pop {r0-r3} + frame address sp,72 + adcs r4,r0 + adcs r5,r1 + adcs r6,r2 + adcs r7,r3 + mov r8,r0 + ;mov r0,r11 + add r0,sp,#32 + stm r0!,{r4-r7} + ;mov r11,r0 + mov r0,r8 + mov r6,r12 + mov r5,r10 + eors r4,r4 + adcs r5,r6 + adcs r6,r4 + adds r0,r5 + adcs r1,r6 + adcs r2,r6 + adcs r3,r6 + ;mov r7,r11 + add r7,sp,#32+16 + stm r7!,{r0-r3} + + ; multiplication done, now reducing + +reduce ;label definition + pop {r0-r7} + frame address sp,40 + adds r3,r0 + adcs r4,r1 + adcs r5,r2 + adcs r6,r0 + mov r8,r2 + mov r9,r3 + mov r10,r4 + mov r11,r5 + mov r12,r6 + adcs r7,r1 + pop {r2-r5} ;8,9,10,11 + frame address sp,24 + adcs r2,r0 ;8+0 + adcs r3,r1 ;9+1 + movs r6,#0 + adcs r4,r6 ;10+#0 + adcs r5,r6 ;11+#0 + adcs r6,r6 ;C + + subs r7,r0 ;7-0 + sbcs r2,r1 ;8-1 + ; r0,r1 dead + mov r0,r8 ;2 + mov r1,r9 ;3 + sbcs r3,r0 ;9-2 + sbcs r4,r1 ;10-3 + movs r0,#0 + sbcs r5,r0 ;11-#0 + sbcs r6,r0 ;C-#0 + + mov r0,r12 ;6 + adds r0,r1 ;6+3 + mov r12,r0 + mov r0,r10 ;4 + adcs r7,r0 ;7+4 + mov lr,r7 + mov r0,r8 ;2 + adcs r2,r0 ;8+2 + adcs r3,r1 ;9+3 + adcs r4,r0 ;10+2 + adcs r5,r1 ;11+3 + movs r7,#0 + adcs r6,r7 ;C+#0 + + ;2-3 are now dead (r8,r9) + ;4 5 6 7 8 9 10 11 C + ;r10 r11 r12 lr r2 r3 r4 r5 r6 + ;r7: 0 + + pop {r0,r1} ;12,13 + frame address sp,16 + + adds r6,r0 ;12+C + adcs r1,r7 ;13+#0 + adcs r7,r7 ;new Carry for 14 + + ;r0 dead + + mov r0,r11 ;5 + adds r2,r0 ;8+5 + mov r8,r2 + mov r2,r12 ;6 + adcs r3,r2 ;9+6 + mov r9,r3 + mov r3,r10 ;4 + adcs r4,r3 ;10+4 + mov r10,r4 + adcs r5,r0 ;11+5 + adcs r6,r3 ;12+4 + adcs r1,r0 ;13+5 + pop {r2,r4} ;14,15 + frame address sp,8 + adcs r2,r7 ;14+C + movs r7,#0 + adcs r4,r7 ;15+#0 + adcs r7,r7 ;new Carry for 16 + + ;4 5 6 7 8 9 10 11 12 13 14 15 C + ;r3 r0 r12 lr r8 r9 r10 r5 r6 r1 r2 r4 r7 + ;r11 is available + + subs r5,r3 ;11-4 + sbcs r6,r0 ;12-5 + mov r3,r12 ;6 + mov r0,lr ;7 + sbcs r1,r3 ;13-6 + sbcs r2,r0 ;14-7 + movs r3,#0 + sbcs r4,r3 ;15-#0 + sbcs r7,r3 ;C-#0 + mov lr,r4 + mov r11,r7 + + mov r4,r10 ;10 + adds r4,r0 ;10+7 + adcs r5,r3 ;11+#0 + mov r7,r12 ;6 + adcs r6,r7 ;12+6 + adcs r1,r0 ;13+7 + adcs r2,r7 ;14+6 + mov r7,lr ;15 + adcs r7,r0 ;15+7 + mov r0,r11 ;C + adcs r0,r3 ;C+#0 + + ; now (T + mN) / R is + ; 8 9 4 5 6 1 2 7 6 (lsb -> msb) + + subs r3,r3 ;set r3 to 0 and C to 1 + mov r10,r0 + mov r0,r8 + adcs r0,r3 + mov r11,r7 + mov r7,r9 + adcs r7,r3 + mov r12,r0 + mov r9,r7 + adcs r4,r3 + sbcs r5,r3 + sbcs r6,r3 + sbcs r1,r3 + movs r3,#1 + sbcs r2,r3 + movs r3,#0 + mov r0,r11 + mov r7,r10 + adcs r0,r3 + sbcs r7,r3 + + ; r12 r9 r4 r5 | r6 r1 r2 r0 + + mov r8,r2 + mov r2,r12 + mov r11,r0 + mov r3,r9 +reduce2 ;label definition + adds r2,r7 + adcs r3,r7 + adcs r4,r7 + movs r0,#0 + adcs r5,r0 + adcs r6,r0 + adcs r1,r0 + pop {r0} + frame address sp,4 + stm r0!,{r2-r6} + movs r5,#1 + ands r5,r7 + mov r2,r8 + mov r3,r11 + adcs r2,r5 + adcs r3,r7 + stm r0!,{r1-r3} + + pop {pc} + + endp + + + if use_mul_for_sqr == 0 + + if use_noninlined_sqr64 == 1 + +P256_sqr64 proc + ; START: sqr 64 Refined Karatsuba + ; Input operands in r4,r5 + ; Result in r0,r1,r2,r3 + ; Clobbers: r4-r6 + ; START: sqr 32 + ; Input operand in r4 + ; Result in r0 ,r1 + ; Clobbers: r2, r3 + uxth r0,r4 + lsrs r1,r4,#16 + mov r2,r0 + muls r2,r1,r2 + muls r0,r0,r0 + muls r1,r1,r1 + lsrs r3,r2,#15 + lsls r2,r2,#17 + adds r0,r2 + adcs r1,r3 + ; End: sqr 32 + ; Result in r0 ,r1 + subs r4,r5 + sbcs r6,r6 + eors r4,r6 + subs r4,r6 + ; START: sqr 32 + ; Input operand in r5 + ; Result in r2 ,r3 + ; Clobbers: r5, r6 + uxth r2,r5 + lsrs r3,r5,#16 + mov r5,r2 + muls r5,r3,r5 + muls r2,r2,r2 + muls r3,r3,r3 + lsrs r6,r5,#15 + lsls r5,r5,#17 + adds r2,r5 + adcs r3,r6 + ; End: sqr 32 + ; Result in r2 ,r3 + movs r6,#0 + adds r2,r1 + adcs r3,r6 + ; START: sqr 32 + ; Input operand in r4 + ; Result in r4 ,r5 + ; Clobbers: r1, r6 + lsrs r5,r4,#16 + uxth r4,r4 + mov r1,r4 + muls r1,r5,r1 + muls r4,r4,r4 + muls r5,r5,r5 + lsrs r6,r1,#15 + lsls r1,r1,#17 + adds r4,r1 + adcs r5,r6 + ; End: sqr 32 + ; Result in r4 ,r5 + mov r1,r2 + subs r1,r4 + sbcs r2,r5 + mov r5,r3 + movs r6,#0 + sbcs r3,r6 + adds r1,r0 + adcs r2,r5 + adcs r3,r6 + ; END: sqr 64 Refined Karatsuba + ; Result in r0,r1,r2,r3 + ; Leaves r6 zero. + bx lr + endp + +P256_sqr128 proc + push {lr} + frame push {lr} + ; sqr 128 Refined Karatsuba + ; Input in r4 ... r7 + ; Result in r0 ... r7 + ; clobbers all registers + mov r0,r4 + mov r1,r5 + subs r0,r6 + sbcs r1,r7 + sbcs r2,r2 + eors r0,r2 + eors r1,r2 + subs r0,r2 + sbcs r1,r2 + mov r8,r0 + mov r9,r1 + mov r10,r6 + + bl P256_sqr64 + + mov r4,r10 + mov r5,r7 + mov r10,r0 + mov r11,r1 + mov r12,r2 + mov r7,r3 + + bl P256_sqr64 + + mov r4,r12 + adds r0,r4 + adcs r1,r7 + adcs r2,r6 + adcs r3,r6 + mov r7,r3 + mov r12,r0 + mov r4,r8 + mov r8,r1 + mov r5,r9 + mov r9,r2 + + bl P256_sqr64 + + mov r4,r12 + mov r5,r8 + mov r6,r9 + subs r4,r0 + sbcs r5,r1 + mov r0,r6 + mov r1,r7 + sbcs r0,r2 + sbcs r1,r3 + movs r2,#0 + sbcs r6,r2 + sbcs r7,r2 + mov r2,r10 + adds r2,r4 + mov r3,r11 + adcs r3,r5 + mov r4,r12 + adcs r4,r0 + mov r5,r8 + adcs r5,r1 + movs r0,#0 + adcs r6,r0 + adcs r7,r0 + mov r0,r10 + mov r1,r11 + ; END: sqr 128 Refined Karatsuba + pop {pc} + endp + else +P256_sqr128 proc + ; sqr 128 Refined Karatsuba + ; Input in r4 ... r7 + ; Result in r0 ... r7 + ; clobbers all registers + mov r0,r4 + mov r1,r5 + subs r0,r6 + sbcs r1,r7 + sbcs r2,r2 + eors r0,r2 + eors r1,r2 + subs r0,r2 + sbcs r1,r2 + mov r8,r0 + mov r9,r1 + mov r10,r6 + ; START: sqr 64 Refined Karatsuba + ; Input operands in r4,r5 + ; Result in r0,r1,r2,r3 + ; Clobbers: r4-r6 + ; START: sqr 32 + ; Input operand in r4 + ; Result in r0 ,r1 + ; Clobbers: r2, r3 + uxth r0,r4 + lsrs r1,r4,#16 + mov r2,r0 + muls r2,r1,r2 + muls r0,r0,r0 + muls r1,r1,r1 + lsrs r3,r2,#15 + lsls r2,r2,#17 + adds r0,r2 + adcs r1,r3 + ; End: sqr 32 + ; Result in r0 ,r1 + subs r4,r5 + sbcs r6,r6 + eors r4,r6 + subs r4,r6 + ; START: sqr 32 + ; Input operand in r5 + ; Result in r2 ,r3 + ; Clobbers: r5, r6 + uxth r2,r5 + lsrs r3,r5,#16 + mov r5,r2 + muls r5,r3,r5 + muls r2,r2,r2 + muls r3,r3,r3 + lsrs r6,r5,#15 + lsls r5,r5,#17 + adds r2,r5 + adcs r3,r6 + ; End: sqr 32 + ; Result in r2 ,r3 + movs r6,#0 + adds r2,r1 + adcs r3,r6 + ; START: sqr 32 + ; Input operand in r4 + ; Result in r4 ,r5 + ; Clobbers: r1, r6 + lsrs r5,r4,#16 + uxth r4,r4 + mov r1,r4 + muls r1,r5,r1 + muls r4,r4,r4 + muls r5,r5,r5 + lsrs r6,r1,#15 + lsls r1,r1,#17 + adds r4,r1 + adcs r5,r6 + ; End: sqr 32 + ; Result in r4 ,r5 + mov r1,r2 + subs r1,r4 + sbcs r2,r5 + mov r5,r3 + movs r6,#0 + sbcs r3,r6 + adds r1,r0 + adcs r2,r5 + adcs r3,r6 + ; END: sqr 64 Refined Karatsuba + ; Result in r0,r1,r2,r3 + ; Leaves r6 zero. + mov r6,r10 + mov r10,r0 + mov r11,r1 + mov r12,r2 + mov r1,r3 + ; START: sqr 64 Refined Karatsuba + ; Input operands in r6,r7 + ; Result in r2,r3,r4,r5 + ; Clobbers: r0,r7,r6 + ; START: sqr 32 + ; Input operand in r6 + ; Result in r2 ,r3 + ; Clobbers: r4, r5 + uxth r2,r6 + lsrs r3,r6,#16 + mov r4,r2 + muls r4,r3,r4 + muls r2,r2,r2 + muls r3,r3,r3 + lsrs r5,r4,#15 + lsls r4,r4,#17 + adds r2,r4 + adcs r3,r5 + ; End: sqr 32 + ; Result in r2 ,r3 + subs r6,r7 + sbcs r4,r4 + eors r6,r4 + subs r6,r4 + ; START: sqr 32 + ; Input operand in r7 + ; Result in r4 ,r5 + ; Clobbers: r0, r7 + uxth r4,r7 + lsrs r5,r7,#16 + mov r0,r4 + muls r0,r5,r0 + muls r4,r4,r4 + muls r5,r5,r5 + lsrs r7,r0,#15 + lsls r0,r0,#17 + adds r4,r0 + adcs r5,r7 + ; End: sqr 32 + ; Result in r4 ,r5 + movs r7,#0 + adds r4,r3 + adcs r5,r7 + ; START: sqr 32 + ; Input operand in r6 + ; Result in r7 ,r0 + ; Clobbers: r6, r3 + uxth r7,r6 + lsrs r0,r6,#16 + mov r6,r7 + muls r6,r0,r6 + muls r7,r7,r7 + muls r0,r0,r0 + lsrs r3,r6,#15 + lsls r6,r6,#17 + adds r7,r6 + adcs r0,r3 + ; End: sqr 32 + ; Result in r7 ,r0 + mov r3,r4 + subs r3,r7 + sbcs r4,r0 + mov r0,r5 + movs r6,#0 + sbcs r5,r6 + adds r3,r2 + adcs r4,r0 + adcs r5,r6 + ; END: sqr 64 Refined Karatsuba + ; Result in r2,r3,r4,r5 + ; Leaves r6 zero. + mov r0,r12 + adds r2,r0 + adcs r3,r1 + adcs r4,r6 + adcs r5,r6 + mov r12,r2 + mov r2,r8 + mov r8,r3 + mov r3,r9 + mov r9,r4 + ; START: sqr 64 Refined Karatsuba + ; Input operands in r2,r3 + ; Result in r6,r7,r0,r1 + ; Clobbers: r2,r3,r4 + ; START: sqr 32 + ; Input operand in r2 + ; Result in r6 ,r7 + ; Clobbers: r0, r1 + uxth r6,r2 + lsrs r7,r2,#16 + mov r0,r6 + muls r0,r7,r0 + muls r6,r6,r6 + muls r7,r7,r7 + lsrs r1,r0,#15 + lsls r0,r0,#17 + adds r6,r0 + adcs r7,r1 + ; End: sqr 32 + ; Result in r6 ,r7 + subs r2,r3 + sbcs r4,r4 + eors r2,r4 + subs r2,r4 + ; START: sqr 32 + ; Input operand in r3 + ; Result in r0 ,r1 + ; Clobbers: r3, r4 + uxth r0,r3 + lsrs r1,r3,#16 + mov r3,r0 + muls r3,r1,r3 + muls r0,r0,r0 + muls r1,r1,r1 + lsrs r4,r3,#15 + lsls r3,r3,#17 + adds r0,r3 + adcs r1,r4 + ; End: sqr 32 + ; Result in r0 ,r1 + movs r4,#0 + adds r0,r7 + adcs r1,r4 + ; START: sqr 32 + ; Input operand in r2 + ; Result in r3 ,r4 + ; Clobbers: r2, r7 + uxth r3,r2 + lsrs r4,r2,#16 + mov r2,r3 + muls r2,r4,r2 + muls r3,r3,r3 + muls r4,r4,r4 + lsrs r7,r2,#15 + lsls r2,r2,#17 + adds r3,r2 + adcs r4,r7 + ; End: sqr 32 + ; Result in r3 ,r4 + mov r7,r0 + subs r7,r3 + sbcs r0,r4 + mov r2,r1 + movs r4,#0 + sbcs r1,r4 + adds r7,r6 + adcs r0,r2 + adcs r1,r4 + ; END: sqr 64 Refined Karatsuba + ; Result in r6,r7,r0,r1 + ; Returns r4 as zero. + mov r2,r12 + mov r3,r8 + mov r4,r9 + subs r2,r6 + sbcs r3,r7 + mov r6,r4 + mov r7,r5 + sbcs r4,r0 + sbcs r5,r1 + movs r0,#0 + sbcs r6,r0 + sbcs r7,r0 + mov r0,r10 + adds r2,r0 + mov r1,r11 + adcs r3,r1 + mov r0,r12 + adcs r4,r0 + mov r0,r8 + adcs r5,r0 + movs r0,#0 + adcs r6,r0 + adcs r7,r0 + mov r0,r10 + ; END: sqr 128 Refined Karatsuba + ; Result in r0 ... r7 + bx lr + endp + + endif + +; ###################### +; ASM Square 256 refined karatsuba: +; ###################### + ; sqr 256 Refined Karatsuba + ; pInput in r1 + ; pResult in r0 +P256_sqrmod proc + push {r0,lr} + frame push {lr} + frame address sp,8 + sub sp,#64 + frame address sp,72 + ;mov lr,sp + push {r1} + frame address sp,76 + ldm r1!,{r4,r5,r6,r7} + + bl P256_sqr128 + + push {r4,r5,r6,r7} + frame address sp,92 + ;mov r4,lr + add r4,sp,#20 + stm r4!,{r0,r1,r2,r3} + ldr r4,[sp,#16] + adds r4,#16 + ldm r4,{r4,r5,r6,r7} + + bl P256_sqr128 + + mov r8,r4 + mov r9,r5 + mov r10,r6 + mov r11,r7 + pop {r4,r5,r6,r7} + frame address sp,76 + adds r0,r4 + adcs r1,r5 + adcs r2,r6 + adcs r3,r7 + mov r4,r8 + mov r5,r9 + mov r6,r10 + mov r7,r11 + mov r8,r0 + movs r0,#0 + adcs r4,r0 + adcs r5,r0 + adcs r6,r0 + adcs r7,r0 + mov r0,r8 + push {r0,r1,r2,r3,r4,r5,r6,r7} + frame address sp,108 + ldr r4,[sp,#32] + ldm r4,{r0,r1,r2,r3,r4,r5,r6,r7} + subs r4,r0 + sbcs r5,r1 + sbcs r6,r2 + sbcs r7,r3 + sbcs r0,r0 + eors r4,r0 + eors r5,r0 + eors r6,r0 + eors r7,r0 + subs r4,r0 + sbcs r5,r0 + sbcs r6,r0 + sbcs r7,r0 + + bl P256_sqr128 + + mvns r0,r0 + mvns r1,r1 + mvns r2,r2 + mvns r3,r3 + mvns r4,r4 + mvns r5,r5 + mvns r6,r6 + mvns r7,r7 + mov r8,r4 + mov r9,r5 + mov r10,r6 + mov r11,r7 + subs r4,r4 + pop {r4,r5,r6,r7} + frame address sp,92 + adcs r0,r4 + adcs r1,r5 + adcs r2,r6 + adcs r3,r7 + mov r12,r4 + ;movs r4,#16 + ;add r4,lr + add r4,sp,#20+16 + stm r4!,{r0,r1,r2,r3} + mov r4,r12 + mov r0,r8 + adcs r0,r4 + mov r8,r0 + mov r1,r9 + adcs r1,r5 + mov r9,r1 + mov r2,r10 + adcs r2,r6 + mov r10,r2 + mov r3,r11 + adcs r3,r7 + mov r11,r3 + movs r0,#0 + adcs r0,r0 + mov r12,r0 + ;mov r0,lr + add r0,sp,#20 + ldm r0,{r0,r1,r2,r3,r4,r5,r6,r7} + adds r0,r4 + adcs r1,r5 + adcs r2,r6 + adcs r3,r7 + ;movs r4,#16 + ;add r4,lr + add r4,sp,#20+16 + stm r4!,{r0,r1,r2,r3} + ;mov lr,r4 + mov r0,r13 + ldm r0!,{r4,r5,r6,r7} + mov r1,r8 + adcs r4,r1 + mov r1,r9 + adcs r5,r1 + mov r1,r10 + adcs r6,r1 + mov r1,r11 + adcs r7,r1 + ;mov r0,lr + add r0,sp,#20+32 + stm r0!,{r4,r5,r6,r7} + pop {r4,r5,r6,r7} + frame address sp,76 + mov r1,r12 + movs r2,#0 + mvns r2,r2 + adcs r1,r2 + asrs r2,r1,#4 + adds r4,r1 + adcs r5,r2 + adcs r6,r2 + adcs r7,r2 + stm r0!,{r4,r5,r6,r7} + add sp,#4 + frame address sp,72 + b reduce + endp + endif + +; *r0 = output, *r1 = a, *r2 = b +P256_addmod proc + push {r0,lr} + frame push {lr} + frame address sp,8 + ldm r1!,{r0,r3,r4} + ldm r2!,{r5,r6,r7} + adds r0,r5 + adcs r3,r6 + adcs r4,r7 + mov r8,r0 + mov r9,r3 + mov r10,r4 + ldm r1!,{r5,r6} + ldm r2!,{r3,r4} + adcs r5,r3 + adcs r6,r4 + ldm r1,{r1,r3,r4} + ldm r2,{r0,r2,r7} + adcs r1,r0 + adcs r3,r2 + adcs r4,r7 + movs r7,#0 + adcs r7,r7 + + subs r0,r0 ;set r0 to 0 and C to 1 + mov r2,r8 + mov r8,r7 + mov r7,r9 + mov r9,r4 + mov r4,r10 + adcs r2,r0 + mov r10,r2 + adcs r7,r0 + mov r11,r7 + adcs r4,r0 + sbcs r5,r0 + sbcs r6,r0 + sbcs r1,r0 + movs r0,#1 + sbcs r3,r0 + movs r0,#0 + mov r2,r9 + adcs r2,r0 + mov r7,r8 + sbcs r7,r0 + + ; r10 r11 r4 r5 | r6 r1 r3 r2 | r7 + + mov r8,r3 + mov r3,r11 + mov r11,r2 + mov r2,r10 + + ; r2 r3 r4 r5 | r6 r1 r8 r11 | r7 + + b reduce2 + + endp + +; *r0 = output, *r1 = a, *r2 = b +P256_submod proc + push {r0,lr} + frame push {lr} + frame address sp,8 + ldm r1!,{r0,r3,r4} + ldm r2!,{r5,r6,r7} + subs r0,r5 + sbcs r3,r6 + sbcs r4,r7 + mov r8,r0 + mov r9,r3 + mov r10,r4 + ldm r1!,{r5,r6} + ldm r2!,{r3,r4} + sbcs r5,r3 + sbcs r6,r4 + ldm r1,{r1,r3,r4} + ldm r2,{r0,r2,r7} + sbcs r1,r0 + sbcs r3,r2 + sbcs r4,r7 + + sbcs r7,r7 + + mov r2,r8 + mov r8,r3 + mov r11,r4 + mov r3,r9 + mov r4,r10 + b reduce2 + + endp + +; in: *r0 = output (8 words) +; out: r0 is preserved +P256_load_1 proc + movs r1,#1 + stm r0!,{r1} + movs r1,#0 + movs r2,#0 + stm r0!,{r1-r2} + stm r0!,{r1-r2} + stm r0!,{r1-r2} + stm r0!,{r1} + subs r0,#32 + bx lr + endp + +; in: *r1 +; out: *r0 +P256_to_montgomery proc + push {r4-r7,lr} + frame push {r4-r7,lr} + adr r2,P256_R2_mod_p + bl P256_mulmod + pop {r4-r7,pc} + endp + + align 4 + ; (2^256)^2 mod p +P256_R2_mod_p + dcd 3 + dcd 0 + dcd 0xffffffff + dcd 0xfffffffb + dcd 0xfffffffe + dcd 0xffffffff + dcd 0xfffffffd + dcd 4 + +; in: *r1 +; out: *r0 +P256_from_montgomery proc + push {r4-r7,lr} + frame push {r4-r7,lr} + movs r2,#0 + movs r3,#0 + push {r2-r3} + frame address sp,28 + push {r2-r3} + frame address sp,36 + push {r2-r3} + frame address sp,44 + movs r2,#1 + push {r2-r3} + frame address sp,52 + mov r2,sp + bl P256_mulmod + add sp,#32 + frame address sp,20 + pop {r4-r7,pc} + endp + +; Elliptic curve operations on the NIST curve P256 + +; Checks if a point is on curve +; in: *r0 = x,y(,scratch) in Montgomery form +; out: r0 = 1 if on curve, otherwise 0 +P256_point_is_on_curve proc + if use_interpreter == 1 + push {r0,lr} + frame push {lr} + frame address sp,8 + adr r2,P256_point_is_on_curve_program + bl P256_interpreter + ldr r0,[sp] + adds r0,#64 + adr r1,P256_b_mont + bl P256_greater_or_equal_than + beq %f0 + adr r0,P256_b_mont + ldr r1,[sp] + adds r1,#64 + bl P256_greater_or_equal_than +0 + pop {r1,pc} + else + push {r0,r4-r7,lr} + frame push {r4-r7,lr} + frame address sp,24 + + ; We verify y^2 - (x^3 - 3x) = b + + ; y^2 + mov r1,r0 + adds r1,#32 + sub sp,#32 + frame address sp,56 + mov r0,sp + bl P256_sqrmod + + ; x^2 + ldr r1,[sp,#32] + sub sp,#32 + frame address sp,88 + mov r0,sp + bl P256_sqrmod + + ; x^3 + mov r0,sp + ldr r1,[sp,#64] + mov r2,sp + bl P256_mulmod + + ; x^3 - 3x + movs r0,#3 +0 + push {r0} + frame address sp,92 + add r0,sp,#4 + add r1,sp,#4 + ldr r2,[sp,#68] + bl P256_submod + pop {r0} + frame address sp,88 + subs r0,#1 + bne %b0 + + ; y^2 - (x^3 - 3x) + mov r0,sp + add r1,sp,#32 + mov r2,sp + bl P256_submod + + ; compare with b + mov r0,sp + adr r1,P256_b_mont + bl P256_greater_or_equal_than + beq %f1 + adr r0,P256_b_mont + mov r1,sp + bl P256_greater_or_equal_than +1 + add sp,#68 + frame address sp,20 + + pop {r4-r7,pc} + endif + + endp + + align 4 +P256_b_mont + dcd 0x29c4bddf + dcd 0xd89cdf62 + dcd 0x78843090 + dcd 0xacf005cd + dcd 0xf7212ed6 + dcd 0xe5a220ab + dcd 0x04874834 + dcd 0xdc30061d + + if use_interpreter == 1 +P256_point_is_on_curve_program + dcw 0x2040 + dcw 0x2130 + dcw 0x1113 + dcw 0x4113 + dcw 0x4113 + dcw 0x4113 + dcw 0x4501 + dcw 0x0000 + endif + +; input: *r0 = value, *r1 = limit +; output: 1 if value >= limit, otherwise 0 +P256_greater_or_equal_than proc + push {r4-r6,lr} + frame push {r4-r6,lr} + subs r5,r5 ; set r5 to 0 and C to 1 + mvns r6,r5 ; set r6 to -1 + movs r2,#8 +0 + ldm r0!,{r3} + ldm r1!,{r4} + sbcs r3,r4 + add r2,r2,r6 + tst r2,r2 + bne %b0 + + adcs r5,r5 + mov r0,r5 + pop {r4-r6,pc} + endp + +; in: *r0 = output location, *r1 = input, *r2 = 0/1, *r3 = m +; if r2 = 0, then *r0 is set to *r1 +; if r2 = 1, then *r0 is set to m - *r1 +; note that *r1 should be in the range [1,m-1] +; out: r0 and r1 will have advanced 32 bytes, r2 will remain as the input +P256_negate_mod_m_if proc + push {r4-r7,lr} + frame push {r4-r7,lr} + movs r4,#1 + rsbs r5,r4,#0 ; r5=-1 + mov r8,r5 + subs r4,r4,r2 ; r4=!r2, C=1 + movs r6,#8 +0 + ldm r1!,{r5} + ldm r3!,{r7} + sbcs r7,r5 + muls r7,r2,r7 + muls r5,r4,r5 + add r7,r7,r5 + stm r0!,{r7} + add r6,r6,r8 + tst r6,r6 + bne %b0 + + pop {r4-r7,pc} + endp + +; copies 8 words +; in: *r0 = result, *r1 = input +; out: *r0 = end of result, *r1 = end of input +P256_copy32 proc + push {r4-r5,lr} + frame push {r4-r5,lr} + ldm r1!,{r2-r5} + stm r0!,{r2-r5} + ldm r1!,{r2-r5} + stm r0!,{r2-r5} + pop {r4-r5,pc} + endp + + +; copies 32 bytes +; in: *r0 = result, *r1 = input +; out: *r0 = end of result, *r1 = end of input +P256_copy32_unaligned proc + movs r2,#32 + add r2,r0 +0 + ldrb r3,[r1] + strb r3,[r0] + adds r1,#1 + adds r0,#1 + cmp r0,r2 + bne %b0 + bx lr + endp + +; Selects one of many values +; *r0 = output, *r1 = table, r2 = index to choose [0..7] +P256_select proc + push {r2,r4-r7,lr} + frame push {r4-r7,lr} + frame address sp,24 + + movs r6,#4 +0 + push {r0,r6} + frame address sp,32 + + movs r7,#0 + mov r8,r7 + mov r9,r7 + mov r10,r7 + mov r11,r7 + mov r12,r7 + mov lr,r7 +1 + ldr r0,[sp,#8] + eors r0,r7 + mrs r0,apsr + lsrs r0,#30 + + ldm r1!,{r2-r4} + muls r2,r0,r2 + muls r3,r0,r3 + muls r4,r0,r4 + add r8,r2 + add r9,r3 + add r10,r4 + ldm r1!,{r2-r4} + muls r2,r0,r2 + muls r3,r0,r3 + muls r4,r0,r4 + add r11,r2 + add r12,r3 + add lr,r4 + + adds r1,#72 + adds r7,#1 + cmp r7,#8 + bne %b1 + + pop {r0,r6} + frame address sp,24 + mov r2,r8 + mov r3,r9 + mov r4,r10 + stm r0!,{r2-r4} + mov r2,r11 + mov r3,r12 + mov r4,lr + stm r0!,{r2-r4} + subs r1,#248 + subs r1,#248 + subs r1,#248 + subs r6,#1 + bne %b0 + + pop {r0,r4-r7,pc} + endp + +; Doubles the point in Jacobian form (integers are in Montgomery form) +; *r0 = out, *r1 = in +P256_double_j proc + if use_interpreter == 1 + adr r2,P256_double_j_prog + b P256_interpreter + else + push {r0,r1,r4-r7,lr} + frame push {r4-r7,lr} + frame address sp,28 + + ; https://eprint.iacr.org/2014/130.pdf, algorithm 10 + + ; t1 = Z1^2 + sub sp,#32 + frame address sp,60 + mov r0,sp + adds r1,#64 + bl P256_sqrmod + + ; Z2 = Y1 * Z1 + ldr r0,[sp,#32] + ldr r1,[sp,#36] + adds r0,#64 + adds r1,#32 + movs r2,#32 + adds r2,r1 + bl P256_mulmod + + ; t2 = X1 + t1 + ldr r1,[sp,#36] + mov r2,sp + sub sp,#32 + frame address sp,92 + mov r0,sp + bl P256_addmod + + ; t1 = X1 - t1 + ldr r1,[sp,#68] + add r2,sp,#32 + mov r0,r2 + bl P256_submod + + ; t1 = t1 * t2 + add r1,sp,#32 + mov r2,sp + mov r0,r1 + bl P256_mulmod + + ; t2 = t1 / 2 + add sp,#32 + frame address sp,60 + mov r7,sp + ldm r7!,{r0-r3} + lsls r6,r0,#31 + asrs r5,r6,#31 + lsrs r6,#31 + movs r4,#0 + adds r0,r5 + adcs r1,r5 + adcs r2,r5 + adcs r3,r4 + push {r0-r3} + frame address sp,76 + ldm r7!,{r0-r3} + adcs r0,r4 + adcs r1,r4 + adcs r2,r6 + adcs r3,r5 + movs r4,#0 + adcs r4,r4 + lsls r7,r4,#31 + lsrs r6,r3,#1 + orrs r7,r6 + lsls r6,r3,#31 + lsrs r5,r2,#1 + orrs r6,r5 + lsls r5,r2,#31 + lsrs r4,r1,#1 + orrs r5,r4 + lsls r4,r1,#31 + lsrs r3,r0,#1 + orrs r4,r3 + lsls r3,r0,#31 + mov r8,r3 + pop {r0-r3} + frame address sp,60 + push {r4-r7} + frame address sp,76 + mov r7,r8 + lsrs r6,r3,#1 + orrs r7,r6 + lsls r6,r3,#31 + lsrs r5,r2,#1 + orrs r6,r5 + lsls r5,r2,#31 + lsrs r4,r1,#1 + orrs r5,r4 + lsls r4,r1,#31 + lsrs r3,r0,#1 + orrs r4,r3 + push {r4-r7} + frame address sp,92 + + ; t1 = t1 + t2 + add r1,sp,#32 + mov r2,sp + mov r0,r1 + bl P256_addmod + + ; t2 = t1^2 + mov r0,sp + add r1,sp,#32 + bl P256_sqrmod + + ; Y2 = Y1^2 + ldr r0,[sp,#64] + ldr r1,[sp,#68] + adds r0,#32 + adds r1,#32 + bl P256_sqrmod + + ; t3 = Y2^2 + ldr r1,[sp,#64] + adds r1,#32 + sub sp,#32 + frame address sp,124 + mov r0,sp + bl P256_sqrmod + + ; Y2 = X1 * Y2 + ldr r0,[sp,#96] + ldr r1,[sp,#100] + adds r0,#32 + mov r2,r0 + bl P256_mulmod + + ; X2 = 2 * Y2 + ldr r0,[sp,#96] + mov r1,r0 + adds r1,#32 + mov r2,r1 + bl P256_addmod + + ; X2 = t2 - X2 + ldr r0,[sp,#96] + add r1,sp,#32 + mov r2,r0 + bl P256_submod + + ; t2 = Y2 - X2 + ldr r2,[sp,#96] + mov r1,r2 + adds r1,#32 + add r0,sp,#32 + bl P256_submod + + ; t1 = t1 * t2 + add r0,sp,#64 + add r1,sp,#64 + add r2,sp,#32 + bl P256_mulmod + + ; Y2 = t1 - t3 + ldr r0,[sp,#96] + adds r0,#32 + add r1,sp,#64 + mov r2,sp + bl P256_submod + + add sp,#104 + frame address sp,20 + + pop {r4-r7,pc} + endif + endp + + +; Adds or subtracts points in Jacobian form (integers are in Montgomery form) +; The first operand is located in *r0, the second in *r1 (may not overlap) +; The result is stored at *r0 +; +; Requirements: +; - no operand is the point at infinity +; - both operand must be different +; - one operand must not be the negation of the other +; If requirements are not met, the returned Z point will be 0 +P256_add_j proc + if use_interpreter == 1 + adr r2,P256_add_j_prog + b P256_interpreter + else + push {r0,r1,r4-r7,lr} + frame push {r4-r7,lr} + frame address sp,28 + + ; Here a variant of + ; https://www.hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-3/addition/add-1998-cmo-2.op3 + ; is used, but rearranged and uses less temporaries. + ; The first operand to the function is both (X3,Y3,Z3) and (X2,Y2,Z2). + ; The second operand to the function is (X1,Y1,Z1) + + ; Z1Z1 = Z1^2 + sub sp,#32 + frame address sp,60 + mov r0,sp + adds r1,#64 + bl P256_sqrmod + + ; U2 = X2*Z1Z1 + ldr r1,[sp,#32] + mov r2,sp + mov r0,r1 + bl P256_mulmod + + ; t1 = Z1*Z1Z1 + ldr r1,[sp,#36] + adds r1,#64 + mov r2,sp + mov r0,sp + bl P256_mulmod + + ; S2 = Y2*t1 + ldr r1,[sp,#32] + adds r1,#32 + mov r2,sp + mov r0,r1 + bl P256_mulmod + + ; Z2Z2 = Z2^2 + sub sp,#32 + frame address sp,92 + mov r0,sp + ldr r1,[sp,#64] + adds r1,#64 + bl P256_sqrmod + + ; U1 = X1*Z2Z2 + ldr r1,[sp,#68] + mov r2,sp + add r0,sp,#32 + bl P256_mulmod + + ; t2 = Z2*Z2Z2 + ldr r1,[sp,#64] + adds r1,#64 + mov r2,sp + mov r0,sp + bl P256_mulmod + + ; S1 = Y1*t2 + ldr r1,[sp,#68] + adds r1,#32 + mov r2,sp + mov r0,sp + bl P256_mulmod + + ; H = U2-U1 + ldr r1,[sp,#64] + add r2,sp,#32 + mov r0,r1 + bl P256_submod + + ; HH = H^2 + ldr r1,[sp,#64] + sub sp,#32 + frame address sp,124 + mov r0,sp + bl P256_sqrmod + + ; Z3 = Z2*H + ldr r2,[sp,#96] + mov r1,r2 + adds r1,#64 + mov r0,r1 + bl P256_mulmod + + ; Z3 = Z1*Z3 + ldr r1,[sp,#100] + adds r1,#64 + ldr r2,[sp,#96] + adds r2,#64 + mov r0,r2 + bl P256_mulmod + + ; HHH = H*HH + ldr r1,[sp,#96] + mov r2,sp + mov r0,r1 + bl P256_mulmod + + ; r = S2-S1 + ldr r1,[sp,#96] + adds r1,#32 + add r2,sp,#32 + mov r0,r1 + bl P256_submod + + ; V = U1*HH + add r1,sp,#64 + mov r2,sp + mov r0,r1 + bl P256_mulmod + + ; t3 = r^2 + ldr r1,[sp,#96] + adds r1,#32 + mov r0,sp + bl P256_sqrmod + + ; t2 = S1*HHH + add r1,sp,#32 + ldr r2,[sp,#96] + add r0,sp,#32 + bl P256_mulmod + + ; X3 = t3-HHH + mov r1,sp + ldr r2,[sp,#96] + mov r0,r2 + bl P256_submod + + ; t3 = 2*V + add r1,sp,#64 + add r2,sp,#64 + mov r0,sp + bl P256_addmod + + ; X3 = X3-t3 + ldr r1,[sp,#96] + mov r2,sp + mov r0,r1 + bl P256_submod + + ; t3 = V-X3 + add r1,sp,#64 + ldr r2,[sp,#96] + mov r0,sp + bl P256_submod + + ; t3 = r*t3 + ldr r1,[sp,#96] + adds r1,#32 + mov r2,sp + mov r0,sp + bl P256_mulmod + + ; Y3 = t3-t2 + mov r1,sp + add r2,sp,#32 + ldr r0,[sp,#96] + adds r0,#32 + bl P256_submod + + add sp,#104 + frame address sp,20 + + pop {r4-r7,pc} + endif + endp + + if use_interpreter == 1 + align 4 +P256_add_j_prog + dcw 0x2080 + dcw 0x1330 + dcw 0x1080 + dcw 0x1440 + dcw 0x2150 + dcw 0x1061 + dcw 0x1151 + dcw 0x1171 + dcw 0x4330 + dcw 0x2230 + dcw 0x1553 + dcw 0x1585 + dcw 0x1332 + dcw 0x4441 + dcw 0x1002 + dcw 0x2240 + dcw 0x1113 + dcw 0x4323 + dcw 0x3200 + dcw 0x4332 + dcw 0x4203 + dcw 0x1242 + dcw 0x4421 + dcw 0x0000 + + align 4 +P256_double_j_prog + dcw 0x2080 + dcw 0x1578 + dcw 0x3160 + dcw 0x4060 + dcw 0x1001 + dcw 0x5100 + dcw 0x3001 + dcw 0x2100 + dcw 0x2470 + dcw 0x2240 + dcw 0x1464 + dcw 0x3344 + dcw 0x4313 + dcw 0x4143 + dcw 0x1001 + dcw 0x4402 + dcw 0x0000 + +; in: *r0 = output, *r1 = input +P256_div2mod proc + mov r9,r0 + mov r7,r1 + ldm r7!,{r0-r3} + lsls r6,r0,#31 + asrs r5,r6,#31 + lsrs r6,#31 + movs r4,#0 + adds r0,r5 + adcs r1,r5 + adcs r2,r5 + adcs r3,r4 + push {r0-r3} + frame address sp,76 + ldm r7!,{r0-r3} + adcs r0,r4 + adcs r1,r4 + adcs r2,r6 + adcs r3,r5 + movs r4,#0 + adcs r4,r4 + lsls r7,r4,#31 + lsrs r6,r3,#1 + orrs r7,r6 + lsls r6,r3,#31 + lsrs r5,r2,#1 + orrs r6,r5 + lsls r5,r2,#31 + lsrs r4,r1,#1 + orrs r5,r4 + lsls r4,r1,#31 + lsrs r3,r0,#1 + orrs r4,r3 + lsls r3,r0,#31 + mov r0,r9 + adds r0,#16 + stm r0!,{r4-r7} + mov r7,r3 + pop {r0-r3} + lsrs r6,r3,#1 + orrs r7,r6 + lsls r6,r3,#31 + lsrs r5,r2,#1 + orrs r6,r5 + lsls r5,r2,#31 + lsrs r4,r1,#1 + orrs r5,r4 + lsls r4,r1,#31 + lsrs r3,r0,#1 + orrs r4,r3 + mov r0,r9 + stm r0!,{r4-r7} + bx lr + endp + +; in: *r0 = op1, *r1 = op2, *r2 = program +; program is an array of 16-bit integers, ending with 0x0000 +; in an opcode, bit 12-15 is function to execute (exit, mul, sqr, add, sub, div2), +; bit 8-11 is dest, bit 4-7 is first operand, bit 0-3 is second operand +; the operand is encoded like this: +; operand 0-2 is temporary variable 0-2 +; operand 3-5 is op1[0], op1[1], op1[2] +; operand 6-8 is op2[0], op2[1], op2[2] +; each variable is 32 bytes +; for a function taking less than two parameters, the extra parameters are ignored +P256_interpreter proc + push {r4-r7,lr} + frame push {r4-r7,lr} + + sub sp,#96 + frame address sp,116 + + movs r3,#32 + mov r4,r1 + adds r5,r1,r3 + adds r6,r5,r3 + push {r4-r6} + frame address sp,128 + mov r4,r0 + adds r5,r0,r3 + adds r6,r5,r3 + push {r4-r6} + frame address sp,140 + add r4,sp,#24 + adds r5,r4,r3 + adds r6,r5,r3 + push {r4-r6} + frame address sp,152 + +0 + movs r4,#0x3c + mov r5,sp + ldrh r3,[r2] + adds r2,#2 + push {r2} + frame address sp,156 + lsls r2,r3,#2 + ands r2,r4 + ldr r2,[r5,r2] + lsrs r1,r3,#2 + ands r1,r4 + ldr r1,[r5,r1] + lsrs r0,r3,#6 + ands r0,r4 + ldr r0,[r5,r0] + adr r5,P256_functions-4 + lsrs r6,r3,#10 + ands r6,r4 + beq %f1 + ldr r6,[r5,r6] + blx r6 + pop {r2} + frame address sp,152 + b %b0 +1 + frame address sp,156 + add sp,#136 + frame address sp,20 + pop {r4-r7,pc} + endp + + align 4 +P256_functions + dcd P256_mulmod ;1 + dcd P256_sqrmod ;2 + dcd P256_addmod ;3 + dcd P256_submod ;4 + dcd P256_div2mod ;5 + + endif + + if use_smaller_modinv == 1 +; in/out: r0-r7 +P256_modinv proc + push {r0-r7,lr} + frame push {r4-r7,lr} + frame address sp,36 + sub sp,#36 + frame address sp,72 + mov r0,sp + bl P256_load_1 + mov r1,r0 + bl P256_to_montgomery + adr r0,P256_p + ldm r0,{r0-r7} + subs r0,#2 + push {r0-r7} + frame address sp,104 + + movs r0,#255 +0 + str r0,[sp,#64] + add r0,sp,#32 + add r1,sp,#32 + bl P256_sqrmod + ldr r0,[sp,#64] + lsrs r1,r0,#3 + add r1,r1,sp + ldrb r1,[r1] + movs r2,#7 + ands r2,r2,r0 + lsrs r1,r2 + movs r2,#1 + tst r1,r2 + beq %f1 + add r0,sp,#32 + add r1,sp,#32 + add r2,sp,#68 + bl P256_mulmod +1 + ldr r0,[sp,#64] + subs r0,#1 + bpl %b0 + + add sp,#32 + frame address sp,72 + pop {r0-r7} + frame address sp,40 + add sp,#36 + frame address sp,4 + pop {pc} + endp + + else + +; in: *r0 = input/output, r1 = count, *r2 = operand for final multiplication +P256_sqrmod_many_and_mulmod proc + push {r0,r2,lr} + frame push {lr} + frame address sp,12 + cmp r1,#0 + beq %f1 +0 + push {r1} + frame address sp,16 + ldr r0,[sp,#4] + mov r1,r0 + bl P256_sqrmod + pop {r1} + frame address sp,12 + subs r1,#1 + bne %b0 +1 + pop {r0,r1} + frame address sp,4 + mov r2,r0 + bl P256_mulmod + pop {pc} + endp + + +; in: *r0 = value in/out +; for modinv, call input a, then if a = A * R % p, then it calculates A^-1 * R % p = (a/R)^-1 * R % p = R^2 / a % p +P256_modinv proc + push {r0,lr} + frame push {lr} + frame address sp,8 + + ldm r0,{r0-r7} + push {r0-r7} + frame address sp,40 + + ; t = a^2*a + ldr r0,[sp,#32] + movs r1,#1 + mov r2,sp + bl P256_sqrmod_many_and_mulmod + ldr r0,[sp,#32] + ldm r0,{r0-r7} + push {r0-r7} + frame address sp,72 + + ; a4_2 = a2_0^(2^2) + + ldr r0,[sp,#64] + mov r1,r0 + bl P256_sqrmod + ldr r0,[sp,#64] + mov r1,r0 + bl P256_sqrmod + ldr r0,[sp,#64] + ldm r0,{r0-r7} + push {r0-r7} + frame address sp,104 + + ; a4_0 = a4_2*a2_0 + ldr r0,[sp,#96] + mov r1,sp + add r2,sp,#32 + bl P256_mulmod + add r0,sp,#32 + ldr r1,[sp,#96] + bl P256_copy32 + + ldr r7,[sp,#96] + movs r4,#0 +0 + adr r2,P256_invtbl + ldrsb r0,[r2,r4] + adds r2,#1 + ldrb r5,[r2,r4] + lsls r6,r0,#2 + bpl %f1 + sub sp,#32 + frame address sp,200 ; not always correct + mov r0,sp + mov r1,r7 + bl P256_copy32 +1 + mov r0,r7 + uxtb r1,r6 + mov r2,r5 + add r2,sp + push {r4,r7} + frame address sp,208 ; not always correct + bl P256_sqrmod_many_and_mulmod + pop {r4,r7} + frame address sp,200 ; not always correct + adds r4,#2 + cmp r4,#22 + bne %b0 + + add sp,#6*32+4 + frame address sp,4 + + pop {pc} + + endp + + align 4 +P256_invtbl + dcb ((8-4)>>2) + dcb 32 + + dcb ((16-8)>>2)+128 + dcb 0 + + dcb (16>>2)+128 + dcb 0 + + dcb (32>>2)+128 + dcb 5*32 + + dcb (192-64)>>2 + dcb 0 + + dcb (224-192)>>2 + dcb 0 + + dcb (240-224)>>2 + dcb 32 + + dcb (248-240)>>2 + dcb 64 + + dcb (252-248)>>2 + dcb 128 + + dcb (256-252)>>2 + dcb 96 + + dcb 0 + dcb 5*32 + + endif + + +; *r0 = output affine montgomery/input jacobian montgomery +P256_jacobian_to_affine proc + push {r0,r4-r7,lr} + frame push {r4-r7,lr} + frame address sp,24 + + adds r0,#64 + ldm r0,{r0-r7} + if use_smaller_modinv == 0 + push {r0-r7} + frame address sp,56 + mov r0,sp + bl P256_modinv + else + bl P256_modinv + push {r0-r7} + frame address sp,56 + endif + + mov r1,sp + sub sp,#32 + frame address sp,88 + mov r0,sp + bl P256_sqrmod + + add r1,sp,#32 + mov r2,sp + mov r0,r1 + bl P256_mulmod + + mov r1,sp + ldr r0,[sp,#64] + mov r2,r0 + bl P256_mulmod + + add r1,sp,#32 + ldr r0,[sp,#64] + adds r0,#32 + mov r2,r0 + bl P256_mulmod + + add sp,#68 + frame address sp,20 + + pop {r4-r7,pc} + endp + +; performs r0 := abs(r0) +P256_abs_int proc + rsbs r2,r0,#0 + asrs r3,r0,#31 + ands r3,r2 + asrs r2,#31 + ands r0,r2 + orrs r0,r0,r3 + bx lr + endp + +; in: *r0 = output, *r1 = point, *r2 = scalar, r3 = include y in result (1/0) +; out: r0 = 1 on success, 0 if invalid point or scalar +P256_pointmult proc + export P256_pointmult + push {r4-r7,lr} + frame push {r4-r7,lr} + mov r4,r8 + mov r5,r9 + mov r6,r10 + mov r7,r11 + push {r0-r1,r4-r7} + frame address sp,44 + frame save {r8-r11},-36 + sub sp,#256 + frame address sp,300 + + lsls r6,r3,#16 + + ; load scalar into an aligned position + add r0,sp,#32 + mov r1,r2 + bl P256_copy32_unaligned + + ; fail if scalar == 0 + mov r0,sp + bl P256_load_1 + add r0,sp,#32 + mov r1,sp + bl P256_greater_or_equal_than + bne %f1 +0 + add sp,#256+8 + frame address sp,36 + b %f10 + frame address sp,300 +1 + ; fail if not (scalar < n) + add r0,sp,#32 + adr r1,P256_order + bl P256_greater_or_equal_than + subs r0,#1 + beq %b0 + + ; select scalar if scalar is odd and -scalar mod n if scalar is even + mov r0,sp + add r1,sp,#32 + ldr r2,[r1] + movs r3,#1 + ands r2,r3 + eors r2,r3 + add r6,r2 ; save original parity of scalar + adr r3,P256_order + bl P256_negate_mod_m_if + + ; stack layout (initially offset 768): + ; 0-767: table of jacobian points P, 3P, 5P, ..., 15P + ; 768-863: current point (in jacobian form) + ; 864-927: scalar rewritten into 4-bit window, each element having an odd signed value + ; 928-1023: extracted selected point from the table + ; 1024-1027: output pointer + ; 1028-1031: input point + + ; rewrite scalar into 4-bit window where every value is odd + add r1,sp,#864-768 + ldr r0,[sp] + lsls r0,#28 + lsrs r0,#28 + movs r2,#1 + mov r4,sp + movs r5,#1 +2 + lsrs r3,r2,#1 + ldrb r3,[r4,r3] + lsls r7,r2,#31 + lsrs r7,#29 + lsrs r3,r7 + lsls r3,#28 + lsrs r3,#28 + movs r7,#1 + ands r7,r3 + eors r7,r5 + lsls r7,#4 + subs r0,r7 + strb r0,[r1] + adds r1,#1 + orrs r3,r5 + mov r0,r3 + adds r2,#1 + cmp r2,#64 + bne %b2 + strb r0,[r1] + + ; load point into an aligned position + ldr r1,[sp,#1028-768] + sub sp,#384 + frame address sp,684 + sub sp,#384 + frame address sp,1068 + mov r0,sp + bl P256_copy32_unaligned + bl P256_copy32_unaligned + + ; fail if not x, y < p + mov r0,sp + adr r1,P256_p + bl P256_greater_or_equal_than + subs r0,#1 + bne %f4 +3 + add sp,#384 + frame address sp,684 + add sp,#384 + frame address sp,300 + b %b0 + frame address sp,1068 +4 + add r0,sp,#32 + adr r1,P256_p + bl P256_greater_or_equal_than + subs r0,#1 + beq %b3 + + ; convert basepoint x, y to montgomery form, + ; and place result as first element in table of Jacobian points + + mov r0,sp + mov r1,sp + bl P256_to_montgomery + add r0,sp,#32 + add r1,sp,#32 + bl P256_to_montgomery + + ; check that the basepoint lies on the curve + mov r0,sp + bl P256_point_is_on_curve + cmp r0,#0 + beq %b3 + + ; load montgomery 1 for Z + add r0,sp,#64 + bl P256_load_1 + mov r1,r0 + bl P256_to_montgomery + + ; temporarily calculate 2P + add r0,sp,#7*96 + mov r1,sp + bl P256_double_j + + ; calculate rest of the table (3P, 5P, ..., 15P) + add r4,sp,#96 + movs r5,#7 +5 + mov r0,r4 + add r1,sp,#7*96 + bl P256_copy32 + bl P256_copy32 + bl P256_copy32 + mov r0,r4 + mov r1,r0 + subs r1,#96 + bl P256_add_j + adds r4,#96 + subs r5,#1 + bne %b5 + + ; select the initial current point based on the first highest 4 scalar bits + add r7,sp,#928 + subs r7,#1 + ldrb r0,[r7] + subs r7,#1 + sxtb r0,r0 + bl P256_abs_int + lsrs r2,r0,#1 + add r0,sp,#768 + mov r1,sp + bl P256_select + + ; main loop iterating from index 62 to 0 of the windowed scalar + add r5,sp,#864 +6 + movs r4,#4 +7 + add r0,sp,#768 + mov r1,r0 + bl P256_double_j + subs r4,#1 + bne %b7 + + ; select the point to add, and then add to the current point + ldrb r0,[r7] + subs r7,#1 + sxtb r0,r0 + lsrs r4,r0,#31 + bl P256_abs_int + lsrs r2,r0,#1 + add r0,sp,#928 + mov r1,sp + bl P256_select + add r0,sp,#960 + mov r1,r0 + mov r2,r4 + adr r3,P256_p + bl P256_negate_mod_m_if + cmp r7,r5 + bge %f8 + ; see note below + add r0,sp,#672 + add r1,sp,#768 + bl P256_double_j +8 + add r0,sp,#768 + add r1,sp,#928 + bl P256_add_j + cmp r7,r5 + bge %b6 + + ; Note: ONLY for the scalars 2 and -2 mod n, the last addition will + ; be an addition where both input values are equal. The addition algorithm + ; fails for such a case (returns Z=0) and we must therefore use the doubling + ; formula. Both values are computed and then the correct value is selected + ; in constant time based on whether the addition formula returned Z=0. + ; Obviously if the scalar (private key) is properly randomized, this would + ; (with extremely high probability), never occur. + mov r0,sp + bl P256_load_1 + add r0,sp,#768+64 + mov r1,sp + bl P256_greater_or_equal_than + adds r2,r0,#6 + add r0,sp,#928 + add r1,sp,#96 + bl P256_select + + add sp,#464 ;928/2 + frame address sp,604 + add sp,#464 + frame address sp,140 + + mov r0,sp + bl P256_jacobian_to_affine + + mov r0,sp + mov r1,sp + bl P256_from_montgomery + add r0,sp,#32 + add r1,sp,#32 + bl P256_from_montgomery + + add r0,sp,#32 + add r1,sp,#32 + uxtb r2,r6 + adr r3,P256_p + bl P256_negate_mod_m_if + + ldr r0,[sp,#96] + mov r1,sp + bl P256_copy32_unaligned + lsrs r6,#16 + beq %f9 + bl P256_copy32_unaligned +9 + + movs r0,#1 + add sp,#96+8 + frame address sp,36 +10 + pop {r4-r7} + frame address sp,20 + mov r8,r4 + mov r9,r5 + mov r10,r6 + mov r11,r7 + pop {r4-r7,pc} + endp + +; in: *r0 = output, *r1 = private key scalar +; out: r0 = 1 on success, 0 if scalar is out of range +P256_ecdh_keygen proc + export P256_ecdh_keygen + mov r2,r1 + adr r1,P256_basepoint + movs r3,#1 + b P256_pointmult + endp + +; in: *r0 = output, *r1 = other's public point, *r2 = private key scalar +; out: r0 = 1 on success, 0 if invalid public point or private key scalar +P256_ecdh_shared_secret proc + export P256_ecdh_shared_secret + movs r3,#0 + b P256_pointmult + endp + + align 4 +P256_p + dcd 0xffffffff + dcd 0xffffffff + dcd 0xffffffff + dcd 0 + dcd 0 + dcd 0 + dcd 1 + dcd 0xffffffff + +P256_order + dcd 0xFC632551 + dcd 0xF3B9CAC2 + dcd 0xA7179E84 + dcd 0xBCE6FAAD + dcd 0xFFFFFFFF + dcd 0xFFFFFFFF + dcd 0 + dcd 0xFFFFFFFF + +P256_basepoint + dcd 0xD898C296 + dcd 0xF4A13945 + dcd 0x2DEB33A0 + dcd 0x77037D81 + dcd 0x63A440F2 + dcd 0xF8BCE6E5 + dcd 0xE12C4247 + dcd 0x6B17D1F2 + dcd 0x37BF51F5 + dcd 0xCBB64068 + dcd 0x6B315ECE + dcd 0x2BCE3357 + dcd 0x7C0F9E16 + dcd 0x8EE7EB4A + dcd 0xFE1A7F9B + dcd 0x4FE342E2 + + end diff --git a/src/components/ethermind/external/crypto/sha256/sha256.c b/src/components/ethermind/external/crypto/sha256/sha256.c new file mode 100644 index 0000000..3ace4bc --- /dev/null +++ b/src/components/ethermind/external/crypto/sha256/sha256.c @@ -0,0 +1,432 @@ +/* + FIPS-180-2 compliant SHA-256 implementation + + Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + SPDX-License-Identifier: Apache-2.0 + + 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 file is part of mbed TLS (https://tls.mbed.org) +*/ +/* + The SHA-256 Secure Hash Standard was published by NIST in 2002. + + http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf +*/ + + +#include "sha256.h" +#include "flash.h" + +#include +#include +#include +#define mbedtls_printf(...) printf(__VA_ARGS__) + + + +#define MBEDTLS_PARAM_FAILED( cond ) \ + mbedtls_printf( "mbed param faile-%s %s", __FILE__, __LINE__ ) + +/** + \brief User supplied callback function for parameter validation failure. + See #MBEDTLS_CHECK_PARAMS for context. + + This function will be called unless an alternative treatement + is defined through the #MBEDTLS_PARAM_FAILED macro. + + This function can return, and the operation will be aborted, or + alternatively, through use of setjmp()/longjmp() can resume + execution in the application code. + + \param failure_condition The assertion that didn't hold. + \param file The file where the assertion failed. + \param line The line in the file where the assertion failed. +*/ + + + +/* Internal macro meant to be called only from within the library. */ +#define MBEDTLS_INTERNAL_VALIDATE_RET( cond, ret ) \ + do { \ + if( !(cond) ) \ + { \ + MBEDTLS_PARAM_FAILED( cond ); \ + return( ret ); \ + } \ + } while( 0 ) + +/* Internal macro meant to be called only from within the library. */ +#define MBEDTLS_INTERNAL_VALIDATE( cond ) \ + do { \ + if( !(cond) ) \ + { \ + MBEDTLS_PARAM_FAILED( cond ); \ + return; \ + } \ + } while( 0 ) + + + + + +#define SHA256_VALIDATE_RET(cond) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_SHA256_BAD_INPUT_DATA ) +#define SHA256_VALIDATE(cond) MBEDTLS_INTERNAL_VALIDATE( cond ) + + +/* + 32-bit integer manipulation macros (big endian) +*/ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ + do { \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ + } while( 0 ) +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ + do { \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ + } while( 0 ) +#endif + +void mbedtls_sha256_init( mbedtls_sha256_context* ctx ) +{ +// SHA256_VALIDATE( ctx != NULL ); + memset( ctx, 0, sizeof( mbedtls_sha256_context ) ); +} + +void mbedtls_sha256_free( mbedtls_sha256_context* ctx ) +{ + if( ctx == NULL ) + return; + + //mbedtls_platform_zeroize( ctx, sizeof( mbedtls_sha256_context ) ); + memset( ctx, 0, sizeof( mbedtls_sha256_context ) ); +} + +void mbedtls_sha256_clone( mbedtls_sha256_context* dst, + const mbedtls_sha256_context* src ) +{ +// SHA256_VALIDATE( dst != NULL ); +// SHA256_VALIDATE( src != NULL ); + *dst = *src; +} + +/* + SHA-256 context setup +*/ +int mbedtls_sha256_starts_ret( mbedtls_sha256_context* ctx, int is224 ) +{ +// SHA256_VALIDATE_RET( ctx != NULL ); +// SHA256_VALIDATE_RET( is224 == 0 || is224 == 1 ); + ctx->total[0] = 0; + ctx->total[1] = 0; + + if( is224 == 0 ) + { + /* SHA-256 */ + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; + } + else + { + /* SHA-224 */ + ctx->state[0] = 0xC1059ED8; + ctx->state[1] = 0x367CD507; + ctx->state[2] = 0x3070DD17; + ctx->state[3] = 0xF70E5939; + ctx->state[4] = 0xFFC00B31; + ctx->state[5] = 0x68581511; + ctx->state[6] = 0x64F98FA7; + ctx->state[7] = 0xBEFA4FA4; + } + + ctx->is224 = is224; + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha256_starts( mbedtls_sha256_context* ctx, + int is224 ) +{ + mbedtls_sha256_starts_ret( ctx, is224 ); +} +#endif + +#if !defined(MBEDTLS_SHA256_PROCESS_ALT) +static const uint32_t K[] = +{ + 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, +}; + +#define SHR(x,n) ((x & 0xFFFFFFFF) >> n) +#define ROTR(x,n) (SHR(x,n) | (x << (32 - n))) + +#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3)) +#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10)) + +#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22)) +#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25)) + +#define F0(x,y,z) ((x & y) | (z & (x | y))) +#define F1(x,y,z) (z ^ (x & (y ^ z))) + +#define R(t) \ + ( \ + W[t] = S1(W[t - 2]) + W[t - 7] + \ + S0(W[t - 15]) + W[t - 16] \ + ) + +#define P(a,b,c,d,e,f,g,h,x,K) \ + { \ + temp1 = h + S3(e) + F1(e,f,g) + K + x; \ + temp2 = S2(a) + F0(a,b,c); \ + d += temp1; h = temp1 + temp2; \ + } + +int mbedtls_internal_sha256_process( mbedtls_sha256_context* ctx, + const unsigned char data[64] ) +{ + uint32_t temp1, temp2, W[64]; + uint32_t A[8]; + unsigned int i; + +// SHA256_VALIDATE_RET( ctx != NULL ); +// SHA256_VALIDATE_RET( (const unsigned char *)data != NULL ); + + for( i = 0; i < 8; i++ ) + A[i] = ctx->state[i]; + + #if defined(MBEDTLS_SHA256_SMALLER) + + for( i = 0; i < 64; i++ ) + { + if( i < 16 ) + GET_UINT32_BE( W[i], data, 4 * i ); + else + R( i ); + + P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i] ); + temp1 = A[7]; + A[7] = A[6]; + A[6] = A[5]; + A[5] = A[4]; + A[4] = A[3]; + A[3] = A[2]; + A[2] = A[1]; + A[1] = A[0]; + A[0] = temp1; + } + + #else /* MBEDTLS_SHA256_SMALLER */ + + for( i = 0; i < 16; i++ ) + GET_UINT32_BE( W[i], data, 4 * i ); + + for( i = 0; i < 16; i += 8 ) + { + P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i+0], K[i+0] ); + P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i+1], K[i+1] ); + P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i+2], K[i+2] ); + P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i+3], K[i+3] ); + P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i+4], K[i+4] ); + P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i+5], K[i+5] ); + P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i+6], K[i+6] ); + P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i+7], K[i+7] ); + } + + for( i = 16; i < 64; i += 8 ) + { + P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(i+0), K[i+0] ); + P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(i+1), K[i+1] ); + P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(i+2), K[i+2] ); + P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(i+3), K[i+3] ); + P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(i+4), K[i+4] ); + P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(i+5), K[i+5] ); + P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(i+6), K[i+6] ); + P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(i+7), K[i+7] ); + } + + #endif /* MBEDTLS_SHA256_SMALLER */ + + for( i = 0; i < 8; i++ ) + ctx->state[i] += A[i]; + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha256_process( mbedtls_sha256_context* ctx, + const unsigned char data[64] ) +{ + mbedtls_internal_sha256_process( ctx, data ); +} +#endif +#endif /* !MBEDTLS_SHA256_PROCESS_ALT */ + +/* + SHA-256 process buffer +*/ +int mbedtls_sha256_update_ret( mbedtls_sha256_context* ctx, + const unsigned char* input, + size_t ilen ) +{ + int ret; + size_t fill; + uint32_t left; + +// SHA256_VALIDATE_RET( ctx != NULL ); +// SHA256_VALIDATE_RET( ilen == 0 || input != NULL ); + + if( ilen == 0 ) + return( 0 ); + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void*) (ctx->buffer + left), input, fill ); + + if( ( ret = mbedtls_internal_sha256_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + if( ( ret = mbedtls_internal_sha256_process( ctx, input ) ) != 0 ) + return( ret ); + + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + memcpy( (void*) (ctx->buffer + left), input, ilen ); + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha256_update( mbedtls_sha256_context* ctx, + const unsigned char* input, + size_t ilen ) +{ + mbedtls_sha256_update_ret( ctx, input, ilen ); +} +#endif + +/* + SHA-256 final digest +*/ +int mbedtls_sha256_finish_ret( mbedtls_sha256_context* ctx, + unsigned char output[32] ) +{ + int ret; + uint32_t used; + uint32_t high, low; +// SHA256_VALIDATE_RET( ctx != NULL ); +// SHA256_VALIDATE_RET( (unsigned char *)output != NULL ); + /* + Add padding: 0x80 then 0x00 until 8 bytes remain for the length + */ + used = ctx->total[0] & 0x3F; + ctx->buffer[used++] = 0x80; + + if( used <= 56 ) + { + /* Enough room for padding + length in current block */ + memset( ctx->buffer + used, 0, 56 - used ); + } + else + { + /* We'll need an extra block */ + memset( ctx->buffer + used, 0, 64 - used ); + + if( ( ret = mbedtls_internal_sha256_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + memset( ctx->buffer, 0, 56 ); + } + + /* + Add message length + */ + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + PUT_UINT32_BE( high, ctx->buffer, 56 ); + PUT_UINT32_BE( low, ctx->buffer, 60 ); + + if( ( ret = mbedtls_internal_sha256_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + /* + Output final state + */ + PUT_UINT32_BE( ctx->state[0], output, 0 ); + PUT_UINT32_BE( ctx->state[1], output, 4 ); + PUT_UINT32_BE( ctx->state[2], output, 8 ); + PUT_UINT32_BE( ctx->state[3], output, 12 ); + PUT_UINT32_BE( ctx->state[4], output, 16 ); + PUT_UINT32_BE( ctx->state[5], output, 20 ); + PUT_UINT32_BE( ctx->state[6], output, 24 ); + + if( ctx->is224 == 0 ) + PUT_UINT32_BE( ctx->state[7], output, 28 ); + + return( 0 ); +} + + + + diff --git a/src/components/ethermind/external/crypto/sha256/sha256.h b/src/components/ethermind/external/crypto/sha256/sha256.h new file mode 100644 index 0000000..7a4dd18 --- /dev/null +++ b/src/components/ethermind/external/crypto/sha256/sha256.h @@ -0,0 +1,156 @@ +/** + \file sha256.h + + \brief This file contains SHA-224 and SHA-256 definitions and functions. + + The Secure Hash Algorithms 224 and 256 (SHA-224 and SHA-256) cryptographic + hash functions are defined in FIPS 180-4: Secure Hash Standard (SHS). +*/ +/* + Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + SPDX-License-Identifier: Apache-2.0 + + 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 file is part of Mbed TLS (https://tls.mbed.org) +*/ +#ifndef MBEDTLS_SHA256_H +#define MBEDTLS_SHA256_H + +#include +#include + + + +/* MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED -0x0037 /**< SHA-256 hardware accelerator failed */ +#define MBEDTLS_ERR_SHA256_BAD_INPUT_DATA -0x0074 /**< SHA-256 input data was malformed. */ + + +#define mbedtls_printf(...) printf(__VA_ARGS__) + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + \brief The SHA-256 context structure. + + The structure is used both for SHA-256 and for SHA-224 + checksum calculations. The choice between these two is + made in the call to mbedtls_sha256_starts_ret(). +*/ +typedef struct mbedtls_sha256_context +{ + uint32_t total[2]; /*!< The number of Bytes processed. */ + uint32_t state[8]; /*!< The intermediate digest state. */ + unsigned char buffer[64]; /*!< The data block being processed. */ + int is224; /*!< Determines which function to use: + 0: Use SHA-256, or 1: Use SHA-224. */ +} +mbedtls_sha256_context; + + +/** + \brief This function initializes a SHA-256 context. + + \param ctx The SHA-256 context to initialize. This must not be \c NULL. +*/ +void mbedtls_sha256_init( mbedtls_sha256_context* ctx ); + +/** + \brief This function clears a SHA-256 context. + + \param ctx The SHA-256 context to clear. This may be \c NULL, in which + case this function returns immediately. If it is not \c NULL, + it must point to an initialized SHA-256 context. +*/ +void mbedtls_sha256_free( mbedtls_sha256_context* ctx ); + +/** + \brief This function clones the state of a SHA-256 context. + + \param dst The destination context. This must be initialized. + \param src The context to clone. This must be initialized. +*/ +void mbedtls_sha256_clone( mbedtls_sha256_context* dst, + const mbedtls_sha256_context* src ); + +/** + \brief This function starts a SHA-224 or SHA-256 checksum + calculation. + + \param ctx The context to use. This must be initialized. + \param is224 This determines which function to use. This must be + either \c 0 for SHA-256, or \c 1 for SHA-224. + + \return \c 0 on success. + \return A negative error code on failure. +*/ +int mbedtls_sha256_starts_ret( mbedtls_sha256_context* ctx, int is224 ); + +/** + \brief This function feeds an input buffer into an ongoing + SHA-256 checksum calculation. + + \param ctx The SHA-256 context. This must be initialized + and have a hash operation started. + \param input The buffer holding the data. This must be a readable + buffer of length \p ilen Bytes. + \param ilen The length of the input data in Bytes. + + \return \c 0 on success. + \return A negative error code on failure. +*/ +int mbedtls_sha256_update_ret( mbedtls_sha256_context* ctx, + const unsigned char* input, + size_t ilen ); + +/** + \brief This function finishes the SHA-256 operation, and writes + the result to the output buffer. + + \param ctx The SHA-256 context. This must be initialized + and have a hash operation started. + \param output The SHA-224 or SHA-256 checksum result. + This must be a writable buffer of length \c 32 Bytes. + + \return \c 0 on success. + \return A negative error code on failure. +*/ +int mbedtls_sha256_finish_ret( mbedtls_sha256_context* ctx, + unsigned char output[32] ); + +/** + \brief This function processes a single data block within + the ongoing SHA-256 computation. This function is for + internal use only. + + \param ctx The SHA-256 context. This must be initialized. + \param data The buffer holding one block of data. This must + be a readable buffer of length \c 64 Bytes. + + \return \c 0 on success. + \return A negative error code on failure. +*/ +int mbedtls_internal_sha256_process( mbedtls_sha256_context* ctx, + const unsigned char data[64] ); + + + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_sha256.h */ diff --git a/src/components/ethermind/lib/meshlibs/phyos/keil/libethermind_ecdh.lib b/src/components/ethermind/lib/meshlibs/phyos/keil/libethermind_ecdh.lib new file mode 100644 index 0000000000000000000000000000000000000000..b7d1c5ac7b135e645211c1015680c0e215ac7a7f GIT binary patch literal 89784 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 literal 0 HcmV?d00001 diff --git a/src/components/ethermind/lib/meshlibs/phyos/keil/libethermind_mesh_core.lib b/src/components/ethermind/lib/meshlibs/phyos/keil/libethermind_mesh_core.lib new file mode 100644 index 0000000000000000000000000000000000000000..0a54917d4b151a96d8447d22747ed76404c827e2 GIT binary patch literal 1293720 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⩔wx~Xq^P*^^>=ag0qw{4@pN_s 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

laFgWDA*v^uxVI; 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 literal 0 HcmV?d00001 diff --git a/src/components/ethermind/mesh/export/appl/appl_main.c b/src/components/ethermind/mesh/export/appl/appl_main.c new file mode 100644 index 0000000..6a6f98b --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/appl_main.c @@ -0,0 +1,82 @@ + +/** + \file appl_main.c + + This File contains the "main" function for the Test Application + to test the Mindtree Mesh stack. +*/ + +/* + Copyright (C) 2016. Mindtree Ltd. + All rights reserved. +*/ + +/* ------------------------------- Header File Inclusion */ +#include "appl_main.h" + +void main_health_server_operations(/* IN */ UINT8 have_menu); + +/* ------------------------------- Global Variables */ + +/* ------------------------------- Functions */ +void main_register_models(void) +{ + MS_ACCESS_NODE_ID node_id; + MS_ACCESS_ELEMENT_DESC element; + MS_ACCESS_ELEMENT_HANDLE element_handle; + MS_ACCESS_MODEL_HANDLE config_server_model_handle; + MS_ACCESS_MODEL_HANDLE health_server_model_handle; + API_RESULT retval; + /* Create Node */ + retval = MS_access_create_node(&node_id); + /* Register Element */ + /** + TBD: Define GATT Namespace Descriptions from + https://www.bluetooth.com/specifications/assigned-numbers/gatt-namespace-descriptors + + Using 'main' (0x0106) as Location temporarily. + */ + element.loc = 0x0106; + retval = MS_access_register_element + ( + node_id, + &element, + &element_handle + ); + + if (API_SUCCESS == retval) + { + retval = MS_config_server_init(element_handle, &config_server_model_handle); + } + + CONSOLE_OUT("Model Registration Status: 0x%04X\n", retval); + #ifndef HSL_DONT_USE_MULTI_ELEMENTS + /* Two additional elements are registerd for HSL Server */ + retval = MS_access_register_element + ( + node_id, + &element, + &sec_element_handle + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT("Secondary Element Handle Registered @: 0x%04X\n", sec_element_handle); + } + + retval = MS_access_register_element + ( + node_id, + &element, + &ter_element_handle + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT("Tertiary Element Handle Registered @: 0x%04X\n", ter_element_handle); + } + + #endif /* HSL_DONT_USE_MULTI_ELEMENTS */ + /* Health Server */ + main_health_server_operations(MS_FALSE); +} diff --git a/src/components/ethermind/mesh/export/appl/appl_main.h b/src/components/ethermind/mesh/export/appl/appl_main.h new file mode 100644 index 0000000..3bd4c0d --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/appl_main.h @@ -0,0 +1,69 @@ + +/** + \file appl_main.h + + Header File for the Test Application to test the Mindtree + Mesh stack. +*/ + +/* + Copyright (C) 2016. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_MAIN_ +#define _H_APPL_MAIN_ + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_access_api.h" +#include "MS_config_api.h" + +/* --------------------------------------------- Global Definitions */ + +/* --------------------------------------------- Structures/Data Types */ + +/* --------------------------------------------- Macros */ + +/* Console Input/Output */ +#define CONSOLE_OUT(...) printf(__VA_ARGS__) +#define CONSOLE_IN(...) scanf(__VA_ARGS__) + +/* --------------------------------------------- Internal Functions */ +void main_register_models(void); +void appl_dump_bytes(UCHAR* buffer, UINT16 length); +void appl_model_power_cycle(void); +void appl_prov_bind(UCHAR brr, UCHAR index); +void appl_prov_get_local_public_key(void); +void appl_prov_input_auth_val (UCHAR mode, void* data, UINT16 datalen); +void appl_prov_register(void); +void appl_prov_set_auth_action +( + UCHAR mode, + UCHAR* s_oob_val, + UCHAR oob_act, + UCHAR oob_sz +); +void appl_prov_setup(UCHAR role, UCHAR brr); +API_RESULT appl_prov_update_remote_uuid +( + UCHAR* uuid, + UINT16 uuid_len, + UINT16 oob_info, + UCHAR* uri +); +void appl_prov_set_uuid (UCHAR* uuid); +void appl_prov_update_uuid (UCHAR octet); + +void appl_proxy_adv +( + UCHAR identification_type, + MS_SUBNET_HANDLE subnet_handle +); +void appl_proxy_register(void); +void appl_prov_set_dev_public_key(void); +void appl_prov_bind_device(UCHAR brr); +void appl_proxy_start_net_id_adv(MS_SUBNET_HANDLE subnet_handle); +API_RESULT appl_is_configured (void); + +#endif /* _H_APPL_MAIN_ */ + diff --git a/src/components/ethermind/mesh/export/appl/appl_prov.c b/src/components/ethermind/mesh/export/appl/appl_prov.c new file mode 100644 index 0000000..d6bb0e2 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/appl_prov.c @@ -0,0 +1,1345 @@ + +/** + \file appl_prov.c + + +*/ + +/* + Copyright (C) 2013. Mindtree Limited. + All rights reserved. +*/ + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_prov_api.h" +#include "prov_pl.h" +#include "appl_main.h" +#include "blebrr.h" +#include "cry.h" + +static inline uint32 clock_time_rtc(void) +{ + return (*(volatile unsigned int*)0x4000f028) & 0xffffff; +} + +/** + Compilation switch to use selected Capabilities and Keys for ease of + PTS testing. + This Flag needs to be disabled by default to explore full range of + provisioning capabilities and have specific peer provided OOB Pbulic keys etc. +*/ +/* #define MESH_PTS_TEST */ + +/* --------------------------------------------- Global Definitions */ +/** Size of beacon list to be maintained by Provisioner */ +#define APPL_UNPROV_BEACON_LIST_SIZE 8 + +/** Beacon setup timeout in seconds */ +#define APPL_PROV_SETUP_TIMEOUT_SECS 30 + +/** Attention timeout for device in seconds */ +#define APPL_PROV_DEVICE_ATTENTION_TIMEOUT 30 + +/** Output OOB Actions supported */ +#ifndef MESH_PTS_TEST +#define APPL_PROV_OUTPUT_OOB_ACTIONS \ + (PROV_MASK_OOOB_ACTION_BLINK | PROV_MASK_OOOB_ACTION_BEEP | \ + PROV_MASK_OOOB_ACTION_VIBRATE | PROV_MASK_OOOB_ACTION_NUMERIC | \ + PROV_MASK_OOOB_ACTION_ALPHANUMERIC) + +/** Output OOB Maximum size supported */ +#define APPL_PROV_OUTPUT_OOB_SIZE 0x08 + +/** Input OOB Actions supported */ +#define APPL_PROV_INPUT_OOB_ACTIONS \ + (PROV_MASK_IOOB_ACTION_PUSH | PROV_MASK_IOOB_ACTION_TWIST | \ + PROV_MASK_IOOB_ACTION_NUMERIC | PROV_MASK_IOOB_ACTION_ALPHANUMERIC) + +/** Input OOB Maximum size supported */ +#define APPL_PROV_INPUT_OOB_SIZE 0x08 +#else /* MESH_PTS_TEST */ +#define APPL_PROV_OUTPUT_OOB_ACTIONS \ + PROV_MASK_OOOB_ACTION_NUMERIC + +/** Output OOB Maximum size supported */ +#define APPL_PROV_OUTPUT_OOB_SIZE 0x04 + +/** Input OOB Actions supported */ +#define APPL_PROV_INPUT_OOB_ACTIONS \ + PROV_MASK_IOOB_ACTION_NUMERIC + +/** Input OOB Maximum size supported */ +#define APPL_PROV_INPUT_OOB_SIZE 0x04 +#endif /* MESH_PTS_TEST */ + +/** Authentication values for OOB Display - To be made random */ +#define APPL_DISPLAY_AUTH_DIGIT 3 +#define APPL_DISPLAY_AUTH_NUMERIC 35007 +#define APPL_DISPLAY_AUTH_STRING "f00l" + +/** Base address as a provisioner */ +#define APPL_UADDR_BASE 0x0001 +#define APPL_DEVICE_PRIMARY_ELEMENT_UCAST_ADDR 0x0100 + +/* --------------------------------------------- External Global Variables */ + +/* --------------------------------------------- Exported Global Variables */ +void appl_prov_setup_provisioner(void); +void appl_prov_start_provisioning(void); +void appl_prov_register(void); + +void appl_prov_input_auth_val (UCHAR mode, void* data, UINT16 datalen); +void appl_prov_set_dev_public_key(void); +void appl_prov_get_local_public_key(void); +void appl_prov_set_debug_keys(void); +void appl_prov_set_auth_action +( + UCHAR mode, + UCHAR* s_oob_val, + UCHAR oob_act, + UCHAR oob_sz +); + +void main_prov_operations (void); +void appl_prov_setup_device(void); +API_RESULT appl_prov_callback +( + PROV_HANDLE* phandle, + UCHAR event_type, + API_RESULT event_result, + void* event_data, + UINT16 event_datalen +); + +/* --------------------------------------------- Static Global Variables */ +/** Registration state of provisioning */ +DECL_STATIC UCHAR appl_prov_ready; + +/** Current role of application - Provisioner/Device */ +DECL_STATIC UCHAR appl_prov_role; + +DECL_STATIC UCHAR appl_prov_device_num_elements; + +/** Provisioning capabilities of local device */ +#ifdef MESH_PTS_TEST +DECL_STATIC PROV_CAPABILITIES_S appl_prov_capab = +{ + /** Number of Elements */ + 0x01, + + /** Supported algorithms */ + PROV_MASK_ALGO_EC_FIPS_P256, + + /** Public key type */ + PROV_MASK_PUBKEY_OOBINFO, + + /** Static OOB type */ + PROV_MASK_STATIC_OOBINFO, + + /** Output OOB information */ + { APPL_PROV_OUTPUT_OOB_ACTIONS, APPL_PROV_OUTPUT_OOB_SIZE }, + + /** Input OOB information */ + { APPL_PROV_INPUT_OOB_ACTIONS, APPL_PROV_INPUT_OOB_SIZE }, +}; +#else /* MESH_PTS_TEST */ +/** + Choose this if application needs to use bare minimum capabilities + to get provisioned against popular mobile phone Mesh Applications. +*/ +DECL_STATIC PROV_CAPABILITIES_S appl_prov_capab = +{ + /** Number of Elements */ + 0x01, + + /** Supported algorithms */ + PROV_MASK_ALGO_EC_FIPS_P256, + + /** Public key type */ + 0x00, + + /** Static OOB type */ + 0x00, + + /** Output OOB information */ + { 0x00, 0x00 }, + + /** Input OOB information */ + { 0x00, 0x00 }, +}; +#endif /* MESH_PTS_TEST */ + +/** Default Provisioning method to start */ +DECL_STATIC PROV_METHOD_S appl_prov_method = +{ + /** Algorithm */ + PROV_ALGO_EC_FIPS_P256, + + /** Public Key */ + PROV_PUBKEY_NO_OOB, + + /** Authentication Method */ + PROV_AUTH_OOB_NONE, + + /** OOB Information */ + {0x0000, 0x00} +}; + +/** Unprovisioned device identifier */ +DECL_STATIC PROV_DEVICE_S appl_lprov_device = +{ + /** UUID */ + /* {0x45, 0x74, 0x68, 0x65, 0x72, 0x4d, 0x69, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x68, 0x44, 0x65, 0x76}, */ + /* {0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, */ + {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}, + + /** OOB Flag */ + 0x00, + + /** + Encoded URI Information + For example, to give a web address, "https://www.abc.com" + the URI encoded data would be - + 0x17 0x2F 0x2F 0x77 0x77 0x77 0x2E 0x61 0x62 0x63 0x2E 0x63 0x6F 0x6D + where 0x17 is the URI encoding for https: + */ + NULL +}; + +/** Data exchanged during Provisiong procedure */ +DECL_STATIC PROV_DATA_S appl_prov_data = +{ + /** NetKey */ + {0x45, 0x74, 0x68, 0x65, 0x72, 0x4d, 0x69, 0x6e, 0x64, 0x4e, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x00}, + + /** Index of the NetKey */ + 0x0000, + + /** Flags bitmask */ + 0x00, + + /** Current value of the IV index */ + 0x00000001, + + /** Unicast address of the primary element */ + APPL_DEVICE_PRIMARY_ELEMENT_UCAST_ADDR +}; + +/** Unprovisioned device beacons list */ +DECL_STATIC PROV_DEVICE_S appl_rprov_device[APPL_UNPROV_BEACON_LIST_SIZE]; + +/** Unprovisioned device beacons count */ +DECL_STATIC CHAR appl_num_devices; + +/** Provisioning Handle */ +DECL_STATIC PROV_HANDLE appl_prov_handle; + +DECL_STATIC const char main_prov_options[] = "\n\ +========= Provisioning Menu =============== \n\ + 0. Exit. \n\ + 1. Refresh \n\ + \n\ + 10. Register Provisioning. \n\ + \n\ + 11. Setup Provisioner. \n\ + 12. Setup Device. \n\ + \n\ + 15. Bind Device. \n\ + 16. Enter OOB Authval. \n\ + \n\ + 30. Set OOB Public Key for Device. \n\ + 31. Set OOB Authentication. \n\ + 32. Get Current Public Key. \n\ + 33. Set ECDH Debug Key Pairs. \n\ + \n\ + 40. Abort Procedure. \n\ + \n\ + 100. Provide Provisioning Data to Network and Transport Layer (for testing)\n\ + \n\ +Your Option ? \0"; + +/* --------------------------------------------- Functions */ +void appl_prov_set_uuid (UCHAR* uuid) +{ + EM_mem_copy (appl_lprov_device.uuid, uuid, MS_DEVICE_UUID_SIZE); +} + +void appl_prov_update_uuid(UCHAR octet) +{ + appl_lprov_device.uuid[0] = octet; +} + +void appl_prov_bind_device(UCHAR brr) +{ + API_RESULT retval; + PROV_DEVICE_S* appl_tmp_dev_to_bind; + + if (PROV_ROLE_PROVISIONER == appl_prov_role) + { + appl_tmp_dev_to_bind = &appl_rprov_device[0x00]; + } + else + { + appl_tmp_dev_to_bind = &appl_lprov_device; + } + + printf("Binding device for provisioning...\n"); + retval = MS_prov_bind + ( + PROV_BRR_GATT, + appl_tmp_dev_to_bind, + APPL_PROV_DEVICE_ATTENTION_TIMEOUT, + &appl_prov_handle + ); + printf("Retval - 0x%04X\n", retval); +} + +API_RESULT appl_prov_callback +( + PROV_HANDLE* phandle, + UCHAR event_type, + API_RESULT event_result, + void* event_data, + UINT16 event_datalen +) +{ + PROV_DEVICE_S* rdev; + PROV_CAPABILITIES_S* rcap; + PROV_DATA_S* rdata; + PROV_OOB_TYPE_S* oob_info; + API_RESULT retval; + UCHAR i; + UCHAR authstr[PROV_AUTHVAL_SIZE_PL << 1]; + UINT32 authnum; + UCHAR authtype; + UCHAR* pauth; + UINT16 authsize; + UCHAR pdata[(MS_DEVICE_UUID_SIZE * 2) + 1]; + UCHAR* t_data; + static UCHAR prov_flag; + static UINT16 prov_keyid; + + /* printf("\n"); */ + + switch (event_type) + { + case PROV_EVT_UNPROVISIONED_BEACON: + if (APPL_UNPROV_BEACON_LIST_SIZE == appl_num_devices) + { + /* printf ("Device List Full. Dropping Beacon...\n"); */ + break; + } + + /* Reference the beacon pointer */ + rdev = (PROV_DEVICE_S*)event_data; + retval = API_SUCCESS; + + for (i = 0; i < APPL_UNPROV_BEACON_LIST_SIZE; i++) + { + if (0 == EM_mem_cmp(rdev->uuid, appl_rprov_device[i].uuid, 16)) + { + /* Mark for filtering */ + retval = API_FAILURE; + /** + Break when there is an exisiting instance for incoming + UUID of the unprovisioned device. + */ + break; + } + } + + if (API_SUCCESS != retval) + { + retval = API_SUCCESS; + break; + } + + printf ("Recvd PROV_EVT_UNPROVISIONED_BEACON\n"); + printf ("Status - 0x%04X\n", event_result); + printf("\nID: %d", appl_num_devices); + printf("\nUUID : ["); + #if 0 + + for (i = 0; i < MS_DEVICE_UUID_SIZE; i++) + { + printf("%02X", rdev->uuid[i]); + } + + #else /* 0 */ + EM_mem_set(pdata, 0x0, sizeof(pdata)); + t_data = pdata; + + for (i = 0; i < (MS_DEVICE_UUID_SIZE); i++) + { + sprintf((char*)t_data,"%02X", rdev->uuid[i]); + t_data += 2; + } + + printf(" %s ", pdata); + #endif /* 0 */ + printf("]"); + printf("\nOOB : 0x%04X", rdev->oob); + printf("\nURI : 0x%08X", rdev->uri); + printf("\n\n"); + /* Copy the beacon to the list */ + EM_mem_copy (&appl_rprov_device[appl_num_devices], rdev, sizeof (PROV_DEVICE_S)); + appl_num_devices++; + break; + + case PROV_EVT_PROVISIONING_SETUP: + printf ("Recvd PROV_EVT_PROVISIONING_SETUP\n"); + printf ("Status - 0x%04X\n", event_result); + + /* Decipher the data based on the role */ + if (PROV_ROLE_PROVISIONER == appl_prov_role) + { + /* Display the capabilities */ + rcap = (PROV_CAPABILITIES_S*)event_data; + printf ("Remote Device Capabilities:\n"); + printf ("\tNum Elements - %d\n", rcap->num_elements); + printf ("\tSupp Algorithms - 0x%04X\n", rcap->supp_algorithms); + printf ("\tSupp PublicKey - 0x%02X\n", rcap->supp_pubkey); + printf ("\tSupp Static OOB - 0x%02X\n", rcap->supp_soob); + printf ("\tOutput OOB Size - %d\n", rcap->ooob.size); + printf ("\tOutput OOB Action- 0x%04X\n", rcap->ooob.action); + printf ("\tInput OOB Size - %d\n", rcap->ioob.size); + printf ("\tInput OOB Action - 0x%04X\n", rcap->ioob.action); + /* Store the current number of elements */ + appl_prov_device_num_elements = rcap->num_elements; + /* Start with default method */ + printf ("Start Provisioning with default method...\n"); + retval = MS_prov_start (phandle, &appl_prov_method); + printf ("Retval - 0x%04X\n", retval); + } + else + { + /* Display the attention timeout */ + printf ("Attention Timeout - %d\n", *((UCHAR*)event_data)); + } + + break; + + case PROV_EVT_OOB_DISPLAY: + printf ("Recvd PROV_EVT_OOB_DISPLAY\n"); + printf ("Status - 0x%04X\n", event_result); + /* Reference the Authenticatio Type information */ + oob_info = (PROV_OOB_TYPE_S*)event_data; + printf("Authenticaion Action - 0x%02X\n", oob_info->action); + printf("Authenticaion Size - 0x%02X\n", oob_info->size); + + /* If role is Device, the action is of Output OOB, else Input OOB */ + if (PROV_ROLE_DEVICE == appl_prov_role) + { + if (PROV_OOOB_ACTION_ALPHANUMERIC == oob_info->action) + { + authtype = 1; + } + else if (PROV_OOOB_ACTION_NUMERIC == oob_info->action) + { + authtype = 2; + } + else + { + authtype = 0; + } + } + else + { + if (PROV_IOOB_ACTION_ALPHANUMERIC == oob_info->action) + { + authtype = 1; + } + else if (PROV_IOOB_ACTION_NUMERIC == oob_info->action) + { + authtype = 2; + } + else + { + authtype = 0; + } + } + + if (1 == authtype) + { + EM_str_copy (authstr, APPL_DISPLAY_AUTH_STRING); + printf("\n\n>>> AuthVal - %s <<<\n\n", authstr); + pauth = authstr; + authsize = EM_str_len(authstr); + } + else if (2 == authtype) + { + authnum = (UINT32)APPL_DISPLAY_AUTH_NUMERIC; + printf("\n\n>>> AuthVal - %d <<<\n\n", authnum); + pauth = (UCHAR*)&authnum; + authsize = sizeof(UINT32); + } + else + { + authnum = (UINT32)APPL_DISPLAY_AUTH_DIGIT; + printf("\n\n>>> AuthVal - %d <<<\n\n", authnum); + pauth = (UCHAR*)&authnum; + authsize = sizeof(UINT32); + } + + /* Call to input the oob */ + printf("Setting the Authval...\n"); + retval = MS_prov_set_authval(&appl_prov_handle, pauth, authsize); + printf("Retval - 0x%04X\n", retval); + break; + + case PROV_EVT_OOB_ENTRY: + printf ("Recvd PROV_EVT_OOB_ENTRY\n"); + printf ("Status - 0x%04X\n", event_result); + /* Reference the Authenticatio Type information */ + oob_info = (PROV_OOB_TYPE_S*)event_data; + printf("Authenticaion Action - 0x%02X\n", oob_info->action); + printf("Authenticaion Size - 0x%02X\n", oob_info->size); + break; + + case PROV_EVT_DEVINPUT_COMPLETE: + printf ("Recvd PROV_EVT_DEVINPUT_COMPLETE\n"); + printf ("Status - 0x%04X\n", event_result); + break; + + case PROV_EVT_PROVDATA_INFO_REQ: + printf ("Recvd PROV_EVT_PROVDATA_INFO_REQ\n"); + printf ("Status - 0x%04X\n", event_result); + /* Send Provisioning Data */ + printf ("Send Provisioning Data...\n"); + retval = MS_prov_data (phandle, &appl_prov_data); + printf ("Retval - 0x%04X\n", retval); + printf ("NetKey : "); + appl_dump_bytes(appl_prov_data.netkey, PROV_KEY_NETKEY_SIZE); + printf ("Key ID : 0x%04X\n", appl_prov_data.keyid); + printf ("Flags : 0x%02X\n", appl_prov_data.flags); + printf ("IVIndex : 0x%08X\n", appl_prov_data.ivindex); + printf ("UAddr : 0x%04X\n", appl_prov_data.uaddr); + break; + + case PROV_EVT_PROVDATA_INFO: + printf ("Recvd PROV_EVT_PROVDATA_INFO\n"); + printf ("Status - 0x%04X\n", event_result); + /* Reference the Provisioning Data */ + rdata = (PROV_DATA_S*)event_data; + printf ("NetKey : "); + appl_dump_bytes(rdata->netkey, PROV_KEY_NETKEY_SIZE); + printf ("Key ID : 0x%04X\n", rdata->keyid); + printf ("Flags : 0x%02X\n", rdata->flags); + printf ("IVIndex : 0x%08X\n", rdata->ivindex); + printf ("UAddr : 0x%04X\n", rdata->uaddr); + // ========HZF + UINT32 T1, T2; + blebrr_scan_pl(FALSE); + T1 = clock_time_rtc();//read_current_fine_time(); + /* Provide Provisioning Data to Access Layer */ + MS_access_cm_set_prov_data + ( + rdata + ); + T2 = clock_time_rtc(); + printf("consume time of function MS_access_cm_set_prov_data-1: %d RTC tick\r\n", (T2 - T1)); + /* Cache the Flags and Key Index to the Globals */ + prov_flag = rdata->flags; + prov_keyid = rdata->keyid; + break; + + case PROV_EVT_PROVISIONING_COMPLETE: + printf ("Recvd PROV_EVT_PROVISIONING_COMPLETE\n"); + printf ("Status - 0x%04X\n", event_result); + printf ("appl_prov_role - 0x%02X\n", appl_prov_role); + + if (API_SUCCESS == event_result) + { + if (PROV_ROLE_PROVISIONER == appl_prov_role) + { + if (APPL_DEVICE_PRIMARY_ELEMENT_UCAST_ADDR == appl_prov_data.uaddr) + { + /* Holding a temporary structure for local prov data */ + PROV_DATA_S temp_ps_prov_data; + EM_mem_copy + ( + &temp_ps_prov_data, + &appl_prov_data, + sizeof(appl_prov_data) + ); + /** + Assigning the Local Unicast Address of the Provisioner + to the Access Layer along with other related keys. + */ + temp_ps_prov_data.uaddr = 0x0001; +// ========HZF + UINT32 T1, T2; + blebrr_scan_pl(FALSE); + T1 = clock_time_rtc();//read_current_fine_time(); + /* Provide Provisioning Data to Access Layer */ + MS_access_cm_set_prov_data + ( + &temp_ps_prov_data + ); + T2 = clock_time_rtc(); + printf("consume time of function MS_access_cm_set_prov_data-2: %d RTC tick\r\n", (T2 - T1)); + /** + TODO: + Increment the appl_prov_data.uaddr for the next + set of device which is getting provisioned based on + the address and number of elements present in the last + provisioned device. + */ + } + + appl_prov_data.uaddr += appl_prov_device_num_elements; + } + else + { + /* Already Set while handling PROV_EVT_PROVDATA_INFO */ + + /** + TODO/NOTE: + The sending of Secure Network Beacon from Provisioning + Complete might not be feasible over GATT Bearer. + This is because the Provisioner might disconnect the + link once Provisioning is completed! + To then send an "SNB", one can use the CLI commands or + make use of the Callback event "BLEBRR_GATT_IFACE_DOWN" + received through * the callback registered using the API + \ref blebrr_register_gatt_iface_event_pl(...) + */ + if (0x00 != prov_flag) + { + MS_SUBNET_HANDLE subnet; + /* Get associated Subnet Handle */ + retval = MS_access_cm_find_subnet + ( + prov_keyid, + &subnet + ); + + if (API_SUCCESS == retval) + { + /* Send the Secure Network Beacon */ + MS_net_broadcast_secure_beacon(subnet); + } + } + } + } + + #ifdef MESH_PTS_TEST + + /** + This piece is added for Unprovisioned beacon Auto Start. + This was needed for few invalid behaviour PTS testcases. + */ + if (API_SUCCESS != event_result) + { + if (PROV_ROLE_DEVICE == appl_prov_role) + { + printf ("Setting up Device...\n"); + retval = MS_prov_setup + ( + PROV_BRR_ADV, + PROV_ROLE_DEVICE, + &appl_lprov_device, + APPL_PROV_SETUP_TIMEOUT_SECS, + APPL_PROV_SETUP_TIMEOUT_SECS + ); + printf ("Retval - 0x%04X\n", retval); + appl_prov_role = PROV_ROLE_DEVICE; + retval = MS_prov_bind(PROV_BRR_ADV, &appl_rprov_device[0x00], APPL_PROV_DEVICE_ATTENTION_TIMEOUT, &appl_prov_handle); + printf("Retval - 0x%04X\n", retval); + } + } + + #endif /* MESH_PTS_TEST */ + break; + + default: + printf ("Unknown Event - 0x%02X\n", event_type); + } + + return API_SUCCESS; +} + +void main_prov_operations (void) +{ + UCHAR pubkey[PROV_PUBKEY_SIZE_PL]; + UCHAR auth[PROV_AUTHVAL_SIZE_PL]; + API_RESULT retval; + int choice; + UCHAR brr, i; + UCHAR authstr[PROV_AUTHVAL_SIZE_PL << 1]; + UINT32 authnum; + UCHAR* pauth; + UINT16 authsize; + + while (1) + { + printf("%s", main_prov_options); + scanf("%d", &choice); + + if (choice < 0) + { + printf("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 10: + appl_prov_register(); + break; + + case 11: + appl_prov_setup_provisioner(); + break; + + case 12: + printf ("Select the Bearer (0: PB-ADV, 1: PB-GATT): "); + fflush (stdout); + scanf ("%d", &choice); + /* Set the Bearer */ + brr = (0 != choice)? PROV_BRR_GATT: PROV_BRR_ADV; + + if (PROV_BRR_GATT == brr) + { + blebrr_gatt_mode_set(BLEBRR_GATT_PROV_MODE); + } + + printf ("Setting up Device...\n"); + retval = MS_prov_setup + ( + brr, + PROV_ROLE_DEVICE, + &appl_lprov_device, + APPL_PROV_SETUP_TIMEOUT_SECS, + APPL_PROV_SETUP_TIMEOUT_SECS + ); + printf ("Retval - 0x%04X\n", retval); + appl_prov_role = PROV_ROLE_DEVICE; + break; + + case 15: + appl_prov_start_provisioning(); + break; + + case 16: + printf("Select OOB type (0 - Number, 1- String): "); + scanf("%d", &choice); + + if (0 != choice) + { + printf("Enter the Authentication String: "); + scanf("%s", authstr); + pauth = authstr; + authsize = EM_str_len(authstr); + } + else + { + printf("Enter the Authentication Value: "); + scanf("%d", &choice); + authnum = (UINT32)choice; + pauth = (UCHAR*)&authnum; + authsize = sizeof (UINT32); + } + + /* Call to input the oob */ + printf("Input the Authval...\n"); + retval = MS_prov_input_authval(&appl_prov_handle, pauth, authsize); + printf("Retval - 0x%04X\n", retval); + break; + + case 30: + #ifndef MESH_PTS_TEST + printf("Device supports OOB Public Key? (1/0): "); + scanf("%d", &choice); + /* Update the Public Key OOB in method */ + appl_prov_method.pubkey = (choice)? PROV_PUBKEY_OOB: PROV_PUBKEY_OOB; + + if (0 != choice) + { + /* Set the OOB Public Key */ + printf("Enter OOB Public Key of device (64 octets):\n"); + + for (i = 0; i < sizeof(pubkey); i++) + { + scanf("%x", &choice); + pubkey[i] = (UCHAR)choice; + } + + prov_set_device_oob_pubkey_pl(pubkey, sizeof(pubkey)); + } + + #else /* MESH_PTS_TEST */ + appl_prov_set_dev_public_key(); + #endif /* MESH_PTS_TEST */ + break; + + case 31: + printf("Select OOB Authentication type?\n 0 - None\n 1 - Static\n 2 - Output\n 3 - Input\n: "); + scanf("%d", &choice); + /* Update the Public Key OOB in method */ + appl_prov_method.auth = choice; + + if (PROV_AUTH_OOB_STATIC == choice) + { + /* Set the Static OOB Auth Key */ + printf("Enter OOB Authrntication value (16 octets):\n"); + + for (i = 0; i < sizeof(auth); i++) + { + #ifndef MESH_PTS_TEST + scanf("%x", &choice); + auth[i] = (UCHAR)choice; + #else /* MESH_PTS_TEST */ + /** + Set the STATIC OOB value in PTS PIXIT table: + OOB: 0x11111111111111111111111111111111[16 Octets 0f 0x11] + */ + auth[i] = 0x11; + #endif /* MESH_PTS_TEST */ + } + + prov_set_static_oob_auth_pl(auth, sizeof(auth)); + } + else if (PROV_AUTH_OOB_OUTPUT == choice) + { + /* Enter the OOB action to be used */ + printf("Enter OOB Action?\n 0 - Blink\n 1 - Beep\n 2 - Vibrate\n 3 - Numeric\n 4 - Alphanumeric\n: "); + scanf("%d", &choice); + appl_prov_method.oob.action = (UCHAR)choice; + /* Enter the OOB size to be used */ + printf("Enter OOB Size (1 - 8): "); + scanf("%d", &choice); + appl_prov_method.oob.size = (UCHAR)choice; + } + else if (PROV_AUTH_OOB_INPUT == choice) + { + /* Enter the OOB action to be used */ + printf("Enter OOB Action?\n 0 - Push\n 1 - Twist\n 2 - Numeric\n 3 - Alphanumeric\n: "); + scanf("%d", &choice); + appl_prov_method.oob.action = (UCHAR)choice; + /* Enter the OOB size to be used */ + printf("Enter OOB Size (1 - 8): "); + scanf("%d", &choice); + appl_prov_method.oob.size = (UCHAR)choice; + } + + break; + + case 32: + /* Print the Local ECDH Public Key */ + appl_prov_get_local_public_key(); + break; + + case 33: + #ifdef MESH_PTS_TEST + /* PTS defines the below Public/PrivateKey as its Default in PIXIT */ + appl_prov_set_debug_keys(); + #endif /* MESH_PTS_TEST */ + break; + + case 40: + printf("Enter the reason to Abort (in Hex): "); + scanf("%x", &choice); + printf("Aborting...\n"); + retval = MS_prov_abort(&appl_prov_handle, (UCHAR)choice); + printf("Retval - 0x%04X\n", retval); + break; + + case 100: + break; + + default: + break; + } + } +} + +API_RESULT appl_prov_update_remote_uuid +( + UCHAR* uuid, + UINT16 uuid_len, + UINT16 oob_info, + UCHAR* uri +) +{ + API_RESULT retval; + UINT32 i; + retval = API_SUCCESS; + + for (i = 0; i < APPL_UNPROV_BEACON_LIST_SIZE; i++) + { + if (0 == EM_mem_cmp(uuid, appl_rprov_device[i].uuid, 16)) + { + /* Mark for filtering */ + retval = API_FAILURE; + /** + Break when there is an exisiting instance for incoming + UUID of the unprovisioned device. + */ + break; + } + } + + if (API_SUCCESS != retval) + { + return retval; + } + + printf ("Recvd PROV_EVT_UNPROVISIONED_BEACON"); + printf ("Status - 0x%04X", API_SUCCESS); + /* printf("\nID: %d", appl_num_devices); */ + printf("UUID : [%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X]", + uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], + uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11], + uuid[2], uuid[13], uuid[14], uuid[15]); + printf("OOB : 0x%04X", oob_info); + + if (NULL != uri) + { + printf("\nURI : 0x%08X", uri); + } + + /* Copy the beacon to the list */ + EM_mem_copy (&appl_rprov_device[appl_num_devices].uuid, uuid, MS_DEVICE_UUID_SIZE); + appl_rprov_device[appl_num_devices].oob = oob_info; + /* appl_rprov_device[appl_num_devices].uri = uri; */ + /* Increment the list */ + appl_num_devices++; + return retval; +} + + + +void appl_prov_register(void) +{ + API_RESULT retval; + MS_PROV_DEV_ENTRY prov_dev_list[MS_MAX_DEV_KEYS]; + UINT16 num_entries; + UINT16 pointer_entries; + + if (MS_TRUE == appl_prov_ready) + { + return; + } + + appl_prov_ready = MS_TRUE; + /* Fetch the number of elements in local node */ + MS_access_cm_get_element_count(&appl_prov_capab.num_elements); + num_entries = MS_MAX_DEV_KEYS; + /* Update the next device address if provisioned devices are present in database */ + retval = MS_access_cm_get_prov_devices_list + ( + &prov_dev_list[0], + &num_entries, + &pointer_entries + ); + + if ((API_SUCCESS == retval) && + (0 != num_entries)) + { + appl_prov_data.uaddr = prov_dev_list[num_entries - 1].uaddr + + prov_dev_list[num_entries - 1].num_elements; + printf("Updating Provisioning Start Addr to 0x%04X\n", appl_prov_data.uaddr); + } + + printf("Registering with Provisioning layer...\n"); + retval = MS_prov_register(&appl_prov_capab, appl_prov_callback); + printf("Retval - 0x%04X\n", retval); +} + +void appl_prov_setup(UCHAR role, UCHAR brr) +{ + API_RESULT retval; + + if (PROV_BRR_GATT == brr) + { + blebrr_gatt_mode_set(BLEBRR_GATT_PROV_MODE); + } + + if (PROV_ROLE_PROVISIONER != role) + { + printf("Setting up Device for Provisioning ...\n"); + retval = MS_prov_setup + ( + brr, + role, + &appl_lprov_device, + APPL_PROV_SETUP_TIMEOUT_SECS, + APPL_PROV_SETUP_TIMEOUT_SECS + ); + appl_prov_role = PROV_ROLE_DEVICE; + } + else + { + printf("Setting up Provisioner for Provisioning ...\n"); + retval = MS_prov_setup + ( + brr, + role, + NULL, + APPL_PROV_SETUP_TIMEOUT_SECS, + APPL_PROV_SETUP_TIMEOUT_SECS + ); + appl_prov_role = PROV_ROLE_PROVISIONER; + appl_num_devices = 0; + /* Clear the list of Unprovisioned Device Here */ + EM_mem_set(appl_rprov_device, 0x0, sizeof(appl_rprov_device)); + /* Enable Scan */ + blebrr_scan_enable(); + } + + printf("Retval - 0x%04X\n", retval); +} + +void appl_prov_bind(UCHAR brr, UCHAR index) +{ + API_RESULT retval; + /* Call to bind with the selected device */ + printf("Binding with the selected device...\n"); + + if (PROV_ROLE_PROVISIONER == appl_prov_role) + { + retval = MS_prov_bind(brr, &appl_rprov_device[index], APPL_PROV_DEVICE_ATTENTION_TIMEOUT, &appl_prov_handle); + } + else + { + retval = MS_prov_bind(brr, &appl_lprov_device, APPL_PROV_DEVICE_ATTENTION_TIMEOUT, &appl_prov_handle); + } + + printf("Retval - 0x%04X\n", retval); +} + +void appl_prov_setup_provisioner(void) +{ +// API_RESULT retval; + UCHAR brr; + int choice; + printf ("Select the Bearer (0: PB-ADV, 1: PB-GATT): "); + fflush (stdout); + scanf ("%d", &choice); + /* Set the Bearer */ + brr = (0 != choice)? PROV_BRR_GATT: PROV_BRR_ADV; + appl_prov_setup(PROV_ROLE_PROVISIONER, brr); +} + +void appl_prov_setup_device(void) +{ +// API_RESULT retval; + UCHAR brr; + int choice; + printf("Select the Bearer (0: PB-ADV, 1: PB-GATT): "); + fflush(stdout); + scanf("%d", &choice); + /* Set the Bearer */ + brr = (0 != choice) ? PROV_BRR_GATT : PROV_BRR_ADV; + appl_prov_setup(PROV_ROLE_DEVICE, brr); + + if (PROV_BRR_ADV == brr) + { + appl_prov_bind(brr, 0); + } +} + +static void appl_list_beacons(void) +{ + UINT8 i, j; + + if (0 == appl_num_devices) + { + printf("No Unprovisioned beacon in list...\n"); + return; + } + + for (i = 0; i < appl_num_devices; i++) + { + printf("%d. [", i); + + for (j = 0; j < MS_DEVICE_UUID_SIZE; j++) + { + printf("%02X", appl_rprov_device[i].uuid[j]); + } + + printf("]\n"); + } +} + +void appl_prov_start_provisioning(void) +{ +// API_RESULT retval; + UCHAR brr, i; + int choice; + + if (PROV_ROLE_PROVISIONER == appl_prov_role) + { + if (0 == appl_num_devices) + { + printf("No Unprovisioned beacon in list...\n"); + return; + } + + printf("Select the device to provision:\n"); + appl_list_beacons(); + scanf("%d", &choice); + i = choice; + } + else + { + i = 0; + } + + printf("Select the Bearer (0: PB-ADV, 1: PB-GATT): "); + fflush(stdout); + scanf("%d", &choice); + /* Set the Bearer */ + brr = (0 != choice) ? PROV_BRR_GATT : PROV_BRR_ADV; + appl_prov_bind(brr, i); +} + +void appl_prov_input_auth_val (UCHAR mode, void* data, UINT16 datalen) +{ + UCHAR* pauth; + UINT16 authsize; + UINT32 authnum; + API_RESULT retval; + + /** + MODE = 0 -> Numeric + MODE = 1 -> Alphanumeric + */ + if (0 != mode) + { + pauth = (UCHAR*) data; + authsize = datalen; + } + else + { + authnum = *((UINT32*)data); + pauth = (UCHAR*)&authnum; + authsize = sizeof (UINT32); + } + + /* Call to input the oob */ + printf("Input the Authval...\n"); + retval = MS_prov_input_authval(&appl_prov_handle, pauth, authsize); + printf("Retval - 0x%04X\n", retval); +} + +void appl_prov_set_dev_public_key(void) +{ + /* PTS defines the below Publickey as its Default in PIXIT */ + UCHAR appl_t_pub_key[PROV_PUBKEY_SIZE_PL] = + { + 0xF4, 0x65, 0xE4, 0x3F, 0xF2, 0x3D, 0x3F, 0x1B, + 0x9D, 0xC7, 0xDF, 0xC0, 0x4D, 0xA8, 0x75, 0x81, + 0x84, 0xDB, 0xC9, 0x66, 0x20, 0x47, 0x96, 0xEC, + 0xCF, 0x0D, 0x6C, 0xF5, 0xE1, 0x65, 0x00, 0xCC, + 0x02, 0x01, 0xD0, 0x48, 0xBC, 0xBB, 0xD8, 0x99, + 0xEE, 0xEF, 0xC4, 0x24, 0x16, 0x4E, 0x33, 0xC2, + 0x01, 0xC2, 0xB0, 0x10, 0xCA, 0x6B, 0x4D, 0x43, + 0xA8, 0xA1, 0x55, 0xCA, 0xD8, 0xEC, 0xB2, 0x79 + }; + /* Update the Public Key OOB in method */ + appl_prov_method.pubkey = PROV_PUBKEY_OOB; + prov_set_device_oob_pubkey_pl(appl_t_pub_key, sizeof(appl_t_pub_key)); + printf ("Setting Device Public Key : \n"); + appl_dump_bytes(appl_t_pub_key, sizeof(appl_t_pub_key)); +} + +void appl_prov_get_local_public_key(void) +{ + UCHAR appl_t_pub_key[PROV_PUBKEY_SIZE_PL]; + UCHAR pdata[(PROV_PUBKEY_SIZE_PL * 2) + 1]; + UCHAR* t_data; +// INT32 ret; + UINT32 i; + EM_mem_set(appl_t_pub_key, 0x0, PROV_PUBKEY_SIZE_PL); + EM_mem_set(pdata, 0x0, sizeof(pdata)); + t_data = pdata; + MS_prov_get_local_public_key(appl_t_pub_key); + printf("\n Local ECDH P256 Public Key: [Dump]\n"); + appl_dump_bytes(appl_t_pub_key, PROV_PUBKEY_SIZE_PL); + printf("\n Local ECDH P256 Public Key: [MSB-LSB]:\n"); + #if 0 + + for (i = 0; i < PROV_PUBKEY_SIZE_PL; i++) + { + printf("%02X", appl_t_pub_key[i]); + } + + printf("\n"); + #else + + for (i = 0; i < (PROV_PUBKEY_SIZE_PL); i++) + { + sprintf((char*)t_data,"%02X", appl_t_pub_key[i]); + t_data += 2; + } + + printf("%s\n", pdata); + #endif +} + +void appl_prov_set_debug_keys(void) +{ + /* PTS defines the below Public/PrivateKey as its Default in PIXIT */ + UCHAR appl_t_pvt_key[(PROV_PUBKEY_SIZE_PL/2)] = + { + 0x52, 0x9A, 0xA0, 0x67, 0x0D, 0x72, 0xCD, 0x64, + 0x97, 0x50, 0x2E, 0xD4, 0x73, 0x50, 0x2B, 0x03, + 0x7E, 0x88, 0x03, 0xB5, 0xC6, 0x08, 0x29, 0xA5, + 0xA3, 0xCA, 0xA2, 0x19, 0x50, 0x55, 0x30, 0xBA + }; + UCHAR appl_t_pub_key[PROV_PUBKEY_SIZE_PL] = + { + 0xF4, 0x65, 0xE4, 0x3F, 0xF2, 0x3D, 0x3F, 0x1B, + 0x9D, 0xC7, 0xDF, 0xC0, 0x4D, 0xA8, 0x75, 0x81, + 0x84, 0xDB, 0xC9, 0x66, 0x20, 0x47, 0x96, 0xEC, + 0xCF, 0x0D, 0x6C, 0xF5, 0xE1, 0x65, 0x00, 0xCC, + 0x02, 0x01, 0xD0, 0x48, 0xBC, 0xBB, 0xD8, 0x99, + 0xEE, 0xEF, 0xC4, 0x24, 0x16, 0x4E, 0x33, 0xC2, + 0x01, 0xC2, 0xB0, 0x10, 0xCA, 0x6B, 0x4D, 0x43, + 0xA8, 0xA1, 0x55, 0xCA, 0xD8, 0xEC, 0xB2, 0x79 + }; + cry_set_ecdh_debug_keypair(appl_t_pvt_key, appl_t_pub_key); + printf ("Setting Debug Public Key : \n"); + appl_dump_bytes(appl_t_pub_key, sizeof(appl_t_pub_key)); + printf ("Setting Debug Private Key : \n"); + appl_dump_bytes(appl_t_pvt_key, sizeof(appl_t_pvt_key)); +} + +void appl_prov_set_auth_action +( + UCHAR mode, + UCHAR* s_oob_val, + UCHAR oob_act, + UCHAR oob_sz +) +{ + UCHAR auth[PROV_AUTHVAL_SIZE_PL]; + /** + Valid Values of Mode for OOB usage are: + 0x00 - None + 0x01 - Static + 0x02 - Output + 0x03 - Input + */ + /* Update the Authentication method based on "Mode" in "method" */ + appl_prov_method.auth = mode; + + if (PROV_AUTH_OOB_STATIC == mode) + { + /** + TODO: Have a User provided value from CLI through "s_oob_val" + */ + /** + Set the STATIC OOB value in PTS PIXIT table: + OOB: 0x11111111111111111111111111111111[16 Octets 0f 0x11] + */ + EM_mem_set(auth, 0x11, sizeof(auth)); + prov_set_static_oob_auth_pl(auth, sizeof(auth)); + printf("\n Setting PROV_AUTH_OOB_STATIC mode"); + printf("\n Static OOB used is:\n"); + appl_dump_bytes(auth, sizeof(auth)); + } + else if (PROV_AUTH_OOB_OUTPUT == mode) + { + /** + Output OOB Action valid values + 0x00 - Blink + 0x01 - Beep + 0x02 - Vibrate + 0x03 - Numeric + 0x04 - Alphanumeric + */ + appl_prov_method.oob.action = oob_act; + appl_prov_method.oob.size = oob_sz; + printf("\n Setting PROV_AUTH_OOB_OUTPUT mode\n"); + printf("\n OOB of size: %02d", oob_sz); + printf("\n OOB action : %s\n", + (0x00 == oob_act) ? "Blink" : + (0x01 == oob_act) ? "Beep": + (0x02 == oob_act) ? "Vibrate": + (0x03 == oob_act) ? "Numeric": + (0x04 == oob_act) ? "Alphanumeric": "Unknown"); + } + else if (PROV_AUTH_OOB_INPUT == mode) + { + /** + Input OOB Action valid values + 0x00 - Push + 0x01 - Twist + 0x02 - Numeric + 0x03 - Alphanumeric + */ + appl_prov_method.oob.action = oob_act; + appl_prov_method.oob.size = oob_sz; + printf("\n Setting PROV_AUTH_OOB_INPUT mode"); + printf("\n OOB of size: %02d", oob_sz); + printf("\n OOB action : %s\n", + (0x00 == oob_act) ? "Push" : + (0x01 == oob_act) ? "Twist": + (0x02 == oob_act) ? "Numeric": + (0x03 == oob_act) ? "Alphanumeric": "Unknown"); + } + else + { + /* Assign default OOB mode */ + appl_prov_method.auth = PROV_AUTH_OOB_NONE; + printf("\n Setting PROV_AUTH_OOB_NONE mode\n"); + } +} + +API_RESULT appl_is_configured (void) +{ + MS_APPKEY_HANDLE handle; + UINT8* key; + UINT8 aid; + DECL_CONST UINT8 t_key[16] = {0}; + MS_NET_ADDR addr; + API_RESULT retval; + CONSOLE_OUT("Check for Primary Unicast Address\n"); + retval = MS_access_cm_get_primary_unicast_address(&addr); + + if ((API_SUCCESS != retval) || + (MS_NET_ADDR_UNASSIGNED == addr)) + { + return API_FAILURE; + } + + CONSOLE_OUT("Fetching App Key for Handle 0x0000\n"); + handle = 0x0000; + retval = MS_access_cm_get_app_key + ( + handle, + &key, + &aid + ); + + /* Check Retval. Print App Key */ + if (API_SUCCESS == retval) + { + CONSOLE_OUT("App Key[0x%02X]: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\r\n", + handle, key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7], + key[8], key[9], key[10], key[11], key[12], key[13], key[14], key[15]); + + if (0 == EM_mem_cmp(key, t_key, 16)) + { + /* NO AppKey Bound */ + retval = API_FAILURE; + } + else + { + /* Found a Valid App Key */ + /* Keeping the retval as API_SUCCESS */ + } + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/appl_proxy.c b/src/components/ethermind/mesh/export/appl/appl_proxy.c new file mode 100644 index 0000000..5b7ee0d --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/appl_proxy.c @@ -0,0 +1,346 @@ + +/** + \file appl_proxy.c + + +*/ + +/* + Copyright (C) 2017. Mindtree Limited. + All rights reserved. +*/ + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_main.h" +#include "blebrr.h" +#include "MS_net_api.h" + +#ifdef MS_PROXY_SUPPORT +/* --------------------------------------------- External Global Variables */ + +/* --------------------------------------------- Exported Global Variables */ + +/* --------------------------------------------- Static Global Variables */ +DECL_STATIC const char main_proxy_options[] = "\n\ +========= Network Menu =============== \n\ + 0. Exit. \n\ + 1. Refresh \n\ + \n\ + 10. Register with Proxy Layer \n\ + \n\ + 20. Start Proxy ADV with Network ID \n\ + 21. Start Proxy ADV with Node Identity \n\ + 22. Stop Proxy ADV \n\ + \n\ + 30. Set WhiteList Filter Type \n\ + 31. Set BlackList Filter Type \n\ + 32. Add Address to Filter \n\ + 33. Remove Address from Filter \n\ + \n\ + 200. Enable Proxy \n\ + 201. Disable Proxy \n\ +Your Option ? \0"; + +/* Global Network Interface Handle : Initialize to MAX Ifaces[Invalid Value] */ +NETIF_HANDLE g_appl_netif_hndl; + +/* --------------------------------------------- Functions */ +void appl_proxy_callback +( + NETIF_HANDLE* handle, + UCHAR p_evt, + UCHAR* data_param, + UINT16 data_len +); +void appl_add_or_del_filter_addr(UCHAR opcode); +void appl_proxy_start_net_id_adv(MS_SUBNET_HANDLE subnet_handle); +void appl_proxy_start_node_identity_adv(MS_SUBNET_HANDLE subnet_handle); +void main_proxy_operations (void); + +void main_proxy_operations (void) +{ + int choice; + static UINT8 first_time = 0; + + if (0 == first_time) + { + g_appl_netif_hndl = (NETIF_HANDLE)MS_CONFIG_LIMITS(MS_NUM_NETWORK_INTERFACES); + first_time = 1; + } + + MS_LOOP_FOREVER() + { + printf("%s", main_proxy_options); + scanf("%d", &choice); + + if (choice < 0) + { + printf("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 10: + /* Register with the Proxy Layer */ + MS_proxy_register(appl_proxy_callback); + break; + + case 20: + #ifdef MS_PROXY_SERVER + /* Start Proxy ADV with Network ID */ + printf("\nEnter Subnet Handle :\n"); + scanf("%d", &choice); + appl_proxy_start_net_id_adv((MS_SUBNET_HANDLE)choice); + #else /* MS_PROXY_SERVER */ + CONSOLE_OUT( + "Proxy Server Feature Currently Disabled!!!\n"); + #endif /* MS_PROXY_SERVER */ + break; + + case 21: + #ifdef MS_PROXY_SERVER + /* Start Proxy ADV with Node Identity */ + printf("\nEnter Subnet Handle :\n"); + scanf("%d", &choice); + appl_proxy_start_node_identity_adv((MS_SUBNET_HANDLE)choice); + #else /* MS_PROXY_SERVER */ + CONSOLE_OUT( + "Proxy Server Feature Currently Disabled!!!\n"); + #endif /* MS_PROXY_SERVER */ + break; + + case 22: + #ifdef MS_PROXY_SERVER + /* Stop Proxy ADV */ + MS_proxy_server_adv_stop(); + #else /* MS_PROXY_SERVER */ + CONSOLE_OUT( + "Proxy Server Feature Currently Disabled!!!\n"); + #endif /* MS_PROXY_SERVER */ + break; + + case 30: + #ifdef MS_PROXY_CLIENT + /* Set Filter Type as WhiteList */ + MS_proxy_set_whitelist_filter(&g_appl_netif_hndl, 0x0000); + #else /* MS_PROXY_CLIENT */ + CONSOLE_OUT( + "Proxy Client Feature Currently Disabled!!!\n"); + #endif /* MS_PROXY_CLIENT */ + break; + + case 31: + #ifdef MS_PROXY_CLIENT + /* Set Filter Type as BlackList */ + MS_proxy_set_blacklist_filter(&g_appl_netif_hndl, 0x0000); + #else /* MS_PROXY_CLIENT */ + CONSOLE_OUT( + "Proxy Client Feature Currently Disabled!!!\n"); + #endif /* MS_PROXY_CLIENT */ + break; + + case 32: + /* Add Address to Filters */ + appl_add_or_del_filter_addr(MS_PROXY_ADD_TO_FILTER_OPCODE); + break; + + case 33: + /* Remove Address from Filters */ + appl_add_or_del_filter_addr(MS_PROXY_REM_FROM_FILTER_OPCODE); + break; + + case 200: + /* Enable Proxy */ + MS_ENABLE_PROXY_FEATURE(); + break; + + case 201: + /* Disable Proxy */ + MS_DISABLE_PROXY_FEATURE(); + break; + + default: + printf ("Invalid option %d\n", choice); + } + } +} + +void appl_proxy_callback +( + NETIF_HANDLE* handle, + UCHAR p_evt, + UCHAR* data_param, + UINT16 data_len +) +{ + PROXY_FILTER_TYPE filter_type; + UINT16 count; + UCHAR role; + MS_IGNORE_UNUSED_PARAM(data_len); + + switch(p_evt) + { + case MS_PROXY_UP_EVENT: + CONSOLE_OUT( + "\n\n[PROXY APPL]: MS_PROXY_UP_EVENT Received for NETIF Handle 0x%02X\n\n", *handle); + g_appl_netif_hndl = *handle; + CONSOLE_OUT( + "\n[PROXY APPL]: Enabling Proxy Feature!!\n"); + + if (NULL != data_param) + { + /* Catch the current role into a local */ + role = data_param[0]; + + if (BRR_SERVER_ROLE == role) + { + /* Enable Proxy */ + MS_ENABLE_PROXY_FEATURE(); + /* Send Secure Network Beacons */ + MS_net_broadcast_secure_beacon(0x0000); + } + } + + break; + + case MS_PROXY_DOWN_EVENT: + CONSOLE_OUT( + "\n\n[PROXY APPL]: MS_PROXY_DOWN_EVENT Received for NETIF Handle 0x%02X\n\n", *handle); + g_appl_netif_hndl = (NETIF_HANDLE)MS_CONFIG_LIMITS(MS_NUM_NETWORK_INTERFACES); + CONSOLE_OUT( + "\n[PROXY APPL]: Disabling Proxy Feature!!\n"); + /* Disable Proxy */ + MS_DISABLE_PROXY_FEATURE(); + break; + + case MS_PROXY_STATUS_EVENT: + /* TODO: Length Check */ + /* Extract the Status contents */ + filter_type = data_param[0]; + MS_UNPACK_BE_2_BYTE(&count, &data_param[1]); + CONSOLE_OUT( + "\n\n[PROXY APPL]: MS_PROXY_STATUS_EVENT Received for NETIF Handle 0x%02X\n" + "Filter Type :- %s\r\n Addr Count :- %04d\n\n", + *handle, + (MS_PROXY_WHITELIST_FILTER == filter_type)? "WhiteList": + "BlackList", + count); + break; + + default: + CONSOLE_OUT( + "\n\n[PROXY APPL ERR]: Unknown Event Received for NETIF Handle 0x%02X!!\n\n", *handle); + break; + } +} + +void appl_add_or_del_filter_addr(UCHAR opcode) +{ + #ifdef MS_PROXY_CLIENT + PROXY_ADDR appl_proxy_addr_list[5]; + UINT16 addr_count; + UINT32 index; + int read_in; + /* Read and fill Addresses */ + CONSOLE_OUT("Enter Count of Address to be Added (in Hex)\n"); + CONSOLE_IN("%x", &read_in); + addr_count = (UINT16)read_in; + + for (index = 0; index < addr_count; index++) + { + CONSOLE_OUT("Enter %d'th Address[in HEX]: \n", (index + 1)); + CONSOLE_IN("%x", &read_in); + appl_proxy_addr_list[index] = (UINT8)read_in; + } + + if (MS_PROXY_ADD_TO_FILTER_OPCODE == opcode) + { + MS_proxy_add_to_list + ( + &g_appl_netif_hndl, + 0x0000, + appl_proxy_addr_list, + addr_count + ); + } + else + { + MS_proxy_del_from_list + ( + &g_appl_netif_hndl, + 0x0000, + appl_proxy_addr_list, + addr_count + ); + } + + #else /* MS_PROXY_CLIENT */ + MS_IGNORE_UNUSED_PARAM(opcode); + CONSOLE_OUT( + "Proxy Client Feature Currently Disabled!!!\n"); + #endif /* MS_PROXY_CLIENT */ +} + +void appl_proxy_register(void) +{ + MS_proxy_register(appl_proxy_callback); +} + +void appl_proxy_start_net_id_adv(MS_SUBNET_HANDLE subnet_handle) +{ + #ifdef MS_PROXY_SERVER + /* Set the role to Proxy with bearer */ + blebrr_gatt_mode_set(BLEBRR_GATT_PROXY_MODE); + MS_proxy_server_adv_start + ( + subnet_handle, + MS_PROXY_NET_ID_ADV_MODE + ); + #else /* MS_PROXY_SERVER */ + CONSOLE_OUT( + "Proxy Server Feature Currently Disabled!!!\n"); + return API_FAILURE; + #endif /* MS_PROXY_SERVER */ +} + +void appl_proxy_start_node_identity_adv(MS_SUBNET_HANDLE subnet_handle) +{ + #ifdef MS_PROXY_SERVER + /* Set the role to Proxy with bearer */ + blebrr_gatt_mode_set(BLEBRR_GATT_PROXY_MODE); + MS_proxy_server_adv_start + ( + subnet_handle, + MS_PROXY_NODE_ID_ADV_MODE + ); + #else /* MS_PROXY_SERVER */ + CONSOLE_OUT( + "Proxy Server Feature Currently Disabled!!!\n"); + return API_FAILURE; + #endif /* MS_PROXY_SERVER */ +} + +void appl_proxy_adv +( + UCHAR identification_type, + MS_SUBNET_HANDLE subnet_handle +) +{ + #ifdef MS_PROXY_SERVER + (MS_PROXY_NET_ID_ADV_MODE == identification_type) ? + appl_proxy_start_net_id_adv(subnet_handle) : appl_proxy_start_node_identity_adv(subnet_handle); + #else /* MS_PROXY_SERVER */ + CONSOLE_OUT( + "Proxy Server Feature Currently Disabled!!!\n"); + return API_FAILURE; + #endif /* MS_PROXY_SERVER */ +} + +#endif /* MS_PROXY_SUPPORT */ diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_config_client.c b/src/components/ethermind/mesh/export/appl/model/client/appl_config_client.c new file mode 100644 index 0000000..ff6efd8 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_config_client.c @@ -0,0 +1,1951 @@ +/** + \file appl_config_client.c + + \brief This file defines the Mesh Configuration Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_config_client.h" + + +/* --------------------------------------------- Global Definitions */ +/* #define APPL_CONFIG_CLIENT_PRINT_COMP_DATA */ + +#ifdef APPL_CONFIG_CLIENT_PRINT_COMP_DATA +void appl_config_client_print_composition_data +( + /* IN */ UCHAR* comp_data, + /* IN */ UINT16 data_len +); +#else +#define appl_config_client_print_composition_data(c, d) +#endif /* APPL_CONFIG_CLIENT_PRINT_COMP_DATA */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_config_client_options[] = "\n\ +======== Configuration Client Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 20. Send Config Beacon Set. \n\ + 21. Send Config Beacon Get. \n\ + 22. Send Config Composition Data Get. \n\ + 23. Send Config Default Ttl Set. \n\ + 24. Send Config Default Ttl Get. \n\ + 25. Send Config Gatt Proxy Set. \n\ + 26. Send Config Gatt Proxy Get. \n\ + 27. Send Config Friend Set. \n\ + 28. Send Config Friend Get. \n\ + 29. Send Config Relay Set. \n\ + 30. Send Config Relay Get. \n\ + 31. Send Config Model Publication Set. \n\ + 32. Send Config Model Publication Virtual Address Set. \n\ + 33. Send Config Model Publication Get. \n\ + 34. Send Config Model Subscription Add. \n\ + 35. Send Config Model Subscription Virtual Address Add. \n\ + 36. Send Config Model Subscription Overwrite. \n\ + 37. Send Config Model Subscription Virtual Address Overwrite. \n\ + 38. Send Config Model Subscription Delete. \n\ + 39. Send Config Model Subscription Virtual Address Delete. \n\ + 40. Send Config Model Subscription Delete All. \n\ + 41. Send Config Sig Model Subscription Get. \n\ + 42. Send Config Vendor Model Subscription Get. \n\ + 43. Send Config Netkey Add. \n\ + 44. Send Config Netkey Update. \n\ + 45. Send Config Netkey Delete. \n\ + 46. Send Config Netkey Get. \n\ + 47. Send Config Appkey Add. \n\ + 48. Send Config Appkey Update. \n\ + 49. Send Config Appkey Delete. \n\ + 50. Send Config Appkey Get. \n\ + 51. Send Config Model App Bind. \n\ + 52. Send Config Model App Unbind. \n\ + 53. Send Config Sig Model App Get. \n\ + 54. Send Config Vendor Model App Get. \n\ + 55. Send Config Node Identity Set. \n\ + 56. Send Config Node Identity Get. \n\ + 57. Send Config Node Reset. \n\ + 58. Send Config Heartbeat Publication Set. \n\ + 59. Send Config Heartbeat Publication Get. \n\ + 60. Send Config Heartbeat Subscription Set. \n\ + 61. Send Config Heartbeat Subscription Get. \n\ + 62. Send Config Network Transmit Set. \n\ + 63. Send Config Network Transmit Get. \n\ + 64. Send Config Low Power Node Polltimeout Get. \n\ + 65. Send Config Key Refresh Phase Set. \n\ + 66. Send Config Key Refresh Phase Get. \n\ + \n\ + 100. Get Model Handle. \n\ + 101. Set Publish Address. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_config_client_model_handle; + + +/* --------------------------------------------- Function */ +/* config client application entry point */ +void main_config_client_operations(void) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_config_client_init + ( + element_handle, + &appl_config_client_model_handle, + appl_config_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Configuration Client Initialized. Model Handle: 0x%04X\n", + appl_config_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Configuration Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_config_client_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 20: /* Send Config Beacon Set */ + appl_send_config_beacon_set(); + break; + + case 21: /* Send Config Beacon Get */ + appl_send_config_beacon_get(); + break; + + case 22: /* Send Config Composition Data Get */ + appl_send_config_composition_data_get(); + break; + + case 23: /* Send Config Default Ttl Set */ + appl_send_config_default_ttl_set(); + break; + + case 24: /* Send Config Default Ttl Get */ + appl_send_config_default_ttl_get(); + break; + + case 25: /* Send Config Gatt Proxy Set */ + appl_send_config_gatt_proxy_set(); + break; + + case 26: /* Send Config Gatt Proxy Get */ + appl_send_config_gatt_proxy_get(); + break; + + case 27: /* Send Config Friend Set */ + appl_send_config_friend_set(); + break; + + case 28: /* Send Config Friend Get */ + appl_send_config_friend_get(); + break; + + case 29: /* Send Config Relay Set */ + appl_send_config_relay_set(); + break; + + case 30: /* Send Config Relay Get */ + appl_send_config_relay_get(); + break; + + case 31: /* Send Config Model Publication Set */ + appl_send_config_model_publication_set(); + break; + + case 32: /* Send Config Model Publication Virtual Address Set */ + appl_send_config_model_publication_virtual_address_set(); + break; + + case 33: /* Send Config Model Publication Get */ + appl_send_config_model_publication_get(); + break; + + case 34: /* Send Config Model Subscription Add */ + appl_send_config_model_subscription_add(); + break; + + case 35: /* Send Config Model Subscription Virtual Address Add */ + appl_send_config_model_subscription_virtual_address_add(); + break; + + case 36: /* Send Config Model Subscription Overwrite */ + appl_send_config_model_subscription_overwrite(); + break; + + case 37: /* Send Config Model Subscription Virtual Address Overwrite */ + appl_send_config_model_subscription_virtual_address_overwrite(); + break; + + case 38: /* Send Config Model Subscription Delete */ + appl_send_config_model_subscription_delete(); + break; + + case 39: /* Send Config Model Subscription Virtual Address Delete */ + appl_send_config_model_subscription_virtual_address_delete(); + break; + + case 40: /* Send Config Model Subscription Delete All */ + appl_send_config_model_subscription_delete_all(); + break; + + case 41: /* Send Config Sig Model Subscription Get */ + appl_send_config_sig_model_subscription_get(); + break; + + case 42: /* Send Config Vendor Model Subscription Get */ + appl_send_config_vendor_model_subscription_get(); + break; + + case 43: /* Send Config Netkey Add */ + appl_send_config_netkey_add(); + break; + + case 44: /* Send Config Netkey Update */ + appl_send_config_netkey_update(); + break; + + case 45: /* Send Config Netkey Delete */ + appl_send_config_netkey_delete(); + break; + + case 46: /* Send Config Netkey Get */ + appl_send_config_netkey_get(); + break; + + case 47: /* Send Config Appkey Add */ + appl_send_config_appkey_add(); + break; + + case 48: /* Send Config Appkey Update */ + appl_send_config_appkey_update(); + break; + + case 49: /* Send Config Appkey Delete */ + appl_send_config_appkey_delete(); + break; + + case 50: /* Send Config Appkey Get */ + appl_send_config_appkey_get(); + break; + + case 51: /* Send Config Model App Bind */ + appl_send_config_model_app_bind(); + break; + + case 52: /* Send Config Model App Unbind */ + appl_send_config_model_app_unbind(); + break; + + case 53: /* Send Config Sig Model App Get */ + appl_send_config_sig_model_app_get(); + break; + + case 54: /* Send Config Vendor Model App Get */ + appl_send_config_vendor_model_app_get(); + break; + + case 55: /* Send Config Node Identity Set */ + appl_send_config_node_identity_set(); + break; + + case 56: /* Send Config Node Identity Get */ + appl_send_config_node_identity_get(); + break; + + case 57: /* Send Config Node Reset */ + appl_send_config_node_reset(); + break; + + case 58: /* Send Config Heartbeat Publication Set */ + appl_send_config_heartbeat_publication_set(); + break; + + case 59: /* Send Config Heartbeat Publication Get */ + appl_send_config_heartbeat_publication_get(); + break; + + case 60: /* Send Config Heartbeat Subscription Set */ + appl_send_config_heartbeat_subscription_set(); + break; + + case 61: /* Send Config Heartbeat Subscription Get */ + appl_send_config_heartbeat_subscription_get(); + break; + + case 62: /* Send Config Network Transmit Set */ + appl_send_config_network_transmit_set(); + break; + + case 63: /* Send Config Network Transmit Get */ + appl_send_config_network_transmit_get(); + break; + + case 64: /* Send Config Low Power Node Polltimeout Get */ + appl_send_config_low_power_node_polltimeout_get(); + break; + + case 65: /* Send Config Key Refresh Phase Set */ + appl_send_config_key_refresh_phase_set(); + break; + + case 66: /* Send Config Key Refresh Phase Get */ + appl_send_config_key_refresh_phase_get(); + break; + + case 100: /* Get Model Handle */ + appl_config_client_get_model_handle(); + break; + + case 101: /* Set Publish Address */ + appl_config_client_set_publish_address(); + break; + } + } +} + +/* Send Config Model App Unbind */ +void appl_send_config_model_app_unbind(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODEL_APP_UNBIND_PARAM param; + CONSOLE_OUT + (">> Send Config Model App Unbind\n"); + CONSOLE_OUT + ("Enter ElementAddress (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.element_address = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKeyIndex (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.appkey_index = (UINT16)choice; + CONSOLE_OUT + ("Enter ModelIdentifier\n"); + CONSOLE_OUT + ("Enter Model ID Type. (0 -> SIG, 1 -> Vendor\n"); + CONSOLE_IN + ("%x", &choice); + param.model.type = (UCHAR)choice; + CONSOLE_OUT + ("Enter Model ID.\n"); + CONSOLE_IN + ("%x", &choice); + param.model.id = (UINT32)choice; + CONSOLE_OUT + ("Enter Corresponding Local ModelIdentifier\n"); + CONSOLE_OUT + ("Enter Model ID Type. (0 -> SIG, 1 -> Vendor\n"); + CONSOLE_IN + ("%x", &choice); + param.client_model.type = (UCHAR)choice; + CONSOLE_OUT + ("Enter Model ID.\n"); + CONSOLE_IN + ("%x", &choice); + param.client_model.id = (UINT32)choice; + retval = MS_config_client_model_app_unbind(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Friend Get */ +void appl_send_config_friend_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Config Friend Get\n"); + retval = MS_config_client_friend_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Gatt Proxy Get */ +void appl_send_config_gatt_proxy_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Config Gatt Proxy Get\n"); + retval = MS_config_client_gatt_proxy_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Model Subscription Virtual Address Overwrite */ +void appl_send_config_model_subscription_virtual_address_overwrite(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODELSUB_VADDR_OVERWRITE_PARAM param; + CONSOLE_OUT + (">> Send Config Model Subscription Virtual Address Overwrite\n"); + CONSOLE_OUT + ("Enter ElementAddress (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.element_address = (UINT16)choice; + CONSOLE_OUT + ("Enter Address (16-octets in HEX)\n"); + { + UINT16 index; + + for(index = 0; index < 16; index++) + { + CONSOLE_IN + ("%x", &choice); + param.label[index] = (UCHAR)choice; + } + } + CONSOLE_OUT + ("Enter ModelIdentifier\n"); + CONSOLE_OUT + ("Enter Model ID Type. (0 -> SIG, 1 -> Vendor\n"); + CONSOLE_IN + ("%x", &choice); + param.model.type = (UCHAR)choice; + CONSOLE_OUT + ("Enter Model ID.\n"); + CONSOLE_IN + ("%x", &choice); + param.model.id = (UINT32)choice; + retval = MS_config_client_model_subscription_vaddr_overwrite(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Sig Model App Get */ +void appl_send_config_sig_model_app_get(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_SIG_MODEL_APP_GET_PARAM param; + CONSOLE_OUT + (">> Send Config Sig Model App Get\n"); + CONSOLE_OUT + ("Enter ElementAddress (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.element_address = (UINT16)choice; + CONSOLE_OUT + ("Enter ModelIdentifier (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.model_id = (UINT16)choice; + retval = MS_config_client_sig_model_app_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Model Subscription Add */ +void appl_send_config_model_subscription_add(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODELSUB_ADD_PARAM param; + CONSOLE_OUT + (">> Send Config Model Subscription Add\n"); + CONSOLE_OUT + ("Enter ElementAddress (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.element_address= (UINT16)choice; + CONSOLE_OUT + ("Enter Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.address = (UINT16)choice; + CONSOLE_OUT + ("Enter ModelIdentifier\n"); + CONSOLE_OUT + ("Enter Model ID Type. (0 -> SIG, 1 -> Vendor\n"); + CONSOLE_IN + ("%x", &choice); + param.model.type = (UCHAR)choice; + CONSOLE_OUT + ("Enter Model ID.\n"); + CONSOLE_IN + ("%x", &choice); + param.model.id = (UINT32)choice; + retval = MS_config_client_model_subscription_add(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Network Transmit Set */ +void appl_send_config_network_transmit_set(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_NETWORK_TRANSMIT_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Network Transmit Set\n"); + CONSOLE_OUT + ("Enter NetWork Transmit Count (in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.net_tx_count = (UINT16)choice; + CONSOLE_OUT + ("Enter NetWork Transmit Interval Steps (in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.net_tx_interval_steps = (UINT16)choice; + retval = MS_config_client_network_transmit_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Model Subscription Delete */ +void appl_send_config_model_subscription_delete(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODELSUB_DEL_PARAM param; + CONSOLE_OUT + (">> Send Config Model Subscription Delete\n"); + CONSOLE_OUT + ("Enter ElementAddress (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.element_address = (UINT16)choice; + CONSOLE_OUT + ("Enter Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.address = (UINT16)choice; + CONSOLE_OUT + ("Enter ModelIdentifier\n"); + CONSOLE_OUT + ("Enter Model ID Type. (0 -> SIG, 1 -> Vendor\n"); + CONSOLE_IN + ("%x", &choice); + param.model.type = (UCHAR)choice; + CONSOLE_OUT + ("Enter Model ID.\n"); + CONSOLE_IN + ("%x", &choice); + param.model.id = (UINT32)choice; + retval = MS_config_client_model_subscription_delete(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Relay Get */ +void appl_send_config_relay_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Config Relay Get\n"); + retval = MS_config_client_relay_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Heartbeat Subscription Set */ +void appl_send_config_heartbeat_subscription_set(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_HEARTBEATSUB_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Heartbeat Subscription Set\n"); + CONSOLE_OUT + ("Enter Source (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.source = (UINT16)choice; + CONSOLE_OUT + ("Enter Destination (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.destination = (UINT16)choice; + CONSOLE_OUT + ("Enter PeriodLog (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.periodlog = (UCHAR)choice; + retval = MS_config_client_heartbeat_subscription_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Beacon Set */ +void appl_send_config_beacon_set(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_BEACON_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Beacon Set\n"); + CONSOLE_OUT + ("Enter Beacon (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.beacon = (UCHAR)choice; + retval = MS_config_client_beacon_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Node Reset */ +void appl_send_config_node_reset(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Config Node Reset\n"); + retval = MS_config_client_node_reset(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Relay Set */ +void appl_send_config_relay_set(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_RELAY_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Relay Set\n"); + CONSOLE_OUT + ("Enter Relay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.relay = (UCHAR)choice; + CONSOLE_OUT + ("Enter RelayRetransmitCount (3-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.relay_rtx_count = (UCHAR)choice; + CONSOLE_OUT + ("Enter RelayRetransmitIntervalSteps (5-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.relay_rtx_interval_steps = (UCHAR)choice; + retval = MS_config_client_relay_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Key Refresh Phase Get */ +void appl_send_config_key_refresh_phase_get(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_KEYREFRESH_PHASE_GET_PARAM param; + CONSOLE_OUT + (">> Send Config Key Refresh Phase Get\n"); + CONSOLE_OUT + ("Enter NetKeyIndex (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.netkey_index = (UINT16)choice; + retval = MS_config_client_keyrefresh_phase_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Model Subscription Virtual Address Delete */ +void appl_send_config_model_subscription_virtual_address_delete(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODELSUB_VADDR_DEL_PARAM param; + CONSOLE_OUT + (">> Send Config Model Subscription Virtual Address Delete\n"); + CONSOLE_OUT + ("Enter ElementAddress (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.element_address = (UINT16)choice; + CONSOLE_OUT + ("Enter Label (16-octets in HEX)\n"); + { + UINT16 index; + + for(index = 0; index < 16; index++) + { + CONSOLE_IN + ("%x", &choice); + param.label[index] = (UCHAR)choice; + } + } + CONSOLE_OUT + ("Enter ModelIdentifier\n"); + CONSOLE_OUT + ("Enter Model ID Type. (0 -> SIG, 1 -> Vendor\n"); + CONSOLE_IN + ("%x", &choice); + param.model.type = (UCHAR)choice; + CONSOLE_OUT + ("Enter Model ID.\n"); + CONSOLE_IN + ("%x", &choice); + param.model.id = (UINT32)choice; + retval = MS_config_client_model_subscription_vaddr_delete(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Model Publication Virtual Address Set */ +void appl_send_config_model_publication_virtual_address_set(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODELPUB_VADDR_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Model Publication Virtual Address Set\n"); + CONSOLE_OUT + ("Enter ElementAddress (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.element_address = (UINT16)choice; + CONSOLE_OUT + ("Enter PublishAddress (16-octets in HEX)\n"); + { + UINT16 index; + + for(index = 0; index < 16; index++) + { + CONSOLE_IN + ("%x", &choice); + param.publish_address[index] = (UCHAR)choice; + } + } + CONSOLE_OUT + ("Enter AppKeyIndex (12-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.appkey_index = (UINT16)choice; + CONSOLE_OUT + ("Enter CredentialFlag (1-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.credential_flag = (UCHAR)choice; + CONSOLE_OUT + ("Enter PublishTTL (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.publish_ttl = (UCHAR)choice; + CONSOLE_OUT + ("Enter PublishPeriod (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.publish_period = (UCHAR)choice; + CONSOLE_OUT + ("Enter PublishRetransmitCount (3-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.publish_rtx_count = (UCHAR)choice; + CONSOLE_OUT + ("Enter PublishRetransmitIntervalSteps (5-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.publish_rtx_interval_steps = (UCHAR)choice; + CONSOLE_OUT + ("Enter ModelIdentifier\n"); + CONSOLE_OUT + ("Enter Model ID Type. (0 -> SIG, 1 -> Vendor\n"); + CONSOLE_IN + ("%x", &choice); + param.model.type = (UCHAR)choice; + CONSOLE_OUT + ("Enter Model ID.\n"); + CONSOLE_IN + ("%x", &choice); + param.model.id = (UINT32)choice; + retval = MS_config_client_model_publication_vaddr_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Gatt Proxy Set */ +void appl_send_config_gatt_proxy_set(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_GATT_PROXY_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Gatt Proxy Set\n"); + CONSOLE_OUT + ("Enter GATTProxy (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.proxy = (UCHAR)choice; + retval = MS_config_client_gatt_proxy_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Model Subscription Virtual Address Add */ +void appl_send_config_model_subscription_virtual_address_add(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODELSUB_VADDR_ADD_PARAM param; + CONSOLE_OUT + (">> Send Config Model Subscription Virtual Address Add\n"); + CONSOLE_OUT + ("Enter ElementAddress (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.element_address = (UINT16)choice; + CONSOLE_OUT + ("Enter Label (16-octets in HEX)\n"); + { + UINT16 index; + + for(index = 0; index < 16; index++) + { + CONSOLE_IN + ("%x", &choice); + param.label[index] = (UCHAR)choice; + } + } + CONSOLE_OUT + ("Enter ModelIdentifier\n"); + CONSOLE_OUT + ("Enter Model ID Type. (0 -> SIG, 1 -> Vendor\n"); + CONSOLE_IN + ("%x", &choice); + param.model.type = (UCHAR)choice; + CONSOLE_OUT + ("Enter Model ID.\n"); + CONSOLE_IN + ("%x", &choice); + param.model.id = (UINT32)choice; + retval = MS_config_client_model_subscription_vaddr_add(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Default Ttl Get */ +void appl_send_config_default_ttl_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Config Default Ttl Get\n"); + retval = MS_config_client_default_ttl_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Model App Bind */ +void appl_send_config_model_app_bind(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODEL_APP_BIND_PARAM param; + CONSOLE_OUT + (">> Send Config Model App Bind\n"); + CONSOLE_OUT + ("Enter ElementAddress (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.element_address = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKeyIndex (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.appkey_index = (UINT16)choice; + CONSOLE_OUT + ("Enter ModelIdentifier\n"); + CONSOLE_OUT + ("Enter Model ID Type. (0 -> SIG, 1 -> Vendor\n"); + CONSOLE_IN + ("%x", &choice); + param.model.type = (UCHAR)choice; + CONSOLE_OUT + ("Enter Model ID.\n"); + CONSOLE_IN + ("%x", &choice); + param.model.id = (UINT32)choice; + CONSOLE_OUT + ("Enter Corresponding Local ModelIdentifier\n"); + CONSOLE_OUT + ("Enter Model ID Type. (0 -> SIG, 1 -> Vendor\n"); + CONSOLE_IN + ("%x", &choice); + param.client_model.type = (UCHAR)choice; + CONSOLE_OUT + ("Enter Model ID.\n"); + CONSOLE_IN + ("%x", &choice); + param.client_model.id = (UINT32)choice; + retval = MS_config_client_model_app_bind(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Node Identity Set */ +void appl_send_config_node_identity_set(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_NODEID_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Node Identity Set\n"); + CONSOLE_OUT + ("Enter NetKeyIndex (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.netkey_index = (UINT16)choice; + CONSOLE_OUT + ("Enter Identity (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.identity = (UCHAR)choice; + retval = MS_config_client_node_identity_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Sig Model Subscription Get */ +void appl_send_config_sig_model_subscription_get(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_SIGMODELSUB_GET_PARAM param; + CONSOLE_OUT + (">> Send Config Sig Model Subscription Get\n"); + CONSOLE_OUT + ("Enter ElementAddress (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.element_address = (UINT16)choice; + CONSOLE_OUT + ("Enter ModelIdentifier (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.model_id = (UINT16)choice; + retval = MS_config_client_sig_model_subscription_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Netkey Add */ +void appl_send_config_netkey_add(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_NETKEY_ADD_PARAM param; + CONSOLE_OUT + (">> Send Config Netkey Add\n"); + CONSOLE_OUT + ("Enter NetKeyIndex (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.netkey_index = (UINT16)choice; + CONSOLE_OUT + ("Enter NetKey (16-octets in HEX)\n"); + { + UINT16 index; + + for(index = 0; index < 16; index++) + { + CONSOLE_IN + ("%x", &choice); + param.netkey[index] = (UCHAR)choice; + } + } + retval = MS_config_client_netkey_add(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Appkey Update */ +void appl_send_config_appkey_update(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_APPKEY_UPDATE_PARAM param; + CONSOLE_OUT + (">> Send Config Appkey Update\n"); + CONSOLE_OUT + ("Enter NetKeyIndex (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.netkey_index = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKeyIndex (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.appkey_index = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKey (16-octets in HEX)\n"); + { + UINT16 index; + + for(index = 0; index < 16; index++) + { + CONSOLE_IN + ("%x", &choice); + param.appkey[index] = (UCHAR)choice; + } + } + retval = MS_config_client_appkey_update(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Heartbeat Subscription Get */ +void appl_send_config_heartbeat_subscription_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Config Heartbeat Subscription Get\n"); + retval = MS_config_client_heartbeat_subscription_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Vendor Model Subscription Get */ +void appl_send_config_vendor_model_subscription_get(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_VENDORMODELSUB_GET_PARAM param; + CONSOLE_OUT + (">> Send Config Vendor Model Subscription Get\n"); + CONSOLE_OUT + ("Enter ElementAddress (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.element_address= (UINT16)choice; + CONSOLE_OUT + ("Enter ModelIdentifier (32-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.model_id = (UINT32)choice; + retval = MS_config_client_vendor_model_subscription_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Vendor Model App Get */ +void appl_send_config_vendor_model_app_get(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_VENDOR_MODEL_APP_GET_PARAM param; + CONSOLE_OUT + (">> Send Config Vendor Model App Get\n"); + CONSOLE_OUT + ("Enter ElementAddress (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.element_address= (UINT16)choice; + CONSOLE_OUT + ("Enter ModelIdentifier (32-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.model_id = (UINT32)choice; + retval = MS_config_client_vendor_model_app_get(¶m); +} + +/* Send Config Model Subscription Overwrite */ +void appl_send_config_model_subscription_overwrite(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODELSUB_OVERWRITE_PARAM param; + CONSOLE_OUT + (">> Send Config Model Subscription Overwrite\n"); + CONSOLE_OUT + ("Enter ElementAddress (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.element_address = (UINT16)choice; + CONSOLE_OUT + ("Enter Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.address = (UINT16)choice; + CONSOLE_OUT + ("Enter ModelIdentifier\n"); + CONSOLE_OUT + ("Enter Model ID Type. (0 -> SIG, 1 -> Vendor\n"); + CONSOLE_IN + ("%x", &choice); + param.model.type = (UCHAR)choice; + CONSOLE_OUT + ("Enter Model ID.\n"); + CONSOLE_IN + ("%x", &choice); + param.model.id = (UINT32)choice; + retval = MS_config_client_model_subscription_overwrite(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Beacon Get */ +void appl_send_config_beacon_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Config Beacon Get\n"); + retval = MS_config_client_beacon_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Model Subscription Delete All */ +void appl_send_config_model_subscription_delete_all(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODELSUB_DELETEALL_PARAM param; + CONSOLE_OUT + (">> Send Config Model Subscription Delete All\n"); + CONSOLE_OUT + ("Enter ElementAddress (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.element_address = (UINT16)choice; + CONSOLE_OUT + ("Enter ModelIdentifier\n"); + CONSOLE_OUT + ("Enter Model ID Type. (0 -> SIG, 1 -> Vendor\n"); + CONSOLE_IN + ("%x", &choice); + param.model.type = (UCHAR)choice; + CONSOLE_OUT + ("Enter Model ID.\n"); + CONSOLE_IN + ("%x", &choice); + param.model.id = (UINT32)choice; + retval = MS_config_client_model_subscription_delete_all(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Netkey Delete */ +void appl_send_config_netkey_delete(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_NETKEY_DELETE_PARAM param; + CONSOLE_OUT + (">> Send Config Netkey Delete\n"); + CONSOLE_OUT + ("Enter NetKeyIndex (12-bit in Hex)\n"); + CONSOLE_IN + ("%d", &choice); + param.netkey_index = (UINT16)choice; + retval = MS_config_client_netkey_delete(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Friend Set */ +void appl_send_config_friend_set(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_FRIEND_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Friend Set\n"); + CONSOLE_OUT + ("Enter Friend (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.friend = (UCHAR)choice; + retval = MS_config_client_friend_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Heartbeat Publication Set */ +void appl_send_config_heartbeat_publication_set(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_HEARTBEATPUB_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Heartbeat Publication Set\n"); + CONSOLE_OUT + ("Enter Destination (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.destination = (UINT16)choice; + CONSOLE_OUT + ("Enter CountLog (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.countlog = (UCHAR)choice; + CONSOLE_OUT + ("Enter PeriodLog (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.periodlog = (UCHAR)choice; + CONSOLE_OUT + ("Enter TTL (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.ttl = (UCHAR)choice; + CONSOLE_OUT + ("Enter Features (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.features = (UINT16)choice; + CONSOLE_OUT + ("Enter NetKeyIndex (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.netkey_index = (UINT16)choice; + retval = MS_config_client_heartbeat_publication_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Node Identity Get */ +void appl_send_config_node_identity_get(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_NODEID_GET_PARAM param; + CONSOLE_OUT + (">> Send Config Node Identity Get\n"); + CONSOLE_OUT + ("Enter NetKeyIndex (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.netkey_index = (UINT16)choice; + retval = MS_config_client_node_identity_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Default Ttl Set */ +void appl_send_config_default_ttl_set(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_DEFAULT_TTL_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Default Ttl Set\n"); + CONSOLE_OUT + ("Enter TTL (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.ttl = (UCHAR)choice; + retval = MS_config_client_default_ttl_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Netkey Update */ +void appl_send_config_netkey_update(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_NETKEY_UPDATE_PARAM param; + CONSOLE_OUT + (">> Send Config Netkey Update\n"); + CONSOLE_OUT + ("Enter NetKeyIndex (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.netkey_index = (UINT16)choice; + CONSOLE_OUT + ("Enter NetKey (16-octets in HEX)\n"); + { + UINT16 index; + + for(index = 0; index < 16; index++) + { + CONSOLE_IN + ("%x", &choice); + param.netkey[index] = (UCHAR)choice; + } + } + /* Set Local NetKey */ + MS_access_cm_add_update_netkey + ( + 0, /* netkey_index */ + MS_ACCESS_CONFIG_NETKEY_UPDATE_OPCODE, /* opcode */ + ¶m.netkey[0] /* net_key */ + ); + retval = MS_config_client_netkey_update(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Heartbeat Publication Get */ +void appl_send_config_heartbeat_publication_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Config Heartbeat Publication Get\n"); + retval = MS_config_client_heartbeat_publication_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Model Publication Set */ +void appl_send_config_model_publication_set(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODELPUB_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Model Publication Set\n"); + CONSOLE_OUT + ("Enter ElementAddress (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.element_address = (UINT16)choice; + CONSOLE_OUT + ("Enter PublishAddress (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.publish_address = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKeyIndex (12-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.appkey_index = (UINT16)choice; + CONSOLE_OUT + ("Enter CredentialFlag (1-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.credential_flag = (UCHAR)choice; + CONSOLE_OUT + ("Enter PublishTTL (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.publish_ttl = (UCHAR)choice; + CONSOLE_OUT + ("Enter PublishPeriod (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.publish_period = (UCHAR)choice; + CONSOLE_OUT + ("Enter PublishRetransmitCount (3-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.publish_rtx_count = (UCHAR)choice; + CONSOLE_OUT + ("Enter PublishRetransmitIntervalSteps (5-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.publish_rtx_interval_steps = (UCHAR)choice; + CONSOLE_OUT + ("Enter ModelIdentifier\n"); + CONSOLE_OUT + ("Enter Model ID Type. (0 -> SIG, 1 -> Vendor\n"); + CONSOLE_IN + ("%x", &choice); + param.model.type = (UCHAR)choice; + CONSOLE_OUT + ("Enter Model ID.\n"); + CONSOLE_IN + ("%x", &choice); + param.model.id = (UINT32)choice; + retval = MS_config_client_model_publication_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Netkey Get */ +void appl_send_config_netkey_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Config Netkey Get\n"); + retval = MS_config_client_netkey_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Model Publication Get */ +void appl_send_config_model_publication_get(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODELPUB_GET_PARAM param; + CONSOLE_OUT + (">> Send Config Model Publication Get\n"); + CONSOLE_OUT + ("Enter ElementAddress (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.element_address = (UINT16)choice; + CONSOLE_OUT + ("Enter ModelIdentifier\n"); + CONSOLE_OUT + ("Enter Model ID Type. (0 -> SIG, 1 -> Vendor\n"); + CONSOLE_IN + ("%x", &choice); + param.model.type = (UCHAR)choice; + CONSOLE_OUT + ("Enter Model ID.\n"); + CONSOLE_IN + ("%x", &choice); + param.model.id = (UINT32)choice; + retval = MS_config_client_model_publication_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Network Transmit Get */ +void appl_send_config_network_transmit_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Config Network Transmit Get\n"); + retval = MS_config_client_network_transmit_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Composition Data Get */ +void appl_send_config_composition_data_get(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_COMPDATA_GET_PARAM param; + CONSOLE_OUT + (">> Send Config Composition Data Get\n"); + CONSOLE_OUT + ("Enter Page (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.page = (UCHAR)choice; + retval = MS_config_client_composition_data_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Appkey Add */ +void appl_send_config_appkey_add(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_APPKEY_ADD_PARAM param; + CONSOLE_OUT + (">> Send Config Appkey Add\n"); + CONSOLE_OUT + ("Enter NetKeyIndex (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.netkey_index = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKeyIndex (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.appkey_index = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKey (16-octets in HEX)\n"); + { + UINT16 index; + + for(index = 0; index < 16; index++) + { + CONSOLE_IN + ("%x", &choice); + param.appkey[index] = (UCHAR)choice; + } + } + retval = MS_config_client_appkey_add(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Key Refresh Phase Set */ +void appl_send_config_key_refresh_phase_set(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_KEYREFRESH_PHASE_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Key Refresh Phase Set\n"); + CONSOLE_OUT + ("Enter NetKeyIndex (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.netkey_index = (UINT16)choice; + CONSOLE_OUT + ("Enter Transition (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition = (UCHAR)choice; + /* Change Local State as well */ + MS_access_cm_set_key_refresh_phase + ( + 0, /* subnet_handle */ + ¶m.transition /* key_refresh_state */ + ); + param.transition = (UCHAR)choice; + retval = MS_config_client_keyrefresh_phase_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Appkey Get */ +void appl_send_config_appkey_get(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_APPKEY_GET_PARAM param; + CONSOLE_OUT + (">> Send Config Appkey Get\n"); + CONSOLE_OUT + ("Enter NetKeyIndex (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.netkey_index = (UINT16)choice; + retval = MS_config_client_appkey_get(¶m); +} + +/* Send Config Appkey Delete */ +void appl_send_config_appkey_delete(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_APPKEY_DELETE_PARAM param; + CONSOLE_OUT + (">> Send Config Appkey Delete\n"); + CONSOLE_OUT + ("Enter NetKeyIndex (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.netkey_index = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKeyIndex (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.appkey_index = (UINT16)choice; + retval = MS_config_client_appkey_delete(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Config Low Power Node Polltimeout Get */ +void appl_send_config_low_power_node_polltimeout_get(void) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_LPNPOLLTIMEOUT_GET_PARAM param; + CONSOLE_OUT + (">> Send Config Low Power Node Polltimeout Get\n"); + CONSOLE_OUT + ("Enter LPNAddress (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.lpn_address = (UINT16)choice; + retval = MS_config_client_lpn_polltimeout_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + + +/* Get Model Handle */ +void appl_config_client_get_model_handle(void) +{ + #if 0 + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_config_client_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + #endif /* 0 */ + return; +} + + +/* Set Publish Address */ +void appl_config_client_set_publish_address(void) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + #if 0 + CONSOLE_OUT + ("Enter Model Handle (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + model_handle = (UINT16)choice; + #else + model_handle = appl_config_client_model_handle; + #endif /* 0 */ + CONSOLE_OUT + ("Enter Configuration client Server Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.addr.addr = (UINT16)choice; + #if 0 + CONSOLE_OUT + ("Enter AppKey Index\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.appkey_index = choice; + #else + publish_info.appkey_index = MS_CONFIG_LIMITS(MS_MAX_APPS); + #endif /* 0 */ + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return; +} + +/* Decode and print composition data */ +#ifdef APPL_CONFIG_CLIENT_PRINT_COMP_DATA +void appl_config_client_print_composition_data +( + /* IN */ UCHAR* comp_data, + /* IN */ UINT16 data_len +) +{ + UINT16 marker; + UINT16 u16_val, elem_index; + marker = 0; + CONSOLE_OUT("[Composition Data]\n"); + appl_dump_bytes(comp_data, data_len); + /* Page 0 */ + CONSOLE_OUT("Page 0: 0x%02X\n", comp_data[marker]); + marker++; + /* CID */ + MS_UNPACK_LE_2_BYTE(&u16_val, &comp_data[marker]); + CONSOLE_OUT("CID: 0x%04X\n", u16_val); + marker += 2; + /* PID */ + MS_UNPACK_LE_2_BYTE(&u16_val, &comp_data[marker]); + CONSOLE_OUT("PID: 0x%04X\n", u16_val); + marker += 2; + /* VID */ + MS_UNPACK_LE_2_BYTE(&u16_val, &comp_data[marker]); + CONSOLE_OUT("VID: 0x%04X\n", u16_val); + marker += 2; + /* CRPL */ + MS_UNPACK_LE_2_BYTE(&u16_val, &comp_data[marker]); + CONSOLE_OUT("CRPL: 0x%04X\n", u16_val); + marker += 2; + /* Features */ + MS_UNPACK_LE_2_BYTE(&u16_val, &comp_data[marker]); + CONSOLE_OUT("Features: 0x%04X\n", u16_val); + marker += 2; + elem_index = 0; + + while (marker < data_len) + { + UINT32 u32_val; + UINT16 nums, numv, index; + /* LOC */ + MS_UNPACK_LE_2_BYTE(&u16_val, &comp_data[marker]); + CONSOLE_OUT("LOC: 0x%04X\n", u16_val); + marker += 2; + /* NumS */ + MS_UNPACK_LE_2_BYTE(&nums, &comp_data[marker]); + CONSOLE_OUT("NumS: 0x%04X\n", nums); + marker += 2; + /* NumV */ + MS_UNPACK_LE_2_BYTE(&numv, &comp_data[marker]); + CONSOLE_OUT("NumV: 0x%04X\n", numv); + marker += 2; + + /* Print SIG Model IDs */ + for (index = 0; index < nums; index++) + { + MS_UNPACK_LE_2_BYTE(&u16_val, &comp_data[marker]); + CONSOLE_OUT("SIG Model[%d]: 0x%04X\n", index, u16_val); + marker += 2; + } + + /* Print Vendor Model IDs */ + for (index = 0; index < numv; index++) + { + MS_UNPACK_LE_4_BYTE(&u32_val, &comp_data[marker]); + CONSOLE_OUT("Vendor Model[%d]: 0x%08X\n", index, u32_val); + marker += 4; + } + + elem_index++; + continue; + } + + return; +} +#endif /* APPL_CONFIG_CLIENT_PRINT_COMP_DATA */ + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Configuration client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_config_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + +// CONSOLE_OUT ( +// "[CONFIG_CLIENT] Callback. Opcode 0x%04X\n", opcode); + +// appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_CONFIG_GATT_PROXY_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_GATT_PROXY_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_HEARTBEAT_PUBLICATION_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_HEARTBEAT_PUBLICATION_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_SIG_MODEL_APP_LIST_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_SIG_MODEL_APP_LIST_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_COMPOSITION_DATA_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_COMPOSITION_DATA_STATUS_OPCODE\n"); + appl_config_client_print_composition_data(data_param, data_len); + } + break; + + case MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_NETKEY_LIST_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_NETKEY_LIST_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_LOW_POWER_NODE_POLLTIMEOUT_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_LOW_POWER_NODE_POLLTIMEOUT_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_SIG_MODEL_SUBSCRIPTION_LIST_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_SIG_MODEL_SUBSCRIPTION_LIST_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_VENDOR_MODEL_SUBSCRIPTION_LIST_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_VENDOR_MODEL_SUBSCRIPTION_LIST_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_APPKEY_LIST_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_APPKEY_LIST_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_APPKEY_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_APPKEY_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_RELAY_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_RELAY_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_FRIEND_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_FRIEND_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_MODEL_APP_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_MODEL_APP_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_NODE_RESET_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_NODE_RESET_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_DEFAULT_TTL_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_DEFAULT_TTL_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_NODE_IDENTITY_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_NODE_IDENTITY_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_HEARTBEAT_SUBSCRIPTION_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_HEARTBEAT_SUBSCRIPTION_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_KEY_REFRESH_PHASE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_KEY_REFRESH_PHASE_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_NETWORK_TRANSMIT_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_NETWORK_TRANSMIT_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_BEACON_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_BEACON_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_MODEL_PUBLICATION_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_MODEL_PUBLICATION_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_NETKEY_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_NETKEY_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_VENDOR_MODEL_APP_LIST_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_VENDOR_MODEL_APP_LIST_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_config_client.h b/src/components/ethermind/mesh/export/appl/model/client/appl_config_client.h new file mode 100644 index 0000000..bb87875 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_config_client.h @@ -0,0 +1,198 @@ +/** + \file appl_config_client.h + + \brief This file defines the Mesh Configuration Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_CONFIG_CLIENT_ +#define _H_APPL_CONFIG_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_config_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* config client application entry point */ +void main_config_client_operations(void); + +/* Send Config Model App Unbind */ +void appl_send_config_model_app_unbind(void); + +/* Send Config Friend Get */ +void appl_send_config_friend_get(void); + +/* Send Config Gatt Proxy Get */ +void appl_send_config_gatt_proxy_get(void); + +/* Send Config Model Subscription Virtual Address Overwrite */ +void appl_send_config_model_subscription_virtual_address_overwrite(void); + +/* Send Config Sig Model App Get */ +void appl_send_config_sig_model_app_get(void); + +/* Send Config Model Subscription Add */ +void appl_send_config_model_subscription_add(void); + +/* Send Config Network Transmit Set */ +void appl_send_config_network_transmit_set(void); + +/* Send Config Model Subscription Delete */ +void appl_send_config_model_subscription_delete(void); + +/* Send Config Relay Get */ +void appl_send_config_relay_get(void); + +/* Send Config Heartbeat Subscription Set */ +void appl_send_config_heartbeat_subscription_set(void); + +/* Send Config Beacon Set */ +void appl_send_config_beacon_set(void); + +/* Send Config Node Reset */ +void appl_send_config_node_reset(void); + +/* Send Config Relay Set */ +void appl_send_config_relay_set(void); + +/* Send Config Key Refresh Phase Get */ +void appl_send_config_key_refresh_phase_get(void); + +/* Send Config Model Subscription Virtual Address Delete */ +void appl_send_config_model_subscription_virtual_address_delete(void); + +/* Send Config Model Publication Virtual Address Set */ +void appl_send_config_model_publication_virtual_address_set(void); + +/* Send Config Gatt Proxy Set */ +void appl_send_config_gatt_proxy_set(void); + +/* Send Config Model Subscription Virtual Address Add */ +void appl_send_config_model_subscription_virtual_address_add(void); + +/* Send Config Default Ttl Get */ +void appl_send_config_default_ttl_get(void); + +/* Send Config Model App Bind */ +void appl_send_config_model_app_bind(void); + +/* Send Config Node Identity Set */ +void appl_send_config_node_identity_set(void); + +/* Send Config Sig Model Subscription Get */ +void appl_send_config_sig_model_subscription_get(void); + +/* Send Config Netkey Add */ +void appl_send_config_netkey_add(void); + +/* Send Config Appkey Update */ +void appl_send_config_appkey_update(void); + +/* Send Config Heartbeat Subscription Get */ +void appl_send_config_heartbeat_subscription_get(void); + +/* Send Config Vendor Model Subscription Get */ +void appl_send_config_vendor_model_subscription_get(void); + +/* Send Config Vendor Model App Get */ +void appl_send_config_vendor_model_app_get(void); + +/* Send Config Model Subscription Overwrite */ +void appl_send_config_model_subscription_overwrite(void); + +/* Send Config Beacon Get */ +void appl_send_config_beacon_get(void); + +/* Send Config Model Subscription Delete All */ +void appl_send_config_model_subscription_delete_all(void); + +/* Send Config Netkey Delete */ +void appl_send_config_netkey_delete(void); + +/* Send Config Friend Set */ +void appl_send_config_friend_set(void); + +/* Send Config Heartbeat Publication Set */ +void appl_send_config_heartbeat_publication_set(void); + +/* Send Config Node Identity Get */ +void appl_send_config_node_identity_get(void); + +/* Send Config Default Ttl Set */ +void appl_send_config_default_ttl_set(void); + +/* Send Config Netkey Update */ +void appl_send_config_netkey_update(void); + +/* Send Config Heartbeat Publication Get */ +void appl_send_config_heartbeat_publication_get(void); + +/* Send Config Model Publication Set */ +void appl_send_config_model_publication_set(void); + +/* Send Config Netkey Get */ +void appl_send_config_netkey_get(void); + +/* Send Config Model Publication Get */ +void appl_send_config_model_publication_get(void); + +/* Send Config Network Transmit Get */ +void appl_send_config_network_transmit_get(void); + +/* Send Config Composition Data Get */ +void appl_send_config_composition_data_get(void); + +/* Send Config Appkey Add */ +void appl_send_config_appkey_add(void); + +/* Send Config Key Refresh Phase Set */ +void appl_send_config_key_refresh_phase_set(void); + +/* Send Config Appkey Get */ +void appl_send_config_appkey_get(void); + +/* Send Config Appkey Delete */ +void appl_send_config_appkey_delete(void); + +/* Send Config Low Power Node Polltimeout Get */ +void appl_send_config_low_power_node_polltimeout_get(void); + +/* Get Model Handle */ +void appl_config_client_get_model_handle(void); + +/* Set Publish Address */ +void appl_config_client_set_publish_address(void); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Configuration client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_config_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_APPL_CONFIG_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_generic_battery_client.c b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_battery_client.c new file mode 100644 index 0000000..db0dfae --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_battery_client.c @@ -0,0 +1,233 @@ +/** + \file appl_generic_battery_client.c + + \brief This file defines the Mesh Generic Battery Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_generic_battery_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_generic_battery_client_options[] = "\n\ +======== Generic_Battery Client Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 10. Send Generic Battery Get. \n\ + \n\ + 11. Get Model Handle. \n\ + 12. Set Publish Address. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_battery_client_model_handle; + + +/* --------------------------------------------- Function */ +/* generic_battery client application entry point */ +void main_generic_battery_client_operations(void) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_battery_client_init + ( + element_handle, + &appl_generic_battery_client_model_handle, + appl_generic_battery_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Battery Client Initialized. Model Handle: 0x%04X\n", + appl_generic_battery_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Battery Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_generic_battery_client_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 10: /* Send Generic Battery Get */ + appl_send_generic_battery_get(); + break; + + case 11: /* Get Model Handle */ + appl_generic_battery_client_get_model_handle(); + break; + + case 12: /* Set Publish Address */ + appl_generic_battery_client_set_publish_address(); + break; + } + } +} + +/* Send Generic Battery Get */ +void appl_send_generic_battery_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Battery Get\n"); + retval = MS_generic_battery_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + + +/* Get Model Handle */ +void appl_generic_battery_client_get_model_handle(void) +{ + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_generic_battery_client_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + return; +} + + +/* Set Publish Address */ +void appl_generic_battery_client_set_publish_address(void) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + CONSOLE_OUT + ("Enter Model Handle (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + model_handle = (UINT16)choice; + CONSOLE_OUT + ("Enter Generic_Battery client Server Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKey Index\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.appkey_index = choice; + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Battery client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_generic_battery_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[GENERIC_BATTERY_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_GENERIC_BATTERY_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_BATTERY_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_generic_battery_client.h b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_battery_client.h new file mode 100644 index 0000000..175df36 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_battery_client.h @@ -0,0 +1,60 @@ +/** + \file appl_generic_battery_client.h + + \brief This file defines the Mesh Generic Battery Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_GENERIC_BATTERY_CLIENT_ +#define _H_APPL_GENERIC_BATTERY_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_battery_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_battery client application entry point */ +void main_generic_battery_client_operations(void); + +/* Send Generic Battery Get */ +void appl_send_generic_battery_get(void); + +/* Get Model Handle */ +void appl_generic_battery_client_get_model_handle(void); + +/* Set Publish Address */ +void appl_generic_battery_client_set_publish_address(void); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Battery client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_generic_battery_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_APPL_GENERIC_BATTERY_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_generic_default_transition_time_client.c b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_default_transition_time_client.c new file mode 100644 index 0000000..2a2cb51 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_default_transition_time_client.c @@ -0,0 +1,289 @@ +/** + \file appl_generic_default_transition_time_client.c + + \brief This file defines the Mesh Generic Default Transition Time Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_generic_default_transition_time_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_generic_default_transition_time_client_options[] = "\n\ +======== Generic_Default_Transition_Time Client Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 10. Send Generic Default Transition Time Get. \n\ + 11. Send Generic Default Transition Time Set. \n\ + 12. Send Generic Default Transition Time Set Unacknowledged. \n\ + \n\ + 13. Get Model Handle. \n\ + 14. Set Publish Address. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_default_transition_time_client_model_handle; + + +/* --------------------------------------------- Function */ +/* generic_default_transition_time client application entry point */ +void main_generic_default_transition_time_client_operations(void) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_default_transition_time_client_init + ( + element_handle, + &appl_generic_default_transition_time_client_model_handle, + appl_generic_default_transition_time_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Default Transition Time Client Initialized. Model Handle: 0x%04X\n", + appl_generic_default_transition_time_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Default Transition Time Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_generic_default_transition_time_client_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 10: /* Send Generic Default Transition Time Get */ + appl_send_generic_default_transition_time_get(); + break; + + case 11: /* Send Generic Default Transition Time Set */ + appl_send_generic_default_transition_time_set(); + break; + + case 12: /* Send Generic Default Transition Time Set Unacknowledged */ + appl_send_generic_default_transition_time_set_unacknowledged(); + break; + + case 13: /* Get Model Handle */ + appl_generic_default_transition_time_client_get_model_handle(); + break; + + case 14: /* Set Publish Address */ + appl_generic_default_transition_time_client_set_publish_address(); + break; + } + } +} + +/* Send Generic Default Transition Time Get */ +void appl_send_generic_default_transition_time_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Default Transition Time Get\n"); + retval = MS_generic_default_transition_time_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Default Transition Time Set */ +void appl_send_generic_default_transition_time_set(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_DEFAULT_TRANSITION_TIME_STRUCT param; + CONSOLE_OUT + (">> Send Generic Default Transition Time Set\n"); + CONSOLE_OUT + ("Enter Transition Number of Steps (6-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_number_of_steps = (UCHAR)choice; + CONSOLE_OUT + ("Enter Transition Step Resolution (2-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_step_resolution = (UCHAR)choice; + retval = MS_generic_default_transition_time_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Default Transition Time Set Unacknowledged */ +void appl_send_generic_default_transition_time_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_DEFAULT_TRANSITION_TIME_STRUCT param; + CONSOLE_OUT + (">> Send Generic Default Transition Time Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Transition Number of Steps (6-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_number_of_steps = (UCHAR)choice; + CONSOLE_OUT + ("Enter Transition Step Resolution (2-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_step_resolution = (UCHAR)choice; + retval = MS_generic_default_transition_time_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + + +/* Get Model Handle */ +void appl_generic_default_transition_time_client_get_model_handle(void) +{ + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_generic_default_transition_time_client_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + return; +} + + +/* Set Publish Address */ +void appl_generic_default_transition_time_client_set_publish_address(void) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + CONSOLE_OUT + ("Enter Model Handle (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + model_handle = (UINT16)choice; + CONSOLE_OUT + ("Enter Generic_Default_Transition_Time client Server Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKey Index\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.appkey_index = choice; + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Default_Transition_Time client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_generic_default_transition_time_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[GENERIC_DEFAULT_TRANSITION_TIME_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_GENERIC_DEFAULT_TRANSITION_TIME_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_DEFAULT_TRANSITION_TIME_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_generic_default_transition_time_client.h b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_default_transition_time_client.h new file mode 100644 index 0000000..6380b6d --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_default_transition_time_client.h @@ -0,0 +1,66 @@ +/** + \file appl_generic_default_transition_time_client.h + + \brief This file defines the Mesh Generic Default Transition Time Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_GENERIC_DEFAULT_TRANSITION_TIME_CLIENT_ +#define _H_APPL_GENERIC_DEFAULT_TRANSITION_TIME_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_default_transition_time_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_default_transition_time client application entry point */ +void main_generic_default_transition_time_client_operations(void); + +/* Send Generic Default Transition Time Get */ +void appl_send_generic_default_transition_time_get(void); + +/* Send Generic Default Transition Time Set */ +void appl_send_generic_default_transition_time_set(void); + +/* Send Generic Default Transition Time Set Unacknowledged */ +void appl_send_generic_default_transition_time_set_unacknowledged(void); + +/* Get Model Handle */ +void appl_generic_default_transition_time_client_get_model_handle(void); + +/* Set Publish Address */ +void appl_generic_default_transition_time_client_set_publish_address(void); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Default_Transition_Time client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_generic_default_transition_time_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_APPL_GENERIC_DEFAULT_TRANSITION_TIME_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_generic_level_client.c b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_level_client.c new file mode 100644 index 0000000..6a80f81 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_level_client.c @@ -0,0 +1,545 @@ +/** + \file appl_generic_level_client.c + + \brief This file defines the Mesh Generic Level Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_generic_level_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_generic_level_client_options[] = "\n\ +======== Generic_Level Client Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 10. Send Generic Delta Set. \n\ + 11. Send Generic Delta Set Unacknowledged. \n\ + 12. Send Generic Level Get. \n\ + 13. Send Generic Level Set. \n\ + 14. Send Generic Level Set Unacknowledged. \n\ + 15. Send Generic Move Set. \n\ + 16. Send Generic Move Set Unacknowledged. \n\ + \n\ + 17. Get Model Handle. \n\ + 18. Set Publish Address. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_level_client_model_handle; + + +/* --------------------------------------------- Function */ +/* generic_level client application entry point */ +void main_generic_level_client_operations(void) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_level_client_init + ( + element_handle, + &appl_generic_level_client_model_handle, + appl_generic_level_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Level Client Initialized. Model Handle: 0x%04X\n", + appl_generic_level_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Level Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_generic_level_client_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 10: /* Send Generic Delta Set */ + appl_send_generic_delta_set(); + break; + + case 11: /* Send Generic Delta Set Unacknowledged */ + appl_send_generic_delta_set_unacknowledged(); + break; + + case 12: /* Send Generic Level Get */ + appl_send_generic_level_get(); + break; + + case 13: /* Send Generic Level Set */ + appl_send_generic_level_set(); + break; + + case 14: /* Send Generic Level Set Unacknowledged */ + appl_send_generic_level_set_unacknowledged(); + break; + + case 15: /* Send Generic Move Set */ + appl_send_generic_move_set(); + break; + + case 16: /* Send Generic Move Set Unacknowledged */ + appl_send_generic_move_set_unacknowledged(); + break; + + case 17: /* Get Model Handle */ + appl_generic_level_client_get_model_handle(); + break; + + case 18: /* Set Publish Address */ + appl_generic_level_client_set_publish_address(); + break; + } + } +} + +/* Send Generic Delta Set */ +void appl_send_generic_delta_set(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_DELTA_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Delta Set\n"); + CONSOLE_OUT + ("Enter Delta Level (32-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delta_level = (UINT32)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_generic_delta_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Delta Set Unacknowledged */ +void appl_send_generic_delta_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_DELTA_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Delta Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Delta Level (32-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delta_level = (UINT32)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_generic_delta_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Level Get */ +void appl_send_generic_level_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Level Get\n"); + retval = MS_generic_level_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Level Set */ +void appl_send_generic_level_set(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_LEVEL_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Level Set\n"); + CONSOLE_OUT + ("Enter Level (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.level = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_generic_level_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Level Set Unacknowledged */ +void appl_send_generic_level_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_LEVEL_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Level Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Level (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.level = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_generic_level_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Move Set */ +void appl_send_generic_move_set(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_MOVE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Move Set\n"); + CONSOLE_OUT + ("Enter Delta Level (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delta_level = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_generic_move_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Move Set Unacknowledged */ +void appl_send_generic_move_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_MOVE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Move Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Delta Level (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delta_level = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_generic_move_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + + +/* Get Model Handle */ +void appl_generic_level_client_get_model_handle(void) +{ + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_generic_level_client_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + return; +} + + +/* Set Publish Address */ +void appl_generic_level_client_set_publish_address(void) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + CONSOLE_OUT + ("Enter Model Handle (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + model_handle = (UINT16)choice; + CONSOLE_OUT + ("Enter Generic_Level client Server Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKey Index\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.appkey_index = choice; + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Level client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_generic_level_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[GENERIC_LEVEL_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_GENERIC_LEVEL_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_LEVEL_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_generic_level_client.h b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_level_client.h new file mode 100644 index 0000000..01f1c99 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_level_client.h @@ -0,0 +1,78 @@ +/** + \file appl_generic_level_client.h + + \brief This file defines the Mesh Generic Level Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_GENERIC_LEVEL_CLIENT_ +#define _H_APPL_GENERIC_LEVEL_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_level_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_level client application entry point */ +void main_generic_level_client_operations(void); + +/* Send Generic Delta Set */ +void appl_send_generic_delta_set(void); + +/* Send Generic Delta Set Unacknowledged */ +void appl_send_generic_delta_set_unacknowledged(void); + +/* Send Generic Level Get */ +void appl_send_generic_level_get(void); + +/* Send Generic Level Set */ +void appl_send_generic_level_set(void); + +/* Send Generic Level Set Unacknowledged */ +void appl_send_generic_level_set_unacknowledged(void); + +/* Send Generic Move Set */ +void appl_send_generic_move_set(void); + +/* Send Generic Move Set Unacknowledged */ +void appl_send_generic_move_set_unacknowledged(void); + +/* Get Model Handle */ +void appl_generic_level_client_get_model_handle(void); + +/* Set Publish Address */ +void appl_generic_level_client_set_publish_address(void); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Level client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_generic_level_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_APPL_GENERIC_LEVEL_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_generic_location_client.c b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_location_client.c new file mode 100644 index 0000000..4be7ad6 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_location_client.c @@ -0,0 +1,408 @@ +/** + \file appl_generic_location_client.c + + \brief This file defines the Mesh Generic Location Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_generic_location_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_generic_location_client_options[] = "\n\ +======== Generic_Location Client Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 10. Send Generic Location Global Get. \n\ + 11. Send Generic Location Global Set. \n\ + 12. Send Generic Location Global Set Unacknowledged. \n\ + 13. Send Generic Location Local Get. \n\ + 14. Send Generic Location Local Set. \n\ + 15. Send Generic Location Local Set Unacknowledged. \n\ + \n\ + 16. Get Model Handle. \n\ + 17. Set Publish Address. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_location_client_model_handle; + + +/* --------------------------------------------- Function */ +/* generic_location client application entry point */ +void main_generic_location_client_operations(void) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_location_client_init + ( + element_handle, + &appl_generic_location_client_model_handle, + appl_generic_location_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Location Client Initialized. Model Handle: 0x%04X\n", + appl_generic_location_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Location Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_generic_location_client_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 10: /* Send Generic Location Global Get */ + appl_send_generic_location_global_get(); + break; + + case 11: /* Send Generic Location Global Set */ + appl_send_generic_location_global_set(); + break; + + case 12: /* Send Generic Location Global Set Unacknowledged */ + appl_send_generic_location_global_set_unacknowledged(); + break; + + case 13: /* Send Generic Location Local Get */ + appl_send_generic_location_local_get(); + break; + + case 14: /* Send Generic Location Local Set */ + appl_send_generic_location_local_set(); + break; + + case 15: /* Send Generic Location Local Set Unacknowledged */ + appl_send_generic_location_local_set_unacknowledged(); + break; + + case 16: /* Get Model Handle */ + appl_generic_location_client_get_model_handle(); + break; + + case 17: /* Set Publish Address */ + appl_generic_location_client_set_publish_address(); + break; + } + } +} + +/* Send Generic Location Global Get */ +void appl_send_generic_location_global_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Location Global Get\n"); + retval = MS_generic_location_global_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Location Global Set */ +void appl_send_generic_location_global_set(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_LOCATION_GLOBAL_STRUCT param; + CONSOLE_OUT + (">> Send Generic Location Global Set\n"); + CONSOLE_OUT + ("Enter Global Latitude (32-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.global_latitude = (UINT32)choice; + CONSOLE_OUT + ("Enter Global Longitude (32-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.global_longitude = (UINT32)choice; + CONSOLE_OUT + ("Enter Global Altitude (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.global_altitude = (UINT16)choice; + retval = MS_generic_location_global_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Location Global Set Unacknowledged */ +void appl_send_generic_location_global_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_LOCATION_GLOBAL_STRUCT param; + CONSOLE_OUT + (">> Send Generic Location Global Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Global Latitude (32-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.global_latitude = (UINT32)choice; + CONSOLE_OUT + ("Enter Global Longitude (32-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.global_longitude = (UINT32)choice; + CONSOLE_OUT + ("Enter Global Altitude (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.global_altitude = (UINT16)choice; + retval = MS_generic_location_global_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Location Local Get */ +void appl_send_generic_location_local_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Location Local Get\n"); + retval = MS_generic_location_local_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Location Local Set */ +void appl_send_generic_location_local_set(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_LOCATION_LOCAL_STRUCT param; + CONSOLE_OUT + (">> Send Generic Location Local Set\n"); + CONSOLE_OUT + ("Enter Local North (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.local_north = (UINT16)choice; + CONSOLE_OUT + ("Enter Local East (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.local_east = (UINT16)choice; + CONSOLE_OUT + ("Enter Local Altitude (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.local_altitude = (UINT16)choice; + CONSOLE_OUT + ("Enter Floor Number (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.floor_number = (UCHAR)choice; + CONSOLE_OUT + ("Enter Uncertainty (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.uncertainty = (UINT16)choice; + retval = MS_generic_location_local_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Location Local Set Unacknowledged */ +void appl_send_generic_location_local_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_LOCATION_LOCAL_STRUCT param; + CONSOLE_OUT + (">> Send Generic Location Local Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Local North (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.local_north = (UINT16)choice; + CONSOLE_OUT + ("Enter Local East (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.local_east = (UINT16)choice; + CONSOLE_OUT + ("Enter Local Altitude (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.local_altitude = (UINT16)choice; + CONSOLE_OUT + ("Enter Floor Number (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.floor_number = (UCHAR)choice; + CONSOLE_OUT + ("Enter Uncertainty (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.uncertainty = (UINT16)choice; + retval = MS_generic_location_local_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + + +/* Get Model Handle */ +void appl_generic_location_client_get_model_handle(void) +{ + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_generic_location_client_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + return; +} + + +/* Set Publish Address */ +void appl_generic_location_client_set_publish_address(void) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + CONSOLE_OUT + ("Enter Model Handle (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + model_handle = (UINT16)choice; + CONSOLE_OUT + ("Enter Generic_Location client Server Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKey Index\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.appkey_index = choice; + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Location client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_generic_location_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[GENERIC_LOCATION_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_GENERIC_LOCATION_GLOBAL_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_LOCATION_GLOBAL_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_GENERIC_LOCATION_LOCAL_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_LOCATION_LOCAL_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_generic_location_client.h b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_location_client.h new file mode 100644 index 0000000..a96eb7d --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_location_client.h @@ -0,0 +1,75 @@ +/** + \file appl_generic_location_client.h + + \brief This file defines the Mesh Generic Location Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_GENERIC_LOCATION_CLIENT_ +#define _H_APPL_GENERIC_LOCATION_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_location_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_location client application entry point */ +void main_generic_location_client_operations(void); + +/* Send Generic Location Global Get */ +void appl_send_generic_location_global_get(void); + +/* Send Generic Location Global Set */ +void appl_send_generic_location_global_set(void); + +/* Send Generic Location Global Set Unacknowledged */ +void appl_send_generic_location_global_set_unacknowledged(void); + +/* Send Generic Location Local Get */ +void appl_send_generic_location_local_get(void); + +/* Send Generic Location Local Set */ +void appl_send_generic_location_local_set(void); + +/* Send Generic Location Local Set Unacknowledged */ +void appl_send_generic_location_local_set_unacknowledged(void); + +/* Get Model Handle */ +void appl_generic_location_client_get_model_handle(void); + +/* Set Publish Address */ +void appl_generic_location_client_set_publish_address(void); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Location client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_generic_location_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_APPL_GENERIC_LOCATION_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_generic_onoff_client.c b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_onoff_client.c new file mode 100644 index 0000000..1f280a4 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_onoff_client.c @@ -0,0 +1,343 @@ +/** + \file appl_generic_onoff_client.c + + \brief This file defines the Mesh Generic Onoff Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_generic_onoff_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_generic_onoff_client_options[] = "\n\ +======== Generic_Onoff Client Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 10. Send Generic Onoff Get. \n\ + 11. Send Generic Onoff Set. \n\ + 12. Send Generic Onoff Set Unacknowledged. \n\ + \n\ + 13. Get Model Handle. \n\ + 14. Set Publish Address. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_onoff_client_model_handle; + + +/* --------------------------------------------- Function */ +/* generic_onoff client application entry point */ +void main_generic_onoff_client_operations(/* IN */ UINT8 have_menu) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_onoff_client_init + ( + element_handle, + &appl_generic_onoff_client_model_handle, + appl_generic_onoff_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Onoff Client Initialized. Model Handle: 0x%04X\n", + appl_generic_onoff_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Onoff Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + if (MS_TRUE != have_menu) + { + CONSOLE_OUT("Not to use menu options\n"); + return; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_generic_onoff_client_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 10: /* Send Generic Onoff Get */ + appl_send_generic_onoff_get(); + break; + + case 11: /* Send Generic Onoff Set */ + appl_send_generic_onoff_set(); + break; + + case 12: /* Send Generic Onoff Set Unacknowledged */ + appl_send_generic_onoff_set_unacknowledged(); + break; + + case 13: /* Get Model Handle */ + appl_generic_onoff_client_get_model_handle(); + break; + + case 14: /* Set Publish Address */ + appl_generic_onoff_client_set_publish_address(); + break; + } + } +} + +/* Send Generic Onoff Get */ +void appl_send_generic_onoff_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Onoff Get\n"); + retval = MS_generic_onoff_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Onoff Set */ +void appl_send_generic_onoff_set(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_ONOFF_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Onoff Set\n"); + CONSOLE_OUT + ("Enter OnOff (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.onoff = (UCHAR)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_generic_onoff_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Onoff Set Unacknowledged */ +void appl_send_generic_onoff_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_ONOFF_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Onoff Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter OnOff (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.onoff = (UCHAR)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_generic_onoff_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + + +/* Get Model Handle */ +void appl_generic_onoff_client_get_model_handle(void) +{ + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_generic_onoff_client_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + return; +} + + +/* Set Publish Address */ +void appl_generic_onoff_client_set_publish_address(void) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + CONSOLE_OUT + ("Enter Model Handle (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + model_handle = (UINT16)choice; + CONSOLE_OUT + ("Enter Generic_Onoff client Server Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKey Index\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.appkey_index = choice; + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_generic_onoff_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[GENERIC_ONOFF_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_GENERIC_ONOFF_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_ONOFF_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_generic_onoff_client.h b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_onoff_client.h new file mode 100644 index 0000000..7b9df77 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_onoff_client.h @@ -0,0 +1,66 @@ +/** + \file appl_generic_onoff_client.h + + \brief This file defines the Mesh Generic Onoff Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_GENERIC_ONOFF_CLIENT_ +#define _H_APPL_GENERIC_ONOFF_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_onoff_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_onoff client application entry point */ +void main_generic_onoff_client_operations(/* IN */ UINT8 have_menu); + +/* Send Generic Onoff Get */ +void appl_send_generic_onoff_get(void); + +/* Send Generic Onoff Set */ +void appl_send_generic_onoff_set(void); + +/* Send Generic Onoff Set Unacknowledged */ +void appl_send_generic_onoff_set_unacknowledged(void); + +/* Get Model Handle */ +void appl_generic_onoff_client_get_model_handle(void); + +/* Set Publish Address */ +void appl_generic_onoff_client_set_publish_address(void); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_generic_onoff_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_APPL_GENERIC_ONOFF_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_generic_power_level_client.c b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_power_level_client.c new file mode 100644 index 0000000..af4741c --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_power_level_client.c @@ -0,0 +1,508 @@ +/** + \file appl_generic_power_level_client.c + + \brief This file defines the Mesh Generic Power Level Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_generic_power_level_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_generic_power_level_client_options[] = "\n\ +======== Generic_Power_Level Client Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 10. Send Generic Power Default Get. \n\ + 11. Send Generic Power Default Set. \n\ + 12. Send Generic Power Default Set Unacknowledged. \n\ + 13. Send Generic Power Last Get. \n\ + 14. Send Generic Power Level Get. \n\ + 15. Send Generic Power Level Set. \n\ + 16. Send Generic Power Level Set Unacknowledged. \n\ + 17. Send Generic Power Range Get. \n\ + 18. Send Generic Power Range Set. \n\ + 19. Send Generic Power Range Set Unacknowledged. \n\ + \n\ + 20. Get Model Handle. \n\ + 21. Set Publish Address. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_power_level_client_model_handle; + + +/* --------------------------------------------- Function */ +/* generic_power_level client application entry point */ +void main_generic_power_level_client_operations(void) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_power_level_client_init + ( + element_handle, + &appl_generic_power_level_client_model_handle, + appl_generic_power_level_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Power Level Client Initialized. Model Handle: 0x%04X\n", + appl_generic_power_level_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Power Level Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_generic_power_level_client_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 10: /* Send Generic Power Default Get */ + appl_send_generic_power_default_get(); + break; + + case 11: /* Send Generic Power Default Set */ + appl_send_generic_power_default_set(); + break; + + case 12: /* Send Generic Power Default Set Unacknowledged */ + appl_send_generic_power_default_set_unacknowledged(); + break; + + case 13: /* Send Generic Power Last Get */ + appl_send_generic_power_last_get(); + break; + + case 14: /* Send Generic Power Level Get */ + appl_send_generic_power_level_get(); + break; + + case 15: /* Send Generic Power Level Set */ + appl_send_generic_power_level_set(); + break; + + case 16: /* Send Generic Power Level Set Unacknowledged */ + appl_send_generic_power_level_set_unacknowledged(); + break; + + case 17: /* Send Generic Power Range Get */ + appl_send_generic_power_range_get(); + break; + + case 18: /* Send Generic Power Range Set */ + appl_send_generic_power_range_set(); + break; + + case 19: /* Send Generic Power Range Set Unacknowledged */ + appl_send_generic_power_range_set_unacknowledged(); + break; + + case 20: /* Get Model Handle */ + appl_generic_power_level_client_get_model_handle(); + break; + + case 21: /* Set Publish Address */ + appl_generic_power_level_client_set_publish_address(); + break; + } + } +} + +/* Send Generic Power Default Get */ +void appl_send_generic_power_default_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Power Default Get\n"); + retval = MS_generic_power_default_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Power Default Set */ +void appl_send_generic_power_default_set(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_POWER_DEFAULT_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Power Default Set\n"); + CONSOLE_OUT + ("Enter Power (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.power = (UINT16)choice; + retval = MS_generic_power_default_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Power Default Set Unacknowledged */ +void appl_send_generic_power_default_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_POWER_DEFAULT_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Power Default Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Power (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.power = (UINT16)choice; + retval = MS_generic_power_default_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Power Last Get */ +void appl_send_generic_power_last_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Power Last Get\n"); + retval = MS_generic_power_last_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Power Level Get */ +void appl_send_generic_power_level_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Power Level Get\n"); + retval = MS_generic_power_level_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Power Level Set */ +void appl_send_generic_power_level_set(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_POWER_LEVEL_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Power Level Set\n"); + CONSOLE_OUT + ("Enter Power (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.power = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_generic_power_level_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Power Level Set Unacknowledged */ +void appl_send_generic_power_level_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_POWER_LEVEL_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Power Level Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Power (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.power = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_generic_power_level_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Power Range Get */ +void appl_send_generic_power_range_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Power Range Get\n"); + retval = MS_generic_power_range_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Power Range Set */ +void appl_send_generic_power_range_set(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_POWER_RANGE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Power Range Set\n"); + CONSOLE_OUT + ("Enter Range Min (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.range_min = (UINT16)choice; + CONSOLE_OUT + ("Enter Range Max (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.range_max = (UINT16)choice; + retval = MS_generic_power_range_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Power Range Set Unacknowledged */ +void appl_send_generic_power_range_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_POWER_RANGE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Power Range Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Range Min (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.range_min = (UINT16)choice; + CONSOLE_OUT + ("Enter Range Max (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.range_max = (UINT16)choice; + retval = MS_generic_power_range_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + + +/* Get Model Handle */ +void appl_generic_power_level_client_get_model_handle(void) +{ + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_generic_power_level_client_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + return; +} + + +/* Set Publish Address */ +void appl_generic_power_level_client_set_publish_address(void) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + CONSOLE_OUT + ("Enter Model Handle (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + model_handle = (UINT16)choice; + CONSOLE_OUT + ("Enter Generic_Power_Level client Server Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKey Index\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.appkey_index = choice; + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Level client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_generic_power_level_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[GENERIC_POWER_LEVEL_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_GENERIC_POWER_DEFAULT_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_POWER_DEFAULT_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_GENERIC_POWER_LAST_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_POWER_LAST_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_GENERIC_POWER_LEVEL_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_POWER_LEVEL_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_GENERIC_POWER_RANGE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_POWER_RANGE_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_generic_power_level_client.h b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_power_level_client.h new file mode 100644 index 0000000..463bf1c --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_power_level_client.h @@ -0,0 +1,87 @@ +/** + \file appl_generic_power_level_client.h + + \brief This file defines the Mesh Generic Power Level Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_GENERIC_POWER_LEVEL_CLIENT_ +#define _H_APPL_GENERIC_POWER_LEVEL_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_power_level_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_power_level client application entry point */ +void main_generic_power_level_client_operations(void); + +/* Send Generic Power Default Get */ +void appl_send_generic_power_default_get(void); + +/* Send Generic Power Default Set */ +void appl_send_generic_power_default_set(void); + +/* Send Generic Power Default Set Unacknowledged */ +void appl_send_generic_power_default_set_unacknowledged(void); + +/* Send Generic Power Last Get */ +void appl_send_generic_power_last_get(void); + +/* Send Generic Power Level Get */ +void appl_send_generic_power_level_get(void); + +/* Send Generic Power Level Set */ +void appl_send_generic_power_level_set(void); + +/* Send Generic Power Level Set Unacknowledged */ +void appl_send_generic_power_level_set_unacknowledged(void); + +/* Send Generic Power Range Get */ +void appl_send_generic_power_range_get(void); + +/* Send Generic Power Range Set */ +void appl_send_generic_power_range_set(void); + +/* Send Generic Power Range Set Unacknowledged */ +void appl_send_generic_power_range_set_unacknowledged(void); + +/* Get Model Handle */ +void appl_generic_power_level_client_get_model_handle(void); + +/* Set Publish Address */ +void appl_generic_power_level_client_set_publish_address(void); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Level client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_generic_power_level_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_APPL_GENERIC_POWER_LEVEL_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_generic_power_onoff_client.c b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_power_onoff_client.c new file mode 100644 index 0000000..e20fb8a --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_power_onoff_client.c @@ -0,0 +1,279 @@ +/** + \file appl_generic_power_onoff_client.c + + \brief This file defines the Mesh Generic Power Onoff Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_generic_power_onoff_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_generic_power_onoff_client_options[] = "\n\ +======== Generic_Power_Onoff Client Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 10. Send Generic Onpowerup Get. \n\ + 11. Send Generic Onpowerup Set. \n\ + 12. Send Generic Onpowerup Set Unacknowledged. \n\ + \n\ + 13. Get Model Handle. \n\ + 14. Set Publish Address. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_power_onoff_client_model_handle; + + +/* --------------------------------------------- Function */ +/* generic_power_onoff client application entry point */ +void main_generic_power_onoff_client_operations(void) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_power_onoff_client_init + ( + element_handle, + &appl_generic_power_onoff_client_model_handle, + appl_generic_power_onoff_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Power Onoff Client Initialized. Model Handle: 0x%04X\n", + appl_generic_power_onoff_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Power Onoff Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_generic_power_onoff_client_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 10: /* Send Generic Onpowerup Get */ + appl_send_generic_onpowerup_get(); + break; + + case 11: /* Send Generic Onpowerup Set */ + appl_send_generic_onpowerup_set(); + break; + + case 12: /* Send Generic Onpowerup Set Unacknowledged */ + appl_send_generic_onpowerup_set_unacknowledged(); + break; + + case 13: /* Get Model Handle */ + appl_generic_power_onoff_client_get_model_handle(); + break; + + case 14: /* Set Publish Address */ + appl_generic_power_onoff_client_set_publish_address(); + break; + } + } +} + +/* Send Generic Onpowerup Get */ +void appl_send_generic_onpowerup_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Onpowerup Get\n"); + retval = MS_generic_onpowerup_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Onpowerup Set */ +void appl_send_generic_onpowerup_set(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_ONPOWERUP_STRUCT param; + CONSOLE_OUT + (">> Send Generic Onpowerup Set\n"); + CONSOLE_OUT + ("Enter OnPowerUp (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.onpowerup = (UCHAR)choice; + retval = MS_generic_onpowerup_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Onpowerup Set Unacknowledged */ +void appl_send_generic_onpowerup_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_ONPOWERUP_STRUCT param; + CONSOLE_OUT + (">> Send Generic Onpowerup Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter OnPowerUp (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.onpowerup = (UCHAR)choice; + retval = MS_generic_onpowerup_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + + +/* Get Model Handle */ +void appl_generic_power_onoff_client_get_model_handle(void) +{ + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_generic_power_onoff_client_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + return; +} + + +/* Set Publish Address */ +void appl_generic_power_onoff_client_set_publish_address(void) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + CONSOLE_OUT + ("Enter Model Handle (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + model_handle = (UINT16)choice; + CONSOLE_OUT + ("Enter Generic_Power_Onoff client Server Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKey Index\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.appkey_index = choice; + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Onoff client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_generic_power_onoff_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[GENERIC_POWER_ONOFF_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_GENERIC_ONPOWERUP_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_ONPOWERUP_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_generic_power_onoff_client.h b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_power_onoff_client.h new file mode 100644 index 0000000..003c29e --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_power_onoff_client.h @@ -0,0 +1,66 @@ +/** + \file appl_generic_power_onoff_client.h + + \brief This file defines the Mesh Generic Power Onoff Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_GENERIC_POWER_ONOFF_CLIENT_ +#define _H_APPL_GENERIC_POWER_ONOFF_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_power_onoff_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_power_onoff client application entry point */ +void main_generic_power_onoff_client_operations(void); + +/* Send Generic Onpowerup Get */ +void appl_send_generic_onpowerup_get(void); + +/* Send Generic Onpowerup Set */ +void appl_send_generic_onpowerup_set(void); + +/* Send Generic Onpowerup Set Unacknowledged */ +void appl_send_generic_onpowerup_set_unacknowledged(void); + +/* Get Model Handle */ +void appl_generic_power_onoff_client_get_model_handle(void); + +/* Set Publish Address */ +void appl_generic_power_onoff_client_set_publish_address(void); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Onoff client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_generic_power_onoff_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_APPL_GENERIC_POWER_ONOFF_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_generic_property_client.c b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_property_client.c new file mode 100644 index 0000000..dd97cad --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_property_client.c @@ -0,0 +1,685 @@ +/** + \file appl_generic_property_client.c + + \brief This file defines the Mesh Generic Property Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_generic_property_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_generic_property_client_options[] = "\n\ +======== Generic_Property Client Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 10. Send Generic Admin Properties Get. \n\ + 11. Send Generic Admin Property Get. \n\ + 12. Send Generic Admin Property Set. \n\ + 13. Send Generic Admin Property Set Unacknowledged. \n\ + 14. Send Generic Client Properties Get. \n\ + 15. Send Generic Manufacturer Properties Get. \n\ + 16. Send Generic Manufacturer Property Get. \n\ + 17. Send Generic Manufacturer Property Set. \n\ + 18. Send Generic Manufacturer Property Set Unacknowledged. \n\ + 19. Send Generic User Properties Get. \n\ + 20. Send Generic User Property Get. \n\ + 21. Send Generic User Property Set. \n\ + 22. Send Generic User Property Set Unacknowledged. \n\ + \n\ + 23. Get Model Handle. \n\ + 24. Set Publish Address. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_property_client_model_handle; + + +/* --------------------------------------------- Function */ +/* generic_property client application entry point */ +void main_generic_property_client_operations(void) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_property_client_init + ( + element_handle, + &appl_generic_property_client_model_handle, + appl_generic_property_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Property Client Initialized. Model Handle: 0x%04X\n", + appl_generic_property_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Property Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_generic_property_client_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 10: /* Send Generic Admin Properties Get */ + appl_send_generic_admin_properties_get(); + break; + + case 11: /* Send Generic Admin Property Get */ + appl_send_generic_admin_property_get(); + break; + + case 12: /* Send Generic Admin Property Set */ + appl_send_generic_admin_property_set(); + break; + + case 13: /* Send Generic Admin Property Set Unacknowledged */ + appl_send_generic_admin_property_set_unacknowledged(); + break; + + case 14: /* Send Generic Client Properties Get */ + appl_send_generic_client_properties_get(); + break; + + case 15: /* Send Generic Manufacturer Properties Get */ + appl_send_generic_manufacturer_properties_get(); + break; + + case 16: /* Send Generic Manufacturer Property Get */ + appl_send_generic_manufacturer_property_get(); + break; + + case 17: /* Send Generic Manufacturer Property Set */ + appl_send_generic_manufacturer_property_set(); + break; + + case 18: /* Send Generic Manufacturer Property Set Unacknowledged */ + appl_send_generic_manufacturer_property_set_unacknowledged(); + break; + + case 19: /* Send Generic User Properties Get */ + appl_send_generic_user_properties_get(); + break; + + case 20: /* Send Generic User Property Get */ + appl_send_generic_user_property_get(); + break; + + case 21: /* Send Generic User Property Set */ + appl_send_generic_user_property_set(); + break; + + case 22: /* Send Generic User Property Set Unacknowledged */ + appl_send_generic_user_property_set_unacknowledged(); + break; + + case 23: /* Get Model Handle */ + appl_generic_property_client_get_model_handle(); + break; + + case 24: /* Set Publish Address */ + appl_generic_property_client_set_publish_address(); + break; + } + } +} + +/* Send Generic Admin Properties Get */ +void appl_send_generic_admin_properties_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Admin Properties Get\n"); + retval = MS_generic_admin_properties_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Admin Property Get */ +void appl_send_generic_admin_property_get(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_ADMIN_PROPERTY_GET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Admin Property Get\n"); + CONSOLE_OUT + ("Enter Admin Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.admin_property_id = (UINT16)choice; + retval = MS_generic_admin_property_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Admin Property Set */ +void appl_send_generic_admin_property_set(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_ADMIN_PROPERTY_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Admin Property Set\n"); + CONSOLE_OUT + ("Enter Admin Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.admin_property_id = (UINT16)choice; + CONSOLE_OUT + ("Enter Admin User Access (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.admin_user_access = (UCHAR)choice; + CONSOLE_OUT + ("Enter Admin Property Value Length (in decimal)\n"); + CONSOLE_IN + ("%d", &choice); + CONSOLE_OUT + ("Enter Admin Property Value (%d-octets in HEX)\n", (UINT16)choice); + { + UINT16 index, input_len; + input_len = (UINT16)choice; + param.admin_property_value = EM_alloc_mem(input_len); + + if(NULL == param.admin_property_value) + { + CONSOLE_OUT + ("Memory allocation failed for Admin Property Value. Returning\n"); + return; + } + + param.admin_property_value_len = (UINT16) input_len; + + for(index = 0; index < input_len; index++) + { + CONSOLE_IN + ("%x", &choice); + param.admin_property_value[index] = (UCHAR)choice; + } + } + retval = MS_generic_admin_property_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.admin_property_value) + { + EM_free_mem(param.admin_property_value); + } +} + +/* Send Generic Admin Property Set Unacknowledged */ +void appl_send_generic_admin_property_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_ADMIN_PROPERTY_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Admin Property Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Admin Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.admin_property_id = (UINT16)choice; + CONSOLE_OUT + ("Enter Admin User Access (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.admin_user_access = (UCHAR)choice; + CONSOLE_OUT + ("Enter Admin Property Value Length (in decimal)\n"); + CONSOLE_IN + ("%d", &choice); + CONSOLE_OUT + ("Enter Admin Property Value (%d-octets in HEX)\n", (UINT16)choice); + { + UINT16 index, input_len; + input_len = (UINT16)choice; + param.admin_property_value = EM_alloc_mem(input_len); + + if(NULL == param.admin_property_value) + { + CONSOLE_OUT + ("Memory allocation failed for Admin Property Value. Returning\n"); + return; + } + + param.admin_property_value_len = (UINT16) input_len; + + for(index = 0; index < input_len; index++) + { + CONSOLE_IN + ("%x", &choice); + param.admin_property_value[index] = (UCHAR)choice; + } + } + retval = MS_generic_admin_property_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.admin_property_value) + { + EM_free_mem(param.admin_property_value); + } +} + +/* Send Generic Client Properties Get */ +void appl_send_generic_client_properties_get(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_CLIENT_PROPERTIES_GET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Client Properties Get\n"); + CONSOLE_OUT + ("Enter Client Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.client_property_id = (UINT16)choice; + retval = MS_generic_client_properties_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Manufacturer Properties Get */ +void appl_send_generic_manufacturer_properties_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Manufacturer Properties Get\n"); + retval = MS_generic_manufacturer_properties_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Manufacturer Property Get */ +void appl_send_generic_manufacturer_property_get(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_MANUFACTURER_PROPERTY_GET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Manufacturer Property Get\n"); + CONSOLE_OUT + ("Enter Manufacturer Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.manufacturer_property_id = (UINT16)choice; + retval = MS_generic_manufacturer_property_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Manufacturer Property Set */ +void appl_send_generic_manufacturer_property_set(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_MANUFACTURER_PROPERTY_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Manufacturer Property Set\n"); + CONSOLE_OUT + ("Enter Manufacturer Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.manufacturer_property_id = (UINT16)choice; + CONSOLE_OUT + ("Enter Manufacturer User Access (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.manufacturer_user_access = (UCHAR)choice; + retval = MS_generic_manufacturer_property_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic Manufacturer Property Set Unacknowledged */ +void appl_send_generic_manufacturer_property_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_MANUFACTURER_PROPERTY_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Manufacturer Property Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Manufacturer Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.manufacturer_property_id = (UINT16)choice; + CONSOLE_OUT + ("Enter Manufacturer User Access (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.manufacturer_user_access = (UCHAR)choice; + retval = MS_generic_manufacturer_property_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic User Properties Get */ +void appl_send_generic_user_properties_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic User Properties Get\n"); + retval = MS_generic_user_properties_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic User Property Get */ +void appl_send_generic_user_property_get(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_USER_PROPERTY_GET_STRUCT param; + CONSOLE_OUT + (">> Send Generic User Property Get\n"); + CONSOLE_OUT + ("Enter User Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.user_property_id = (UINT16)choice; + retval = MS_generic_user_property_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Generic User Property Set */ +void appl_send_generic_user_property_set(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_USER_PROPERTY_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic User Property Set\n"); + CONSOLE_OUT + ("Enter User Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.user_property_id = (UINT16)choice; + CONSOLE_OUT + ("Enter User Property Value Length (in decimal)\n"); + CONSOLE_IN + ("%d", &choice); + CONSOLE_OUT + ("Enter User Property Value (%d-octets in HEX)\n", (UINT16)choice); + { + UINT16 index, input_len; + input_len = (UINT16)choice; + param.user_property_value = EM_alloc_mem(input_len); + + if(NULL == param.user_property_value) + { + CONSOLE_OUT + ("Memory allocation failed for User Property Value. Returning\n"); + return; + } + + param.user_property_value_len = (UINT16) input_len; + + for(index = 0; index < input_len; index++) + { + CONSOLE_IN + ("%x", &choice); + param.user_property_value[index] = (UCHAR)choice; + } + } + retval = MS_generic_user_property_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.user_property_value) + { + EM_free_mem(param.user_property_value); + } +} + +/* Send Generic User Property Set Unacknowledged */ +void appl_send_generic_user_property_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_GENERIC_USER_PROPERTY_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic User Property Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter User Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.user_property_id = (UINT16)choice; + CONSOLE_OUT + ("Enter User Property Value Length (in decimal)\n"); + CONSOLE_IN + ("%d", &choice); + CONSOLE_OUT + ("Enter User Property Value (%d-octets in HEX)\n", (UINT16)choice); + { + UINT16 index, input_len; + input_len = (UINT16)choice; + param.user_property_value = EM_alloc_mem(input_len); + + if(NULL == param.user_property_value) + { + CONSOLE_OUT + ("Memory allocation failed for User Property Value. Returning\n"); + return; + } + + param.user_property_value_len = (UINT16) input_len; + + for(index = 0; index < input_len; index++) + { + CONSOLE_IN + ("%x", &choice); + param.user_property_value[index] = (UCHAR)choice; + } + } + retval = MS_generic_user_property_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.user_property_value) + { + EM_free_mem(param.user_property_value); + } +} + + +/* Get Model Handle */ +void appl_generic_property_client_get_model_handle(void) +{ + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_generic_property_client_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + return; +} + + +/* Set Publish Address */ +void appl_generic_property_client_set_publish_address(void) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + CONSOLE_OUT + ("Enter Model Handle (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + model_handle = (UINT16)choice; + CONSOLE_OUT + ("Enter Generic_Property client Server Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKey Index\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.appkey_index = choice; + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Property client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_generic_property_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[GENERIC_PROPERTY_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_GENERIC_ADMIN_PROPERTIES_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_ADMIN_PROPERTIES_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_GENERIC_ADMIN_PROPERTY_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_ADMIN_PROPERTY_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_GENERIC_CLIENT_PROPERTIES_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_CLIENT_PROPERTIES_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_GENERIC_MANUFACTURER_PROPERTIES_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_MANUFACTURER_PROPERTIES_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_GENERIC_MANUFACTURER_PROPERTY_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_MANUFACTURER_PROPERTY_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_GENERIC_USER_PROPERTIES_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_USER_PROPERTIES_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_GENERIC_USER_PROPERTY_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_USER_PROPERTY_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_generic_property_client.h b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_property_client.h new file mode 100644 index 0000000..4fadb36 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_generic_property_client.h @@ -0,0 +1,96 @@ +/** + \file appl_generic_property_client.h + + \brief This file defines the Mesh Generic Property Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_GENERIC_PROPERTY_CLIENT_ +#define _H_APPL_GENERIC_PROPERTY_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_property_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_property client application entry point */ +void main_generic_property_client_operations(void); + +/* Send Generic Admin Properties Get */ +void appl_send_generic_admin_properties_get(void); + +/* Send Generic Admin Property Get */ +void appl_send_generic_admin_property_get(void); + +/* Send Generic Admin Property Set */ +void appl_send_generic_admin_property_set(void); + +/* Send Generic Admin Property Set Unacknowledged */ +void appl_send_generic_admin_property_set_unacknowledged(void); + +/* Send Generic Client Properties Get */ +void appl_send_generic_client_properties_get(void); + +/* Send Generic Manufacturer Properties Get */ +void appl_send_generic_manufacturer_properties_get(void); + +/* Send Generic Manufacturer Property Get */ +void appl_send_generic_manufacturer_property_get(void); + +/* Send Generic Manufacturer Property Set */ +void appl_send_generic_manufacturer_property_set(void); + +/* Send Generic Manufacturer Property Set Unacknowledged */ +void appl_send_generic_manufacturer_property_set_unacknowledged(void); + +/* Send Generic User Properties Get */ +void appl_send_generic_user_properties_get(void); + +/* Send Generic User Property Get */ +void appl_send_generic_user_property_get(void); + +/* Send Generic User Property Set */ +void appl_send_generic_user_property_set(void); + +/* Send Generic User Property Set Unacknowledged */ +void appl_send_generic_user_property_set_unacknowledged(void); + +/* Get Model Handle */ +void appl_generic_property_client_get_model_handle(void); + +/* Set Publish Address */ +void appl_generic_property_client_set_publish_address(void); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Property client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_generic_property_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_APPL_GENERIC_PROPERTY_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_health_client.c b/src/components/ethermind/mesh/export/appl/model/client/appl_health_client.c new file mode 100644 index 0000000..c07d13d --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_health_client.c @@ -0,0 +1,492 @@ +/** + \file appl_health_client.c + + \brief This file defines the Mesh Health Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_health_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_health_client_options[] = "\n\ +======== Health Client Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 10. Send Health Attention Get. \n\ + 11. Send Health Attention Set. \n\ + 12. Send Health Attention Set Unacknowledged. \n\ + 13. Send Health Fault Clear. \n\ + 14. Send Health Fault Clear Unacknowledged. \n\ + 15. Send Health Fault Get. \n\ + 16. Send Health Fault Test. \n\ + 17. Send Health Fault Test Unacknowledged. \n\ + 18. Send Health Period Get. \n\ + 19. Send Health Period Set. \n\ + 20. Send Health Period Set Unacknowledged. \n\ + \n\ + 21. Get Model Handle. \n\ + 22. Set Publish Address. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_health_client_model_handle; + + +/* --------------------------------------------- Function */ +/* health client application entry point */ +void main_health_client_operations(void) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_health_client_init + ( + element_handle, + &appl_health_client_model_handle, + appl_health_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Health Client Initialized. Model Handle: 0x%04X\n", + appl_health_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Health Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_health_client_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 10: /* Send Health Attention Get */ + appl_send_health_attention_get(); + break; + + case 11: /* Send Health Attention Set */ + appl_send_health_attention_set(); + break; + + case 12: /* Send Health Attention Set Unacknowledged */ + appl_send_health_attention_set_unacknowledged(); + break; + + case 13: /* Send Health Fault Clear */ + appl_send_health_fault_clear(); + break; + + case 14: /* Send Health Fault Clear Unacknowledged */ + appl_send_health_fault_clear_unacknowledged(); + break; + + case 15: /* Send Health Fault Get */ + appl_send_health_fault_get(); + break; + + case 16: /* Send Health Fault Test */ + appl_send_health_fault_test(); + break; + + case 17: /* Send Health Fault Test Unacknowledged */ + appl_send_health_fault_test_unacknowledged(); + break; + + case 18: /* Send Health Period Get */ + appl_send_health_period_get(); + break; + + case 19: /* Send Health Period Set */ + appl_send_health_period_set(); + break; + + case 20: /* Send Health Period Set Unacknowledged */ + appl_send_health_period_set_unacknowledged(); + break; + + case 21: /* Get Model Handle */ + appl_health_client_get_model_handle(); + break; + + case 22: /* Set Publish Address */ + appl_health_client_set_publish_address(); + break; + } + } +} + +/* Send Health Attention Get */ +void appl_send_health_attention_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Health Attention Get\n"); + retval = MS_health_attention_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Health Attention Set */ +void appl_send_health_attention_set(void) +{ + API_RESULT retval; + int choice; + MS_HEALTH_ATTENTION_STRUCT param; + CONSOLE_OUT + (">> Send Health Attention Set\n"); + CONSOLE_OUT + ("Enter Attention (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.attention = (UCHAR)choice; + retval = MS_health_attention_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Health Attention Set Unacknowledged */ +void appl_send_health_attention_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_HEALTH_ATTENTION_STRUCT param; + CONSOLE_OUT + (">> Send Health Attention Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Attention (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.attention = (UCHAR)choice; + retval = MS_health_attention_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Health Fault Clear */ +void appl_send_health_fault_clear(void) +{ + API_RESULT retval; + int choice; + MS_HEALTH_FAULT_GET_CLEAR_STRUCT param; + CONSOLE_OUT + (">> Send Health Fault Clear\n"); + CONSOLE_OUT + ("Enter Company ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.company_id = (UINT16)choice; + retval = MS_health_fault_clear(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Health Fault Clear Unacknowledged */ +void appl_send_health_fault_clear_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_HEALTH_FAULT_GET_CLEAR_STRUCT param; + CONSOLE_OUT + (">> Send Health Fault Clear Unacknowledged\n"); + CONSOLE_OUT + ("Enter Company ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.company_id = (UINT16)choice; + retval = MS_health_fault_clear_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Health Fault Get */ +void appl_send_health_fault_get(void) +{ + API_RESULT retval; + int choice; + MS_HEALTH_FAULT_GET_CLEAR_STRUCT param; + CONSOLE_OUT + (">> Send Health Fault Get\n"); + CONSOLE_OUT + ("Enter Company ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.company_id = (UINT16)choice; + retval = MS_health_fault_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Health Fault Test */ +void appl_send_health_fault_test(void) +{ + API_RESULT retval; + int choice; + MS_HEALTH_FAULT_TEST_STRUCT param; + CONSOLE_OUT + (">> Send Health Fault Test\n"); + CONSOLE_OUT + ("Enter Test ID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.test_id = (UCHAR)choice; + CONSOLE_OUT + ("Enter Company ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.company_id = (UINT16)choice; + retval = MS_health_fault_test(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Health Fault Test Unacknowledged */ +void appl_send_health_fault_test_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_HEALTH_FAULT_TEST_STRUCT param; + CONSOLE_OUT + (">> Send Health Fault Test Unacknowledged\n"); + CONSOLE_OUT + ("Enter Test ID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.test_id = (UCHAR)choice; + CONSOLE_OUT + ("Enter Company ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.company_id = (UINT16)choice; + retval = MS_health_fault_test_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Health Period Get */ +void appl_send_health_period_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Health Period Get\n"); + retval = MS_health_period_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Health Period Set */ +void appl_send_health_period_set(void) +{ + API_RESULT retval; + int choice; + MS_HEALTH_PERIOD_STRUCT param; + CONSOLE_OUT + (">> Send Health Period Set\n"); + CONSOLE_OUT + ("Enter FastPeriodDivisor (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.fastperioddivisor = (UCHAR)choice; + retval = MS_health_period_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Health Period Set Unacknowledged */ +void appl_send_health_period_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_HEALTH_PERIOD_STRUCT param; + CONSOLE_OUT + (">> Send Health Period Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter FastPeriodDivisor (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.fastperioddivisor = (UCHAR)choice; + retval = MS_health_period_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + + +/* Get Model Handle */ +void appl_health_client_get_model_handle(void) +{ + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_health_client_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + return; +} + + +/* Set Publish Address */ +void appl_health_client_set_publish_address(void) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + CONSOLE_OUT + ("Enter Model Handle (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + model_handle = (UINT16)choice; + CONSOLE_OUT + ("Enter Health client Server Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.addr.addr = (UINT16)choice; + /** + Foundation Models use Device Key for transport layer encryption. + + Taking network index as input. + */ + CONSOLE_OUT + ("Enter Network Index (0 if part of a single network)\n"); + CONSOLE_IN + ("%d", &choice); + publish_info.appkey_index = (UINT16)(MS_CONFIG_LIMITS(MS_MAX_APPS) + choice); + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Health client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_health_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[HEALTH_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_HEALTH_ATTENTION_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_HEALTH_ATTENTION_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_HEALTH_CURRENT_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_HEALTH_CURRENT_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_HEALTH_FAULT_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_HEALTH_FAULT_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_HEALTH_PERIOD_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_HEALTH_PERIOD_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_health_client.h b/src/components/ethermind/mesh/export/appl/model/client/appl_health_client.h new file mode 100644 index 0000000..f1485bb --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_health_client.h @@ -0,0 +1,90 @@ +/** + \file appl_health_client.h + + \brief This file defines the Mesh Health Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_HEALTH_CLIENT_ +#define _H_APPL_HEALTH_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_health_client_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* health client application entry point */ +void main_health_client_operations(void); + +/* Send Health Attention Get */ +void appl_send_health_attention_get(void); + +/* Send Health Attention Set */ +void appl_send_health_attention_set(void); + +/* Send Health Attention Set Unacknowledged */ +void appl_send_health_attention_set_unacknowledged(void); + +/* Send Health Fault Clear */ +void appl_send_health_fault_clear(void); + +/* Send Health Fault Clear Unacknowledged */ +void appl_send_health_fault_clear_unacknowledged(void); + +/* Send Health Fault Get */ +void appl_send_health_fault_get(void); + +/* Send Health Fault Test */ +void appl_send_health_fault_test(void); + +/* Send Health Fault Test Unacknowledged */ +void appl_send_health_fault_test_unacknowledged(void); + +/* Send Health Period Get */ +void appl_send_health_period_get(void); + +/* Send Health Period Set */ +void appl_send_health_period_set(void); + +/* Send Health Period Set Unacknowledged */ +void appl_send_health_period_set_unacknowledged(void); + +/* Get Model Handle */ +void appl_health_client_get_model_handle(void); + +/* Set Publish Address */ +void appl_health_client_set_publish_address(void); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Health client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_health_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_APPL_HEALTH_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_light_ctl_client.c b/src/components/ethermind/mesh/export/appl/model/client/appl_light_ctl_client.c new file mode 100644 index 0000000..ad82bf3 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_light_ctl_client.c @@ -0,0 +1,662 @@ +/** + \file appl_light_ctl_client.c + + \brief This file defines the Mesh Light Ctl Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_light_ctl_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_light_ctl_client_options[] = "\n\ +======== Light_Ctl Client Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 10. Send Light Ctl Default Get. \n\ + 11. Send Light Ctl Default Set. \n\ + 12. Send Light Ctl Default Set Unacknowledged. \n\ + 13. Send Light Ctl Get. \n\ + 14. Send Light Ctl Set. \n\ + 15. Send Light Ctl Set Unacknowledged. \n\ + 16. Send Light Ctl Temperature Get. \n\ + 17. Send Light Ctl Temperature Range Get. \n\ + 18. Send Light Ctl Temperature Range Set. \n\ + 19. Send Light Ctl Temperature Range Set Unacknowledged. \n\ + 20. Send Light Ctl Temperature Set. \n\ + 21. Send Light Ctl Temperature Set Unacknowledged. \n\ + \n\ + 22. Get Model Handle. \n\ + 23. Set Publish Address. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_light_ctl_client_model_handle; + + +/* --------------------------------------------- Function */ +/* light_ctl client application entry point */ +void main_light_ctl_client_operations(void) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_light_ctl_client_init + ( + element_handle, + &appl_light_ctl_client_model_handle, + appl_light_ctl_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Ctl Client Initialized. Model Handle: 0x%04X\n", + appl_light_ctl_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Ctl Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_light_ctl_client_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 10: /* Send Light Ctl Default Get */ + appl_send_light_ctl_default_get(); + break; + + case 11: /* Send Light Ctl Default Set */ + appl_send_light_ctl_default_set(); + break; + + case 12: /* Send Light Ctl Default Set Unacknowledged */ + appl_send_light_ctl_default_set_unacknowledged(); + break; + + case 13: /* Send Light Ctl Get */ + appl_send_light_ctl_get(); + break; + + case 14: /* Send Light Ctl Set */ + appl_send_light_ctl_set(); + break; + + case 15: /* Send Light Ctl Set Unacknowledged */ + appl_send_light_ctl_set_unacknowledged(); + break; + + case 16: /* Send Light Ctl Temperature Get */ + appl_send_light_ctl_temperature_get(); + break; + + case 17: /* Send Light Ctl Temperature Range Get */ + appl_send_light_ctl_temperature_range_get(); + break; + + case 18: /* Send Light Ctl Temperature Range Set */ + appl_send_light_ctl_temperature_range_set(); + break; + + case 19: /* Send Light Ctl Temperature Range Set Unacknowledged */ + appl_send_light_ctl_temperature_range_set_unacknowledged(); + break; + + case 20: /* Send Light Ctl Temperature Set */ + appl_send_light_ctl_temperature_set(); + break; + + case 21: /* Send Light Ctl Temperature Set Unacknowledged */ + appl_send_light_ctl_temperature_set_unacknowledged(); + break; + + case 22: /* Get Model Handle */ + appl_light_ctl_client_get_model_handle(); + break; + + case 23: /* Set Publish Address */ + appl_light_ctl_client_set_publish_address(); + break; + } + } +} + +/* Send Light Ctl Default Get */ +void appl_send_light_ctl_default_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Ctl Default Get\n"); + retval = MS_light_ctl_default_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Ctl Default Set */ +void appl_send_light_ctl_default_set(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_CTL_DEFAULT_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Ctl Default Set\n"); + CONSOLE_OUT + ("Enter Lightness (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.lightness = (UINT16)choice; + CONSOLE_OUT + ("Enter Temperature (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.temperature = (UINT16)choice; + CONSOLE_OUT + ("Enter Delta UV (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delta_uv = (UINT16)choice; + retval = MS_light_ctl_default_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Ctl Default Set Unacknowledged */ +void appl_send_light_ctl_default_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_CTL_DEFAULT_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Ctl Default Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Lightness (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.lightness = (UINT16)choice; + CONSOLE_OUT + ("Enter Temperature (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.temperature = (UINT16)choice; + CONSOLE_OUT + ("Enter Delta UV (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delta_uv = (UINT16)choice; + retval = MS_light_ctl_default_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Ctl Get */ +void appl_send_light_ctl_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Ctl Get\n"); + retval = MS_light_ctl_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Ctl Set */ +void appl_send_light_ctl_set(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_CTL_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Ctl Set\n"); + CONSOLE_OUT + ("Enter CTL Lightness (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.ctl_lightness = (UINT16)choice; + CONSOLE_OUT + ("Enter CTL Temperature (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.ctl_temperature = (UINT16)choice; + CONSOLE_OUT + ("Enter CTL Delta UV (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.ctl_delta_uv = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_light_ctl_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Ctl Set Unacknowledged */ +void appl_send_light_ctl_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_CTL_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Ctl Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter CTL Lightness (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.ctl_lightness = (UINT16)choice; + CONSOLE_OUT + ("Enter CTL Temperature (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.ctl_temperature = (UINT16)choice; + CONSOLE_OUT + ("Enter CTL Delta UV (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.ctl_delta_uv = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_light_ctl_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Ctl Temperature Get */ +void appl_send_light_ctl_temperature_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Ctl Temperature Get\n"); + retval = MS_light_ctl_temperature_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Ctl Temperature Range Get */ +void appl_send_light_ctl_temperature_range_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Ctl Temperature Range Get\n"); + retval = MS_light_ctl_temperature_range_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Ctl Temperature Range Set */ +void appl_send_light_ctl_temperature_range_set(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_CTL_TEMPERATURE_RANGE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Ctl Temperature Range Set\n"); + CONSOLE_OUT + ("Enter Range Min (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.range_min = (UINT16)choice; + CONSOLE_OUT + ("Enter Range Max (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.range_max = (UINT16)choice; + retval = MS_light_ctl_temperature_range_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Ctl Temperature Range Set Unacknowledged */ +void appl_send_light_ctl_temperature_range_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_CTL_TEMPERATURE_RANGE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Ctl Temperature Range Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Range Min (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.range_min = (UINT16)choice; + CONSOLE_OUT + ("Enter Range Max (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.range_max = (UINT16)choice; + retval = MS_light_ctl_temperature_range_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Ctl Temperature Set */ +void appl_send_light_ctl_temperature_set(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_CTL_TEMPERATURE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Ctl Temperature Set\n"); + CONSOLE_OUT + ("Enter CTL Temperature (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.ctl_temperature = (UINT16)choice; + CONSOLE_OUT + ("Enter CTL Delta UV (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.ctl_delta_uv = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_light_ctl_temperature_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Ctl Temperature Set Unacknowledged */ +void appl_send_light_ctl_temperature_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_CTL_TEMPERATURE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Ctl Temperature Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter CTL Temperature (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.ctl_temperature = (UINT16)choice; + CONSOLE_OUT + ("Enter CTL Delta UV (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.ctl_delta_uv = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_light_ctl_temperature_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + + +/* Get Model Handle */ +void appl_light_ctl_client_get_model_handle(void) +{ + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_light_ctl_client_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + return; +} + + +/* Set Publish Address */ +void appl_light_ctl_client_set_publish_address(void) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + CONSOLE_OUT + ("Enter Model Handle (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + model_handle = (UINT16)choice; + CONSOLE_OUT + ("Enter Light_Ctl client Server Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKey Index\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.appkey_index = choice; + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Light_Ctl client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_light_ctl_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[LIGHT_CTL_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_LIGHT_CTL_DEFAULT_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_CTL_DEFAULT_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_CTL_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_CTL_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_CTL_TEMPERATURE_RANGE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_CTL_TEMPERATURE_RANGE_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_CTL_TEMPERATURE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_CTL_TEMPERATURE_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_light_ctl_client.h b/src/components/ethermind/mesh/export/appl/model/client/appl_light_ctl_client.h new file mode 100644 index 0000000..0b05e80 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_light_ctl_client.h @@ -0,0 +1,93 @@ +/** + \file appl_light_ctl_client.h + + \brief This file defines the Mesh Light Ctl Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_LIGHT_CTL_CLIENT_ +#define _H_APPL_LIGHT_CTL_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_light_ctl_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* light_ctl client application entry point */ +void main_light_ctl_client_operations(void); + +/* Send Light Ctl Default Get */ +void appl_send_light_ctl_default_get(void); + +/* Send Light Ctl Default Set */ +void appl_send_light_ctl_default_set(void); + +/* Send Light Ctl Default Set Unacknowledged */ +void appl_send_light_ctl_default_set_unacknowledged(void); + +/* Send Light Ctl Get */ +void appl_send_light_ctl_get(void); + +/* Send Light Ctl Set */ +void appl_send_light_ctl_set(void); + +/* Send Light Ctl Set Unacknowledged */ +void appl_send_light_ctl_set_unacknowledged(void); + +/* Send Light Ctl Temperature Get */ +void appl_send_light_ctl_temperature_get(void); + +/* Send Light Ctl Temperature Range Get */ +void appl_send_light_ctl_temperature_range_get(void); + +/* Send Light Ctl Temperature Range Set */ +void appl_send_light_ctl_temperature_range_set(void); + +/* Send Light Ctl Temperature Range Set Unacknowledged */ +void appl_send_light_ctl_temperature_range_set_unacknowledged(void); + +/* Send Light Ctl Temperature Set */ +void appl_send_light_ctl_temperature_set(void); + +/* Send Light Ctl Temperature Set Unacknowledged */ +void appl_send_light_ctl_temperature_set_unacknowledged(void); + +/* Get Model Handle */ +void appl_light_ctl_client_get_model_handle(void); + +/* Set Publish Address */ +void appl_light_ctl_client_set_publish_address(void); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Light_Ctl client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_light_ctl_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_APPL_LIGHT_CTL_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_light_hsl_client.c b/src/components/ethermind/mesh/export/appl/model/client/appl_light_hsl_client.c new file mode 100644 index 0000000..e6dec30 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_light_hsl_client.c @@ -0,0 +1,822 @@ +/** + \file appl_light_hsl_client.c + + \brief This file defines the Mesh Light Hsl Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_light_hsl_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_light_hsl_client_options[] = "\n\ +======== Light_Hsl Client Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 10. Send Light Hsl Default Get. \n\ + 11. Send Light Hsl Default Set. \n\ + 12. Send Light Hsl Default Set Unacknowledged. \n\ + 13. Send Light Hsl Get. \n\ + 14. Send Light Hsl Hue Get. \n\ + 15. Send Light Hsl Hue Set. \n\ + 16. Send Light Hsl Hue Set Unacknowledged. \n\ + 17. Send Light Hsl Range Get. \n\ + 18. Send Light Hsl Range Set. \n\ + 19. Send Light Hsl Range Set Unacknowledged. \n\ + 20. Send Light Hsl Saturation Get. \n\ + 21. Send Light Hsl Saturation Set. \n\ + 22. Send Light Hsl Saturation Set Unacknowledged. \n\ + 23. Send Light Hsl Set. \n\ + 24. Send Light Hsl Set Unacknowledged. \n\ + 25. Send Light Hsl Target Get. \n\ + \n\ + 26. Get Model Handle. \n\ + 27. Set Publish Address. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_light_hsl_client_model_handle; + + +/* --------------------------------------------- Function */ +/* light_hsl client application entry point */ +void main_light_hsl_client_operations(void) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_light_hsl_client_init + ( + element_handle, + &appl_light_hsl_client_model_handle, + appl_light_hsl_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Hsl Client Initialized. Model Handle: 0x%04X\n", + appl_light_hsl_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Hsl Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_light_hsl_client_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 10: /* Send Light Hsl Default Get */ + appl_send_light_hsl_default_get(); + break; + + case 11: /* Send Light Hsl Default Set */ + appl_send_light_hsl_default_set(); + break; + + case 12: /* Send Light Hsl Default Set Unacknowledged */ + appl_send_light_hsl_default_set_unacknowledged(); + break; + + case 13: /* Send Light Hsl Get */ + appl_send_light_hsl_get(); + break; + + case 14: /* Send Light Hsl Hue Get */ + appl_send_light_hsl_hue_get(); + break; + + case 15: /* Send Light Hsl Hue Set */ + appl_send_light_hsl_hue_set(); + break; + + case 16: /* Send Light Hsl Hue Set Unacknowledged */ + appl_send_light_hsl_hue_set_unacknowledged(); + break; + + case 17: /* Send Light Hsl Range Get */ + appl_send_light_hsl_range_get(); + break; + + case 18: /* Send Light Hsl Range Set */ + appl_send_light_hsl_range_set(); + break; + + case 19: /* Send Light Hsl Range Set Unacknowledged */ + appl_send_light_hsl_range_set_unacknowledged(); + break; + + case 20: /* Send Light Hsl Saturation Get */ + appl_send_light_hsl_saturation_get(); + break; + + case 21: /* Send Light Hsl Saturation Set */ + appl_send_light_hsl_saturation_set(); + break; + + case 22: /* Send Light Hsl Saturation Set Unacknowledged */ + appl_send_light_hsl_saturation_set_unacknowledged(); + break; + + case 23: /* Send Light Hsl Set */ + appl_send_light_hsl_set(); + break; + + case 24: /* Send Light Hsl Set Unacknowledged */ + appl_send_light_hsl_set_unacknowledged(); + break; + + case 25: /* Send Light Hsl Target Get */ + appl_send_light_hsl_target_get(); + break; + + case 26: /* Get Model Handle */ + appl_light_hsl_client_get_model_handle(); + break; + + case 27: /* Set Publish Address */ + appl_light_hsl_client_set_publish_address(); + break; + } + } +} + +/* Send Light Hsl Default Get */ +void appl_send_light_hsl_default_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Hsl Default Get\n"); + retval = MS_light_hsl_default_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Hsl Default Set */ +void appl_send_light_hsl_default_set(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_HSL_DEFAULT_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Hsl Default Set\n"); + CONSOLE_OUT + ("Enter Lightness (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.lightness = (UINT16)choice; + CONSOLE_OUT + ("Enter Hue (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.hue = (UINT16)choice; + CONSOLE_OUT + ("Enter Saturation (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.saturation = (UINT16)choice; + retval = MS_light_hsl_default_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Hsl Default Set Unacknowledged */ +void appl_send_light_hsl_default_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_HSL_DEFAULT_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Hsl Default Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Lightness (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.lightness = (UINT16)choice; + CONSOLE_OUT + ("Enter Hue (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.hue = (UINT16)choice; + CONSOLE_OUT + ("Enter Saturation (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.saturation = (UINT16)choice; + retval = MS_light_hsl_default_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Hsl Get */ +void appl_send_light_hsl_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Hsl Get\n"); + retval = MS_light_hsl_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Hsl Hue Get */ +void appl_send_light_hsl_hue_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Hsl Hue Get\n"); + retval = MS_light_hsl_hue_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Hsl Hue Set */ +void appl_send_light_hsl_hue_set(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_HSL_HUE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Hsl Hue Set\n"); + CONSOLE_OUT + ("Enter Hue (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.hue = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_light_hsl_hue_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Hsl Hue Set Unacknowledged */ +void appl_send_light_hsl_hue_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_HSL_HUE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Hsl Hue Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Hue (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.hue = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_light_hsl_hue_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Hsl Range Get */ +void appl_send_light_hsl_range_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Hsl Range Get\n"); + retval = MS_light_hsl_range_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Hsl Range Set */ +void appl_send_light_hsl_range_set(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_HSL_RANGE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Hsl Range Set\n"); + CONSOLE_OUT + ("Enter Hue Range Min (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.hue_range_min = (UINT16)choice; + CONSOLE_OUT + ("Enter Hue Range Max (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.hue_range_max = (UINT16)choice; + CONSOLE_OUT + ("Enter Saturation Range Min (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.saturation_range_min = (UINT16)choice; + CONSOLE_OUT + ("Enter Saturation Range Max (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.saturation_range_max = (UINT16)choice; + retval = MS_light_hsl_range_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Hsl Range Set Unacknowledged */ +void appl_send_light_hsl_range_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_HSL_RANGE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Hsl Range Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Hue Range Min (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.hue_range_min = (UINT16)choice; + CONSOLE_OUT + ("Enter Hue Range Max (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.hue_range_max = (UINT16)choice; + CONSOLE_OUT + ("Enter Saturation Range Min (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.saturation_range_min = (UINT16)choice; + CONSOLE_OUT + ("Enter Saturation Range Max (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.saturation_range_max = (UINT16)choice; + retval = MS_light_hsl_range_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Hsl Saturation Get */ +void appl_send_light_hsl_saturation_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Hsl Saturation Get\n"); + retval = MS_light_hsl_saturation_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Hsl Saturation Set */ +void appl_send_light_hsl_saturation_set(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_HSL_SATURATION_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Hsl Saturation Set\n"); + CONSOLE_OUT + ("Enter Saturation (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.saturation = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_light_hsl_saturation_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Hsl Saturation Set Unacknowledged */ +void appl_send_light_hsl_saturation_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_HSL_SATURATION_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Hsl Saturation Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Saturation (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.saturation = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_light_hsl_saturation_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Hsl Set */ +void appl_send_light_hsl_set(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_HSL_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Hsl Set\n"); + CONSOLE_OUT + ("Enter HSL Lightness (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.hsl_lightness = (UINT16)choice; + CONSOLE_OUT + ("Enter HSL Hue (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.hsl_hue = (UINT16)choice; + CONSOLE_OUT + ("Enter HSL Saturation (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.hsl_saturation = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_light_hsl_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Hsl Set Unacknowledged */ +void appl_send_light_hsl_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_HSL_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Hsl Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter HSL Lightness (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.hsl_lightness = (UINT16)choice; + CONSOLE_OUT + ("Enter HSL Hue (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.hsl_hue = (UINT16)choice; + CONSOLE_OUT + ("Enter HSL Saturation (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.hsl_saturation = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_light_hsl_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Hsl Target Get */ +void appl_send_light_hsl_target_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Hsl Target Get\n"); + retval = MS_light_hsl_target_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + + +/* Get Model Handle */ +void appl_light_hsl_client_get_model_handle(void) +{ + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_light_hsl_client_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + return; +} + + +/* Set Publish Address */ +void appl_light_hsl_client_set_publish_address(void) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + CONSOLE_OUT + ("Enter Model Handle (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + model_handle = (UINT16)choice; + CONSOLE_OUT + ("Enter Light_Hsl client Server Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKey Index\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.appkey_index = choice; + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Light_Hsl client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_light_hsl_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[LIGHT_HSL_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_LIGHT_HSL_DEFAULT_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_HSL_DEFAULT_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_HSL_HUE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_HSL_HUE_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_HSL_RANGE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_HSL_RANGE_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_HSL_SATURATION_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_HSL_SATURATION_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_HSL_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_HSL_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_HSL_TARGET_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_HSL_TARGET_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_light_hsl_client.h b/src/components/ethermind/mesh/export/appl/model/client/appl_light_hsl_client.h new file mode 100644 index 0000000..8e80ce6 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_light_hsl_client.h @@ -0,0 +1,105 @@ +/** + \file appl_light_hsl_client.h + + \brief This file defines the Mesh Light Hsl Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_LIGHT_HSL_CLIENT_ +#define _H_APPL_LIGHT_HSL_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_light_hsl_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* light_hsl client application entry point */ +void main_light_hsl_client_operations(void); + +/* Send Light Hsl Default Get */ +void appl_send_light_hsl_default_get(void); + +/* Send Light Hsl Default Set */ +void appl_send_light_hsl_default_set(void); + +/* Send Light Hsl Default Set Unacknowledged */ +void appl_send_light_hsl_default_set_unacknowledged(void); + +/* Send Light Hsl Get */ +void appl_send_light_hsl_get(void); + +/* Send Light Hsl Hue Get */ +void appl_send_light_hsl_hue_get(void); + +/* Send Light Hsl Hue Set */ +void appl_send_light_hsl_hue_set(void); + +/* Send Light Hsl Hue Set Unacknowledged */ +void appl_send_light_hsl_hue_set_unacknowledged(void); + +/* Send Light Hsl Range Get */ +void appl_send_light_hsl_range_get(void); + +/* Send Light Hsl Range Set */ +void appl_send_light_hsl_range_set(void); + +/* Send Light Hsl Range Set Unacknowledged */ +void appl_send_light_hsl_range_set_unacknowledged(void); + +/* Send Light Hsl Saturation Get */ +void appl_send_light_hsl_saturation_get(void); + +/* Send Light Hsl Saturation Set */ +void appl_send_light_hsl_saturation_set(void); + +/* Send Light Hsl Saturation Set Unacknowledged */ +void appl_send_light_hsl_saturation_set_unacknowledged(void); + +/* Send Light Hsl Set */ +void appl_send_light_hsl_set(void); + +/* Send Light Hsl Set Unacknowledged */ +void appl_send_light_hsl_set_unacknowledged(void); + +/* Send Light Hsl Target Get */ +void appl_send_light_hsl_target_get(void); + +/* Get Model Handle */ +void appl_light_hsl_client_get_model_handle(void); + +/* Set Publish Address */ +void appl_light_hsl_client_set_publish_address(void); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Light_Hsl client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_light_hsl_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_APPL_LIGHT_HSL_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_light_lc_client.c b/src/components/ethermind/mesh/export/appl/model/client/appl_light_lc_client.c new file mode 100644 index 0000000..f523af2 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_light_lc_client.c @@ -0,0 +1,615 @@ +/** + \file appl_light_lc_client.c + + \brief This file defines the Mesh Light Lc Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_light_lc_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_light_lc_client_options[] = "\n\ +======== Light_Lc Client Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 10. Send Light Lc Light Onoff Get. \n\ + 11. Send Light Lc Light Onoff Set. \n\ + 12. Send Light Lc Light Onoff Set Unacknowledged. \n\ + 13. Send Light Lc Mode Get. \n\ + 14. Send Light Lc Mode Set. \n\ + 15. Send Light Lc Mode Set Unacknowledged. \n\ + 16. Send Light Lc Om Get. \n\ + 17. Send Light Lc Om Set. \n\ + 18. Send Light Lc Om Set Unacknowledged. \n\ + 19. Send Light Lc Property Get. \n\ + 20. Send Light Lc Property Set. \n\ + 21. Send Light Lc Property Set Unacknowledged. \n\ + \n\ + 22. Get Model Handle. \n\ + 23. Set Publish Address. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_light_lc_client_model_handle; + + +/* --------------------------------------------- Function */ +/* light_lc client application entry point */ +void main_light_lc_client_operations(void) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_light_lc_client_init + ( + element_handle, + &appl_light_lc_client_model_handle, + appl_light_lc_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Lc Client Initialized. Model Handle: 0x%04X\n", + appl_light_lc_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Lc Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_light_lc_client_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 10: /* Send Light Lc Light Onoff Get */ + appl_send_light_lc_light_onoff_get(); + break; + + case 11: /* Send Light Lc Light Onoff Set */ + appl_send_light_lc_light_onoff_set(); + break; + + case 12: /* Send Light Lc Light Onoff Set Unacknowledged */ + appl_send_light_lc_light_onoff_set_unacknowledged(); + break; + + case 13: /* Send Light Lc Mode Get */ + appl_send_light_lc_mode_get(); + break; + + case 14: /* Send Light Lc Mode Set */ + appl_send_light_lc_mode_set(); + break; + + case 15: /* Send Light Lc Mode Set Unacknowledged */ + appl_send_light_lc_mode_set_unacknowledged(); + break; + + case 16: /* Send Light Lc Om Get */ + appl_send_light_lc_om_get(); + break; + + case 17: /* Send Light Lc Om Set */ + appl_send_light_lc_om_set(); + break; + + case 18: /* Send Light Lc Om Set Unacknowledged */ + appl_send_light_lc_om_set_unacknowledged(); + break; + + case 19: /* Send Light Lc Property Get */ + appl_send_light_lc_property_get(); + break; + + case 20: /* Send Light Lc Property Set */ + appl_send_light_lc_property_set(); + break; + + case 21: /* Send Light Lc Property Set Unacknowledged */ + appl_send_light_lc_property_set_unacknowledged(); + break; + + case 22: /* Get Model Handle */ + appl_light_lc_client_get_model_handle(); + break; + + case 23: /* Set Publish Address */ + appl_light_lc_client_set_publish_address(); + break; + } + } +} + +/* Send Light Lc Light Onoff Get */ +void appl_send_light_lc_light_onoff_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Lc Light Onoff Get\n"); + retval = MS_light_lc_light_onoff_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lc Light Onoff Set */ +void appl_send_light_lc_light_onoff_set(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LC_LIGHT_ONOFF_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lc Light Onoff Set\n"); + CONSOLE_OUT + ("Enter Light OnOff (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.light_onoff = (UCHAR)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_light_lc_light_onoff_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lc Light Onoff Set Unacknowledged */ +void appl_send_light_lc_light_onoff_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LC_LIGHT_ONOFF_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lc Light Onoff Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Light OnOff (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.light_onoff = (UCHAR)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_light_lc_light_onoff_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lc Mode Get */ +void appl_send_light_lc_mode_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Lc Mode Get\n"); + retval = MS_light_lc_mode_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lc Mode Set */ +void appl_send_light_lc_mode_set(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LC_MODE_STRUCT param; + CONSOLE_OUT + (">> Send Light Lc Mode Set\n"); + CONSOLE_OUT + ("Enter Mode (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.mode = (UCHAR)choice; + retval = MS_light_lc_mode_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lc Mode Set Unacknowledged */ +void appl_send_light_lc_mode_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LC_MODE_STRUCT param; + CONSOLE_OUT + (">> Send Light Lc Mode Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Mode (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.mode = (UCHAR)choice; + retval = MS_light_lc_mode_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lc Om Get */ +void appl_send_light_lc_om_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Lc Om Get\n"); + retval = MS_light_lc_om_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lc Om Set */ +void appl_send_light_lc_om_set(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LC_OM_STRUCT param; + CONSOLE_OUT + (">> Send Light Lc Om Set\n"); + CONSOLE_OUT + ("Enter Mode (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.mode = (UCHAR)choice; + retval = MS_light_lc_om_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lc Om Set Unacknowledged */ +void appl_send_light_lc_om_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LC_OM_STRUCT param; + CONSOLE_OUT + (">> Send Light Lc Om Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Mode (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.mode = (UCHAR)choice; + retval = MS_light_lc_om_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lc Property Get */ +void appl_send_light_lc_property_get(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LC_PROPERTY_GET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lc Property Get\n"); + CONSOLE_OUT + ("Enter Light LC Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.light_lc_property_id = (UINT16)choice; + retval = MS_light_lc_property_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lc Property Set */ +void appl_send_light_lc_property_set(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LC_PROPERTY_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lc Property Set\n"); + CONSOLE_OUT + ("Enter Light LC Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.light_lc_property_id = (UINT16)choice; + CONSOLE_OUT + ("Enter Light LC Property Value Length (in decimal)\n"); + CONSOLE_IN + ("%d", &choice); + CONSOLE_OUT + ("Enter Light LC Property Value (%d-octets in HEX)\n", (UINT16)choice); + { + UINT16 index, input_len; + input_len = (UINT16)choice; + param.light_lc_property_value = EM_alloc_mem(input_len); + + if(NULL == param.light_lc_property_value) + { + CONSOLE_OUT + ("Memory allocation failed for Light LC Property Value. Returning\n"); + return; + } + + param.light_lc_property_value_len = (UINT16) input_len; + + for(index = 0; index < input_len; index++) + { + CONSOLE_IN + ("%x", &choice); + param.light_lc_property_value[index] = (UCHAR)choice; + } + } + retval = MS_light_lc_property_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.light_lc_property_value) + { + EM_free_mem(param.light_lc_property_value); + } +} + +/* Send Light Lc Property Set Unacknowledged */ +void appl_send_light_lc_property_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LC_PROPERTY_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lc Property Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Light LC Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.light_lc_property_id = (UINT16)choice; + CONSOLE_OUT + ("Enter Light LC Property Value Length (in decimal)\n"); + CONSOLE_IN + ("%d", &choice); + CONSOLE_OUT + ("Enter Light LC Property Value (%d-octets in HEX)\n", (UINT16)choice); + { + UINT16 index, input_len; + input_len = (UINT16)choice; + param.light_lc_property_value = EM_alloc_mem(input_len); + + if(NULL == param.light_lc_property_value) + { + CONSOLE_OUT + ("Memory allocation failed for Light LC Property Value. Returning\n"); + return; + } + + param.light_lc_property_value_len = (UINT16) input_len; + + for(index = 0; index < input_len; index++) + { + CONSOLE_IN + ("%x", &choice); + param.light_lc_property_value[index] = (UCHAR)choice; + } + } + retval = MS_light_lc_property_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.light_lc_property_value) + { + EM_free_mem(param.light_lc_property_value); + } +} + + +/* Get Model Handle */ +void appl_light_lc_client_get_model_handle(void) +{ + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_light_lc_client_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + return; +} + + +/* Set Publish Address */ +void appl_light_lc_client_set_publish_address(void) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + CONSOLE_OUT + ("Enter Model Handle (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + model_handle = (UINT16)choice; + CONSOLE_OUT + ("Enter Light_Lc client Server Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKey Index\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.appkey_index = choice; + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Light_Lc client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_light_lc_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[LIGHT_LC_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_LIGHT_LC_LIGHT_ONOFF_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_LC_LIGHT_ONOFF_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_LC_MODE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_LC_MODE_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_LC_OM_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_LC_OM_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_LC_PROPERTY_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_LC_PROPERTY_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_light_lc_client.h b/src/components/ethermind/mesh/export/appl/model/client/appl_light_lc_client.h new file mode 100644 index 0000000..96b0c13 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_light_lc_client.h @@ -0,0 +1,93 @@ +/** + \file appl_light_lc_client.h + + \brief This file defines the Mesh Light Lc Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_LIGHT_LC_CLIENT_ +#define _H_APPL_LIGHT_LC_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_light_lc_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* light_lc client application entry point */ +void main_light_lc_client_operations(void); + +/* Send Light Lc Light Onoff Get */ +void appl_send_light_lc_light_onoff_get(void); + +/* Send Light Lc Light Onoff Set */ +void appl_send_light_lc_light_onoff_set(void); + +/* Send Light Lc Light Onoff Set Unacknowledged */ +void appl_send_light_lc_light_onoff_set_unacknowledged(void); + +/* Send Light Lc Mode Get */ +void appl_send_light_lc_mode_get(void); + +/* Send Light Lc Mode Set */ +void appl_send_light_lc_mode_set(void); + +/* Send Light Lc Mode Set Unacknowledged */ +void appl_send_light_lc_mode_set_unacknowledged(void); + +/* Send Light Lc Om Get */ +void appl_send_light_lc_om_get(void); + +/* Send Light Lc Om Set */ +void appl_send_light_lc_om_set(void); + +/* Send Light Lc Om Set Unacknowledged */ +void appl_send_light_lc_om_set_unacknowledged(void); + +/* Send Light Lc Property Get */ +void appl_send_light_lc_property_get(void); + +/* Send Light Lc Property Set */ +void appl_send_light_lc_property_set(void); + +/* Send Light Lc Property Set Unacknowledged */ +void appl_send_light_lc_property_set_unacknowledged(void); + +/* Get Model Handle */ +void appl_light_lc_client_get_model_handle(void); + +/* Set Publish Address */ +void appl_light_lc_client_set_publish_address(void); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Light_Lc client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_light_lc_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_APPL_LIGHT_LC_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_light_lightness_client.c b/src/components/ethermind/mesh/export/appl/model/client/appl_light_lightness_client.c new file mode 100644 index 0000000..5126ebf --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_light_lightness_client.c @@ -0,0 +1,579 @@ +/** + \file appl_light_lightness_client.c + + \brief This file defines the Mesh Light Lightness Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_light_lightness_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_light_lightness_client_options[] = "\n\ +======== Light_Lightness Client Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 10. Send Light Lightness Default Get. \n\ + 11. Send Light Lightness Default Set. \n\ + 12. Send Light Lightness Default Set Unacknowledged. \n\ + 13. Send Light Lightness Get. \n\ + 14. Send Light Lightness Last Get. \n\ + 15. Send Light Lightness Linear Get. \n\ + 16. Send Light Lightness Linear Set. \n\ + 17. Send Light Lightness Linear Set Unacknowledged. \n\ + 18. Send Light Lightness Range Get. \n\ + 19. Send Light Lightness Range Set. \n\ + 20. Send Light Lightness Range Set Unacknowledged. \n\ + 21. Send Light Lightness Set. \n\ + 22. Send Light Lightness Set Unacknowledged. \n\ + \n\ + 23. Get Model Handle. \n\ + 24. Set Publish Address. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_light_lightness_client_model_handle; + + +/* --------------------------------------------- Function */ +/* light_lightness client application entry point */ +void main_light_lightness_client_operations(void) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_light_lightness_client_init + ( + element_handle, + &appl_light_lightness_client_model_handle, + appl_light_lightness_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Lightness Client Initialized. Model Handle: 0x%04X\n", + appl_light_lightness_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Lightness Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_light_lightness_client_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 10: /* Send Light Lightness Default Get */ + appl_send_light_lightness_default_get(); + break; + + case 11: /* Send Light Lightness Default Set */ + appl_send_light_lightness_default_set(); + break; + + case 12: /* Send Light Lightness Default Set Unacknowledged */ + appl_send_light_lightness_default_set_unacknowledged(); + break; + + case 13: /* Send Light Lightness Get */ + appl_send_light_lightness_get(); + break; + + case 14: /* Send Light Lightness Last Get */ + appl_send_light_lightness_last_get(); + break; + + case 15: /* Send Light Lightness Linear Get */ + appl_send_light_lightness_linear_get(); + break; + + case 16: /* Send Light Lightness Linear Set */ + appl_send_light_lightness_linear_set(); + break; + + case 17: /* Send Light Lightness Linear Set Unacknowledged */ + appl_send_light_lightness_linear_set_unacknowledged(); + break; + + case 18: /* Send Light Lightness Range Get */ + appl_send_light_lightness_range_get(); + break; + + case 19: /* Send Light Lightness Range Set */ + appl_send_light_lightness_range_set(); + break; + + case 20: /* Send Light Lightness Range Set Unacknowledged */ + appl_send_light_lightness_range_set_unacknowledged(); + break; + + case 21: /* Send Light Lightness Set */ + appl_send_light_lightness_set(); + break; + + case 22: /* Send Light Lightness Set Unacknowledged */ + appl_send_light_lightness_set_unacknowledged(); + break; + + case 23: /* Get Model Handle */ + appl_light_lightness_client_get_model_handle(); + break; + + case 24: /* Set Publish Address */ + appl_light_lightness_client_set_publish_address(); + break; + } + } +} + +/* Send Light Lightness Default Get */ +void appl_send_light_lightness_default_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Lightness Default Get\n"); + retval = MS_light_lightness_default_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lightness Default Set */ +void appl_send_light_lightness_default_set(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LIGHTNESS_DEFAULT_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lightness Default Set\n"); + CONSOLE_OUT + ("Enter Lightness (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.lightness = (UINT16)choice; + retval = MS_light_lightness_default_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lightness Default Set Unacknowledged */ +void appl_send_light_lightness_default_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LIGHTNESS_DEFAULT_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lightness Default Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Lightness (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.lightness = (UINT16)choice; + retval = MS_light_lightness_default_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lightness Get */ +void appl_send_light_lightness_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Lightness Get\n"); + retval = MS_light_lightness_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lightness Last Get */ +void appl_send_light_lightness_last_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Lightness Last Get\n"); + retval = MS_light_lightness_last_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lightness Linear Get */ +void appl_send_light_lightness_linear_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Lightness Linear Get\n"); + retval = MS_light_lightness_linear_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lightness Linear Set */ +void appl_send_light_lightness_linear_set(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LIGHTNESS_LINEAR_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lightness Linear Set\n"); + CONSOLE_OUT + ("Enter Lightness (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.lightness = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + retval = MS_light_lightness_linear_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lightness Linear Set Unacknowledged */ +void appl_send_light_lightness_linear_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LIGHTNESS_LINEAR_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lightness Linear Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Lightness (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.lightness = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + retval = MS_light_lightness_linear_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lightness Range Get */ +void appl_send_light_lightness_range_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Lightness Range Get\n"); + retval = MS_light_lightness_range_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lightness Range Set */ +void appl_send_light_lightness_range_set(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LIGHTNESS_RANGE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lightness Range Set\n"); + CONSOLE_OUT + ("Enter Range Min (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.range_min = (UINT16)choice; + CONSOLE_OUT + ("Enter Range Max (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.range_max = (UINT16)choice; + retval = MS_light_lightness_range_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lightness Range Set Unacknowledged */ +void appl_send_light_lightness_range_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LIGHTNESS_RANGE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lightness Range Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Range Min (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.range_min = (UINT16)choice; + CONSOLE_OUT + ("Enter Range Max (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.range_max = (UINT16)choice; + retval = MS_light_lightness_range_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lightness Set */ +void appl_send_light_lightness_set(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LIGHTNESS_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lightness Set\n"); + CONSOLE_OUT + ("Enter Lightness (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.lightness = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + retval = MS_light_lightness_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Lightness Set Unacknowledged */ +void appl_send_light_lightness_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LIGHTNESS_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lightness Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Lightness (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.lightness = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + retval = MS_light_lightness_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + + +/* Get Model Handle */ +void appl_light_lightness_client_get_model_handle(void) +{ + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_light_lightness_client_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + return; +} + + +/* Set Publish Address */ +void appl_light_lightness_client_set_publish_address(void) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + CONSOLE_OUT + ("Enter Model Handle (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + model_handle = (UINT16)choice; + CONSOLE_OUT + ("Enter Light_Lightness client Server Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKey Index\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.appkey_index = choice; + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Light_Lightness client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_light_lightness_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[LIGHT_LIGHTNESS_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_LIGHT_LIGHTNESS_DEFAULT_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_LIGHTNESS_DEFAULT_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_LIGHTNESS_LAST_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_LIGHTNESS_LAST_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_LIGHTNESS_LINEAR_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_LIGHTNESS_LINEAR_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_LIGHTNESS_RANGE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_LIGHTNESS_RANGE_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_LIGHTNESS_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_LIGHTNESS_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_light_lightness_client.h b/src/components/ethermind/mesh/export/appl/model/client/appl_light_lightness_client.h new file mode 100644 index 0000000..f96f527 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_light_lightness_client.h @@ -0,0 +1,96 @@ +/** + \file appl_light_lightness_client.h + + \brief This file defines the Mesh Light Lightness Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_LIGHT_LIGHTNESS_CLIENT_ +#define _H_APPL_LIGHT_LIGHTNESS_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_light_lightness_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* light_lightness client application entry point */ +void main_light_lightness_client_operations(void); + +/* Send Light Lightness Default Get */ +void appl_send_light_lightness_default_get(void); + +/* Send Light Lightness Default Set */ +void appl_send_light_lightness_default_set(void); + +/* Send Light Lightness Default Set Unacknowledged */ +void appl_send_light_lightness_default_set_unacknowledged(void); + +/* Send Light Lightness Get */ +void appl_send_light_lightness_get(void); + +/* Send Light Lightness Last Get */ +void appl_send_light_lightness_last_get(void); + +/* Send Light Lightness Linear Get */ +void appl_send_light_lightness_linear_get(void); + +/* Send Light Lightness Linear Set */ +void appl_send_light_lightness_linear_set(void); + +/* Send Light Lightness Linear Set Unacknowledged */ +void appl_send_light_lightness_linear_set_unacknowledged(void); + +/* Send Light Lightness Range Get */ +void appl_send_light_lightness_range_get(void); + +/* Send Light Lightness Range Set */ +void appl_send_light_lightness_range_set(void); + +/* Send Light Lightness Range Set Unacknowledged */ +void appl_send_light_lightness_range_set_unacknowledged(void); + +/* Send Light Lightness Set */ +void appl_send_light_lightness_set(void); + +/* Send Light Lightness Set Unacknowledged */ +void appl_send_light_lightness_set_unacknowledged(void); + +/* Get Model Handle */ +void appl_light_lightness_client_get_model_handle(void); + +/* Set Publish Address */ +void appl_light_lightness_client_set_publish_address(void); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Light_Lightness client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_light_lightness_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_APPL_LIGHT_LIGHTNESS_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_light_xyl_client.c b/src/components/ethermind/mesh/export/appl/model/client/appl_light_xyl_client.c new file mode 100644 index 0000000..90b9525 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_light_xyl_client.c @@ -0,0 +1,568 @@ +/** + \file appl_light_xyl_client.c + + \brief This file defines the Mesh Light Xyl Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_light_xyl_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_light_xyl_client_options[] = "\n\ +======== Light_Xyl Client Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 10. Send Light Xyl Default Get. \n\ + 11. Send Light Xyl Default Set. \n\ + 12. Send Light Xyl Default Set Unacknowledged. \n\ + 13. Send Light Xyl Get. \n\ + 14. Send Light Xyl Range Get. \n\ + 15. Send Light Xyl Range Set. \n\ + 16. Send Light Xyl Range Set Unacknowledged. \n\ + 17. Send Light Xyl Set. \n\ + 18. Send Light Xyl Set Unacknowledged. \n\ + 19. Send Light Xyl Target Get. \n\ + \n\ + 20. Get Model Handle. \n\ + 21. Set Publish Address. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_light_xyl_client_model_handle; + + +/* --------------------------------------------- Function */ +/* light_xyl client application entry point */ +void main_light_xyl_client_operations(void) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_light_xyl_client_init + ( + element_handle, + &appl_light_xyl_client_model_handle, + appl_light_xyl_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Xyl Client Initialized. Model Handle: 0x%04X\n", + appl_light_xyl_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Xyl Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_light_xyl_client_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 10: /* Send Light Xyl Default Get */ + appl_send_light_xyl_default_get(); + break; + + case 11: /* Send Light Xyl Default Set */ + appl_send_light_xyl_default_set(); + break; + + case 12: /* Send Light Xyl Default Set Unacknowledged */ + appl_send_light_xyl_default_set_unacknowledged(); + break; + + case 13: /* Send Light Xyl Get */ + appl_send_light_xyl_get(); + break; + + case 14: /* Send Light Xyl Range Get */ + appl_send_light_xyl_range_get(); + break; + + case 15: /* Send Light Xyl Range Set */ + appl_send_light_xyl_range_set(); + break; + + case 16: /* Send Light Xyl Range Set Unacknowledged */ + appl_send_light_xyl_range_set_unacknowledged(); + break; + + case 17: /* Send Light Xyl Set */ + appl_send_light_xyl_set(); + break; + + case 18: /* Send Light Xyl Set Unacknowledged */ + appl_send_light_xyl_set_unacknowledged(); + break; + + case 19: /* Send Light Xyl Target Get */ + appl_send_light_xyl_target_get(); + break; + + case 20: /* Get Model Handle */ + appl_light_xyl_client_get_model_handle(); + break; + + case 21: /* Set Publish Address */ + appl_light_xyl_client_set_publish_address(); + break; + } + } +} + +/* Send Light Xyl Default Get */ +void appl_send_light_xyl_default_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Xyl Default Get\n"); + retval = MS_light_xyl_default_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Xyl Default Set */ +void appl_send_light_xyl_default_set(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_XYL_DEFAULT_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Xyl Default Set\n"); + CONSOLE_OUT + ("Enter Lightness (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.lightness = (UINT16)choice; + CONSOLE_OUT + ("Enter xyL x (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.xyl_x = (UINT16)choice; + CONSOLE_OUT + ("Enter xyL y (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.xyl_y = (UINT16)choice; + retval = MS_light_xyl_default_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Xyl Default Set Unacknowledged */ +void appl_send_light_xyl_default_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_XYL_DEFAULT_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Xyl Default Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Lightness (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.lightness = (UINT16)choice; + CONSOLE_OUT + ("Enter xyL x (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.xyl_x = (UINT16)choice; + CONSOLE_OUT + ("Enter xyL y (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.xyl_y = (UINT16)choice; + retval = MS_light_xyl_default_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Xyl Get */ +void appl_send_light_xyl_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Xyl Get\n"); + retval = MS_light_xyl_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Xyl Range Get */ +void appl_send_light_xyl_range_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Xyl Range Get\n"); + retval = MS_light_xyl_range_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Xyl Range Set */ +void appl_send_light_xyl_range_set(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_XYL_RANGE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Xyl Range Set\n"); + CONSOLE_OUT + ("Enter xyL x Range Min (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.xyl_x_range_min = (UINT16)choice; + CONSOLE_OUT + ("Enter xyL x Range Max (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.xyl_x_range_max = (UINT16)choice; + CONSOLE_OUT + ("Enter xyL y Range Min (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.xyl_y_range_min = (UINT16)choice; + CONSOLE_OUT + ("Enter xyL y Range Max (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.xyl_y_range_max = (UINT16)choice; + retval = MS_light_xyl_range_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Xyl Range Set Unacknowledged */ +void appl_send_light_xyl_range_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_XYL_RANGE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Xyl Range Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter xyL x Range Min (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.xyl_x_range_min = (UINT16)choice; + CONSOLE_OUT + ("Enter xyL x Range Max (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.xyl_x_range_max = (UINT16)choice; + CONSOLE_OUT + ("Enter xyL y Range Min (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.xyl_y_range_min = (UINT16)choice; + CONSOLE_OUT + ("Enter xyL y Range Max (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.xyl_y_range_max = (UINT16)choice; + retval = MS_light_xyl_range_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Xyl Set */ +void appl_send_light_xyl_set(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_XYL_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Xyl Set\n"); + CONSOLE_OUT + ("Enter xyL Lightness (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.xyl_lightness = (UINT16)choice; + CONSOLE_OUT + ("Enter xyL x (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.xyl_x = (UINT16)choice; + CONSOLE_OUT + ("Enter xyL y (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.xyl_y = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_light_xyl_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Xyl Set Unacknowledged */ +void appl_send_light_xyl_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_LIGHT_XYL_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Xyl Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter xyL Lightness (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.xyl_lightness = (UINT16)choice; + CONSOLE_OUT + ("Enter xyL x (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.xyl_x = (UINT16)choice; + CONSOLE_OUT + ("Enter xyL y (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.xyl_y = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_light_xyl_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Light Xyl Target Get */ +void appl_send_light_xyl_target_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Xyl Target Get\n"); + retval = MS_light_xyl_target_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + + +/* Get Model Handle */ +void appl_light_xyl_client_get_model_handle(void) +{ + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_light_xyl_client_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + return; +} + + +/* Set Publish Address */ +void appl_light_xyl_client_set_publish_address(void) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + CONSOLE_OUT + ("Enter Model Handle (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + model_handle = (UINT16)choice; + CONSOLE_OUT + ("Enter Light_Xyl client Server Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKey Index\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.appkey_index = choice; + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Light_Xyl client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_light_xyl_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[LIGHT_XYL_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_LIGHT_XYL_DEFAULT_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_XYL_DEFAULT_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_XYL_RANGE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_XYL_RANGE_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_XYL_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_XYL_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_XYL_TARGET_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_XYL_TARGET_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_light_xyl_client.h b/src/components/ethermind/mesh/export/appl/model/client/appl_light_xyl_client.h new file mode 100644 index 0000000..acf7cf2 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_light_xyl_client.h @@ -0,0 +1,87 @@ +/** + \file appl_light_xyl_client.h + + \brief This file defines the Mesh Light Xyl Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_LIGHT_XYL_CLIENT_ +#define _H_APPL_LIGHT_XYL_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_light_xyl_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* light_xyl client application entry point */ +void main_light_xyl_client_operations(void); + +/* Send Light Xyl Default Get */ +void appl_send_light_xyl_default_get(void); + +/* Send Light Xyl Default Set */ +void appl_send_light_xyl_default_set(void); + +/* Send Light Xyl Default Set Unacknowledged */ +void appl_send_light_xyl_default_set_unacknowledged(void); + +/* Send Light Xyl Get */ +void appl_send_light_xyl_get(void); + +/* Send Light Xyl Range Get */ +void appl_send_light_xyl_range_get(void); + +/* Send Light Xyl Range Set */ +void appl_send_light_xyl_range_set(void); + +/* Send Light Xyl Range Set Unacknowledged */ +void appl_send_light_xyl_range_set_unacknowledged(void); + +/* Send Light Xyl Set */ +void appl_send_light_xyl_set(void); + +/* Send Light Xyl Set Unacknowledged */ +void appl_send_light_xyl_set_unacknowledged(void); + +/* Send Light Xyl Target Get */ +void appl_send_light_xyl_target_get(void); + +/* Get Model Handle */ +void appl_light_xyl_client_get_model_handle(void); + +/* Set Publish Address */ +void appl_light_xyl_client_set_publish_address(void); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Light_Xyl client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_light_xyl_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_APPL_LIGHT_XYL_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_main_model_client.c b/src/components/ethermind/mesh/export/appl/model/client/appl_main_model_client.c new file mode 100644 index 0000000..ca996bf --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_main_model_client.c @@ -0,0 +1,154 @@ + +/** + \file appl_main_model_client.c + + This File contains the "main" function for the Test Application + to test the Model Clients of Mindtree Mesh stack. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* ------------------------------- Header File Inclusion */ +#include "appl_main.h" + +/* ------------------------------- Global Variables */ +char main_model_client_options[] = " \n\ +================ M A I N M E N U ================ \n\ + 0. Exit. \n\ + 1. Refresh this Menu. \n\ + \n\ + 10. Config Client Operations. \n\ + 20. Health Client Operations. \n\ + \n\ + 30. Generic Onoff Client Operations. \n\ + 31. Generic Level Client Operations. \n\ + 32. Generic Default Transition Time Client Operations. \n\ + 33. Generic Power OnOff Client Operations. \n\ + 34. Generic Power Level Client Operations. \n\ + 35. Generic Battery Client Operations. \n\ + 36. Generic Location Client Operations. \n\ + 37. Generic Property Client Operations. \n\ + \n\ + 40. Sensor Client Operations. \n\ + \n\ + 50. Time Client Operations. \n\ + 51. Scene Client Operations. \n\ + 52. Scheduler Client Operations. \n\ + \n\ + 60. Light Lightness Client Operations. \n\ + 61. Light CTL Client Operations. \n\ + 62. Light HSL Client Operations. \n\ + 63. Light xyL Client Operations. \n\ + 64. Light LC Client Operations. \n\ + \n\ +Your Option ? \0"; + +/* ------------------------------- Functions */ +int main_model_client_operations (int argc, char** argv) +{ + int choice; + API_RESULT retval; + + while (1) + { + printf("\n"); + printf("%s", main_model_client_options); + scanf("%d", &choice); + + switch(choice) + { + case 0: + return 0; + + case 1: + printf("\nRefreshing ...\n\n"); + break; + + case 10: /* Config Client Operations */ + main_config_client_operations(); + break; + + case 20: /* Health Client Operations */ + main_health_client_operations(); + break; + + case 30: /* Generic Onoff Client Operations */ + main_generic_onoff_client_operations(); + break; + + case 31: /* Generic Level Client Operations */ + main_generic_level_client_operations(); + break; + + case 32: /* Generic Default Transition Time Client Operations */ + main_generic_default_transition_time_client_operations(); + break; + + case 33: /* Generic Power OnOff Client Operations */ + main_generic_power_onoff_client_operations(); + break; + + case 34: /* Generic Power Level Client Operations */ + main_generic_power_level_client_operations(); + break; + + case 35: /* Generic Battery Client Operations */ + main_generic_battery_client_operations(); + break; + + case 36: /* Generic Location Client Operations */ + main_generic_location_client_operations(); + break; + + case 37: /* Generic Property Client Operations */ + main_generic_property_client_operations(); + break; + + case 40: /* Sensor Client Operations */ + main_sensor_client_operations(); + break; + + case 50: /* Time Client Operations */ + main_time_client_operations(); + break; + + case 51: /* Scene Client Operations */ + main_scene_client_operations(); + break; + + case 52: /* Scheduler Client Operations */ + main_scheduler_client_operations(); + break; + + case 60: /* Light Lightness Client Operations */ + main_light_lightness_client_operations(); + break; + + case 61: /* Light CTL Client Operations */ + main_light_ctl_client_operations(); + break; + + case 62: /* Light HSL Client Operations */ + main_light_hsl_client_operations(); + break; + + case 63: /* Light xyL Client Operations */ + main_light_xyl_client_operations(); + break; + + case 64: /* Light LC Client Operations */ + main_light_lc_client_operations(); + break; + + default: + printf("Invalid Option : %d.\n", choice); + break; + } + } + + return 0; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_scene_client.c b/src/components/ethermind/mesh/export/appl/model/client/appl_scene_client.c new file mode 100644 index 0000000..94390bf --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_scene_client.c @@ -0,0 +1,452 @@ +/** + \file appl_scene_client.c + + \brief This file defines the Mesh Scene Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_scene_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_scene_client_options[] = "\n\ +======== Scene Client Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 10. Send Scene Delete. \n\ + 11. Send Scene Delete Unacknowledged. \n\ + 12. Send Scene Get. \n\ + 13. Send Scene Recall. \n\ + 14. Send Scene Recall Unacknowledged. \n\ + 15. Send Scene Register Get. \n\ + 16. Send Scene Store. \n\ + 17. Send Scene Store Unacknowledged. \n\ + \n\ + 18. Get Model Handle. \n\ + 19. Set Publish Address. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_scene_client_model_handle; + + +/* --------------------------------------------- Function */ +/* scene client application entry point */ +void main_scene_client_operations(void) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_scene_client_init + ( + element_handle, + &appl_scene_client_model_handle, + appl_scene_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Scene Client Initialized. Model Handle: 0x%04X\n", + appl_scene_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Scene Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_scene_client_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 10: /* Send Scene Delete */ + appl_send_scene_delete(); + break; + + case 11: /* Send Scene Delete Unacknowledged */ + appl_send_scene_delete_unacknowledged(); + break; + + case 12: /* Send Scene Get */ + appl_send_scene_get(); + break; + + case 13: /* Send Scene Recall */ + appl_send_scene_recall(); + break; + + case 14: /* Send Scene Recall Unacknowledged */ + appl_send_scene_recall_unacknowledged(); + break; + + case 15: /* Send Scene Register Get */ + appl_send_scene_register_get(); + break; + + case 16: /* Send Scene Store */ + appl_send_scene_store(); + break; + + case 17: /* Send Scene Store Unacknowledged */ + appl_send_scene_store_unacknowledged(); + break; + + case 18: /* Get Model Handle */ + appl_scene_client_get_model_handle(); + break; + + case 19: /* Set Publish Address */ + appl_scene_client_set_publish_address(); + break; + } + } +} + +/* Send Scene Delete */ +void appl_send_scene_delete(void) +{ + API_RESULT retval; + int choice; + MS_SCENE_STRUCT param; + CONSOLE_OUT + (">> Send Scene Delete\n"); + CONSOLE_OUT + ("Enter Scene Number (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.scene_number = (UINT16)choice; + retval = MS_scene_delete(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Scene Delete Unacknowledged */ +void appl_send_scene_delete_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_SCENE_STRUCT param; + CONSOLE_OUT + (">> Send Scene Delete Unacknowledged\n"); + CONSOLE_OUT + ("Enter Scene Number (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.scene_number = (UINT16)choice; + retval = MS_scene_delete_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Scene Get */ +void appl_send_scene_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Scene Get\n"); + retval = MS_scene_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Scene Recall */ +void appl_send_scene_recall(void) +{ + API_RESULT retval; + int choice; + MS_SCENE_RECALL_STRUCT param; + CONSOLE_OUT + (">> Send Scene Recall\n"); + CONSOLE_OUT + ("Enter Scene Number (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.scene_number = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_scene_recall(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Scene Recall Unacknowledged */ +void appl_send_scene_recall_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_SCENE_RECALL_STRUCT param; + CONSOLE_OUT + (">> Send Scene Recall Unacknowledged\n"); + CONSOLE_OUT + ("Enter Scene Number (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.scene_number = (UINT16)choice; + CONSOLE_OUT + ("Enter TID (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tid = (UCHAR)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Transition Time (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT + ("Enter Delay (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.delay = (UCHAR)choice; + } + + retval = MS_scene_recall_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Scene Register Get */ +void appl_send_scene_register_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Scene Register Get\n"); + retval = MS_scene_register_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Scene Store */ +void appl_send_scene_store(void) +{ + API_RESULT retval; + int choice; + MS_SCENE_STRUCT param; + CONSOLE_OUT + (">> Send Scene Store\n"); + CONSOLE_OUT + ("Enter Scene Number (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.scene_number = (UINT16)choice; + retval = MS_scene_store(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Scene Store Unacknowledged */ +void appl_send_scene_store_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_SCENE_STRUCT param; + CONSOLE_OUT + (">> Send Scene Store Unacknowledged\n"); + CONSOLE_OUT + ("Enter Scene Number (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.scene_number = (UINT16)choice; + retval = MS_scene_store_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + + +/* Get Model Handle */ +void appl_scene_client_get_model_handle(void) +{ + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_scene_client_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + return; +} + + +/* Set Publish Address */ +void appl_scene_client_set_publish_address(void) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + CONSOLE_OUT + ("Enter Model Handle (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + model_handle = (UINT16)choice; + CONSOLE_OUT + ("Enter Scene client Server Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKey Index\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.appkey_index = choice; + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Scene client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_scene_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[SCENE_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_SCENE_REGISTER_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SCENE_REGISTER_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_SCENE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SCENE_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_scene_client.h b/src/components/ethermind/mesh/export/appl/model/client/appl_scene_client.h new file mode 100644 index 0000000..27d7725 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_scene_client.h @@ -0,0 +1,81 @@ +/** + \file appl_scene_client.h + + \brief This file defines the Mesh Scene Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_SCENE_CLIENT_ +#define _H_APPL_SCENE_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_scene_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* scene client application entry point */ +void main_scene_client_operations(void); + +/* Send Scene Delete */ +void appl_send_scene_delete(void); + +/* Send Scene Delete Unacknowledged */ +void appl_send_scene_delete_unacknowledged(void); + +/* Send Scene Get */ +void appl_send_scene_get(void); + +/* Send Scene Recall */ +void appl_send_scene_recall(void); + +/* Send Scene Recall Unacknowledged */ +void appl_send_scene_recall_unacknowledged(void); + +/* Send Scene Register Get */ +void appl_send_scene_register_get(void); + +/* Send Scene Store */ +void appl_send_scene_store(void); + +/* Send Scene Store Unacknowledged */ +void appl_send_scene_store_unacknowledged(void); + +/* Get Model Handle */ +void appl_scene_client_get_model_handle(void); + +/* Set Publish Address */ +void appl_scene_client_set_publish_address(void); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Scene client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_scene_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_APPL_SCENE_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_scheduler_client.c b/src/components/ethermind/mesh/export/appl/model/client/appl_scheduler_client.c new file mode 100644 index 0000000..e95fdfd --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_scheduler_client.c @@ -0,0 +1,371 @@ +/** + \file appl_scheduler_client.c + + \brief This file defines the Mesh Scheduler Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_scheduler_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_scheduler_client_options[] = "\n\ +======== Scheduler Client Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 10. Send Scheduler Action Get. \n\ + 11. Send Scheduler Action Set. \n\ + 12. Send Scheduler Action Set Unacknowledged. \n\ + 13. Send Scheduler Get. \n\ + \n\ + 14. Get Model Handle. \n\ + 15. Set Publish Address. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_scheduler_client_model_handle; + + +/* --------------------------------------------- Function */ +/* scheduler client application entry point */ +void main_scheduler_client_operations(void) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_scheduler_client_init + ( + element_handle, + &appl_scheduler_client_model_handle, + appl_scheduler_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Scheduler Client Initialized. Model Handle: 0x%04X\n", + appl_scheduler_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Scheduler Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_scheduler_client_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 10: /* Send Scheduler Action Get */ + appl_send_scheduler_action_get(); + break; + + case 11: /* Send Scheduler Action Set */ + appl_send_scheduler_action_set(); + break; + + case 12: /* Send Scheduler Action Set Unacknowledged */ + appl_send_scheduler_action_set_unacknowledged(); + break; + + case 13: /* Send Scheduler Get */ + appl_send_scheduler_get(); + break; + + case 14: /* Get Model Handle */ + appl_scheduler_client_get_model_handle(); + break; + + case 15: /* Set Publish Address */ + appl_scheduler_client_set_publish_address(); + break; + } + } +} + +/* Send Scheduler Action Get */ +void appl_send_scheduler_action_get(void) +{ + API_RESULT retval; + int choice; + MS_SCHEDULER_ACTION_GET_STRUCT param; + CONSOLE_OUT + (">> Send Scheduler Action Get\n"); + CONSOLE_OUT + ("Enter Index (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.index = (UCHAR)choice; + retval = MS_scheduler_action_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Scheduler Action Set */ +void appl_send_scheduler_action_set(void) +{ + API_RESULT retval; + int choice; + MS_SCHEDULER_ACTION_SET_STRUCT param; + CONSOLE_OUT + (">> Send Scheduler Action Set\n"); + CONSOLE_OUT + ("Enter Index (4-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.index = (UCHAR)choice; + CONSOLE_OUT + ("Enter Schedule Register\n"); + appl_input_schedule_register(¶m); + retval = MS_scheduler_action_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Scheduler Action Set Unacknowledged */ +void appl_send_scheduler_action_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_SCHEDULER_ACTION_SET_STRUCT param; + CONSOLE_OUT + (">> Send Scheduler Action Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Index (4-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.index = (UCHAR)choice; + CONSOLE_OUT + ("Enter Schedule Register\n"); + appl_input_schedule_register(¶m); + retval = MS_scheduler_action_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* User input for Schedule Register fields */ +void appl_input_schedule_register( /* OUT */ MS_SCHEDULER_ACTION_SET_STRUCT* schedule_register) +{ + int choice; + CONSOLE_OUT + ("Enter Scheduled year for the action (7-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + schedule_register->year = (UINT8)choice; + CONSOLE_OUT + ("Enter Scheduled month for the action (12-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + schedule_register->month = (UINT16)choice; + CONSOLE_OUT + ("Enter Scheduled day of the month for the action (5-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + schedule_register->day = (UINT8)choice; + CONSOLE_OUT + ("Enter Scheduled hour for the action (5-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + schedule_register->hour = (UINT8)choice; + CONSOLE_OUT + ("Enter Scheduled minute for the action (6-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + schedule_register->minute = (UINT8)choice; + CONSOLE_OUT + ("Enter Scheduled second for the action (6-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + schedule_register->second = (UINT8)choice; + CONSOLE_OUT + ("Enter Scheduled days of the week for the action (7-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + schedule_register->day_of_week = (UINT8)choice; + CONSOLE_OUT + ("Enter Action to be performed at the scheduled time (4-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + schedule_register->action = (UINT8)choice; + CONSOLE_OUT + ("Enter Transition time for this action (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + schedule_register->transition_time = (UINT8)choice; + CONSOLE_OUT + ("Enter Scene number to be used for some actions (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + schedule_register->scene_number = (UINT16)choice; +} + +/* Send Scheduler Get */ +void appl_send_scheduler_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Scheduler Get\n"); + retval = MS_scheduler_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + + +/* Get Model Handle */ +void appl_scheduler_client_get_model_handle(void) +{ + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_scheduler_client_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + return; +} + + +/* Set Publish Address */ +void appl_scheduler_client_set_publish_address(void) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + CONSOLE_OUT + ("Enter Model Handle (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + model_handle = (UINT16)choice; + CONSOLE_OUT + ("Enter Scheduler client Server Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKey Index\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.appkey_index = choice; + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Scheduler client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_scheduler_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[SCHEDULER_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_SCHEDULER_ACTION_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SCHEDULER_ACTION_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_SCHEDULER_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SCHEDULER_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_scheduler_client.h b/src/components/ethermind/mesh/export/appl/model/client/appl_scheduler_client.h new file mode 100644 index 0000000..f14a1fb --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_scheduler_client.h @@ -0,0 +1,72 @@ +/** + \file appl_scheduler_client.h + + \brief This file defines the Mesh Scheduler Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_SCHEDULER_CLIENT_ +#define _H_APPL_SCHEDULER_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_scheduler_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* scheduler client application entry point */ +void main_scheduler_client_operations(void); + +/* Send Scheduler Action Get */ +void appl_send_scheduler_action_get(void); + +/* Send Scheduler Action Set */ +void appl_send_scheduler_action_set(void); + +/* Send Scheduler Action Set Unacknowledged */ +void appl_send_scheduler_action_set_unacknowledged(void); + +/* User input for Schedule Register fields */ +void appl_input_schedule_register( /* OUT */ MS_SCHEDULER_ACTION_SET_STRUCT* schedule_register); + +/* Send Scheduler Get */ +void appl_send_scheduler_get(void); + +/* Get Model Handle */ +void appl_scheduler_client_get_model_handle(void); + +/* Set Publish Address */ +void appl_scheduler_client_set_publish_address(void); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Scheduler client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_scheduler_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_APPL_SCHEDULER_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_sensor_client.c b/src/components/ethermind/mesh/export/appl/model/client/appl_sensor_client.c new file mode 100644 index 0000000..4dc430a --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_sensor_client.c @@ -0,0 +1,980 @@ +/** + \file appl_sensor_client.c + + \brief This file defines the Mesh Sensor Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_sensor_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_sensor_client_options[] = "\n\ +======== Sensor Client Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 10. Send Sensor Cadence Get. \n\ + 11. Send Sensor Cadence Set. \n\ + 12. Send Sensor Cadence Set Unacknowledged. \n\ + 13. Send Sensor Column Get. \n\ + 14. Send Sensor Descriptor Get. \n\ + 15. Send Sensor Get. \n\ + 16. Send Sensor Series Get. \n\ + 17. Send Sensor Setting Get. \n\ + 18. Send Sensor Setting Set. \n\ + 19. Send Sensor Setting Set Unacknowledged. \n\ + 20. Send Sensor Settings Get. \n\ + \n\ + 21. Get Model Handle. \n\ + 22. Set Publish Address. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_sensor_client_model_handle; + + +/* --------------------------------------------- Function */ +/* sensor client application entry point */ +void main_sensor_client_operations(void) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_sensor_client_init + ( + element_handle, + &appl_sensor_client_model_handle, + appl_sensor_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Sensor Client Initialized. Model Handle: 0x%04X\n", + appl_sensor_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Sensor Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_sensor_client_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 10: /* Send Sensor Cadence Get */ + appl_send_sensor_cadence_get(); + break; + + case 11: /* Send Sensor Cadence Set */ + appl_send_sensor_cadence_set(); + break; + + case 12: /* Send Sensor Cadence Set Unacknowledged */ + appl_send_sensor_cadence_set_unacknowledged(); + break; + + case 13: /* Send Sensor Column Get */ + appl_send_sensor_column_get(); + break; + + case 14: /* Send Sensor Descriptor Get */ + appl_send_sensor_descriptor_get(); + break; + + case 15: /* Send Sensor Get */ + appl_send_sensor_get(); + break; + + case 16: /* Send Sensor Series Get */ + appl_send_sensor_series_get(); + break; + + case 17: /* Send Sensor Setting Get */ + appl_send_sensor_setting_get(); + break; + + case 18: /* Send Sensor Setting Set */ + appl_send_sensor_setting_set(); + break; + + case 19: /* Send Sensor Setting Set Unacknowledged */ + appl_send_sensor_setting_set_unacknowledged(); + break; + + case 20: /* Send Sensor Settings Get */ + appl_send_sensor_settings_get(); + break; + + case 21: /* Get Model Handle */ + appl_sensor_client_get_model_handle(); + break; + + case 22: /* Set Publish Address */ + appl_sensor_client_set_publish_address(); + break; + } + } +} + +/* Send Sensor Cadence Get */ +void appl_send_sensor_cadence_get(void) +{ + API_RESULT retval; + int choice; + MS_SENSOR_CADENCE_GET_STRUCT param; + CONSOLE_OUT + (">> Send Sensor Cadence Get\n"); + CONSOLE_OUT + ("Enter Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.property_id = (UINT16)choice; + retval = MS_sensor_cadence_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Sensor Cadence Set */ +void appl_send_sensor_cadence_set(void) +{ + API_RESULT retval; + int choice; + MS_SENSOR_CADENCE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Sensor Cadence Set\n"); + CONSOLE_OUT + ("Enter Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.property_id = (UINT16)choice; + CONSOLE_OUT + ("Enter Fast Cadence Period Divisor (7-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.fast_cadence_period_divisor = (UCHAR)choice; + CONSOLE_OUT + ("Enter Status Trigger Type (1-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.status_trigger_type = (UCHAR)choice; + CONSOLE_OUT + ("Enter Status Trigger Delta Down Length (in decimal)\n"); + CONSOLE_IN + ("%d", &choice); + CONSOLE_OUT + ("Enter Status Trigger Delta Down (%d-octets in HEX)\n", (UINT16)choice); + { + UINT16 index, input_len; + input_len = (UINT16)choice; + param.status_trigger_delta_down = EM_alloc_mem(input_len); + + if(NULL == param.status_trigger_delta_down) + { + CONSOLE_OUT + ("Memory allocation failed for Status Trigger Delta Down. Returning\n"); + return; + } + + param.status_trigger_delta_down_len = (UINT16) input_len; + + for(index = 0; index < input_len; index++) + { + CONSOLE_IN + ("%x", &choice); + param.status_trigger_delta_down[index] = (UCHAR)choice; + } + } + CONSOLE_OUT + ("Enter Status Trigger Delta Up Length (in decimal)\n"); + CONSOLE_IN + ("%d", &choice); + CONSOLE_OUT + ("Enter Status Trigger Delta Up (%d-octets in HEX)\n", (UINT16)choice); + { + UINT16 index, input_len; + input_len = (UINT16)choice; + param.status_trigger_delta_up = EM_alloc_mem(input_len); + + if(NULL == param.status_trigger_delta_up) + { + CONSOLE_OUT + ("Memory allocation failed for Status Trigger Delta Up. Returning\n"); + return; + } + + param.status_trigger_delta_up_len = (UINT16) input_len; + + for(index = 0; index < input_len; index++) + { + CONSOLE_IN + ("%x", &choice); + param.status_trigger_delta_up[index] = (UCHAR)choice; + } + } + CONSOLE_OUT + ("Enter Status Min Interval (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.status_min_interval = (UCHAR)choice; + CONSOLE_OUT + ("Enter Fast Cadence Low Length (in decimal)\n"); + CONSOLE_IN + ("%d", &choice); + CONSOLE_OUT + ("Enter Fast Cadence Low (%d-octets in HEX)\n", (UINT16)choice); + { + UINT16 index, input_len; + input_len = (UINT16)choice; + param.fast_cadence_low = EM_alloc_mem(input_len); + + if(NULL == param.fast_cadence_low) + { + CONSOLE_OUT + ("Memory allocation failed for Fast Cadence Low. Returning\n"); + return; + } + + param.fast_cadence_low_len = (UINT16) input_len; + + for(index = 0; index < input_len; index++) + { + CONSOLE_IN + ("%x", &choice); + param.fast_cadence_low[index] = (UCHAR)choice; + } + } + CONSOLE_OUT + ("Enter Fast Cadence High Length (in decimal)\n"); + CONSOLE_IN + ("%d", &choice); + CONSOLE_OUT + ("Enter Fast Cadence High (%d-octets in HEX)\n", (UINT16)choice); + { + UINT16 index, input_len; + input_len = (UINT16)choice; + param.fast_cadence_high = EM_alloc_mem(input_len); + + if(NULL == param.fast_cadence_high) + { + CONSOLE_OUT + ("Memory allocation failed for Fast Cadence High. Returning\n"); + return; + } + + param.fast_cadence_high_len = (UINT16) input_len; + + for(index = 0; index < input_len; index++) + { + CONSOLE_IN + ("%x", &choice); + param.fast_cadence_high[index] = (UCHAR)choice; + } + } + retval = MS_sensor_cadence_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.fast_cadence_high) + { + EM_free_mem(param.fast_cadence_high); + } +} + +/* Send Sensor Cadence Set Unacknowledged */ +void appl_send_sensor_cadence_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_SENSOR_CADENCE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Sensor Cadence Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.property_id = (UINT16)choice; + CONSOLE_OUT + ("Enter Fast Cadence Period Divisor (7-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.fast_cadence_period_divisor = (UCHAR)choice; + CONSOLE_OUT + ("Enter Status Trigger Type (1-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.status_trigger_type = (UCHAR)choice; + CONSOLE_OUT + ("Enter Status Trigger Delta Down Length (in decimal)\n"); + CONSOLE_IN + ("%d", &choice); + CONSOLE_OUT + ("Enter Status Trigger Delta Down (%d-octets in HEX)\n", (UINT16)choice); + { + UINT16 index, input_len; + input_len = (UINT16)choice; + param.status_trigger_delta_down = EM_alloc_mem(input_len); + + if(NULL == param.status_trigger_delta_down) + { + CONSOLE_OUT + ("Memory allocation failed for Status Trigger Delta Down. Returning\n"); + return; + } + + param.status_trigger_delta_down_len = (UINT16) input_len; + + for(index = 0; index < input_len; index++) + { + CONSOLE_IN + ("%x", &choice); + param.status_trigger_delta_down[index] = (UCHAR)choice; + } + } + CONSOLE_OUT + ("Enter Status Trigger Delta Up Length (in decimal)\n"); + CONSOLE_IN + ("%d", &choice); + CONSOLE_OUT + ("Enter Status Trigger Delta Up (%d-octets in HEX)\n", (UINT16)choice); + { + UINT16 index, input_len; + input_len = (UINT16)choice; + param.status_trigger_delta_up = EM_alloc_mem(input_len); + + if(NULL == param.status_trigger_delta_up) + { + CONSOLE_OUT + ("Memory allocation failed for Status Trigger Delta Up. Returning\n"); + return; + } + + param.status_trigger_delta_up_len = (UINT16) input_len; + + for(index = 0; index < input_len; index++) + { + CONSOLE_IN + ("%x", &choice); + param.status_trigger_delta_up[index] = (UCHAR)choice; + } + } + CONSOLE_OUT + ("Enter Status Min Interval (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.status_min_interval = (UCHAR)choice; + CONSOLE_OUT + ("Enter Fast Cadence Low Length (in decimal)\n"); + CONSOLE_IN + ("%d", &choice); + CONSOLE_OUT + ("Enter Fast Cadence Low (%d-octets in HEX)\n", (UINT16)choice); + { + UINT16 index, input_len; + input_len = (UINT16)choice; + param.fast_cadence_low = EM_alloc_mem(input_len); + + if(NULL == param.fast_cadence_low) + { + CONSOLE_OUT + ("Memory allocation failed for Fast Cadence Low. Returning\n"); + return; + } + + param.fast_cadence_low_len = (UINT16) input_len; + + for(index = 0; index < input_len; index++) + { + CONSOLE_IN + ("%x", &choice); + param.fast_cadence_low[index] = (UCHAR)choice; + } + } + CONSOLE_OUT + ("Enter Fast Cadence High Length (in decimal)\n"); + CONSOLE_IN + ("%d", &choice); + CONSOLE_OUT + ("Enter Fast Cadence High (%d-octets in HEX)\n", (UINT16)choice); + { + UINT16 index, input_len; + input_len = (UINT16)choice; + param.fast_cadence_high = EM_alloc_mem(input_len); + + if(NULL == param.fast_cadence_high) + { + CONSOLE_OUT + ("Memory allocation failed for Fast Cadence High. Returning\n"); + return; + } + + param.fast_cadence_high_len = (UINT16) input_len; + + for(index = 0; index < input_len; index++) + { + CONSOLE_IN + ("%x", &choice); + param.fast_cadence_high[index] = (UCHAR)choice; + } + } + retval = MS_sensor_cadence_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.fast_cadence_high) + { + EM_free_mem(param.fast_cadence_high); + } +} + +/* Send Sensor Column Get */ +void appl_send_sensor_column_get(void) +{ + API_RESULT retval; + int choice; + MS_SENSOR_COLUMN_GET_STRUCT param; + CONSOLE_OUT + (">> Send Sensor Column Get\n"); + CONSOLE_OUT + ("Enter Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.property_id = (UINT16)choice; + CONSOLE_OUT + ("Enter Raw Value X Length (in decimal)\n"); + CONSOLE_IN + ("%d", &choice); + CONSOLE_OUT + ("Enter Raw Value X (%d-octets in HEX)\n", (UINT16)choice); + { + UINT16 index, input_len; + input_len = (UINT16)choice; + param.raw_value_x = EM_alloc_mem(input_len); + + if(NULL == param.raw_value_x) + { + CONSOLE_OUT + ("Memory allocation failed for Raw Value X. Returning\n"); + return; + } + + param.raw_value_x_len = (UINT16) input_len; + + for(index = 0; index < input_len; index++) + { + CONSOLE_IN + ("%x", &choice); + param.raw_value_x[index] = (UCHAR)choice; + } + } + retval = MS_sensor_column_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.raw_value_x) + { + EM_free_mem(param.raw_value_x); + } +} + +/* Send Sensor Descriptor Get */ +void appl_send_sensor_descriptor_get(void) +{ + API_RESULT retval; + int choice; + MS_SENSOR_DESCRIPTOR_GET_STRUCT param; + CONSOLE_OUT + (">> Send Sensor Descriptor Get\n"); + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.property_id = (UINT16)choice; + } + + retval = MS_sensor_descriptor_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Sensor Get */ +void appl_send_sensor_get(void) +{ + API_RESULT retval; + int choice; + MS_SENSOR_GET_STRUCT param; + CONSOLE_OUT + (">> Send Sensor Get\n"); + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.property_id = (UINT16)choice; + } + + retval = MS_sensor_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Sensor Series Get */ +void appl_send_sensor_series_get(void) +{ + API_RESULT retval; + int choice; + MS_SENSOR_SERIES_GET_STRUCT param; + CONSOLE_OUT + (">> Send Sensor Series Get\n"); + CONSOLE_OUT + ("Enter Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.property_id = (UINT16)choice; + CONSOLE_OUT + ("Enter if optional fields to be send (1 - Yes, 0 - No)\n"); + CONSOLE_IN + ("%d", &choice); + + if(0 == choice) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Enter Raw Value X1 Length (in decimal)\n"); + CONSOLE_IN + ("%d", &choice); + CONSOLE_OUT + ("Enter Raw Value X1 (%d-octets in HEX)\n", (UINT16)choice); + { + UINT16 index, input_len; + input_len = (UINT16)choice; + param.raw_value_x1 = EM_alloc_mem(input_len); + + if(NULL == param.raw_value_x1) + { + CONSOLE_OUT + ("Memory allocation failed for Raw Value X1. Returning\n"); + return; + } + + param.raw_value_x1_len = (UINT16) input_len; + + for(index = 0; index < input_len; index++) + { + CONSOLE_IN + ("%x", &choice); + param.raw_value_x1[index] = (UCHAR)choice; + } + } + CONSOLE_OUT + ("Enter Raw Value X2 Length (in decimal)\n"); + CONSOLE_IN + ("%d", &choice); + CONSOLE_OUT + ("Enter Raw Value X2 (%d-octets in HEX)\n", (UINT16)choice); + { + UINT16 index, input_len; + input_len = (UINT16)choice; + param.raw_value_x2 = EM_alloc_mem(input_len); + + if(NULL == param.raw_value_x2) + { + CONSOLE_OUT + ("Memory allocation failed for Raw Value X2. Returning\n"); + return; + } + + param.raw_value_x2_len = (UINT16) input_len; + + for(index = 0; index < input_len; index++) + { + CONSOLE_IN + ("%x", &choice); + param.raw_value_x2[index] = (UCHAR)choice; + } + } + } + + retval = MS_sensor_series_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.raw_value_x2) + { + EM_free_mem(param.raw_value_x2); + } +} + +/* Send Sensor Setting Get */ +void appl_send_sensor_setting_get(void) +{ + API_RESULT retval; + int choice; + MS_SENSOR_SETTING_GET_STRUCT param; + CONSOLE_OUT + (">> Send Sensor Setting Get\n"); + CONSOLE_OUT + ("Enter Sensor Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.sensor_property_id = (UINT16)choice; + CONSOLE_OUT + ("Enter Sensor Setting Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.sensor_setting_property_id = (UINT16)choice; + retval = MS_sensor_setting_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Sensor Setting Set */ +void appl_send_sensor_setting_set(void) +{ + API_RESULT retval; + int choice; + MS_SENSOR_SETTING_SET_STRUCT param; + CONSOLE_OUT + (">> Send Sensor Setting Set\n"); + CONSOLE_OUT + ("Enter Sensor Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.sensor_property_id = (UINT16)choice; + CONSOLE_OUT + ("Enter Sensor Setting Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.sensor_setting_property_id = (UINT16)choice; + CONSOLE_OUT + ("Enter Sensor Setting Raw Length (in decimal)\n"); + CONSOLE_IN + ("%d", &choice); + CONSOLE_OUT + ("Enter Sensor Setting Raw (%d-octets in HEX)\n", (UINT16)choice); + { + UINT16 index, input_len; + input_len = (UINT16)choice; + param.sensor_setting_raw = EM_alloc_mem(input_len); + + if(NULL == param.sensor_setting_raw) + { + CONSOLE_OUT + ("Memory allocation failed for Sensor Setting Raw. Returning\n"); + return; + } + + param.sensor_setting_raw_len = (UINT16) input_len; + + for(index = 0; index < input_len; index++) + { + CONSOLE_IN + ("%x", &choice); + param.sensor_setting_raw[index] = (UCHAR)choice; + } + } + retval = MS_sensor_setting_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.sensor_setting_raw) + { + EM_free_mem(param.sensor_setting_raw); + } +} + +/* Send Sensor Setting Set Unacknowledged */ +void appl_send_sensor_setting_set_unacknowledged(void) +{ + API_RESULT retval; + int choice; + MS_SENSOR_SETTING_SET_STRUCT param; + CONSOLE_OUT + (">> Send Sensor Setting Set Unacknowledged\n"); + CONSOLE_OUT + ("Enter Sensor Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.sensor_property_id = (UINT16)choice; + CONSOLE_OUT + ("Enter Sensor Setting Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.sensor_setting_property_id = (UINT16)choice; + CONSOLE_OUT + ("Enter Sensor Setting Raw Length (in decimal)\n"); + CONSOLE_IN + ("%d", &choice); + CONSOLE_OUT + ("Enter Sensor Setting Raw (%d-octets in HEX)\n", (UINT16)choice); + { + UINT16 index, input_len; + input_len = (UINT16)choice; + param.sensor_setting_raw = EM_alloc_mem(input_len); + + if(NULL == param.sensor_setting_raw) + { + CONSOLE_OUT + ("Memory allocation failed for Sensor Setting Raw. Returning\n"); + return; + } + + param.sensor_setting_raw_len = (UINT16) input_len; + + for(index = 0; index < input_len; index++) + { + CONSOLE_IN + ("%x", &choice); + param.sensor_setting_raw[index] = (UCHAR)choice; + } + } + retval = MS_sensor_setting_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.sensor_setting_raw) + { + EM_free_mem(param.sensor_setting_raw); + } +} + +/* Send Sensor Settings Get */ +void appl_send_sensor_settings_get(void) +{ + API_RESULT retval; + int choice; + MS_SENSOR_SETTINGS_GET_STRUCT param; + CONSOLE_OUT + (">> Send Sensor Settings Get\n"); + CONSOLE_OUT + ("Enter Sensor Property ID (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.sensor_property_id = (UINT16)choice; + retval = MS_sensor_settings_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + + +/* Get Model Handle */ +void appl_sensor_client_get_model_handle(void) +{ + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_sensor_client_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + return; +} + + +/* Set Publish Address */ +void appl_sensor_client_set_publish_address(void) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + CONSOLE_OUT + ("Enter Model Handle (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + model_handle = (UINT16)choice; + CONSOLE_OUT + ("Enter Sensor client Server Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKey Index\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.appkey_index = choice; + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Sensor client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_sensor_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[SENSOR_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_SENSOR_CADENCE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SENSOR_CADENCE_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_SENSOR_COLUMN_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SENSOR_COLUMN_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_SENSOR_DESCRIPTOR_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SENSOR_DESCRIPTOR_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_SENSOR_SERIES_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SENSOR_SERIES_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_SENSOR_SETTING_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SENSOR_SETTING_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_SENSOR_SETTINGS_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SENSOR_SETTINGS_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_SENSOR_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SENSOR_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_sensor_client.h b/src/components/ethermind/mesh/export/appl/model/client/appl_sensor_client.h new file mode 100644 index 0000000..e08e780 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_sensor_client.h @@ -0,0 +1,90 @@ +/** + \file appl_sensor_client.h + + \brief This file defines the Mesh Sensor Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_SENSOR_CLIENT_ +#define _H_APPL_SENSOR_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_sensor_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* sensor client application entry point */ +void main_sensor_client_operations(void); + +/* Send Sensor Cadence Get */ +void appl_send_sensor_cadence_get(void); + +/* Send Sensor Cadence Set */ +void appl_send_sensor_cadence_set(void); + +/* Send Sensor Cadence Set Unacknowledged */ +void appl_send_sensor_cadence_set_unacknowledged(void); + +/* Send Sensor Column Get */ +void appl_send_sensor_column_get(void); + +/* Send Sensor Descriptor Get */ +void appl_send_sensor_descriptor_get(void); + +/* Send Sensor Get */ +void appl_send_sensor_get(void); + +/* Send Sensor Series Get */ +void appl_send_sensor_series_get(void); + +/* Send Sensor Setting Get */ +void appl_send_sensor_setting_get(void); + +/* Send Sensor Setting Set */ +void appl_send_sensor_setting_set(void); + +/* Send Sensor Setting Set Unacknowledged */ +void appl_send_sensor_setting_set_unacknowledged(void); + +/* Send Sensor Settings Get */ +void appl_send_sensor_settings_get(void); + +/* Get Model Handle */ +void appl_sensor_client_get_model_handle(void); + +/* Set Publish Address */ +void appl_sensor_client_set_publish_address(void); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Sensor client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_sensor_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_APPL_SENSOR_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_time_client.c b/src/components/ethermind/mesh/export/appl/model/client/appl_time_client.c new file mode 100644 index 0000000..e5a54f5 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_time_client.c @@ -0,0 +1,455 @@ +/** + \file appl_time_client.c + + \brief This file defines the Mesh Time Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_time_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_time_client_options[] = "\n\ +======== Time Client Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 10. Send Tai Utc Delta Get. \n\ + 11. Send Tai Utc Delta Set. \n\ + 12. Send Time Get. \n\ + 13. Send Time Role Get. \n\ + 14. Send Time Role Set. \n\ + 15. Send Time Set. \n\ + 16. Send Time Zone Get. \n\ + 17. Send Time Zone Set. \n\ + \n\ + 18. Get Model Handle. \n\ + 19. Set Publish Address. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_time_client_model_handle; + + +/* --------------------------------------------- Function */ +/* time client application entry point */ +void main_time_client_operations(void) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_time_client_init + ( + element_handle, + &appl_time_client_model_handle, + appl_time_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Time Client Initialized. Model Handle: 0x%04X\n", + appl_time_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Time Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_time_client_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 10: /* Send Tai Utc Delta Get */ + appl_send_tai_utc_delta_get(); + break; + + case 11: /* Send Tai Utc Delta Set */ + appl_send_tai_utc_delta_set(); + break; + + case 12: /* Send Time Get */ + appl_send_time_get(); + break; + + case 13: /* Send Time Role Get */ + appl_send_time_role_get(); + break; + + case 14: /* Send Time Role Set */ + appl_send_time_role_set(); + break; + + case 15: /* Send Time Set */ + appl_send_time_set(); + break; + + case 16: /* Send Time Zone Get */ + appl_send_time_zone_get(); + break; + + case 17: /* Send Time Zone Set */ + appl_send_time_zone_set(); + break; + + case 18: /* Get Model Handle */ + appl_time_client_get_model_handle(); + break; + + case 19: /* Set Publish Address */ + appl_time_client_set_publish_address(); + break; + } + } +} + +/* Send Tai Utc Delta Get */ +void appl_send_tai_utc_delta_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Tai Utc Delta Get\n"); + retval = MS_tai_utc_delta_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Tai Utc Delta Set */ +void appl_send_tai_utc_delta_set(void) +{ + API_RESULT retval; + int choice; + MS_TAI_UTC_DELTA_SET_STRUCT param; + CONSOLE_OUT + (">> Send Tai Utc Delta Set\n"); + CONSOLE_OUT + ("Enter TAI UTC Delta New (15-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tai_utc_delta_new = (UINT16)choice; + CONSOLE_OUT + ("Enter Padding (1-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.padding = (UCHAR)choice; + CONSOLE_OUT + ("Enter TAI of Delta Change (5-octets in HEX)\n"); + { + UINT16 index; + + for(index = 0; index < 5; index++) + { + CONSOLE_IN + ("%x", &choice); + param.tai_of_delta_change[index] = (UCHAR)choice; + } + } + retval = MS_tai_utc_delta_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Time Get */ +void appl_send_time_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Time Get\n"); + retval = MS_time_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Time Role Get */ +void appl_send_time_role_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Time Role Get\n"); + retval = MS_time_role_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Time Role Set */ +void appl_send_time_role_set(void) +{ + API_RESULT retval; + int choice; + MS_TIME_ROLE_STRUCT param; + CONSOLE_OUT + (">> Send Time Role Set\n"); + CONSOLE_OUT + ("Enter Time Role (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.time_role = (UCHAR)choice; + retval = MS_time_role_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Time Set */ +void appl_send_time_set(void) +{ + API_RESULT retval; + int choice; + MS_TIME_STRUCT param; + CONSOLE_OUT + (">> Send Time Set\n"); + CONSOLE_OUT + ("Enter TAI Seconds (5-octets in HEX)\n"); + { + UINT16 index; + + for(index = 0; index < 5; index++) + { + CONSOLE_IN + ("%x", &choice); + param.tai_seconds[index] = (UCHAR)choice; + } + } + CONSOLE_OUT + ("Enter Subsecond (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.subsecond = (UCHAR)choice; + CONSOLE_OUT + ("Enter Uncertainty (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.uncertainty = (UCHAR)choice; + CONSOLE_OUT + ("Enter Time Authority (1-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.time_authority = (UCHAR)choice; + CONSOLE_OUT + ("Enter TAI UTC Delta (15-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.tai_utc_delta = (UINT16)choice; + CONSOLE_OUT + ("Enter Time Zone Offset (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.time_zone_offset = (UCHAR)choice; + retval = MS_time_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Time Zone Get */ +void appl_send_time_zone_get(void) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Time Zone Get\n"); + retval = MS_time_zone_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + +/* Send Time Zone Set */ +void appl_send_time_zone_set(void) +{ + API_RESULT retval; + int choice; + MS_TIME_ZONE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Time Zone Set\n"); + CONSOLE_OUT + ("Enter Time Zone Offset New (8-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + param.time_zone_offset_new = (UCHAR)choice; + CONSOLE_OUT + ("Enter TAI of Zone Change (5-octets in HEX)\n"); + { + UINT16 index; + + for(index = 0; index < 5; index++) + { + CONSOLE_IN + ("%x", &choice); + param.tai_of_zone_change[index] = (UCHAR)choice; + } + } + retval = MS_time_zone_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); +} + + +/* Get Model Handle */ +void appl_time_client_get_model_handle(void) +{ + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_time_client_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + return; +} + + +/* Set Publish Address */ +void appl_time_client_set_publish_address(void) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + CONSOLE_OUT + ("Enter Model Handle (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + model_handle = (UINT16)choice; + CONSOLE_OUT + ("Enter Time client Server Address (16-bit in HEX)\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT + ("Enter AppKey Index\n"); + CONSOLE_IN + ("%x", &choice); + publish_info.appkey_index = choice; + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Time client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_time_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[TIME_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_TAI_UTC_DELTA_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_TAI_UTC_DELTA_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_TIME_ROLE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_TIME_ROLE_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_TIME_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_TIME_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_TIME_ZONE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_TIME_ZONE_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/client/appl_time_client.h b/src/components/ethermind/mesh/export/appl/model/client/appl_time_client.h new file mode 100644 index 0000000..492c995 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/client/appl_time_client.h @@ -0,0 +1,81 @@ +/** + \file appl_time_client.h + + \brief This file defines the Mesh Time Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_TIME_CLIENT_ +#define _H_APPL_TIME_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_time_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* time client application entry point */ +void main_time_client_operations(void); + +/* Send Tai Utc Delta Get */ +void appl_send_tai_utc_delta_get(void); + +/* Send Tai Utc Delta Set */ +void appl_send_tai_utc_delta_set(void); + +/* Send Time Get */ +void appl_send_time_get(void); + +/* Send Time Role Get */ +void appl_send_time_role_get(void); + +/* Send Time Role Set */ +void appl_send_time_role_set(void); + +/* Send Time Set */ +void appl_send_time_set(void); + +/* Send Time Zone Get */ +void appl_send_time_zone_get(void); + +/* Send Time Zone Set */ +void appl_send_time_zone_set(void); + +/* Get Model Handle */ +void appl_time_client_get_model_handle(void); + +/* Set Publish Address */ +void appl_time_client_set_publish_address(void); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Time client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_time_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_APPL_TIME_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/appl_main_model_server.c b/src/components/ethermind/mesh/export/appl/model/server/appl_main_model_server.c new file mode 100644 index 0000000..bff0efb --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/appl_main_model_server.c @@ -0,0 +1,147 @@ + +/** + \file appl_main_model_server.c + + This File contains the "main" function for the Test Application + to test the Model Servers of Mindtree Mesh stack. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* ------------------------------- Header File Inclusion */ +#include "appl_main.h" + +#if 0 +/* ------------------------------- Global Variables */ +char main_model_server_options[] = " \n\ +================ M A I N M E N U ================ \n\ + 0. Exit. \n\ + 1. Refresh this Menu. \n\ + \n\ + 10. Health Server Operations. \n\ + \n\ + 20. Generic Onoff Server Operations. \n\ + 21. Generic Level Server Operations. \n\ + 22. Generic Default Transition Time Server Operations. \n\ + 23. Generic Power OnOff Server Operations. \n\ + 24. Generic Power Level Server Operations. \n\ + 25. Generic Battery Server Operations. \n\ + 26. Generic Location Server Operations. \n\ + 27. Generic Property Server Operations. \n\ + \n\ + 40. Sensor Server Operations. \n\ + \n\ + 50. Time Server Operations. \n\ + 51. Scene Server Operations. \n\ + 52. Scheduler Server Operations. \n\ + \n\ + 60. Light Lightness Server Operations. \n\ + 61. Light CTL Server Operations. \n\ + 62. Light HSL Server Operations. \n\ + 63. Light xyL Server Operations. \n\ + 64. Light LC Server Operations. \n\ + \n\ +Your Option ? \0"; + +/* ------------------------------- Functions */ +int main_model_server_operations (int argc, char** argv) +{ + int choice; + MS_LOOP_FOREVER() + { + printf("\n"); + printf("%s", main_model_server_options); + scanf("%d", &choice); + + switch(choice) + { + case 0: + return 0; + + case 1: + printf("\nRefreshing ...\n\n"); + break; + + case 10: /* Health Server Operations */ + main_health_server_operations(MS_TRUE); + break; + + case 20: /* Generic Onoff Server Operations */ + main_generic_onoff_server_operations(MS_TRUE); + break; + + case 21: /* Generic Level Server Operations */ + main_generic_level_server_operations(MS_TRUE); + break; + + case 22: /* Generic Default Transition Time Server Operations */ + main_generic_default_transition_time_server_operations(MS_TRUE); + break; + + case 23: /* Generic Power OnOff Server Operations */ + main_generic_power_onoff_server_operations(MS_TRUE); + break; + + case 24: /* Generic Power Level Server Operations */ + main_generic_power_level_server_operations(MS_TRUE); + break; + + case 25: /* Generic Battery Server Operations */ + main_generic_battery_server_operations(MS_TRUE); + break; + + case 26: /* Generic Location Server Operations */ + main_generic_location_server_operations(MS_TRUE); + break; + + case 27: /* Generic Property Server Operations */ + main_generic_property_server_operations(MS_TRUE); + break; + + case 40: /* Sensor Server Operations */ + main_sensor_server_operations(MS_TRUE); + break; + + case 50: /* Time Server Operations */ + main_time_server_operations(MS_TRUE); + break; + + case 51: /* Scene Server Operations */ + main_scene_server_operations(MS_TRUE); + break; + + case 52: /* Scheduler Server Operations */ + main_scheduler_server_operations(MS_TRUE); + break; + + case 60: /* Light Lightness Server Operations */ + main_light_lightness_server_operations(MS_TRUE); + break; + + case 61: /* Light CTL Server Operations */ + main_light_ctl_server_operations(MS_TRUE); + break; + + case 62: /* Light HSL Server Operations */ + main_light_hsl_server_operations(MS_TRUE); + break; + + case 63: /* Light xyL Server Operations */ + main_light_xyl_server_operations(MS_TRUE); + break; + + case 64: /* Light LC Server Operations */ + main_light_lc_server_operations(MS_TRUE); + break; + + default: + printf("Invalid Option : %d.\n", choice); + break; + } + } + return 0; +} +#endif /* 0 */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/appl_model_server_callback.c b/src/components/ethermind/mesh/export/appl/model/server/appl_model_server_callback.c new file mode 100644 index 0000000..f59a14b --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/appl_model_server_callback.c @@ -0,0 +1,2345 @@ +/** + \file appl_model_server_callback.c + + \brief + This file contains reference implementation of model server callbacks. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_main.h" +#include "MS_scene_api.h" +#include "MS_generic_onoff_api.h" +#include "MS_generic_level_api.h" +#include "MS_generic_power_onoff_api.h" +#include "MS_generic_power_level_api.h" +#include "MS_generic_battery_api.h" +#include "MS_generic_location_api.h" +#include "MS_generic_property_api.h" +#include "MS_light_lightness_api.h" +#include "MS_light_ctl_api.h" +#include "MS_light_hsl_api.h" +#include "MS_light_xyl_api.h" +#include "MS_light_lc_api.h" + +void* appl_scene_save_current_state(/* IN */ UINT32 scene_index); +void* appl_scene_delete_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context); +void* appl_scene_recall_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context); +API_RESULT appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); +API_RESULT appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +/* --------------------------------------------- Global Definitions */ +#define MS_MODEL_SERVER_APPL_CB_DECL(cb) \ + API_RESULT (cb) \ + ( \ + MS_ACCESS_MODEL_REQ_MSG_CONTEXT * ctx, \ + MS_ACCESS_MODEL_REQ_MSG_RAW * msg_raw, \ + MS_ACCESS_MODEL_REQ_MSG_T * req_type, \ + MS_ACCESS_MODEL_STATE_PARAMS * state_params, \ + MS_ACCESS_MODEL_EXT_PARAMS * ext_params \ + ); + +MS_MODEL_SERVER_APPL_CB_DECL(appl_generic_onoff_server_cb); +MS_MODEL_SERVER_APPL_CB_DECL(appl_generic_level_server_cb); +MS_MODEL_SERVER_APPL_CB_DECL(appl_generic_power_onoff_server_cb); +MS_MODEL_SERVER_APPL_CB_DECL(appl_generic_power_level_server_cb); +MS_MODEL_SERVER_APPL_CB_DECL(appl_generic_battery_server_cb); +MS_MODEL_SERVER_APPL_CB_DECL(appl_generic_location_server_cb); +MS_MODEL_SERVER_APPL_CB_DECL(appl_generic_user_property_server_cb); +MS_MODEL_SERVER_APPL_CB_DECL(appl_generic_admin_property_server_cb); +MS_MODEL_SERVER_APPL_CB_DECL(appl_generic_manufacturer_property_server_cb); +MS_MODEL_SERVER_APPL_CB_DECL(appl_generic_client_property_server_cb); +MS_MODEL_SERVER_APPL_CB_DECL(appl_light_lightness_server_cb); +MS_MODEL_SERVER_APPL_CB_DECL(appl_light_ctl_server_cb); +MS_MODEL_SERVER_APPL_CB_DECL(appl_light_ctl_temperature_server_cb); +MS_MODEL_SERVER_APPL_CB_DECL(appl_light_hsl_server_cb); +MS_MODEL_SERVER_APPL_CB_DECL(appl_light_hsl_hue_server_cb); +MS_MODEL_SERVER_APPL_CB_DECL(appl_light_hsl_saturation_server_cb); +MS_MODEL_SERVER_APPL_CB_DECL(appl_light_xyl_server_cb); +MS_MODEL_SERVER_APPL_CB_DECL(appl_light_lc_server_cb); + +void* appl_scene_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT8 event_type, + /* IN */ void* event_param, + /* IN */ UINT16 event_length, + /* IN */ void* context +); + +/* --------------------------------------------- Static Global Variables */ + + +/* --------------------------------------------- External Global Variables */ + + +/* --------------------------------------------- Function */ +/** + \brief Generic_Onoff Server Get Model Handle. + + \par Description + Function to get Generic_Onoff server Model Handle. + + \param [out] model_handle Model Handle. + \param [in] state_inst State Instance. +*/ +API_RESULT appl_generic_onoff_server_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ UINT16 state_inst +) +{ + API_RESULT retval; + MS_ACCESS_MODEL_ID model_id; + MS_ACCESS_ELEMENT_HANDLE elem_handle; + /* TODO: Not always true */ + elem_handle = (MS_ACCESS_ELEMENT_HANDLE)state_inst; + model_id.id = MS_MODEL_ID_GENERIC_ONOFF_SERVER; + model_id.type = MS_ACCESS_MODEL_TYPE_SIG; + *model_handle = 0x0000; + retval = MS_access_get_model_handle + ( + elem_handle, + model_id, + model_handle + ); + return retval; +} + +void appl_generic_onoff_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +) +{ + MS_STATE_GENERIC_ONOFF_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_ACCESS_MODEL_REQ_MSG_CONTEXT ctx; + /* Modle Handle of Generic OnOff */ + appl_generic_onoff_server_get_model_handle(&ctx.handle, state_inst); + ctx.saddr = 0; /* Unassigned address */ + appl_model_state_get(state_type, 0, ¶m, 0); + current_state_params.state_type = state_type; + current_state_params.state = ¶m; + CONSOLE_OUT( + "[GENERIC_ONOFF] Sending Status.\n"); + MS_generic_onoff_server_state_update(&ctx, ¤t_state_params, NULL, 0, NULL); +} + + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONOFF_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(msg_raw); + MS_IGNORE_UNUSED_PARAM(ext_params); + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + /* Using same as target state and remaining time as 0 */ + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] SET Request.\n"); + retval = appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT("[GENERIC_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Generic_Level Server Get Model Handle. + + \par Description + Function to get Generic_Level server Model Handle. + + \param [out] model_handle Model Handle. + \param [in] state_inst State Instance. +*/ +API_RESULT appl_generic_level_server_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ UINT16 state_inst +) +{ + API_RESULT retval; + MS_ACCESS_MODEL_ID model_id; + MS_ACCESS_ELEMENT_HANDLE elem_handle; + /* TODO: Not always true */ + elem_handle = (MS_ACCESS_ELEMENT_HANDLE)state_inst; + model_id.id = MS_MODEL_ID_GENERIC_LEVEL_SERVER; + model_id.type = MS_ACCESS_MODEL_TYPE_SIG; + *model_handle = 0x0000; + retval = MS_access_get_model_handle + ( + elem_handle, + model_id, + model_handle + ); + return retval; +} + +void appl_generic_level_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +) +{ + MS_STATE_GENERIC_LEVEL_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_ACCESS_MODEL_REQ_MSG_CONTEXT ctx; + /* Modle Handle of Generic level */ + appl_generic_level_server_get_model_handle(&ctx.handle, state_inst); + ctx.saddr = 0; /* Unassigned address */ + appl_model_state_get(state_type, 0, ¶m, 0); + current_state_params.state_type = state_type; + current_state_params.state = ¶m; + CONSOLE_OUT( + "[GENERIC_LEVEL] Sending Status.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + MS_generic_level_server_state_update(&ctx, ¤t_state_params, NULL, 0, NULL); +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Level server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_level_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_LEVEL_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(ext_params); + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] SET Request.\n"); + + if ((MS_ACCESS_GENERIC_LEVEL_SET_OPCODE == msg_raw->opcode) || + (MS_ACCESS_GENERIC_LEVEL_SET_UNACKNOWLEDGED_OPCODE == msg_raw->opcode)) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Level SET Request.\n"); + } + else if ((MS_ACCESS_GENERIC_DELTA_SET_OPCODE == msg_raw->opcode) || + (MS_ACCESS_GENERIC_DELTA_SET_UNACKNOWLEDGED_OPCODE == msg_raw->opcode)) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Delta SET Request.\n"); + } + else if ((MS_ACCESS_GENERIC_MOVE_SET_OPCODE == msg_raw->opcode) || + (MS_ACCESS_GENERIC_MOVE_SET_UNACKNOWLEDGED_OPCODE == msg_raw->opcode)) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Move SET Request.\n"); + } + + /* TODO: Right now not handling different type of SET requests separately */ + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_LEVEL_STRUCT*)state_params->state, 0); + current_state_params.state_type = MS_STATE_GENERIC_LEVEL_T; + current_state_params.state = (MS_STATE_GENERIC_LEVEL_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_level_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + + +/** + \brief Generic_Power_Onoff Server Get Model Handle. + + \par Description + Function to get Generic_Power_Onoff server Model Handle. + + \param [out] model_handle Model Handle. + \param [in] state_inst State Instance. +*/ +API_RESULT appl_generic_power_onoff_server_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ UINT16 state_inst +) +{ + API_RESULT retval; + MS_ACCESS_MODEL_ID model_id; + MS_ACCESS_ELEMENT_HANDLE elem_handle; + /* TODO: Not always true */ + elem_handle = (MS_ACCESS_ELEMENT_HANDLE)state_inst; + model_id.id = MS_MODEL_ID_GENERIC_POWER_ONOFF_SERVER; + model_id.type = MS_ACCESS_MODEL_TYPE_SIG; + *model_handle = 0x0000; + retval = MS_access_get_model_handle + ( + elem_handle, + model_id, + model_handle + ); + return retval; +} + +void appl_generic_power_onoff_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +) +{ + MS_STATE_GENERIC_ONPOWERUP_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_ACCESS_MODEL_REQ_MSG_CONTEXT ctx; + /* Modle Handle of Generic OnOff */ + appl_generic_power_onoff_server_get_model_handle(&ctx.handle, state_inst); + ctx.saddr = 0; /* Unassigned address */ + appl_model_state_get(state_type, 0, ¶m, 0); + current_state_params.state_type = state_type; + current_state_params.state = ¶m; + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] Sending Status.\n"); + MS_generic_power_onoff_server_state_update(&ctx, ¤t_state_params, NULL, 0, NULL); +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_power_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONPOWERUP_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(msg_raw); + MS_IGNORE_UNUSED_PARAM(ext_params); + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_power_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Generic_Power_Level Server Get Model Handle. + + \par Description + Function to get Generic_Power_Level server Model Handle. + + \param [out] model_handle Model Handle. + \param [in] state_inst State Instance. +*/ +API_RESULT appl_generic_power_level_server_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ UINT16 state_inst +) +{ + API_RESULT retval; + MS_ACCESS_MODEL_ID model_id; + MS_ACCESS_ELEMENT_HANDLE elem_handle; + /* TODO: Not always true */ + elem_handle = (MS_ACCESS_ELEMENT_HANDLE)state_inst; + model_id.id = MS_MODEL_ID_GENERIC_POWER_LEVEL_SERVER; + model_id.type = MS_ACCESS_MODEL_TYPE_SIG; + *model_handle = 0x0000; + retval = MS_access_get_model_handle + ( + elem_handle, + model_id, + model_handle + ); + return retval; +} + + +void appl_generic_power_level_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +) +{ + MS_STATE_GENERIC_POWER_LEVEL_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_ACCESS_MODEL_REQ_MSG_CONTEXT ctx; + void* param_p; + /* Modle Handle of Generic Power Level */ + appl_generic_power_level_server_get_model_handle(&ctx.handle, state_inst); + ctx.saddr = 0; /* Unassigned address */ + + switch (state_type) + { + case MS_STATE_GENERIC_POWER_ACTUAL_T: + { + param_p = (MS_STATE_GENERIC_POWER_ACTUAL_STRUCT*)¶m.generic_power_actual; + } + break; + + case MS_STATE_GENERIC_POWER_LAST_T: + { + param_p = (MS_STATE_GENERIC_POWER_LAST_STRUCT*)¶m.generic_power_last; + } + break; + + case MS_STATE_GENERIC_POWER_DEFAULT_T: + { + param_p = (MS_STATE_GENERIC_POWER_DEFAULT_STRUCT*)¶m.generic_power_default; + } + break; + + case MS_STATE_GENERIC_POWER_RANGE_T: + { + param_p = (MS_STATE_GENERIC_POWER_RANGE_STRUCT*)¶m.generic_power_range; + } + break; + } + + appl_model_state_get(state_type, 0, param_p, 0); + current_state_params.state_type = state_type; + current_state_params.state = param_p; + CONSOLE_OUT( + "[GENERIC_POWER_LEVEL] Sending Status.\n"); + MS_generic_power_level_server_state_update(&ctx, ¤t_state_params, NULL, 0, NULL); +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Level server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_power_level_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_POWER_LEVEL_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_ACCESS_MODEL_EXT_PARAMS ext_param; + MS_EXT_STATUS_STRUCT status; + void* param_p; + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(msg_raw); + MS_IGNORE_UNUSED_PARAM(ext_params); + retval = API_SUCCESS; + param_p = NULL; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_POWER_LEVEL] GET Request.\n"); + + switch (state_params->state_type) + { + case MS_STATE_GENERIC_POWER_ACTUAL_T: + { + param_p = (MS_STATE_GENERIC_POWER_ACTUAL_STRUCT*)¶m.generic_power_actual; + } + break; + + case MS_STATE_GENERIC_POWER_LAST_T: + { + param_p = (MS_STATE_GENERIC_POWER_LAST_STRUCT*)¶m.generic_power_last; + } + break; + + case MS_STATE_GENERIC_POWER_DEFAULT_T: + { + param_p = (MS_STATE_GENERIC_POWER_DEFAULT_STRUCT*)¶m.generic_power_default; + } + break; + + case MS_STATE_GENERIC_POWER_RANGE_T: + { + param_p = (MS_STATE_GENERIC_POWER_RANGE_STRUCT*)¶m.generic_power_range; + } + break; + } + + appl_model_state_get(state_params->state_type, 0, param_p, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param_p; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_POWER_LEVEL] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_POWER_LEVEL_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_POWER_LEVEL_STRUCT*)state_params->state; + /* Assign Status */ + ext_param.ext_type = MS_EXT_STATUS_STRUCT_T; + ext_param.ext = &status; + status.status = 0x00; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_POWER_LEVEL] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_power_level_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + (void)ext_param; + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Battery server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_battery_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_BATTERY_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(msg_raw); + MS_IGNORE_UNUSED_PARAM(ext_params); + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_BATTERY] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_BATTERY] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_battery_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Location or Generic_Location_Setup server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_location_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_LOCATION_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(msg_raw); + MS_IGNORE_UNUSED_PARAM(ext_params); + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_LOCATION] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_LOCATION] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_LOCATION_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_LOCATION_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_LOCATION] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_location_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_User_Property server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_user_property_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_USER_PROPERTY_STRUCT user_prop_param; + MS_STATE_GENERIC_PROPERTY_IDS_STRUCT prop_ids; + void* param = NULL; + /* As sample example. The array size need to defined, based on the final configuration */ + UINT16 prop_ids_list[10]; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(msg_raw); + MS_IGNORE_UNUSED_PARAM(ext_params); + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_USER_PROPERTY] GET Request. Type: 0x%02X\n", state_params->state_type); + + if (MS_STATE_GENERIC_USER_PROPERTY_T == state_params->state_type) + { + user_prop_param.property_id = ((MS_STATE_GENERIC_PROPERTY_ID_STRUCT*)state_params->state)->property_id; + param = &user_prop_param; + } + else if (MS_STATE_GENERIC_USER_PROPERTY_IDS_T == state_params->state_type) + { + param = &prop_ids; + prop_ids.property_ids = prop_ids_list; + prop_ids.property_ids_count = sizeof(prop_ids_list) / sizeof(UINT16); + } + + if(param != NULL) + { + appl_model_state_get(state_params->state_type, 0, param, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param; + } + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_USER_PROPERTY] SET Request.\n"); + retval = appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_USER_PROPERTY_STRUCT*)state_params->state, 0); + + if (API_SUCCESS != retval) + { + req_type->to_be_acked = 0x00; + } + else + { + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_USER_PROPERTY_STRUCT*)state_params->state; + } + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_USER_PROPERTY] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_user_property_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Generic_Admin_Property Server Get Model Handle. + + \par Description + Function to get Generic_Admin_Property server Model Handle. + + \param [out] model_handle Model Handle. + \param [in] state_inst State Instance. +*/ +API_RESULT appl_generic_admin_property_server_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ UINT16 state_inst +) +{ + API_RESULT retval; + MS_ACCESS_MODEL_ID model_id; + MS_ACCESS_ELEMENT_HANDLE elem_handle; + /* TODO: Not always true */ + elem_handle = (MS_ACCESS_ELEMENT_HANDLE)state_inst; + model_id.id = MS_MODEL_ID_GENERIC_ADMIN_PROPERTY_SERVER; + model_id.type = MS_ACCESS_MODEL_TYPE_SIG; + *model_handle = 0x0000; + retval = MS_access_get_model_handle + ( + elem_handle, + model_id, + model_handle + ); + return retval; +} + +void appl_generic_admin_property_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst, + /* IN */ UINT16 property_id +) +{ + MS_STATE_GENERIC_ADMIN_PROPERTY_STRUCT prop_param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_ACCESS_MODEL_REQ_MSG_CONTEXT ctx; + /* Modle Handle of Generic Admin Property */ + appl_generic_admin_property_server_get_model_handle(&ctx.handle, state_inst); + ctx.saddr = 0; /* Unassigned address */ + prop_param.property_id = property_id; + appl_model_state_get(state_type, 0, &prop_param, 0); + current_state_params.state_type = state_type; + current_state_params.state = &prop_param; + CONSOLE_OUT( + "[GENERIC_ADMIN_PROPERTY] Sending Status.\n"); + MS_generic_admin_property_server_state_update(&ctx, ¤t_state_params, NULL, 0, NULL); +} + + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Admin_Property server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_admin_property_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ADMIN_PROPERTY_STRUCT prop_param; + MS_STATE_GENERIC_PROPERTY_IDS_STRUCT prop_ids; + void* param = NULL; + /* As sample example. The array size need to defined, based on the final configuration */ + UINT16 prop_ids_list[10]; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(msg_raw); + MS_IGNORE_UNUSED_PARAM(ext_params); + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_ADMIN_PROPERTY] GET Request. Type: 0x%02X\n", state_params->state_type); + + if (MS_STATE_GENERIC_ADMIN_PROPERTY_T == state_params->state_type) + { + prop_param.property_id = ((MS_STATE_GENERIC_PROPERTY_ID_STRUCT*)state_params->state)->property_id; + param = &prop_param; + } + else if (MS_STATE_GENERIC_ADMIN_PROPERTY_IDS_T == state_params->state_type) + { + param = &prop_ids; + prop_ids.property_ids = prop_ids_list; + prop_ids.property_ids_count = sizeof(prop_ids_list) / sizeof(UINT16); + } + + if(param != NULL) + { + appl_model_state_get(state_params->state_type, 0, param, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param; + } + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_ADMIN_PROPERTY] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ADMIN_PROPERTY_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ADMIN_PROPERTY_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_ADMIN_PROPERTY] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_admin_property_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Generic_Manufacturer_Property Server Get Model Handle. + + \par Description + Function to get Generic_Manufacturer_Property server Model Handle. + + \param [out] model_handle Model Handle. + \param [in] state_inst State Instance. +*/ +API_RESULT appl_generic_manufacturer_property_server_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ UINT16 state_inst +) +{ + API_RESULT retval; + MS_ACCESS_MODEL_ID model_id; + MS_ACCESS_ELEMENT_HANDLE elem_handle; + /* TODO: Not always true */ + elem_handle = (MS_ACCESS_ELEMENT_HANDLE)state_inst; + model_id.id = MS_MODEL_ID_GENERIC_MANUFACTURER_PROPERTY_SERVER; + model_id.type = MS_ACCESS_MODEL_TYPE_SIG; + *model_handle = 0x0000; + retval = MS_access_get_model_handle + ( + elem_handle, + model_id, + model_handle + ); + return retval; +} + +void appl_generic_manufacturer_property_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst, + /* IN */ UINT16 property_id +) +{ + MS_STATE_GENERIC_MANUFACTURER_PROPERTY_STRUCT prop_param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_ACCESS_MODEL_REQ_MSG_CONTEXT ctx; + /* Modle Handle of Generic Manufacturer Property */ + appl_generic_manufacturer_property_server_get_model_handle(&ctx.handle, state_inst); + ctx.saddr = 0; /* Unassigned address */ + prop_param.property_id = property_id; + appl_model_state_get(state_type, 0, &prop_param, 0); + current_state_params.state_type = state_type; + current_state_params.state = &prop_param; + CONSOLE_OUT( + "[GENERIC_MANUFACTURER_PROPERTY] Sending Status.\n"); + MS_generic_manufacturer_property_server_state_update(&ctx, ¤t_state_params, NULL, 0, NULL); +} + + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Manufacturer_Property server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_manufacturer_property_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_MANUFACTURER_PROPERTY_STRUCT prop_param; + MS_STATE_GENERIC_PROPERTY_IDS_STRUCT prop_ids; + void* param = NULL; + /* As sample example. The array size need to defined, based on the final configuration */ + UINT16 prop_ids_list[10]; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(msg_raw); + MS_IGNORE_UNUSED_PARAM(ext_params); + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_MANUFACTURER_PROPERTY] GET Request. Type: 0x%02X\n", state_params->state_type); + + if (MS_STATE_GENERIC_MANUFACTURER_PROPERTY_T == state_params->state_type) + { + prop_param.property_id = ((MS_STATE_GENERIC_PROPERTY_ID_STRUCT*)state_params->state)->property_id; + param = &prop_param; + } + else if (MS_STATE_GENERIC_MANUFACTURER_PROPERTY_IDS_T == state_params->state_type) + { + param = &prop_ids; + prop_ids.property_ids = prop_ids_list; + prop_ids.property_ids_count = sizeof(prop_ids_list) / sizeof(UINT16); + } + + if(param != NULL) + { + appl_model_state_get(state_params->state_type, 0, param, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param; + } + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_MANUFACTURER_PROPERTY] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_MANUFACTURER_PROPERTY_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_MANUFACTURER_PROPERTY_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_MANUFACTURER_PROPERTY] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_manufacturer_property_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Client_Property server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_client_property_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_PROPERTY_IDS_STRUCT prop_ids; + void* param = NULL; + /* As sample example. The array size need to defined, based on the final configuration */ + UINT16 prop_ids_list[10]; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(msg_raw); + MS_IGNORE_UNUSED_PARAM(ext_params); + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_CLIENT_PROPERTY] GET Request. Type: 0x%02X\n", state_params->state_type); + + if (MS_STATE_GENERIC_CLIENT_PROPERTY_IDS_T == state_params->state_type) + { + param = &prop_ids; + prop_ids.property_ids = prop_ids_list; + prop_ids.property_ids_count = sizeof(prop_ids_list) / sizeof(UINT16); + } + + if(param != NULL) + { + appl_model_state_get(state_params->state_type, 0, param, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param; + } + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_CLIENT_PROPERTY] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_client_property_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scene server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. + + TODO: Update +*/ +void* appl_scene_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT8 event_type, + /* IN */ void* event_param, + /* IN */ UINT16 event_length, + /* IN */ void* context +) +{ + void* param_p; + MS_IGNORE_UNUSED_PARAM(handle); + MS_IGNORE_UNUSED_PARAM(event_length); + param_p = NULL; + + switch(event_type) + { + case MS_SCENE_EVENT_STORE: + { + param_p = appl_scene_save_current_state(*(UINT32*)event_param); + } + break; + + case MS_SCENE_EVENT_DELETE: + { + param_p = appl_scene_delete_saved_state(*(UINT32*)event_param, context); + } + break; + + case MS_SCENE_EVENT_RECALL_START: + { + } + break; + + case MS_SCENE_EVENT_RECALL_COMPLETE: + { + param_p = appl_scene_recall_saved_state(*(UINT32*)event_param, context); + } + break; + + case MS_SCENE_EVENT_RECALL_IMMEDIATE: + { + param_p = appl_scene_recall_saved_state(*(UINT32*)event_param, context); + } + break; + } + + return param_p; +} + + +/** + \brief Light_Lightness Server Get Model Handle. + + \par Description + Function to get Light_Lightness server Model Handle. + + \param [out] model_handle Model Handle. + \param [in] state_inst State Instance. +*/ +API_RESULT appl_light_lightness_server_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ UINT16 state_inst +) +{ + API_RESULT retval; + MS_ACCESS_MODEL_ID model_id; + MS_ACCESS_ELEMENT_HANDLE elem_handle; + /* TODO: Not always true */ + elem_handle = (MS_ACCESS_ELEMENT_HANDLE)state_inst; + model_id.id = MS_MODEL_ID_LIGHT_LIGHTNESS_SERVER; + model_id.type = MS_ACCESS_MODEL_TYPE_SIG; + *model_handle = 0x0000; + retval = MS_access_get_model_handle + ( + elem_handle, + model_id, + model_handle + ); + return retval; +} + +void appl_light_lightness_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +) +{ + MS_STATE_LIGHT_LIGHTNESS_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_ACCESS_MODEL_REQ_MSG_CONTEXT ctx; + /* Modle Handle of Light_Lightness */ + appl_light_lightness_server_get_model_handle(&ctx.handle, state_inst); + ctx.saddr = 0; /* Unassigned address */ + appl_model_state_get(state_type, 0, ¶m, 0); + current_state_params.state_type = state_type; + current_state_params.state = ¶m; + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] Sending Status.\n"); + MS_light_lightness_server_state_update(&ctx, ¤t_state_params, NULL, 0, NULL); +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Lightness server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_lightness_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_LIGHT_LIGHTNESS_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(msg_raw); + MS_IGNORE_UNUSED_PARAM(ext_params); + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_lightness_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Light_Ctl Server Get Model Handle. + + \par Description + Function to get Light_Ctl server Model Handle. + + \param [out] model_handle Model Handle. + \param [in] state_inst State Instance. +*/ +API_RESULT appl_light_ctl_server_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ UINT16 state_inst +) +{ + API_RESULT retval; + MS_ACCESS_MODEL_ID model_id; + MS_ACCESS_ELEMENT_HANDLE elem_handle; + /* TODO: Not always true */ + elem_handle = (MS_ACCESS_ELEMENT_HANDLE)state_inst; + model_id.id = MS_MODEL_ID_LIGHT_CTL_SERVER; + model_id.type = MS_ACCESS_MODEL_TYPE_SIG; + *model_handle = 0x0000; + retval = MS_access_get_model_handle + ( + elem_handle, + model_id, + model_handle + ); + return retval; +} + +void appl_light_ctl_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +) +{ + MS_STATE_LIGHT_CTL_STRUCT light_ctl_params; + MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_STRUCT light_ctl_temperature_range_params; + MS_STATE_LIGHT_CTL_DEFAULT_STRUCT light_ctl_default_params; + MS_STATE_LIGHT_CTL_TEMPERATURE_STRUCT light_ctl_temperature_params; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + void* param_p; + MS_ACCESS_MODEL_REQ_MSG_CONTEXT ctx; + /* Modle Handle of Light_Ctl */ + appl_light_ctl_server_get_model_handle(&ctx.handle, state_inst); + ctx.saddr = 0; /* Unassigned address */ + /* Check state type */ + param_p = NULL; + + switch (state_type) + { + case MS_STATE_LIGHT_CTL_DEFAULT_T: + { + param_p = &light_ctl_default_params; + } + break; + + case MS_STATE_LIGHT_CTL_T: + { + param_p = &light_ctl_params; + } + break; + + case MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_T: + { + param_p = &light_ctl_temperature_range_params; + } + break; + + case MS_STATE_LIGHT_CTL_TEMPERATURE_T: + { + param_p = &light_ctl_temperature_params; + } + break; + + default: + break; + } + + if (NULL != param_p) + { + appl_model_state_get(state_type, 0, param_p, 0); + current_state_params.state_type = state_type; + current_state_params.state = param_p; + CONSOLE_OUT( + "[LIGHT_CTL] Sending Status.\n"); + MS_light_ctl_server_state_update(&ctx, ¤t_state_params, NULL, 0, NULL); + } +} + + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Ctl server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_ctl_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_STATE_LIGHT_CTL_STRUCT light_ctl_params; + MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_STRUCT light_ctl_temperature_range_params; + MS_STATE_LIGHT_CTL_DEFAULT_STRUCT light_ctl_default_params; + MS_STATE_LIGHT_CTL_TEMPERATURE_STRUCT light_ctl_temperature_params; + void* param_p; + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(msg_raw); + MS_IGNORE_UNUSED_PARAM(ext_params); + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_CTL] GET Request.\n"); + + switch (state_params->state_type) + { + case MS_STATE_LIGHT_CTL_DEFAULT_T: + { + param_p = &light_ctl_default_params; + } + break; + + case MS_STATE_LIGHT_CTL_T: + { + param_p = &light_ctl_params; + } + break; + + case MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_T: + { + param_p = &light_ctl_temperature_range_params; + } + break; + + case MS_STATE_LIGHT_CTL_TEMPERATURE_T: + { + param_p = &light_ctl_temperature_params; + } + break; + + default: + break; + } + + appl_model_state_get(state_params->state_type, 0, param_p, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param_p; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_CTL] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_CTL] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_ctl_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Light_Ctl_Temperature Server Get Model Handle. + + \par Description + Function to get Light_Ctl_Temperature server Model Handle. + + \param [out] model_handle Model Handle. + \param [in] state_inst State Instance. +*/ +API_RESULT appl_light_ctl_temperature_server_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ UINT16 state_inst +) +{ + API_RESULT retval; + MS_ACCESS_MODEL_ID model_id; + MS_ACCESS_ELEMENT_HANDLE elem_handle; + /* TODO: Not always true */ + elem_handle = (MS_ACCESS_ELEMENT_HANDLE)state_inst; + model_id.id = MS_MODEL_ID_LIGHT_CTL_TEMPERATURE_SERVER; + model_id.type = MS_ACCESS_MODEL_TYPE_SIG; + *model_handle = 0x0000; + retval = MS_access_get_model_handle + ( + elem_handle, + model_id, + model_handle + ); + return retval; +} + +void appl_light_ctl_temperature_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +) +{ + MS_STATE_LIGHT_CTL_TEMPERATURE_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_ACCESS_MODEL_REQ_MSG_CONTEXT ctx; + /* Modle Handle of Light_Ctl_Temperature */ + appl_light_ctl_temperature_server_get_model_handle(&ctx.handle, state_inst); + ctx.saddr = 0; /* Unassigned address */ + appl_model_state_get(state_type, 0, ¶m, 0); + current_state_params.state_type = state_type; + current_state_params.state = ¶m; + CONSOLE_OUT( + "[LIGHT_CTL_TEMPERATURE] Sending Status.\n"); + MS_light_ctl_temperature_server_state_update(&ctx, ¤t_state_params, NULL, 0, NULL); +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Ctl_Temperature server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_ctl_temperature_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_LIGHT_CTL_TEMPERATURE_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(msg_raw); + MS_IGNORE_UNUSED_PARAM(ext_params); + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_CTL_TEMPERATURE] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_CTL_TEMPERATURE] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_LIGHT_CTL_TEMPERATURE_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_LIGHT_CTL_TEMPERATURE_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_CTL_TEMPERATURE] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_ctl_temperature_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Light_HSL Server Get Model Handle. + + \par Description + Function to get Light_HSL server Model Handle. + + \param [out] model_handle Model Handle. + \param [in] state_inst State Instance. +*/ +API_RESULT appl_light_hsl_server_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ UINT16 state_inst +) +{ + API_RESULT retval; + MS_ACCESS_MODEL_ID model_id; + MS_ACCESS_ELEMENT_HANDLE elem_handle; + /* TODO: Not always true */ + elem_handle = (MS_ACCESS_ELEMENT_HANDLE)state_inst; + model_id.id = MS_MODEL_ID_LIGHT_HSL_SERVER; + model_id.type = MS_ACCESS_MODEL_TYPE_SIG; + *model_handle = 0x0000; + retval = MS_access_get_model_handle + ( + elem_handle, + model_id, + model_handle + ); + return retval; +} + +void appl_light_hsl_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +) +{ + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_STATE_LIGHT_HSL_STRUCT param; + MS_STATE_LIGHT_HSL_RANGE_STRUCT param_range; + MS_STATE_LIGHT_HSL_DEFAULT_STRUCT param_default; + void* param_p; + MS_ACCESS_MODEL_REQ_MSG_CONTEXT ctx; + /* Modle Handle of Light_HSL */ + appl_light_hsl_server_get_model_handle(&ctx.handle, state_inst); + ctx.saddr = 0; /* Unassigned address */ + param_p = NULL; + + switch (state_type) + { + case MS_STATE_LIGHT_HSL_T: + case MS_STATE_LIGHT_HSL_HUE_T: + case MS_STATE_LIGHT_HSL_SATURATION_T: + case MS_STATE_LIGHT_HSL_TARGET_T: + { + param_p = ¶m; + } + break; + + case MS_STATE_LIGHT_HSL_DEFAULT_T: + { + param_p = ¶m_default; + } + break; + + case MS_STATE_LIGHT_HSL_RANGE_T: + { + param_p = ¶m_range; + } + break; + + default: + break; + } + + if (NULL != param_p) + { + appl_model_state_get(state_type, 0, param_p, 0); + current_state_params.state_type = state_type; + current_state_params.state = param_p; + CONSOLE_OUT( + "[LIGHT_HSL] Sending Status.\n"); + MS_light_hsl_server_state_update(&ctx, ¤t_state_params, NULL, 0, NULL); + } +} + + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Hsl server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_hsl_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_STATE_LIGHT_HSL_STRUCT param; + MS_STATE_LIGHT_HSL_RANGE_STRUCT param_range; + MS_STATE_LIGHT_HSL_DEFAULT_STRUCT param_default; + void* param_p; + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(msg_raw); + MS_IGNORE_UNUSED_PARAM(ext_params); + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_HSL] GET Request.\n"); + + switch (state_params->state_type) + { + case MS_STATE_LIGHT_HSL_T: + case MS_STATE_LIGHT_HSL_HUE_T: + case MS_STATE_LIGHT_HSL_SATURATION_T: + case MS_STATE_LIGHT_HSL_TARGET_T: + { + param_p = ¶m; + } + break; + + case MS_STATE_LIGHT_HSL_DEFAULT_T: + { + param_p = ¶m_default; + } + break; + + case MS_STATE_LIGHT_HSL_RANGE_T: + { + param_p = ¶m_range; + } + break; + + default: + break; + } + + appl_model_state_get(state_params->state_type, 0, param_p, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param_p; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_HSL] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_HSL] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_hsl_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Light_HSL_HUE Server Get Model Handle. + + \par Description + Function to get Light_HSL_HUE server Model Handle. + + \param [out] model_handle Model Handle. + \param [in] state_inst State Instance. +*/ +API_RESULT appl_light_hsl_hue_server_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ UINT16 state_inst +) +{ + API_RESULT retval; + MS_ACCESS_MODEL_ID model_id; + MS_ACCESS_ELEMENT_HANDLE elem_handle; + /* TODO: Not always true */ + elem_handle = (MS_ACCESS_ELEMENT_HANDLE)state_inst; + model_id.id = MS_MODEL_ID_LIGHT_HSL_HUE_SERVER; + model_id.type = MS_ACCESS_MODEL_TYPE_SIG; + *model_handle = 0x0000; + retval = MS_access_get_model_handle + ( + elem_handle, + model_id, + model_handle + ); + return retval; +} + +void appl_light_hsl_hue_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +) +{ + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_STATE_LIGHT_HSL_STRUCT param; + MS_ACCESS_MODEL_REQ_MSG_CONTEXT ctx; + /* Modle Handle of Light_HSL_HUE */ + appl_light_hsl_hue_server_get_model_handle(&ctx.handle, state_inst); + ctx.saddr = 0; /* Unassigned address */ + appl_model_state_get(state_type, 0, ¶m, 0); + current_state_params.state_type = state_type; + current_state_params.state = ¶m; + CONSOLE_OUT( + "[LIGHT_HSL_HUE] Sending Status.\n"); + MS_light_hsl_hue_server_state_update(&ctx, ¤t_state_params, NULL, 0, NULL); +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Hsl_Hue server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_hsl_hue_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_LIGHT_HSL_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(msg_raw); + MS_IGNORE_UNUSED_PARAM(ext_params); + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_HSL_HUE] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_HSL_HUE] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_HSL_HUE] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_hsl_hue_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief LIGHT_HSL_SATURATION Server Get Model Handle. + + \par Description + Function to get LIGHT_HSL_SATURATION server Model Handle. + + \param [out] model_handle Model Handle. + \param [in] state_inst State Instance. +*/ +API_RESULT appl_light_hsl_saturation_server_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ UINT16 state_inst +) +{ + API_RESULT retval; + MS_ACCESS_MODEL_ID model_id; + MS_ACCESS_ELEMENT_HANDLE elem_handle; + /* TODO: Not always true */ + elem_handle = (MS_ACCESS_ELEMENT_HANDLE)state_inst; + model_id.id = MS_MODEL_ID_LIGHT_HSL_SATURATION_SERVER; + model_id.type = MS_ACCESS_MODEL_TYPE_SIG; + *model_handle = 0x0000; + retval = MS_access_get_model_handle + ( + elem_handle, + model_id, + model_handle + ); + return retval; +} + +void appl_light_hsl_saturation_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +) +{ + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_STATE_LIGHT_HSL_STRUCT param; + MS_ACCESS_MODEL_REQ_MSG_CONTEXT ctx; + /* Modle Handle of Light_HSL_SATURATION */ + appl_light_hsl_saturation_server_get_model_handle(&ctx.handle, state_inst); + ctx.saddr = 0; /* Unassigned address */ + appl_model_state_get(state_type, 0, ¶m, 0); + current_state_params.state_type = state_type; + current_state_params.state = ¶m; + CONSOLE_OUT( + "[LIGHT_HSL_SATURATION] Sending Status.\n"); + MS_light_hsl_saturation_server_state_update(&ctx, ¤t_state_params, NULL, 0, NULL); +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Hsl_Saturation server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_hsl_saturation_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_LIGHT_HSL_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(msg_raw); + MS_IGNORE_UNUSED_PARAM(ext_params); + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_HSL_SATURATION] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_HSL_SATURATION] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_HSL_SATURATION] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_hsl_saturation_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Light_Xyl Server Get Model Handle. + + \par Description + Function to get Light_Xyl server Model Handle. + + \param [out] model_handle Model Handle. + \param [in] state_inst State Instance. +*/ +API_RESULT appl_light_xyl_server_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ UINT16 state_inst +) +{ + API_RESULT retval; + MS_ACCESS_MODEL_ID model_id; + MS_ACCESS_ELEMENT_HANDLE elem_handle; + /* TODO: Not always true */ + elem_handle = (MS_ACCESS_ELEMENT_HANDLE)state_inst; + model_id.id = MS_MODEL_ID_LIGHT_XYL_SERVER; + model_id.type = MS_ACCESS_MODEL_TYPE_SIG; + *model_handle = 0x0000; + retval = MS_access_get_model_handle + ( + elem_handle, + model_id, + model_handle + ); + return retval; +} + +void appl_light_xyl_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +) +{ + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_STATE_LIGHT_XYL_STRUCT param; + MS_STATE_LIGHT_XYL_RANGE_STRUCT param_range; + MS_STATE_LIGHT_XYL_DEFAULT_STRUCT param_default; + void* param_p; + MS_ACCESS_MODEL_REQ_MSG_CONTEXT ctx; + /* Modle Handle of Light_Xyl */ + appl_light_xyl_server_get_model_handle(&ctx.handle, state_inst); + ctx.saddr = 0; /* Unassigned address */ + + switch (state_type) + { + case MS_STATE_LIGHT_XYL_T: + case MS_STATE_LIGHT_XYL_TARGET_T: + { + param_p = ¶m; + } + break; + + case MS_STATE_LIGHT_XYL_DEFAULT_T: + { + param_p = ¶m_default; + } + break; + + case MS_STATE_LIGHT_XYL_RANGE_T: + { + param_p = ¶m_range; + } + break; + + default: + break; + } + + appl_model_state_get(state_type, 0, param_p, 0); + current_state_params.state_type = state_type; + current_state_params.state = param_p; + CONSOLE_OUT( + "[LIGHT_Xyl] Sending Status.\n"); + MS_light_xyl_server_state_update(&ctx, ¤t_state_params, NULL, 0, NULL); +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Xyl server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_xyl_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_STATE_LIGHT_XYL_STRUCT param; + MS_STATE_LIGHT_XYL_RANGE_STRUCT param_range; + MS_STATE_LIGHT_XYL_DEFAULT_STRUCT param_default; + void* param_p; + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(msg_raw); + MS_IGNORE_UNUSED_PARAM(ext_params); + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_XYL] GET Request.\n"); + + switch (state_params->state_type) + { + case MS_STATE_LIGHT_XYL_T: + case MS_STATE_LIGHT_XYL_TARGET_T: + { + param_p = ¶m; + } + break; + + case MS_STATE_LIGHT_XYL_DEFAULT_T: + { + param_p = ¶m_default; + } + break; + + case MS_STATE_LIGHT_XYL_RANGE_T: + { + param_p = ¶m_range; + } + break; + + default: + break; + } + + appl_model_state_get(state_params->state_type, 0, param_p, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param_p; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_XYL] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_XYL] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_xyl_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Light_LC Server Get Model Handle. + + \par Description + Function to get Light_LC server Model Handle. + + \param [out] model_handle Model Handle. + \param [in] state_inst State Instance. +*/ +API_RESULT appl_light_lc_server_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ UINT32 id, + /* IN */ UINT16 state_inst +) +{ + API_RESULT retval; + MS_ACCESS_MODEL_ID model_id; + MS_ACCESS_ELEMENT_HANDLE elem_handle; + /* TODO: Not always true */ + elem_handle = (MS_ACCESS_ELEMENT_HANDLE)state_inst; + model_id.id = id; + model_id.type = MS_ACCESS_MODEL_TYPE_SIG; + *model_handle = 0x0000; + retval = MS_access_get_model_handle + ( + elem_handle, + model_id, + model_handle + ); + return retval; +} + +void appl_light_lc_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst, + /* IN */ UINT16 property_id +) +{ + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_STATE_LIGHT_LC_MODE_STRUCT param_mode; + MS_STATE_LIGHT_LC_OM_STRUCT param_om; + MS_STATE_LIGHT_LC_LIGHT_ONOFF_STRUCT param_onoff; + MS_STATE_LIGHT_LC_PROPERTY_STRUCT param_prop; + void* param_p; + MS_ACCESS_MODEL_REQ_MSG_CONTEXT ctx; + + /* Modle Handle of Light_LC */ + if (MS_STATE_LIGHT_LC_PROPERTY_T == state_type) + { + appl_light_lc_server_get_model_handle(&ctx.handle, MS_MODEL_ID_LIGHT_LC_SETUP_SERVER, state_inst); + } + else + { + appl_light_lc_server_get_model_handle(&ctx.handle, MS_MODEL_ID_LIGHT_LC_SERVER, state_inst); + } + + ctx.saddr = 0; /* Unassigned address */ + param_p = NULL; + + switch (state_type) + { + case MS_STATE_LIGHT_LC_MODE_T: + param_p = ¶m_mode; + break; + + case MS_STATE_LIGHT_LC_OM_T: + param_p = ¶m_om; + break; + + case MS_STATE_LIGHT_LC_LIGHT_ONOFF_T: + param_p = ¶m_onoff; + break; + + case MS_STATE_LIGHT_LC_PROPERTY_T: + param_prop.property_id = property_id; + param_p = ¶m_prop; + break; + + default: + break; + } + + if (NULL != param_p) + { + appl_model_state_get(state_type, 0, param_p, 0); + current_state_params.state_type = state_type; + current_state_params.state = param_p; + CONSOLE_OUT( + "[LIGHT_LC] Sending Status.\n"); + MS_light_lc_server_state_update(&ctx, ¤t_state_params, NULL, 0, NULL); + } +} + + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Lc server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_lc_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_LIGHT_LC_MODE_STRUCT param_mode; + MS_STATE_LIGHT_LC_OM_STRUCT param_om; + MS_STATE_LIGHT_LC_LIGHT_ONOFF_STRUCT param_onoff; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + void* param_p; + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(msg_raw); + MS_IGNORE_UNUSED_PARAM(ext_params); + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_LC] GET Request.\n"); + + switch (state_params->state_type) + { + case MS_STATE_LIGHT_LC_MODE_T: + param_p = ¶m_mode; + break; + + case MS_STATE_LIGHT_LC_OM_T: + param_p = ¶m_om; + break; + + case MS_STATE_LIGHT_LC_LIGHT_ONOFF_T: + param_p = ¶m_onoff; + break; + + case MS_STATE_LIGHT_LC_PROPERTY_T: + param_p = state_params->state; + break; + } + + appl_model_state_get(state_params->state_type, 0, param_p, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param_p; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_LC] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_LC] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_lc_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/server/appl_model_server_state_handler.c b/src/components/ethermind/mesh/export/appl/model/server/appl_model_server_state_handler.c new file mode 100644 index 0000000..9fbe7d4 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/appl_model_server_state_handler.c @@ -0,0 +1,4072 @@ +/** + \file appl_model_server_state_handler.c + + \brief + This file contains function, which handles model state set/get operations. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_common.h" +#include "MS_generic_property_api.h" + +#include "appl_model_state_handler.h" +#include "model_state_handler_pl.h" + +#ifdef MS_STORAGE + #include "nvsto.h" +#endif /* MS_STORAGE */ + +/* -------------------------------------- External Functions */ +extern void appl_generic_power_level_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +); +extern void appl_generic_level_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +); +extern void appl_generic_onoff_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +); +extern void appl_generic_power_onoff_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +); +extern void appl_light_lightness_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +); +extern void appl_light_ctl_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +); +extern void appl_light_ctl_temperature_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +); +extern void appl_light_hsl_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +); +extern void appl_light_hsl_hue_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +); +extern void appl_light_hsl_saturation_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +); +extern void appl_light_xyl_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst +); +extern void appl_light_lc_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst, + /* IN */ UINT16 property_id +); + +extern void appl_generic_admin_property_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst, + /* IN */ UINT16 property_id +); +extern void appl_generic_manufacturer_property_server_publish +( + /* IN */ UINT8 state_type, + /* IN */ UINT16 state_inst, + /* IN */ UINT16 property_id +); +/* --------------------------------------------- Global Definitions */ +API_RESULT appl_model_light_lc_server_set_default_trans_timeout_in_ms(/* IN */ UINT32 time_in_ms); + +/* --------------------------------------------- Data Types/ Structures */ +#define MS_MAX_NUM_STATES 2 + +/* States stored/restored as Scene */ +typedef struct _APPL_STATE_INFO_VAULT +{ + /* Generic OnOff state */ + UINT8 onoff; + + /* Generic Level state */ + UINT16 level; + + /* Generic Power Level */ + UINT16 power_level; + + /* Light Lightness Actual */ + UINT16 lightness_actual; + + /* Light Lightness Linear */ + UINT16 lightness_linear; + + /** Light CTL Lightness */ + UINT16 ctl_lightness; + + /** Light CTL Temperature */ + UINT16 ctl_temperature; + + /** Light CTL Delta UV */ + UINT16 ctl_delta_uv; + + /** The perceived lightness of a light emitted by the element */ + UINT16 hsl_lightness; + + /** The 16-bit value representing the hue */ + UINT16 hsl_hue; + + /** The saturation of a color light */ + UINT16 hsl_saturation; + + /** The perceived lightness of a light emitted by the element */ + UINT16 xyl_lightness; + + /** The 16-bit value representing the x coordinate of a CIE1931 color light */ + UINT16 xyl_x; + + /** The 16-bit value representing the y coordinate of a CIE1931 color light */ + UINT16 xyl_y; + + /* LC Mode */ + UINT8 lc_mode; + + /* LC Property */ + MS_STATE_LIGHT_LC_PROPERTY_STRUCT lc_property; + +} APPL_STATE_INFO_VAULT; + +typedef struct _APPL_GENENRIC_LEVEL_INFO +{ + MS_STATE_GENERIC_LEVEL_STRUCT generic_level; + + /* Operation Type : 0xFF as initial value (invalid) */ + UINT8 operation_type; + + UINT16 transition_time_handle; + +} APPL_GENERIC_LEVEL_INFO; + +/** -- Generics - OnOff State */ +#define APPL_GENERIC_ONOFF_SET(inst, OnOff) \ + appl_generic_onoff[(inst)].onoff = (OnOff); \ + appl_generic_onoff[(inst)].last_onoff = (OnOff) + +static MS_STATE_GENERIC_ONOFF_STRUCT appl_generic_onoff[MS_MAX_NUM_STATES]; + +/** -- Generics - Level State */ +static APPL_GENERIC_LEVEL_INFO appl_generic_level_info[MS_MAX_NUM_STATES]; + +/** -- Generics - Power OnOff State */ +static MS_STATE_GENERIC_ONPOWERUP_STRUCT appl_generic_onpower[MS_MAX_NUM_STATES]; + +/** -- Generics - Power Level State */ +static MS_STATE_GENERIC_POWER_LEVEL_STRUCT appl_generic_power_level[MS_MAX_NUM_STATES]; + +/** -- Generics - Battery */ +static MS_STATE_GENERIC_BATTERY_STRUCT appl_generic_battery[MS_MAX_NUM_STATES]; + +/** -- Generics - Location */ +static MS_STATE_GENERIC_LOCATION_STRUCT appl_generic_location[MS_MAX_NUM_STATES]; + +#define MS_MAX_CLIENT_PROPERTIES 1 /* 3 */ + +/* Example codebase. One Property each for Manufacturer, Admin and User */ +#define MS_MAX_PROPERTIES 3 + +static MS_STATE_GENERIC_PROPERTY_STRUCT appl_generic_property[MS_MAX_NUM_STATES][MS_MAX_PROPERTIES]; + +static MS_STATE_GENERIC_USER_PROPERTY_STRUCT appl_generic_client_property[MS_MAX_NUM_STATES][MS_MAX_CLIENT_PROPERTIES]; + +/** -- Light - Lightness */ +static MS_STATE_LIGHT_LIGHTNESS_STRUCT appl_light_lightness[MS_MAX_NUM_STATES]; + +/** -- Light - CTL */ +#define LIGHT_CTL_TEMPERATURE_T_MIN 0x0320 +#define LIGHT_CTL_TEMPERATURE_T_MAX 0x4E20 + +static MS_STATE_LIGHT_CTL_STRUCT appl_light_ctl[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_STRUCT appl_light_ctl_temperature_range[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_CTL_DEFAULT_STRUCT appl_light_ctl_default[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_CTL_TEMPERATURE_STRUCT appl_light_ctl_temperature[MS_MAX_NUM_STATES]; + +/** -- Light - HSL */ +static MS_STATE_LIGHT_HSL_STRUCT appl_light_hsl[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_HSL_RANGE_STRUCT appl_light_hsl_range[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_HSL_DEFAULT_STRUCT appl_light_hsl_default[MS_MAX_NUM_STATES]; + +/** -- Light - xyL */ +static MS_STATE_LIGHT_XYL_STRUCT appl_light_xyl[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_XYL_DEFAULT_STRUCT appl_light_xyl_default[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_XYL_RANGE_STRUCT appl_light_xyl_range[MS_MAX_NUM_STATES]; + +/** -- Light - LC */ +#define MS_MAX_LC_PROPERTIES 10 +static MS_STATE_LIGHT_LC_MODE_STRUCT appl_light_lc_mode[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_LC_OM_STRUCT appl_light_lc_om[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_LC_LIGHT_ONOFF_STRUCT appl_light_lc_onoff[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_LC_PROPERTY_STRUCT appl_light_lc_property[MS_MAX_NUM_STATES][MS_MAX_LC_PROPERTIES]; +static UINT8 appl_current_property_id_index; + +/* For simplicity keeping same number of state info, as the number of max scences */ +/* Last one is to store Power OnOff related value */ +static APPL_STATE_INFO_VAULT appl_state_info_vault[16 + 1]; +static UINT8 appl_in_transtion; + +static void appl_light_lightness_set_actual(UINT16 state_inst, UINT16 actual, UCHAR forced_publish); +static void appl_light_ctl_lightness_set_actual(UINT16 state_inst, UINT16 lightness, UINT16 temperature, UINT16 delta_uv, UCHAR forced_publish); +static void appl_light_ctl_temp_set_actual(UINT16 state_inst, UINT16 actual, UINT16 delta_uv, UCHAR is_calculated); +static void appl_light_xyl_set_actual(UINT16 state_inst, UINT16 xyl_lightness, UINT16 xyl_x, UINT16 xyl_y); + +static void appl_light_hsl_set_actual(UINT16 state_inst, UINT16 lightness, UINT16 hue, UINT16 saturation, UCHAR forced_publish); + +static void appl_light_lc_set_actual(UINT16 state_inst, UINT16 state_t, UCHAR onoff, UCHAR mode); +static API_RESULT appl_light_lc_set_actual_propery(UINT16 state_inst, UINT16 property_id, UCHAR* property_value, UINT16 property_value_len); + +static void appl_set_generic_onoff(UINT16 state_inst, UINT8 onoff, UINT8 forced_publish); +void appl_light_lightness_set_linear(UINT16 state_inst, UINT16 linear); + +void* appl_scene_save_current_state(/* IN */ UINT32 scene_index); +void* appl_scene_delete_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context); +void* appl_scene_recall_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context); + +#ifdef MS_STORAGE + + /** Maximum number of Application Records in Persistent Storage */ + #define MS_PS_APPL_MAX_RECORDS 2 + + /** Bitmask for all Application PS Access Record types */ + #define MS_PS_APPL_ALL_RECORDS ((1 << MS_PS_APPL_MAX_RECORDS) - 1) + + /** Persistet Storage Application Records (bitfield values) */ + #define MS_PS_RECORD_APPL_SCENE 0x00000001 + #define MS_PS_RECORD_APPL_ON_POWER 0x00000002 + + static void appl_ps_init (void); + static void appl_ps_store(/* IN */ UINT32 records); + static void appl_ps_load(/* IN */ UINT32 records); +#endif /* MS_STORAGE */ + +/* --------------------------------------------- Function */ +static API_RESULT appl_model_state_is_diff_in_range +( + /* IN */ UINT32 value_a, + /* IN */ UINT32 value_b, + /* IN */ UINT32 range +) +{ + API_RESULT retval; + UINT32 value_diff; + retval = API_FAILURE; + + if (value_a < value_b) + { + value_diff = value_b - value_a; + } + else + { + value_diff = value_a - value_b; + } + + if (value_diff <= range) + { + retval = API_SUCCESS; + } + + return retval; +} + +/** ---------------- Model Binding ---- */ +static void appl_set_generic_level(UINT16 state_inst, UINT16 level, UINT8 propagate, UCHAR is_calculated); + +/** + Binding with Power Actual. + + Generic Power Actual = Generic Level + 32768 + Light Lightness Actual = Generic Level + 32768 + Light HSL Hue = Generic Level + 32768 + Light HSL Saturation = Generic Level + 32768 + + Light CTL Temperature = T_MIN + (Generic Level + 32768) * (T_MAX - T_MIN) / 65535 +*/ +static void appl_set_generic_power_level_actual(UINT16 state_inst, UINT16 actual, UINT8 propagate) +{ + UINT16 temperature; + CONSOLE_OUT("[Set Generic Power Level] Level: 0x%04X. Propagate: 0x%02X\n", actual, propagate); + + if (actual != appl_generic_power_level[state_inst].generic_power_actual.power_actual) + { + appl_generic_power_level[state_inst].generic_power_last.power_last = actual; + appl_generic_power_level[state_inst].generic_power_actual.power_actual = actual; + /* Publish State Change */ + appl_generic_power_level_server_publish(MS_STATE_GENERIC_POWER_ACTUAL_T, state_inst); + appl_light_lightness_set_actual(state_inst, actual, MS_FALSE); + /* Light HSL Lightness = Light Lightness Actual */ + appl_light_hsl[state_inst].hsl_lightness = actual; + /* Light Lightness Linear = ((Actual)^2) / 65535 */ + /* appl_light_lightness[state_inst].light_lightness_linear.lightness_linear = ((actual * actual) + 65534) / 65535; */ + #if 0 + /* Light CTL Temperature = T_MIN + (Generic Level + 32768) * (T_MAX - T_MIN) / 65535 */ + appl_light_ctl_temperature[state_inst].ctl_temperature = + appl_light_ctl_temperature_range[state_inst].ctl_temperature_range_min + + ((actual) * (appl_light_ctl_temperature_range[state_inst].ctl_temperature_range_max - + appl_light_ctl_temperature_range[state_inst].ctl_temperature_range_min)) / 65535; + appl_light_ctl[state_inst].ctl_lightness = actual; + #else + /* Light CTL Temperature = T_MIN + (Generic Level + 32768) * (T_MAX - T_MIN) / 65535 */ + temperature = LIGHT_CTL_TEMPERATURE_T_MIN + (((actual) * (LIGHT_CTL_TEMPERATURE_T_MAX - LIGHT_CTL_TEMPERATURE_T_MIN)) / 65535); + appl_light_ctl_temp_set_actual + ( + state_inst, + temperature, + appl_light_ctl[state_inst].ctl_delta_uv, + MS_TRUE + ); + #endif /* 0 */ + #if 0 + appl_light_hsl[state_inst].hsl_hue = actual; + appl_light_hsl[state_inst].hsl_saturation = actual; + #endif /* 0 */ + + /* Binding with Generic OnOff */ + if (0x0000 == actual) + { + appl_set_generic_onoff(state_inst, 0x00, MS_TRUE); + } + else + { + appl_set_generic_onoff(state_inst, 0x01, MS_TRUE); + } + + /* Set Power Actual and rest will be set */ + if (MS_TRUE == propagate) + { + appl_set_generic_level(state_inst, actual - 32768, MS_FALSE, MS_FALSE); + } + } +} + +static void appl_set_generic_power_level_default(UINT16 state_inst, UINT16 actual, UINT8 propagate) +{ + CONSOLE_OUT("[Set Generic Power Level Default] Level: 0x%04X. Propagate: 0x%02X\n", actual, propagate); + + if (actual != appl_generic_power_level[state_inst].generic_power_default.power_default) + { + appl_generic_power_level[state_inst].generic_power_default.power_default = actual; + appl_generic_power_level_server_publish(MS_STATE_GENERIC_POWER_DEFAULT_T, state_inst); + /* Propagate to Generic Power Actual */ + /* appl_set_generic_power_level_actual(state_inst, actual, MS_TRUE); */ + } +} + +/** + Binding with Generic Level. + + Generic Power Actual = Generic Level + 32768 + Light Lightness Actual = Generic Level + 32768 + Light HSL Hue = Generic Level + 32768 + Light HSL Saturation = Generic Level + 32768 + + Light CTL Temperature = T_MIN + (Generic Level + 32768) * (T_MAX - T_MIN) / 65535 +*/ +static void appl_set_generic_level(UINT16 state_inst, UINT16 level, UINT8 propagate, UCHAR is_calculated) +{ + CONSOLE_OUT("[Set Generic Level] New Level: 0x%04X. Propagate: 0x%02X\n", level, propagate); + CONSOLE_OUT("[Set Generic Level] Current Level: 0x%04X.\n", + appl_generic_level_info[state_inst].generic_level.level); + + if ((level == appl_generic_level_info[state_inst].generic_level.level) || + /* If calculated and difference is only one */ + ((MS_TRUE == is_calculated) && (API_SUCCESS == appl_model_state_is_diff_in_range(level, appl_generic_level_info[state_inst].generic_level.level, 0x05))) + ) + { + } + else + { + appl_generic_level_info[state_inst].generic_level.level = level; + appl_generic_level_info[state_inst].generic_level.target_level = 0; + appl_generic_level_info[state_inst].generic_level.delta_level = 0; + appl_generic_level_server_publish(MS_STATE_GENERIC_LEVEL_T, state_inst); + + /* Set Power Actual and rest will be set */ + if (MS_TRUE == propagate) + { + appl_set_generic_power_level_actual(state_inst, level + 32768, MS_FALSE); + } + } +} + +/** --------------------- Generics - OnOff ---- */ +/* Initialization */ +static void appl_generic_onoff_states_initialization(void) +{ + UINT32 index; + EM_mem_set(appl_generic_onoff, 0, sizeof(appl_generic_onoff)); + + for (index = 0; index < MS_MAX_NUM_STATES; index++) + { + appl_generic_onoff[index].transition_time_handle = 0xFFFF; + } +} + +/* Transition Timer Handlers */ +static void appl_generic_onoff_transition_start_cb(void* blob) +{ + /** + Because binary states cannot support transitions, when changing to 0x01 (On), + the Generic OnOff state shall change immediately when the transition starts, + and when changing to 0x00, the state shall change when the transition finishes. + */ + if (0 == appl_generic_onoff[0].onoff) + { + /* appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; */ + appl_set_generic_onoff(0, appl_generic_onoff[0].target_onoff, MS_FALSE); + } +} + +static void appl_generic_onoff_transition_complete_cb(void* blob) +{ + CONSOLE_OUT("Generic OnOff Transition Complete Callback\n"); + /* State Transition Complete */ + appl_generic_onoff[0].transition_time_handle = 0xFFFF; + appl_generic_onoff[0].transition_time = 0; + appl_set_generic_onoff(0, appl_generic_onoff[0].target_onoff, MS_TRUE); + appl_generic_onoff[0].target_onoff = 0; +} + +/* Generic OnOff Model Get Handlers */ +static API_RESULT appl_model_generic_onoff_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + API_RESULT ret; + UINT8 transition_time; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_generic_onoff[0]; + + if (0 != param_p->transition_time) + { + ret = MS_common_get_remaining_transition_time + ( + appl_generic_onoff[0].transition_time_handle, + &transition_time + ); + + if (API_SUCCESS == ret) + { + param_p->transition_time = transition_time; + } + } + + CONSOLE_OUT("Generic OnOff State Get. Returning: 0x%02X\n", param_p->onoff); + } + break; + + default: + break; + } + + return retval; +} + +/* Generic OnOff Model Set Handlers */ +static API_RESULT appl_model_generic_onoff_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + CONSOLE_OUT("Generic OnOff State Set: 0x%02X\n", param_p->onoff); + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + appl_generic_onoff[0].target_onoff = param_p->onoff; + appl_generic_onoff[0].transition_time = param_p->transition_time; + appl_generic_onoff[0].last_onoff = param_p->onoff; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_generic_onoff_transition_start_cb; + transition.transition_complete_cb = appl_generic_onoff_transition_complete_cb; + *param_p = appl_generic_onoff[0]; + MS_common_start_transition_timer + ( + &transition, + &appl_generic_onoff[0].transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + appl_set_generic_onoff(state_inst, param_p->onoff, MS_FALSE); + *param_p = appl_generic_onoff[0]; + } + + CONSOLE_OUT("[state] current: 0x%02X\n", appl_generic_onoff[0].onoff); + CONSOLE_OUT("[state] target: 0x%02X\n", appl_generic_onoff[0].target_onoff); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_generic_onoff[0].transition_time); + /* Ignoring Instance and direction right now */ + /* Call platform specific handling for generic set */ + generic_onoff_set_pl (appl_generic_onoff[0].onoff); + } + break; + + default: + break; + } + + return retval; +} + +/** --------------------- Generics - Level ---- */ +/* Initialization */ +static void appl_model_generic_level_states_initialization(void) +{ + UINT32 index; + + for (index = 0; index < MS_MAX_NUM_STATES; index++) + { + EM_mem_set(&appl_generic_level_info[index], 0, sizeof(APPL_GENERIC_LEVEL_INFO)); + appl_generic_level_info[index].operation_type = 0xFF; + appl_generic_level_info[index].transition_time_handle = 0xFFFF; + } +} + +static void appl_set_delta_level(UINT16 state_inst, INT32 delta, UINT8 immediate) +{ + /* TODO: See if this to be stored */ + if (0x01 == immediate) + { + appl_set_generic_level(state_inst, (appl_generic_level_info[state_inst].generic_level.level + delta), MS_TRUE, MS_FALSE); + } + else if (0x00 == immediate) + { + appl_generic_level_info[0].generic_level.target_level = (appl_generic_level_info[state_inst].generic_level.level + delta); + appl_generic_level_info[state_inst].generic_level.delta_level = delta; + } + else + { + /* Do nothing right now */ + } +} + +static void appl_set_move_level(UINT16 state_inst, UINT16 move, UINT8 immediate) +{ + /* TODO: See if this to be stored */ + appl_generic_level_info[state_inst].generic_level.move_level = move; +} + +/* Transition Timer Handlers */ +static void appl_generic_level_transition_start_cb(void* blob) +{ + UINT16 state_t; + state_t = (UINT16)((intptr_t)(blob)); + (void)state_t; +} + +static void appl_generic_level_transition_complete_cb(void* blob) +{ + UINT16 state_t; + state_t = (UINT16)((intptr_t)(blob)); + appl_generic_level_info[0].generic_level.transition_time = 0x00; + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + + switch (state_t) + { + case MS_STATE_GENERIC_LEVEL_T: + { + appl_set_generic_level(0, appl_generic_level_info[0].generic_level.target_level, MS_TRUE, MS_FALSE); + } + break; + + case MS_STATE_DELTA_LEVEL_T: + { + appl_set_generic_level(0, appl_generic_level_info[0].generic_level.target_level, MS_TRUE, MS_FALSE); + } + break; + + case MS_STATE_MOVE_LEVEL_T: + { + appl_set_move_level(0, appl_generic_level_info[0].generic_level.delta_level, 0x01); + /* TODO: Remove Bad Logic */ + appl_generic_level_info[0].generic_level.move_level = 0; + } + break; + } +} + +static API_RESULT appl_model_generic_level_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_LEVEL_T: + { + MS_STATE_GENERIC_LEVEL_STRUCT* param_p; + API_RESULT ret; + UINT8 transition_time; + param_p = (MS_STATE_GENERIC_LEVEL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_generic_level_info[0].generic_level; + param_p->level = appl_generic_level_info[0].generic_level.level + appl_generic_level_info[0].generic_level.delta_level; + + if (0 != param_p->transition_time) + { + ret = MS_common_get_remaining_transition_time + ( + appl_generic_level_info[0].transition_time_handle, + &transition_time + ); + + if (API_SUCCESS == ret) + { + param_p->transition_time = transition_time; + } + } + } + break; + + default: + break; + } + + return retval; +} + +static API_RESULT appl_model_generic_level_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + MS_STATE_GENERIC_LEVEL_STRUCT* param_p; + /** + Transaction State: + 0 : Start of Transaction + 1 : Continue + 2 : End of Transaction + */ + UINT8 transaction_state; + param_p = (MS_STATE_GENERIC_LEVEL_STRUCT*)param; + + switch (state_t) + { + case MS_STATE_GENERIC_LEVEL_T: + { + /* Ignoring Instance and direction right now */ + /* TODO: Not handling transaction state */ + { + MS_common_stop_transition_timer(appl_generic_level_info[0].transition_time_handle); + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + + if (0 == param_p->transition_time) + { + appl_set_generic_level(0, param_p->level, MS_TRUE, MS_FALSE); + } + else + { + appl_generic_level_info[0].generic_level.target_level = param_p->level; + param_p->target_level = param_p->level; + } + } + } + break; + + case MS_STATE_DELTA_LEVEL_T: + { + /* Check if a new transaction */ + if (appl_generic_level_info[0].operation_type != state_t) + { + transaction_state = 0x00; + /* Stop associated Transaction Timer, if any */ + MS_common_stop_transition_timer(appl_generic_level_info[0].transition_time_handle); + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + appl_generic_level_info[0].operation_type = state_t; + appl_generic_level_info[0].generic_level.tid = param_p->tid; + } + else if (param_p->tid == appl_generic_level_info[0].generic_level.tid) + { + transaction_state = 0x01; + } + else + { + transaction_state = 0x02; + /* Stop associated Transaction Timer, if any */ + MS_common_stop_transition_timer(appl_generic_level_info[0].transition_time_handle); + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + appl_generic_level_info[0].operation_type = state_t; + appl_generic_level_info[0].generic_level.tid = param_p->tid; + } + + /* Ignoring Instance and direction right now */ + if (0x02 == transaction_state) + { + appl_set_delta_level(0, (INT32)appl_generic_level_info[0].generic_level.delta_level, 0x01); + } + + /* Only update delta */ + appl_set_delta_level(0, (INT32)param_p->delta_level, 0x00); + } + break; + + case MS_STATE_MOVE_LEVEL_T: + { + /* Ignoring Instance and direction right now */ + if (0 == param_p->transition_time) + { + appl_set_move_level(0, param_p->move_level, 0x01); + } + else + { + appl_set_move_level(0, param_p->move_level, 0x00); + appl_generic_level_info[0].generic_level.target_level = param_p->move_level * (param_p->transition_time & 0x3F); + /* TODO: Hardcoding */ + /* appl_generic_level_info[0].generic_level.target_level = 0x7FFF; */ + } + } + break; + + default: + break; + } + + /* TODO: Do we need to check if this is a new transaction? */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + appl_generic_level_info[0].generic_level.transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = (void*)(intptr_t)state_t; + transition.transition_start_cb = appl_generic_level_transition_start_cb; + transition.transition_complete_cb = appl_generic_level_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &appl_generic_level_info[0].transition_time_handle + ); + } + + *param_p = appl_generic_level_info[0].generic_level; + + if (0 == param_p->transition_time) + { + param_p->level = appl_generic_level_info[0].generic_level.level + appl_generic_level_info[0].generic_level.delta_level; + } + + return API_SUCCESS; +} + +/** --------------------- Generics - Default Transition Time ---- */ + +/** --------------------- Generics - Power OnOff ---- */ +static void appl_model_generic_power_onoff_states_initialization(void) +{ + EM_mem_set(appl_generic_onpower, 0, sizeof(appl_generic_onpower)); +} + +static API_RESULT appl_model_generic_power_onoff_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_GENERIC_ONPOWERUP_T: + { + MS_STATE_GENERIC_ONPOWERUP_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_generic_onpower[0]; + } + break; + + default: + break; + } + + return retval; +} + +static API_RESULT appl_model_generic_power_onoff_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_ONPOWERUP_T: + { + MS_STATE_GENERIC_ONPOWERUP_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_generic_onpower[0] = *param_p; + } + break; + + default: + break; + } + + return retval; +} + +/** --------------------- Generics - Power Level ---- */ +static void appl_model_power_level_states_initialization(void) +{ + EM_mem_set(appl_generic_power_level, 0, sizeof(appl_generic_power_level)); +} + +static void appl_power_level_set_actual(UINT16 state_inst, UINT16 actual) +{ + UINT16 min, max; + min = appl_generic_power_level[state_inst].generic_power_range.power_range_min; + max = appl_generic_power_level[state_inst].generic_power_range.power_range_max; + + if ((0 != min) && (actual < min)) + { + actual = min; + } + else if ((0 != max) && (actual > max)) + { + actual = max; + } + + appl_set_generic_power_level_actual(state_inst, actual, MS_TRUE); +} + +static void appl_generic_power_level_set_range(UINT16 state_inst, UINT16 min, UINT16 max) +{ + UINT16 actual; + appl_generic_power_level[state_inst].generic_power_range.power_range_min = min; + appl_generic_power_level[state_inst].generic_power_range.power_range_max = max; + /* Check if actual to be updated */ + actual = appl_generic_power_level[state_inst].generic_power_actual.power_actual; + appl_power_level_set_actual(state_inst, actual); +} + +static void appl_generic_power_level_transition_start_cb(void* blob) +{ + /** + Because binary states cannot support transitions, when changing to 0x01 (On), + the Generic OnOff state shall change immediately when the transition starts, + and when changing to 0x00, the state shall change when the transition finishes. + */ + #if 0 + if (0 == appl_generic_onoff[0].onoff) + { + appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; + } + + #endif +} + +static void appl_generic_power_level_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_generic_power_level[0].generic_power_actual.transition_time = 0; + appl_power_level_set_actual(0, appl_generic_power_level[0].generic_power_actual.power_target); + appl_generic_power_level[0].generic_power_actual.power_target = 0; +} + +static API_RESULT appl_model_generic_power_level_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_POWER_ACTUAL_T: + { + MS_STATE_GENERIC_POWER_ACTUAL_STRUCT* param_p; + API_RESULT ret; + UINT8 transition_time; + param_p = (MS_STATE_GENERIC_POWER_ACTUAL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_generic_power_level[0].generic_power_actual; + + if (0 != param_p->transition_time) + { + ret = MS_common_get_remaining_transition_time + ( + appl_generic_power_level[0].generic_power_actual.transition_time_handle, + &transition_time + ); + + if (API_SUCCESS == ret) + { + param_p->transition_time = transition_time; + } + } + } + break; + + case MS_STATE_GENERIC_POWER_LAST_T: + { + MS_STATE_GENERIC_POWER_LAST_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_POWER_LAST_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_generic_power_level[0].generic_power_last; + } + break; + + case MS_STATE_GENERIC_POWER_DEFAULT_T: + { + MS_STATE_GENERIC_POWER_DEFAULT_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_POWER_DEFAULT_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_generic_power_level[0].generic_power_default; + } + break; + + case MS_STATE_GENERIC_POWER_RANGE_T: + { + MS_STATE_GENERIC_POWER_RANGE_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_POWER_RANGE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_generic_power_level[0].generic_power_range; + } + break; + + default: + break; + } + + return retval; +} + +static API_RESULT appl_model_generic_power_level_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_POWER_ACTUAL_T: + { + MS_STATE_GENERIC_POWER_ACTUAL_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_POWER_ACTUAL_STRUCT*)param; + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + appl_generic_power_level[state_inst].generic_power_actual.power_target = param_p->power_actual; + appl_generic_power_level[state_inst].generic_power_actual.transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_generic_power_level_transition_start_cb; + transition.transition_complete_cb = appl_generic_power_level_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &appl_generic_power_level[state_inst].generic_power_actual.transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + /* Ignoring Instance and direction right now */ + appl_power_level_set_actual(0, param_p->power_actual); + } + + *param_p = appl_generic_power_level[0].generic_power_actual; + CONSOLE_OUT("[state] current: 0x%02X\n", appl_generic_power_level[0].generic_power_actual.power_actual); + CONSOLE_OUT("[state] target: 0x%02X\n", appl_generic_power_level[0].generic_power_actual.power_target); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_generic_power_level[0].generic_power_actual.transition_time); + } + break; + + case MS_STATE_GENERIC_POWER_DEFAULT_T: + { + MS_STATE_GENERIC_POWER_DEFAULT_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_POWER_DEFAULT_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_set_generic_power_level_default(0, param_p->power_default, MS_TRUE); + } + break; + + case MS_STATE_GENERIC_POWER_RANGE_T: + { + MS_STATE_GENERIC_POWER_RANGE_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_POWER_RANGE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_generic_power_level_set_range(0, param_p->power_range_min, param_p->power_range_max); + param_p->status = 0x00; + } + break; + + default: + break; + } + + return retval; +} + +/** --------------------- Generics - Battery ---- */ +static void appl_model_generic_battery_states_initialization(void) +{ + EM_mem_set(appl_generic_battery, 0, sizeof(appl_generic_battery)); +} + +static API_RESULT appl_model_generic_battery_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + switch (state_t) + { + case MS_STATE_GENERIC_BATTERY_T: + { + MS_STATE_GENERIC_BATTERY_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_BATTERY_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_generic_battery[0]; + } + break; + + default: + break; + } + + return API_SUCCESS; +} + +static API_RESULT appl_model_generic_battery_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + switch (state_t) + { + case MS_STATE_GENERIC_BATTERY_T: + { + MS_STATE_GENERIC_BATTERY_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_BATTERY_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_generic_battery[0] = *param_p; + } + break; + + default: + break; + } + + return API_SUCCESS; +} + +/** --------------------- Generics - Location ---- */ +static void appl_model_generic_location_states_initialization(void) +{ + EM_mem_set (appl_generic_location, 0, sizeof(appl_generic_location)); +} + +static API_RESULT appl_model_generic_location_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + switch(state_t) + { + case MS_STATE_GENERIC_LOCATION_GLOBAL_T: + { + MS_STATE_GENERIC_LOCATION_GLOBAL_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_LOCATION_GLOBAL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_generic_location[0].global_location; + } + break; + + case MS_STATE_GENERIC_LOCATION_LOCAL_T: + { + MS_STATE_GENERIC_LOCATION_LOCAL_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_LOCATION_LOCAL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_generic_location[0].local_location; + } + break; + + default: + break; + } + + return API_SUCCESS; +} + +static API_RESULT appl_model_generic_location_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + switch(state_t) + { + case MS_STATE_GENERIC_LOCATION_GLOBAL_T: + { + MS_STATE_GENERIC_LOCATION_GLOBAL_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_LOCATION_GLOBAL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_generic_location[0].global_location = *param_p; + } + break; + + case MS_STATE_GENERIC_LOCATION_LOCAL_T: + { + MS_STATE_GENERIC_LOCATION_LOCAL_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_LOCATION_LOCAL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_generic_location[0].local_location = *param_p; + } + break; + + default: + break; + } + + return API_SUCCESS; +} + +/** --------------------- Generics - Property ---- */ +static void appl_model_generic_property_states_initialization(void) +{ + UINT32 index; + UINT8 access_type; + EM_mem_set(appl_generic_property, 0, sizeof(appl_generic_property)); + /* One Manufacturer Property */ + index = 0; + /* Motion Sensed */ + appl_generic_property[0][index].property_id = MS_DEV_PROP_MOTION_SENSED; + appl_generic_property[0][index].property_type = MS_GENERIC_PROP_TYPE_MANUFACTURER; + appl_generic_property[0][index].access = MS_GENERIC_USER_ACCESS_READ; + appl_generic_property[0][index].property_value_len = 1; + appl_generic_property[0][index].property_value = EM_alloc_mem(appl_generic_property[0][index].property_value_len); + EM_mem_set(appl_generic_property[0][index].property_value, (index + 1), appl_generic_property[0][index].property_value_len); + /* One Admin Property */ + index ++; + /* People Count */ + appl_generic_property[0][index].property_id = MS_DEV_PROP_PEOPLE_COUNT; + appl_generic_property[0][index].property_type = MS_GENERIC_PROP_TYPE_ADMIN; + appl_generic_property[0][index].access = MS_GENERIC_USER_ACCESS_READ; + appl_generic_property[0][index].property_value_len = 1; + appl_generic_property[0][index].property_value = EM_alloc_mem(appl_generic_property[0][index].property_value_len); + EM_mem_set(appl_generic_property[0][index].property_value, (index + 1), appl_generic_property[0][index].property_value_len); + /* One USer Property */ + index++; + /* Presence Detected */ + appl_generic_property[0][index].property_id = MS_DEV_PROP_PRESENCE_DETECTED; + appl_generic_property[0][index].property_type = MS_GENERIC_PROP_TYPE_USER; + appl_generic_property[0][index].access = MS_GENERIC_USER_ACCESS_READ; + appl_generic_property[0][index].property_value_len = 1; + appl_generic_property[0][index].property_value = EM_alloc_mem(appl_generic_property[0][index].property_value_len); + EM_mem_set(appl_generic_property[0][index].property_value, (index + 1), appl_generic_property[0][index].property_value_len); + EM_mem_set(appl_generic_client_property, 0, sizeof(appl_generic_client_property)); + /* Client Properties */ + /* Manufacturer Properties */ + access_type = MS_GENERIC_USER_ACCESS_READ; + + for (index = 0; index < MS_MAX_CLIENT_PROPERTIES; index++) + { + appl_generic_client_property[0][index].property_id = index + 1; + appl_generic_client_property[0][index].user_access = access_type; + /* Allocate and keep some property value */ + appl_generic_client_property[0][index].property_value_len = index + 1; + appl_generic_client_property[0][index].property_value = EM_alloc_mem(index + 1); + /* TODO: Not checking for memeory allocation failure */ + EM_mem_set(appl_generic_client_property[0][index].property_value, (index + 1), (index + 1)); + + if (MS_GENERIC_USER_ACCESS_READ_WRITE == access_type) + { + access_type = MS_GENERIC_USER_ACCESS_READ; + } + else + { + access_type++; + } + } +} + +static API_RESULT appl_model_generic_property_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + UINT32 index; + + switch(state_t) + { + case MS_STATE_GENERIC_USER_PROPERTY_IDS_T: + { + MS_STATE_GENERIC_PROPERTY_IDS_STRUCT* param_p; + UINT8 count; + param_p = (MS_STATE_GENERIC_PROPERTY_IDS_STRUCT*)param; + count = 0; + + for (index = 0; index < MS_MAX_PROPERTIES; index++) + { + if (((MS_GENERIC_PROP_TYPE_MANUFACTURER == appl_generic_property[0][index].property_type) && + (MS_GENERIC_USER_ACCESS_READ == appl_generic_property[0][index].access)) || + ((MS_GENERIC_PROP_TYPE_ADMIN == appl_generic_property[0][index].property_type) && + (MS_GENERIC_USER_ACCESS_PROHIBITED != appl_generic_property[0][index].access)) || + ((MS_GENERIC_PROP_TYPE_USER == appl_generic_property[0][index].property_type) && + (MS_GENERIC_USER_ACCESS_PROHIBITED != appl_generic_property[0][index].access))) + { + param_p->property_ids[count] = appl_generic_property[0][index].property_id; + count++; + } + } + + /* TODO: Not checking 'property_ids_count' in input */ + param_p->property_ids_count = count; + } + break; + + case MS_STATE_GENERIC_ADMIN_PROPERTY_IDS_T: + { + MS_STATE_GENERIC_PROPERTY_IDS_STRUCT* param_p; + UINT8 count; + param_p = (MS_STATE_GENERIC_PROPERTY_IDS_STRUCT*)param; + count = 0; + + for (index = 0; index < MS_MAX_PROPERTIES; index++) + { + if (/* (MS_GENERIC_PROP_TYPE_MANUFACTURER == appl_generic_property[0][index].property_type) || */ + (MS_GENERIC_PROP_TYPE_ADMIN == appl_generic_property[0][index].property_type)) + { + param_p->property_ids[count] = appl_generic_property[0][index].property_id; + count++; + } + } + + /* TODO: Not checking 'property_ids_count' in input */ + param_p->property_ids_count = count; + } + break; + + case MS_STATE_GENERIC_MANUFACTURER_PROPERTY_IDS_T: + { + MS_STATE_GENERIC_PROPERTY_IDS_STRUCT* param_p; + UINT8 count; + param_p = (MS_STATE_GENERIC_PROPERTY_IDS_STRUCT*)param; + count = 0; + + for (index = 0; index < MS_MAX_PROPERTIES; index++) + { + if (MS_GENERIC_PROP_TYPE_MANUFACTURER == appl_generic_property[0][index].property_type) + { + param_p->property_ids[count] = appl_generic_property[0][index].property_id; + count++; + } + } + + /* TODO: Not checking 'property_ids_count' in input */ + param_p->property_ids_count = count; + } + break; + + case MS_STATE_GENERIC_CLIENT_PROPERTY_IDS_T: + { + MS_STATE_GENERIC_PROPERTY_IDS_STRUCT* param_p; + UINT8 count; + param_p = (MS_STATE_GENERIC_PROPERTY_IDS_STRUCT*)param; + count = 0; + + for (index = 0; index < MS_MAX_CLIENT_PROPERTIES; index++) + { + /* Check if Admin Property is not disabled */ + /* if (MS_GENERIC_USER_ACCESS_PROHIBITED != appl_generic_client_property[0][index].user_access) */ + { + param_p->property_ids[index] = appl_generic_client_property[0][index].property_id; + count++; + } + } + + /* TODO: Not checking 'property_ids_count' in input */ + param_p->property_ids_count = count; + } + break; + + case MS_STATE_GENERIC_USER_PROPERTY_T: + { + MS_STATE_GENERIC_USER_PROPERTY_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_USER_PROPERTY_STRUCT*)param; + /* Check for property ID match */ + /* Mark the access as prohibited, to indicate invalid Property ID */ + param_p->user_access = MS_GENERIC_USER_ACCESS_PROHIBITED; + + for (index = 0; index < MS_MAX_PROPERTIES; index++) + { + if (appl_generic_property[0][index].property_id == param_p->property_id) + { + if (MS_GENERIC_USER_ACCESS_PROHIBITED != appl_generic_property[0][index].access) + { + param_p->user_access = appl_generic_property[0][index].access; + + if (MS_GENERIC_USER_ACCESS_WRITE == param_p->user_access) + { + param_p->property_value_len = 0; + } + else + { + param_p->property_value = appl_generic_property[0][index].property_value; + param_p->property_value_len = appl_generic_property[0][index].property_value_len; + } + + printf("GGGGEEETTTTTT::::USER::::: [%d] ID:0x%04X. Access:0x%02X. Len:%d\n", + index, appl_generic_property[0][index].property_id, + appl_generic_property[0][index].access, + appl_generic_property[0][index].property_value_len); + } + + break; + } + } + } + break; + + case MS_STATE_GENERIC_ADMIN_PROPERTY_T: + { + MS_STATE_GENERIC_ADMIN_PROPERTY_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ADMIN_PROPERTY_STRUCT*)param; + /* Check for property ID match */ + /* Mark the access as prohibited, to indicate invalid Property ID */ + param_p->user_access = MS_GENERIC_USER_ACCESS_INVALID_PROPERTY_ID; + param_p->property_value_len = 0; + + for (index = 0; index < MS_MAX_PROPERTIES; index++) + { + if (appl_generic_property[0][index].property_id == param_p->property_id) + { + if (/* (MS_GENERIC_PROP_TYPE_MANUFACTURER == appl_generic_property[0][index].property_type) || */ + (MS_GENERIC_PROP_TYPE_ADMIN == appl_generic_property[0][index].property_type)) + { + param_p->user_access = appl_generic_property[0][index].access; + #if 0 + + if (MS_GENERIC_USER_ACCESS_WRITE == param_p->user_access) + { + param_p->property_value_len = 0; + } + else + #endif /* 0 */ + { + param_p->property_value = appl_generic_property[0][index].property_value; + param_p->property_value_len = appl_generic_property[0][index].property_value_len; + } + + printf("GGGGEEETTTTTT::::ADMIN::::: [%d] ID:0x%04X. Access:0x%02X. Len:%d\n", + index, appl_generic_property[0][index].property_id, + appl_generic_property[0][index].access, + appl_generic_property[0][index].property_value_len); + break; + } + } + } + } + break; + + case MS_STATE_GENERIC_MANUFACTURER_PROPERTY_T: + { + MS_STATE_GENERIC_MANUFACTURER_PROPERTY_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_MANUFACTURER_PROPERTY_STRUCT*)param; + + /* Check for property ID match */ + + for (index = 0; index < MS_MAX_PROPERTIES; index++) + { + if (appl_generic_property[0][index].property_id == param_p->property_id) + { + if (MS_GENERIC_PROP_TYPE_MANUFACTURER == appl_generic_property[0][index].property_type) + { + param_p->user_access = appl_generic_property[0][index].access; + #if 0 + + if (MS_GENERIC_USER_ACCESS_WRITE == param_p->user_access) + { + param_p->property_value_len = 0; + } + else + #endif /* 0 */ + { + param_p->property_value = appl_generic_property[0][index].property_value; + param_p->property_value_len = appl_generic_property[0][index].property_value_len; + } + + printf("GGGGEEETTTTTT::::MANU::::: [%d] ID:0x%04X. Access:0x%02X. Len:%d\n", + index, appl_generic_property[0][index].property_id, + appl_generic_property[0][index].access, + appl_generic_property[0][index].property_value_len); + break; + } + } + } + + /* Mark the access as prohibited, to indicate invalid Property ID */ + if (MS_MAX_PROPERTIES == index) + { + param_p->user_access = MS_GENERIC_USER_ACCESS_INVALID_PROPERTY_ID; + param_p->property_value_len = 0; + } + } + break; + } + + return API_SUCCESS; +} + +static API_RESULT appl_model_generic_property_check_format(MS_STATE_GENERIC_USER_PROPERTY_STRUCT* param) +{ + API_RESULT retval; + retval = API_FAILURE; + + /* Check for all the supported properties - currently only for 0x006B */ + switch (param->property_id) + { + case MS_DEV_PROP_MOTION_SENSED: /* Motion Sensed */ + case MS_DEV_PROP_PRESENCE_DETECTED: /* Presence Detected */ + + /* Check if 8 bit value is received */ + if (1 == param->property_value_len) + { + retval = API_SUCCESS; + } + + break; + + case MS_DEV_PROP_PEOPLE_COUNT: /* People Count */ + + /* Check if 16 bit value is received */ + if (2 == param->property_value_len) + { + retval = API_SUCCESS; + } + + break; + + default: + break; + } + + return retval; +} + +static API_RESULT appl_model_generic_property_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + UINT32 index; + + switch(state_t) + { + case MS_STATE_GENERIC_USER_PROPERTY_T: + { + MS_STATE_GENERIC_USER_PROPERTY_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_USER_PROPERTY_STRUCT*)param; + /* Check for property ID match */ + /* Mark the access as prohibited, to indicate invalid Property ID */ + param_p->user_access = MS_GENERIC_USER_ACCESS_PROHIBITED; + + for (index = 0; index < MS_MAX_PROPERTIES; index++) + { + if (appl_generic_property[0][index].property_id == param_p->property_id) + { + /* Check if the property value is of correct format */ + if (API_SUCCESS != appl_model_generic_property_check_format(param_p)) + { + printf("Invalid format for property ID: 0x%04X\n", param_p->property_id); + return API_FAILURE; + } + + if (MS_GENERIC_USER_ACCESS_PROHIBITED != appl_generic_property[0][index].access) + { + /* Check properties - write is permitted */ + if (MS_GENERIC_USER_ACCESS_READ == appl_generic_property[0][index].access) + { + printf("Can not set read only Generic User Property\n"); + param_p->property_value = NULL; + param_p->property_value_len = 0; + } + else + { + /* Update Value */ + /* Free Memory */ + if (NULL != appl_generic_property[0][index].property_value) + { + EM_free_mem(appl_generic_property[0][index].property_value); + } + + /* Allocate Memory */ + appl_generic_property[0][index].property_value_len = param_p->property_value_len; + appl_generic_property[0][index].property_value = EM_alloc_mem(param_p->property_value_len); + /* TODO: Not checking memory allocation failure */ + /* Copy */ + EM_mem_copy(appl_generic_property[0][index].property_value, param_p->property_value, param_p->property_value_len); + } + + param_p->user_access = appl_generic_property[0][index].access; + printf("SSSEEETTTTTT::::USER::::: [%d] ID:0x%04X. Access:0x%02X. Len:%d\n", + index, appl_generic_property[0][index].property_id, + appl_generic_property[0][index].access, + appl_generic_property[0][index].property_value_len); + } + + break; + } + } + } + break; + + case MS_STATE_GENERIC_ADMIN_PROPERTY_T: + { + MS_STATE_GENERIC_ADMIN_PROPERTY_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ADMIN_PROPERTY_STRUCT*)param; + + /* Check for property ID match */ + + for (index = 0; index < MS_MAX_PROPERTIES; index++) + { + if (appl_generic_property[0][index].property_id == param_p->property_id) + { + if (/* (MS_GENERIC_PROP_TYPE_MANUFACTURER == appl_generic_property[0][index].property_type) || */ + (MS_GENERIC_PROP_TYPE_ADMIN == appl_generic_property[0][index].property_type)) + { + appl_generic_property[0][index].access = param_p->user_access; + /* Check properties - write is permitted */ + /* if (MS_GENERIC_USER_ACCESS_READ != appl_generic_property[0][index].access) */ + { + /* Update Value */ + /* Free Memory */ + if (NULL != appl_generic_property[0][index].property_value) + { + EM_free_mem(appl_generic_property[0][index].property_value); + } + + /* Allocate Memory */ + appl_generic_property[0][index].property_value_len = param_p->property_value_len; + appl_generic_property[0][index].property_value = EM_alloc_mem(param_p->property_value_len); + /* TODO: Not checking memory allocation failure */ + /* Copy */ + EM_mem_copy(appl_generic_property[0][index].property_value, param_p->property_value, param_p->property_value_len); + appl_generic_admin_property_server_publish(MS_STATE_GENERIC_ADMIN_PROPERTY_T, 0x00, param_p->property_id); + } + param_p->property_value = appl_generic_property[0][index].property_value; + param_p->property_value_len = appl_generic_property[0][index].property_value_len; + printf("SSSSSSSEEETTTTTT::::ADMIN::::: [%d] ID:0x%04X. Access:0x%02X. Len:%d\n", + index, appl_generic_property[0][index].property_id, + appl_generic_property[0][index].access, + appl_generic_property[0][index].property_value_len); + break; + } + } + } + + /* Check if match found. Else set prohibited access */ + if (MS_MAX_PROPERTIES == index) + { + /* Mark the access as prohibited, to indicate invalid Property ID */ + param_p->user_access = MS_GENERIC_USER_ACCESS_INVALID_PROPERTY_ID; + param_p->property_value_len = 0; + } + } + break; + + case MS_STATE_GENERIC_MANUFACTURER_PROPERTY_T: + { + MS_STATE_GENERIC_MANUFACTURER_PROPERTY_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_MANUFACTURER_PROPERTY_STRUCT*)param; + + /* Check for property ID match */ + /* Mark the access as prohibited, to indicate invalid Property ID */ + for (index = 0; index < MS_MAX_PROPERTIES; index++) + { + if (appl_generic_property[0][index].property_id == param_p->property_id) + { + if (MS_GENERIC_PROP_TYPE_MANUFACTURER == appl_generic_property[0][index].property_type) + { + /* Check properties - write is permitted */ + if (MS_GENERIC_USER_ACCESS_WRITE == (MS_GENERIC_USER_ACCESS_WRITE & (appl_generic_property[0][index].access | param_p->user_access))) + { + /* Update Value */ + /* Free Memory */ + if ((0 != param_p->property_value_len) && (NULL != appl_generic_property[0][index].property_value)) + { + EM_free_mem(appl_generic_property[0][index].property_value); + /* Allocate Memory */ + appl_generic_property[0][index].property_value_len = param_p->property_value_len; + appl_generic_property[0][index].property_value = EM_alloc_mem(param_p->property_value_len); + /* TODO: Not checking memory allocation failure */ + /* Copy */ + EM_mem_copy(appl_generic_property[0][index].property_value, param_p->property_value, param_p->property_value_len); + } + } + + appl_generic_property[0][index].access = param_p->user_access; + appl_generic_manufacturer_property_server_publish(MS_STATE_GENERIC_MANUFACTURER_PROPERTY_T, 0x00, param_p->property_id); + param_p->user_access = appl_generic_property[0][index].access; + param_p->property_value = appl_generic_property[0][index].property_value; + param_p->property_value_len = appl_generic_property[0][index].property_value_len; + printf("SSSSSSSEEETTTTTT::::MANUFACTURER::::: [%d] ID:0x%04X. Access:0x%02X. Len:%d\n", + index, appl_generic_property[0][index].property_id, + appl_generic_property[0][index].access, + appl_generic_property[0][index].property_value_len); + break; + } + } + } + + /* Mark the access as prohibited, to indicate invalid Property ID */ + if (MS_MAX_PROPERTIES == index) + { + param_p->user_access = MS_GENERIC_USER_ACCESS_INVALID_PROPERTY_ID; + param_p->property_value_len = 0; + } + } + break; + } + + return API_SUCCESS; +} + +/** --------------------- Scene ---- */ +void* appl_scene_save_current_state(/* IN */ UINT32 scene_index) +{ + /* Store current state */ + appl_state_info_vault[scene_index].onoff = appl_generic_onoff[0].onoff; + appl_state_info_vault[scene_index].level = appl_generic_level_info[0].generic_level.level; + appl_state_info_vault[scene_index].power_level = appl_generic_power_level[0].generic_power_actual.power_actual; + appl_state_info_vault[scene_index].lightness_actual = appl_light_lightness[0].light_lightness_actual.lightness_actual; + appl_state_info_vault[scene_index].lightness_linear = appl_light_lightness[0].light_lightness_linear.lightness_linear; + appl_state_info_vault[scene_index].ctl_lightness = appl_light_ctl[0].ctl_lightness; + appl_state_info_vault[scene_index].ctl_temperature = appl_light_ctl[0].ctl_temperature; + appl_state_info_vault[scene_index].ctl_delta_uv = appl_light_ctl[0].ctl_delta_uv; + appl_state_info_vault[scene_index].hsl_lightness = appl_light_hsl[0].hsl_lightness; + appl_state_info_vault[scene_index].hsl_hue = appl_light_hsl[0].hsl_hue; + appl_state_info_vault[scene_index].hsl_saturation = appl_light_hsl[0].hsl_saturation; + appl_state_info_vault[scene_index].xyl_lightness = appl_light_xyl[0].xyl_lightness; + appl_state_info_vault[scene_index].xyl_x = appl_light_xyl[0].xyl_x; + appl_state_info_vault[scene_index].xyl_y = appl_light_xyl[0].xyl_y; + appl_state_info_vault[scene_index].lc_mode = appl_light_lc_mode[0].present_mode; + /* Allocate memory for LC Property Value */ + CONSOLE_OUT("[Store] Prop ID: 0x%04X. Len: 0x%04X\n", + appl_light_lc_property[0][appl_current_property_id_index].property_id, + appl_light_lc_property[0][appl_current_property_id_index].property_value_len); + appl_state_info_vault[scene_index].lc_property.property_id = + appl_light_lc_property[0][appl_current_property_id_index].property_id; + + if (0 != appl_light_lc_property[0][appl_current_property_id_index].property_value_len) + { + /* Free memory */ + if (NULL != appl_state_info_vault[scene_index].lc_property.property_value) + { + EM_free_mem(appl_state_info_vault[scene_index].lc_property.property_value); + } + + appl_state_info_vault[scene_index].lc_property.property_value = + EM_alloc_mem(appl_light_lc_property[0][appl_current_property_id_index].property_value_len); + + if (NULL != appl_state_info_vault[scene_index].lc_property.property_value) + { + EM_mem_copy + ( + appl_state_info_vault[scene_index].lc_property.property_value, + appl_light_lc_property[0][appl_current_property_id_index].property_value, + appl_light_lc_property[0][appl_current_property_id_index].property_value_len + ); + CONSOLE_OUT("Storing property value\n"); + appl_dump_bytes + ( + appl_state_info_vault[scene_index].lc_property.property_value, + appl_light_lc_property[0][appl_current_property_id_index].property_value_len + ); + } + } + + appl_state_info_vault[scene_index].lc_property.property_value_len = + appl_light_lc_property[0][appl_current_property_id_index].property_value_len; + /* TODO: optimize by not writing all the 16 scenes */ + appl_ps_store(MS_PS_RECORD_APPL_SCENE); + return (void*)scene_index; +} + +void* appl_scene_save_current_state_ex(/* IN */ UINT32 scene_index) +{ + /* Store current state */ + /* Check if transition ongoing */ + if (0x00 != appl_generic_onoff[0].transition_time) + { + appl_state_info_vault[scene_index].onoff = appl_generic_onoff[0].target_onoff; + } + else + { + appl_state_info_vault[scene_index].onoff = appl_generic_onoff[0].onoff; + } + + appl_state_info_vault[scene_index].level = appl_generic_level_info[0].generic_level.level; + appl_state_info_vault[scene_index].power_level = appl_generic_power_level[0].generic_power_actual.power_actual; + appl_state_info_vault[scene_index].lightness_actual = appl_light_lightness[0].light_lightness_actual.lightness_actual; + appl_state_info_vault[scene_index].lightness_linear = appl_light_lightness[0].light_lightness_linear.lightness_linear; + appl_state_info_vault[scene_index].ctl_lightness = appl_light_ctl[0].ctl_lightness; + appl_state_info_vault[scene_index].ctl_temperature = appl_light_ctl[0].ctl_temperature; + appl_state_info_vault[scene_index].ctl_delta_uv = appl_light_ctl[0].ctl_delta_uv; + appl_state_info_vault[scene_index].hsl_lightness = appl_light_hsl[0].hsl_lightness; + appl_state_info_vault[scene_index].hsl_hue = appl_light_hsl[0].hsl_hue; + appl_state_info_vault[scene_index].hsl_saturation = appl_light_hsl[0].hsl_saturation; + appl_state_info_vault[scene_index].xyl_lightness = appl_light_xyl[0].xyl_lightness; + appl_state_info_vault[scene_index].xyl_x = appl_light_xyl[0].xyl_x; + appl_state_info_vault[scene_index].xyl_y = appl_light_xyl[0].xyl_y; + appl_state_info_vault[scene_index].lc_mode = appl_light_lc_mode[0].present_mode; + /* Allocate memory for LC Property Value */ + CONSOLE_OUT("[Store] Prop ID: 0x%04X. Len: 0x%04X\n", + appl_light_lc_property[0][appl_current_property_id_index].property_id, + appl_light_lc_property[0][appl_current_property_id_index].property_value_len); + appl_state_info_vault[scene_index].lc_property.property_id = + appl_light_lc_property[0][appl_current_property_id_index].property_id; + + if (0 != appl_light_lc_property[0][appl_current_property_id_index].property_value_len) + { + /* Free memory */ + if (NULL != appl_state_info_vault[scene_index].lc_property.property_value) + { + EM_free_mem(appl_state_info_vault[scene_index].lc_property.property_value); + } + + appl_state_info_vault[scene_index].lc_property.property_value = + EM_alloc_mem(appl_light_lc_property[0][appl_current_property_id_index].property_value_len); + + if (NULL != appl_state_info_vault[scene_index].lc_property.property_value) + { + EM_mem_copy + ( + appl_state_info_vault[scene_index].lc_property.property_value, + appl_light_lc_property[0][appl_current_property_id_index].property_value, + appl_light_lc_property[0][appl_current_property_id_index].property_value_len + ); + CONSOLE_OUT("Storing property value\n"); + appl_dump_bytes + ( + appl_state_info_vault[scene_index].lc_property.property_value, + appl_light_lc_property[0][appl_current_property_id_index].property_value_len + ); + } + } + + appl_state_info_vault[scene_index].lc_property.property_value_len = + appl_light_lc_property[0][appl_current_property_id_index].property_value_len; + + /* TODO: optimize by not writing all the 16 scenes */ + if (16 > scene_index) + { + appl_ps_store(MS_PS_RECORD_APPL_SCENE); + } + + return (void*)scene_index; +} + +void* appl_scene_delete_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ + /* Free context - if any */ + /* Invalid value */ + appl_state_info_vault[scene_index].onoff = 0x02; + appl_state_info_vault[scene_index].level = 0xFFFF; + appl_state_info_vault[scene_index].power_level = 0xFFFF; + appl_state_info_vault[scene_index].lightness_actual = 0x0000; + appl_state_info_vault[scene_index].lightness_linear = 0x0000; + appl_state_info_vault[scene_index].ctl_lightness = 0x0000; + appl_state_info_vault[scene_index].ctl_temperature = 0x0000; + appl_state_info_vault[scene_index].ctl_delta_uv = 0x0000; + appl_state_info_vault[scene_index].hsl_lightness = 0x0000; + appl_state_info_vault[scene_index].hsl_hue = 0x0000; + appl_state_info_vault[scene_index].hsl_saturation = 0x0000; + appl_state_info_vault[scene_index].xyl_lightness = 0x0000; + appl_state_info_vault[scene_index].xyl_x = 0x0000; + appl_state_info_vault[scene_index].xyl_y = 0x0000; + appl_state_info_vault[scene_index].lc_mode = 0x00; + appl_state_info_vault[scene_index].lc_property.property_id = 0x0000; + + if (NULL != appl_state_info_vault[scene_index].lc_property.property_value) + { + EM_free_mem(appl_state_info_vault[scene_index].lc_property.property_value); + appl_state_info_vault[scene_index].lc_property.property_value = NULL; + } + + appl_state_info_vault[scene_index].lc_property.property_value_len = 0x0000; + /* TODO: optimize by not writing all the 16 scenes */ + appl_ps_store(MS_PS_RECORD_APPL_SCENE); + return (void*)NULL; +} + +void* appl_scene_recall_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ +// UINT32 index; + /* Recall context - if any */ + appl_set_generic_onoff(0, appl_state_info_vault[scene_index].onoff, MS_FALSE); + appl_set_generic_level(0, appl_state_info_vault[scene_index].level, MS_FALSE, MS_FALSE); + appl_power_level_set_actual(0, appl_state_info_vault[scene_index].power_level); + appl_light_lightness_set_actual(0, appl_state_info_vault[scene_index].lightness_actual, MS_TRUE); + appl_light_lightness[0].light_lightness_linear.lightness_linear = appl_state_info_vault[scene_index].lightness_linear; + appl_light_ctl_lightness_set_actual + ( + 0, + appl_state_info_vault[scene_index].ctl_lightness, + appl_state_info_vault[scene_index].ctl_temperature, + appl_state_info_vault[scene_index].ctl_delta_uv, + MS_TRUE + ); + #if 0 + appl_light_ctl[0].ctl_lightness = appl_state_info_vault[scene_index].ctl_lightness; + appl_light_ctl[0].ctl_temperature = appl_state_info_vault[scene_index].ctl_temperature; + appl_light_ctl[0].ctl_delta_uv = appl_state_info_vault[scene_index].ctl_delta_uv; + #endif /* 0 */ + appl_light_hsl_set_actual + ( + 0, + appl_state_info_vault[scene_index].hsl_lightness, + appl_state_info_vault[scene_index].hsl_hue, + appl_state_info_vault[scene_index].hsl_saturation, + MS_TRUE + ); + #if 0 + appl_light_hsl[0].hsl_lightness = appl_state_info_vault[scene_index].hsl_lightness; + appl_light_hsl[0].hsl_hue = appl_state_info_vault[scene_index].hsl_hue; + appl_light_hsl[0].hsl_saturation = appl_state_info_vault[scene_index].hsl_saturation; + #endif /* 0 */ + #if 0 + appl_light_xyl[0].xyl_lightness = appl_state_info_vault[scene_index].xyl_lightness; + appl_light_xyl[0].xyl_x = appl_state_info_vault[scene_index].xyl_x; + appl_light_xyl[0].xyl_y = appl_state_info_vault[scene_index].xyl_y; + #else + appl_light_xyl_set_actual + ( + 0, + appl_state_info_vault[scene_index].xyl_lightness, + appl_state_info_vault[scene_index].xyl_x, + appl_state_info_vault[scene_index].xyl_y + ); + #endif /* 0 */ + appl_light_lc_set_actual(0, MS_STATE_LIGHT_LC_MODE_T, 0x00, appl_state_info_vault[scene_index].lc_mode); + + if (16 < scene_index) + { + CONSOLE_OUT("[Restore] Prop ID: 0x%04X. Len: 0x%04X\n", + appl_state_info_vault[scene_index].lc_property.property_id, + appl_state_info_vault[scene_index].lc_property.property_value_len); + appl_light_lc_set_actual_propery + ( + 0, + appl_state_info_vault[scene_index].lc_property.property_id, + appl_state_info_vault[scene_index].lc_property.property_value, + appl_state_info_vault[scene_index].lc_property.property_value_len + ); + } + + return (void*)NULL; +} + + +/** --------------------- Light - Lightness ---- */ +static void appl_model_light_lightness_states_initialization(void) +{ + EM_mem_set (appl_light_lightness, 0, sizeof(appl_light_lightness)); + appl_light_lightness[0].light_lightness_last.lightness_last = 0x0000; /* 0xFFFF; */ + appl_light_lightness[1].light_lightness_last.lightness_last = 0x0000; /* 0xFFFF; */ +} + +static void appl_light_lightness_transition_start_cb(void* blob) +{ +} + +static void appl_light_lightness_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_light_lightness[0].light_lightness_actual.transition_time = 0; + appl_light_lightness_set_actual(0, appl_light_lightness[0].light_lightness_actual.lightness_target, MS_FALSE); + appl_light_lightness[0].light_lightness_actual.lightness_target = 0; +} + +static void appl_light_lightness_linear_transition_start_cb(void* blob) +{ +} + +static void appl_light_lightness_linear_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_light_lightness[0].light_lightness_linear.transition_time = 0; + appl_light_lightness_set_linear(0, appl_light_lightness[0].light_lightness_linear.lightness_target); + appl_light_lightness[0].light_lightness_linear.lightness_target = 0; +} + +static void appl_light_lightness_set_actual(UINT16 state_inst, UINT16 actual, UCHAR forced_publish) +{ + UINT16 min, max; + printf("appl_light_lightness_set_actual: Actual: 0x%04X\n", actual); + /* Generic OnOff binding */ + min = appl_light_lightness[state_inst].light_lightness_range.lightness_range_min; + max = appl_light_lightness[state_inst].light_lightness_range.lightness_range_max; + + if ((0 != min) && (actual < min)) + { + actual = min; + } + else if ((0 != max) && (actual > max)) + { + actual = max; + } + + if (actual != appl_light_lightness[state_inst].light_lightness_actual.lightness_actual) + { + appl_light_lightness[state_inst].light_lightness_actual.lightness_actual = actual; + /* Publish State Change */ + appl_light_lightness_server_publish(MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T, state_inst); + + /* If Lightness Actual is non-zero, save as Lightness Last */ + if (0x0000 != actual) + { + appl_light_lightness[state_inst].light_lightness_last.lightness_last = actual; + appl_light_hsl_set_actual(state_inst, actual, appl_light_hsl[state_inst].hsl_hue, appl_light_hsl[state_inst].hsl_saturation, MS_FALSE); + } + + /* Light Lightness Linear = ((Actual)^2) / 65535 */ + appl_light_lightness[state_inst].light_lightness_linear.lightness_linear = ((actual * actual) + 65534) / 65535; + appl_set_generic_level(state_inst, actual - 32768, MS_TRUE, MS_FALSE); + } + else if (MS_TRUE == forced_publish) + { + /* Publish State Change */ + appl_light_lightness_server_publish(MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T, state_inst); + } +} + +#if 0 +/* Not used */ +static void appl_light_lightness_set_range(UINT16 state_inst, UINT16 min, UINT16 max) +{ + UINT16 actual; + appl_light_lightness[state_inst].light_lightness_range.lightness_range_min = min; + appl_light_lightness[state_inst].light_lightness_range.lightness_range_max = max; + /* Check if actual to be updated */ + actual = appl_light_lightness[state_inst].light_lightness_actual.lightness_actual; + appl_light_lightness_set_actual(state_inst, actual); +} +#endif /* 0 */ + +/* Todo: Remove the dependency */ +#include "math.h" + +/* TODO: Make the below function static */ +void appl_light_lightness_set_linear(UINT16 state_inst, UINT16 linear) +{ + UINT16 actual; + UINT32 mul_val; + mul_val = linear * 65535; + actual = (UINT16)sqrt(mul_val); + /* Light Lightness actual = sqrt(Linear * 65535) */ + appl_light_lightness_set_actual(state_inst, actual, MS_FALSE); +} + +static void appl_set_generic_onoff(UINT16 state_inst, UINT8 onoff, UINT8 forced_publish) +{ + UINT16 actual; + + /* Check if there is change in state */ + if (appl_generic_onoff[state_inst].onoff != onoff) + { + /* TODO: See if this to be stored */ + APPL_GENERIC_ONOFF_SET(state_inst, onoff); + /* Publish State Change */ + appl_generic_onoff_server_publish(MS_STATE_GENERIC_ONOFF_T, 0x00); + appl_light_lc_onoff[state_inst].present_light_onoff = onoff; + + /* Binding */ + if (onoff == 0x00) + { + appl_light_lightness_set_actual(state_inst, 0x00, MS_FALSE); + appl_power_level_set_actual(state_inst, 0x00); + } + else + { + if (0x0000 == appl_light_lightness[state_inst].light_lightness_default.lightness_default) + { + actual = appl_light_lightness[state_inst].light_lightness_last.lightness_last; + } + else + { + actual = appl_light_lightness[state_inst].light_lightness_default.lightness_default; + } + + if (0x0000 != actual) + { + appl_light_lightness_set_actual(state_inst, actual, MS_FALSE); + } + + if (0x0000 == appl_generic_power_level[state_inst].generic_power_default.power_default) + { + actual = appl_generic_power_level[state_inst].generic_power_last.power_last; + } + else + { + actual = appl_generic_power_level[state_inst].generic_power_default.power_default; + } + + if (0x0000 != actual) + { + appl_power_level_set_actual(state_inst, actual); + } + } + } + else if (MS_TRUE == forced_publish) + { + /* Publish State Change */ + appl_generic_onoff_server_publish(MS_STATE_GENERIC_ONOFF_T, 0x00); + } +} + +static API_RESULT appl_model_light_lightness_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + MS_STATE_LIGHT_LIGHTNESS_STRUCT* param_p; + API_RESULT ret; + UINT8 transition_time; + param_p = (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)param; + + switch (state_t) + { + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_default = appl_light_lightness[0].light_lightness_default; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_range = appl_light_lightness[0].light_lightness_range; + param_p->range_status = 0x00; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_linear = appl_light_lightness[0].light_lightness_linear; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_last = appl_light_lightness[0].light_lightness_last; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_actual = appl_light_lightness[0].light_lightness_actual; + + if (0 != param_p->light_lightness_actual.transition_time) + { + ret = MS_common_get_remaining_transition_time + ( + param_p->light_lightness_actual.transition_time_handle, + &transition_time + ); + + if (API_SUCCESS == ret) + { + param_p->light_lightness_actual.transition_time = transition_time; + } + } + + CONSOLE_OUT("Light Lightness Actual State Get.\n"); + } + break; + + default: + break; + } + + return API_SUCCESS; +} + +static API_RESULT appl_model_light_lightness_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + MS_STATE_LIGHT_LIGHTNESS_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)param; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: + { + /* Ignoring Instance and direction right now */ + appl_light_lightness[0].light_lightness_default = param_p->light_lightness_default; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: + { + /* Check range min and max */ + if (param_p->light_lightness_range.lightness_range_min > param_p->light_lightness_range.lightness_range_max) + { + /* TODO: add macro define */ + /** + Table 7.2: + 0x00 - Success + 0x01 - Cannot Set Range Min + 0x02 - Cannot Set Range Max + */ + param_p->range_status = 0x01; + } + else + { + /* Ignoring Instance and direction right now */ + appl_light_lightness[0].light_lightness_range = param_p->light_lightness_range; + param_p->range_status = 0x00; + } + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: + { + if (0 != param_p->light_lightness_linear.transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_lightness[0].light_lightness_linear.lightness_target = param_p->light_lightness_linear.lightness_linear; + appl_light_lightness[0].light_lightness_linear.transition_time = param_p->light_lightness_linear.transition_time; + transition.delay = param_p->light_lightness_linear.delay; + transition.transition_time = param_p->light_lightness_linear.transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_light_lightness_linear_transition_start_cb; + transition.transition_complete_cb = appl_light_lightness_linear_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + /* appl_generic_onoff[0].onoff = param_p->onoff; */ + appl_light_lightness_set_linear(0, param_p->light_lightness_linear.lightness_linear); + } + + *param_p = appl_light_lightness[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", param_p->light_lightness_linear.lightness_linear); + CONSOLE_OUT("[state] target: 0x%02X\n", param_p->light_lightness_linear.lightness_target); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", param_p->light_lightness_linear.transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: + { + /* Ignoring Instance and direction right now */ + appl_light_lightness[0].light_lightness_last = param_p->light_lightness_last; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + { + printf("**** MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T ***\n"); + + if (0 != param_p->light_lightness_actual.transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + appl_light_lightness[0].light_lightness_actual.lightness_target = param_p->light_lightness_actual.lightness_actual; + appl_light_lightness[0].light_lightness_actual.transition_time = param_p->light_lightness_actual.transition_time; + transition.delay = param_p->light_lightness_actual.delay; + transition.transition_time = param_p->light_lightness_actual.transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_light_lightness_transition_start_cb; + transition.transition_complete_cb = appl_light_lightness_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &appl_light_lightness[0].light_lightness_actual.transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + /* appl_generic_onoff[0].onoff = param_p->onoff; */ + appl_light_lightness_set_actual(0, param_p->light_lightness_actual.lightness_actual, MS_FALSE); + } + + *param_p = appl_light_lightness[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", param_p->light_lightness_actual.lightness_actual); + CONSOLE_OUT("[state] target: 0x%02X\n", param_p->light_lightness_actual.lightness_target); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", param_p->light_lightness_actual.transition_time); + } + break; + + default: + break; + } + + return retval; +} + +/** --------------------- Light - CTL ---- */ +static void appl_model_light_ctl_states_initialization(void) +{ + UINT16 level; + EM_mem_set (appl_light_ctl, 0, sizeof(appl_light_ctl)); + /** + Color temperature of white light in Kelvin + (0x0320 = 800 Kelvin, 0x4E20 = 20000 Kelvin) + */ + /* EM_mem_set(appl_light_ctl_temperature_range, 0, sizeof(appl_light_ctl_temperature_range)); */ + appl_light_ctl_temperature_range[0].ctl_temperature_range_min = LIGHT_CTL_TEMPERATURE_T_MIN; + appl_light_ctl_temperature_range[0].ctl_temperature_range_max = LIGHT_CTL_TEMPERATURE_T_MAX; + EM_mem_set(appl_light_ctl_default, 0, sizeof(appl_light_ctl_default)); + EM_mem_set (appl_light_ctl_temperature, 0, sizeof(appl_light_ctl_temperature)); + level = appl_generic_level_info[0].generic_level.level; + /* Light CTL Temperature = T_MIN + (Generic Level + 32768) * (T_MAX - T_MIN) / 65535 */ + appl_light_ctl_temperature[0].ctl_temperature = + appl_light_ctl_temperature_range[0].ctl_temperature_range_min + + ((level + 32768) * (appl_light_ctl_temperature_range[0].ctl_temperature_range_max - + appl_light_ctl_temperature_range[0].ctl_temperature_range_min)) / 65535; +} + +static void appl_light_ctl_lightness_set_actual(UINT16 state_inst, UINT16 lightness, UINT16 temperature, UINT16 delta_uv, UCHAR forced_publish) +{ + printf("appl_light_ctl_lightness_set_actual: lightness:0x%04X, temp:0x%04X, delta_uv:0x%04X\n", + lightness, temperature, delta_uv); + + if (lightness != appl_light_ctl[state_inst].ctl_lightness) + { + appl_light_ctl[state_inst].ctl_lightness = lightness; + appl_light_ctl_temp_set_actual(state_inst, temperature, delta_uv, MS_FALSE); + /* Publish State Change */ + appl_light_ctl_server_publish(MS_STATE_LIGHT_CTL_T, state_inst); + appl_light_lightness_set_actual(state_inst, lightness, MS_FALSE); + } + else if (MS_TRUE == forced_publish) + { + /* Publish State Change */ + appl_light_ctl_server_publish(MS_STATE_LIGHT_CTL_T, state_inst); + } +} + +static void appl_light_ctl_temp_set_actual(UINT16 state_inst, UINT16 actual, UINT16 delta_uv, UCHAR is_calculated) +{ + UINT16 min, max; + printf("appl_light_ctl_temp_set_actual: actual:0x%04X, is_calculated:%02X\n", actual, is_calculated); + min = appl_light_ctl_temperature_range[state_inst].ctl_temperature_range_min; + max = appl_light_ctl_temperature_range[state_inst].ctl_temperature_range_max; + + if ((0 != min) && (actual < min)) + { + actual = min; + } + else if ((0 != max) && (actual > max)) + { + actual = max; + } + + if ((actual == appl_light_ctl[state_inst].ctl_temperature) || + /* If calculated and difference is only one */ + ((MS_TRUE == is_calculated) && (API_SUCCESS == appl_model_state_is_diff_in_range(actual, appl_light_ctl[state_inst].ctl_temperature, 0x01))) + ) + { + } + else + { + printf("appl_light_ctl_temp_set_actual: Setting CTL Temperature:0x%04X, Delta UV:0x%04X\n", + actual, delta_uv); + appl_light_ctl[state_inst].ctl_temperature = actual; + appl_light_ctl[state_inst].ctl_delta_uv = delta_uv; + appl_light_ctl_temperature[state_inst].ctl_temperature = actual; + appl_light_ctl_temperature[state_inst].ctl_delta_uv = delta_uv; + appl_light_ctl_temperature_server_publish(MS_STATE_LIGHT_CTL_TEMPERATURE_T, state_inst); + + /* Check min and max are not the same */ + if (max != min) + { + appl_set_generic_level + ( + state_inst, + (((actual - LIGHT_CTL_TEMPERATURE_T_MIN) * 0xFFFF) / (LIGHT_CTL_TEMPERATURE_T_MAX - LIGHT_CTL_TEMPERATURE_T_MIN)) - 32768, + MS_TRUE, + MS_TRUE + ); + } + } +} + +static void appl_light_ctl_temp_set_range(UINT16 state_inst, UINT16 min, UINT16 max) +{ + UINT16 actual; + appl_light_ctl_temperature_range[state_inst].ctl_temperature_range_min = min; + appl_light_ctl_temperature_range[state_inst].ctl_temperature_range_max = max; + /* Check if actual to be updated */ + actual = appl_light_ctl[state_inst].ctl_temperature; + + if (actual < min) + { + appl_light_ctl[state_inst].ctl_temperature = min; + } + else if (actual > max) + { + appl_light_ctl[state_inst].ctl_temperature = max; + } +} + +static void appl_light_ctl_transition_start_cb(void* blob) +{ +} + +static void appl_light_ctl_transition_complete_cb(void* blob) +{ + appl_light_ctl[0].transition_time = 0x0000; + appl_light_ctl_temp_set_actual(0, appl_light_ctl[0].target_ctl_temperature, appl_light_ctl[0].ctl_delta_uv, MS_FALSE); + appl_light_ctl[0].ctl_lightness = appl_light_ctl[0].target_ctl_lightness; + appl_light_ctl[0].target_ctl_temperature = 0x0000; + appl_light_ctl[0].target_ctl_lightness = 0x0000; +} + +static void appl_light_ctl_temperature_transition_start_cb(void* blob) +{ +} + +static void appl_light_ctl_temperature_transition_complete_cb(void* blob) +{ + appl_light_ctl_temp_set_actual(0, appl_light_ctl_temperature[0].target_ctl_temperature, appl_light_ctl_temperature[0].target_ctl_delta_uv, MS_FALSE); + /* appl_light_ctl_temperature[0].ctl_delta_uv = appl_light_ctl_temperature[0].target_ctl_delta_uv; */ + appl_light_ctl_temperature[0].target_ctl_temperature = 0x0000; + appl_light_ctl_temperature[0].target_ctl_delta_uv= 0x0000; + appl_light_ctl_temperature[0].transition_time = 0x0000; +} + +static API_RESULT appl_model_light_ctl_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + switch(state_t) + { + case MS_STATE_LIGHT_CTL_DEFAULT_T: + { + MS_STATE_LIGHT_CTL_DEFAULT_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_CTL_DEFAULT_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_ctl_default[0]; + } + break; + + case MS_STATE_LIGHT_CTL_T: + { + MS_STATE_LIGHT_CTL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_CTL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_ctl[0]; + } + break; + + case MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_T: + { + MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_ctl_temperature_range[0]; + param_p->status = 0x00; + } + break; + + case MS_STATE_LIGHT_CTL_TEMPERATURE_T: + { + MS_STATE_LIGHT_CTL_TEMPERATURE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_CTL_TEMPERATURE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_ctl_temperature[0]; + } + break; + + default: + break; + } + + return API_SUCCESS; +} + +static API_RESULT appl_model_light_ctl_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_LIGHT_CTL_DEFAULT_T: + { + MS_STATE_LIGHT_CTL_DEFAULT_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_CTL_DEFAULT_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_light_ctl_default[0] = *param_p; + } + break; + + case MS_STATE_LIGHT_CTL_T: + { + MS_STATE_LIGHT_CTL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_CTL_STRUCT*)param; + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_ctl[0].target_ctl_lightness = param_p->ctl_lightness; + appl_light_ctl[0].target_ctl_temperature = param_p->ctl_temperature; + appl_light_ctl[0].ctl_delta_uv = param_p->ctl_delta_uv; + appl_light_ctl[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_light_ctl_transition_start_cb; + transition.transition_complete_cb = appl_light_ctl_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + /* appl_light_ctl[0] = *param_p; */ + appl_light_ctl_lightness_set_actual(0, param_p->ctl_lightness, param_p->ctl_temperature, param_p->ctl_delta_uv, MS_FALSE); + /* appl_light_ctl_temp_set_actual(0, param_p->ctl_temperature); */ + appl_light_ctl[0].ctl_delta_uv = param_p->ctl_delta_uv; + appl_light_ctl[0].tid = param_p->tid; + appl_light_lightness[state_inst].light_lightness_actual.lightness_actual = param_p->ctl_lightness; + /* appl_light_ctl[state_inst].ctl_lightness = param_p->ctl_lightness; */ + } + + *param_p = appl_light_ctl[0]; + CONSOLE_OUT("[state] current Lightness: 0x%02X\n", appl_light_ctl[0].ctl_lightness); + CONSOLE_OUT("[state] target Lightness: 0x%02X\n", appl_light_ctl[0].target_ctl_lightness); + CONSOLE_OUT("[state] current Temperature: 0x%02X\n", appl_light_ctl[0].ctl_temperature); + CONSOLE_OUT("[state] target Temperature: 0x%02X\n", appl_light_ctl[0].target_ctl_temperature); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_light_ctl[0].transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + case MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_T: + { + MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_light_ctl_temp_set_range(0, param_p->ctl_temperature_range_min, param_p->ctl_temperature_range_max); + param_p->status = 0x00; + } + break; + + case MS_STATE_LIGHT_CTL_TEMPERATURE_T: + { + MS_STATE_LIGHT_CTL_TEMPERATURE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_CTL_TEMPERATURE_STRUCT*)param; + printf("Set MS_STATE_LIGHT_CTL_TEMPERATURE_T: 0x%04X\n", param_p->ctl_temperature); + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_ctl_temperature[0].target_ctl_temperature = param_p->ctl_temperature; + appl_light_ctl_temperature[0].target_ctl_delta_uv = param_p->ctl_delta_uv; + appl_light_ctl_temperature[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_light_ctl_temperature_transition_start_cb; + transition.transition_complete_cb = appl_light_ctl_temperature_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + /* appl_light_ctl_temperature[0] = *param_p; */ + appl_light_ctl_temp_set_actual(0, param_p->ctl_temperature, param_p->ctl_delta_uv, MS_FALSE); + } + + *param_p = appl_light_ctl_temperature[0]; + CONSOLE_OUT("[state] current Temperature: 0x%02X\n", appl_light_ctl_temperature[0].ctl_temperature); + CONSOLE_OUT("[state] target Temperature: 0x%02X\n", appl_light_ctl_temperature[0].target_ctl_temperature); + CONSOLE_OUT("[state] current Delta UV: 0x%02X\n", appl_light_ctl_temperature[0].ctl_delta_uv); + CONSOLE_OUT("[state] target Delta UV: 0x%02X\n", appl_light_ctl_temperature[0].ctl_delta_uv); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_light_ctl_temperature[0].transition_time); + } + break; + + default: + break; + } + + return retval; +} + +/** --------------------- Light - HSL ---- */ +static void appl_model_light_hsl_states_initialization(void) +{ + UINT32 index; + EM_mem_set (appl_light_hsl, 0, sizeof(appl_light_hsl)); + EM_mem_set(appl_light_hsl_range, 0, sizeof(appl_light_hsl_range)); + EM_mem_set(appl_light_hsl_default, 0, sizeof(appl_light_hsl_default)); + + for (index = 0; index < MS_MAX_NUM_STATES; index++) + { + /* Light HSL Hue = Generic Level + 32768 */ + appl_light_hsl[index].hsl_hue = 32768; + /* Light HSL Saturation = Generic Level + 32768 */ + appl_light_hsl[index].hsl_saturation = 32768; + } + + #if 0 + + for (index = 0; index < MS_MAX_NUM_STATES; index++) + { + appl_light_hsl_set_hue(index, 0x0000); + appl_light_hsl_set_saturation(index, 0x0000); + } + + #endif /* 0 */ +} + +static void appl_light_hsl_set_actual(UINT16 state_inst, UINT16 lightness, UINT16 hue, UINT16 saturation, UCHAR forced_publish) +{ + printf("appl_light_hsl_set_actual: L:0x%04X, H:0x%04X, S:0x%04X, F:%d\n", + lightness, hue, saturation, forced_publish); + + if (lightness != appl_light_hsl[state_inst].hsl_lightness) + { + appl_light_hsl[state_inst].hsl_lightness = lightness; + appl_light_hsl[state_inst].hsl_hue = hue; + appl_light_hsl[state_inst].hsl_saturation = saturation; + appl_light_hsl_server_publish(MS_STATE_LIGHT_HSL_T, state_inst); + /* appl_light_lightness[state_inst].light_lightness_actual.lightness_actual = param_p->hsl_lightness; */ + appl_light_lightness_set_actual(state_inst, lightness, MS_FALSE); + } + else if (MS_TRUE == forced_publish) + { + appl_light_hsl[state_inst].hsl_lightness = lightness; + appl_light_hsl[state_inst].hsl_hue = hue; + appl_light_hsl[state_inst].hsl_saturation = saturation; + appl_light_hsl_server_publish(MS_STATE_LIGHT_HSL_T, state_inst); + } +} + +static void appl_light_hsl_set_hue(UINT16 state_inst, UINT16 actual) +{ + UINT16 min, max; + CONSOLE_OUT("[Set Light HSL HUE] Actual: 0x%04X\n", actual); + min = appl_light_hsl_range[state_inst].hue_range_min; + max = appl_light_hsl_range[state_inst].hue_range_max; + + if ((0 != min) && (actual < min)) + { + actual = min; + } + else if ((0 != max) && (actual > max)) + { + actual = max; + } + + /* Generic Level = (Light CTL Temperature - T _MIN) * 65535 / (T_MAX - T_MIN) - 32768 */ + #if 0 + appl_set_generic_level(state_inst, actual - 32768, MS_TRUE, MS_FALSE); + #else + + if (actual != appl_light_hsl[state_inst].hsl_hue) + { + appl_light_hsl[state_inst].hsl_hue = actual; + appl_light_hsl_hue_server_publish(MS_STATE_LIGHT_HSL_HUE_T, state_inst); + appl_set_generic_level(state_inst, actual - 32768, MS_TRUE, MS_FALSE); + } + + #endif /* 0 */ +} + +static void appl_light_hsl_set_saturation(UINT16 state_inst, UINT16 actual) +{ + UINT16 min, max; + min = appl_light_hsl_range[state_inst].saturation_range_min; + max = appl_light_hsl_range[state_inst].saturation_range_max; + + if ((0 != min) && (actual < min)) + { + actual = min; + } + else if ((0 != max) && (actual > max)) + { + actual = max; + } + + if (actual != appl_light_hsl[state_inst].hsl_saturation) + { + appl_light_hsl[state_inst].hsl_saturation = actual; + appl_light_hsl_saturation_server_publish(MS_STATE_LIGHT_HSL_SATURATION_T, state_inst); + /* Generic Level = (Light CTL Temperature - T _MIN) * 65535 / (T_MAX - T_MIN) - 32768 */ + appl_set_generic_level(state_inst, actual - 32768, MS_TRUE, MS_FALSE); + } +} + +static void appl_light_hsl_set_range(UINT16 state_inst, UINT16 hue_min, UINT16 hue_max, UINT16 saturation_min, UINT16 saturation_max) +{ + UINT16 actual_hue, actual_saturation; + appl_light_hsl_range[state_inst].hue_range_min = hue_min; + appl_light_hsl_range[state_inst].hue_range_max = hue_max; + appl_light_hsl_range[state_inst].saturation_range_min = saturation_min; + appl_light_hsl_range[state_inst].saturation_range_max = saturation_max; + /* Check if actual to be updated */ + actual_hue = appl_light_hsl[state_inst].hsl_hue; + appl_light_hsl_set_hue(state_inst, actual_hue); + actual_saturation = appl_light_hsl[state_inst].hsl_hue; + appl_light_hsl_set_saturation(state_inst, actual_saturation); +} + +static void appl_light_hsl_transition_start_cb(void* blob) +{ +} + +static void appl_light_hsl_transition_complete_cb(void* blob) +{ + UINT16 state_t; + UINT16 lightness, hue, saturation; + state_t = (UINT16)((intptr_t)(blob)); + appl_light_hsl[0].transition_time = 0x00; + + switch(state_t) + { + case MS_STATE_LIGHT_HSL_T: + { + #if 0 + appl_light_hsl[0].hsl_hue = appl_light_hsl[0].target_hsl_hue; + appl_light_hsl[0].hsl_saturation = appl_light_hsl[0].target_hsl_saturation; + appl_light_hsl[0].hsl_lightness = appl_light_hsl[0].target_hsl_lightness; + #else + hue = appl_light_hsl[0].target_hsl_hue; + saturation = appl_light_hsl[0].target_hsl_saturation; + lightness = appl_light_hsl[0].target_hsl_lightness; + #endif /* 0 */ + appl_light_lightness[0].light_lightness_actual.lightness_actual = appl_light_hsl[0].hsl_lightness; + appl_light_hsl[0].target_hsl_hue = 0x0000; + appl_light_hsl[0].target_hsl_saturation = 0x0000; + appl_light_hsl[0].target_hsl_lightness = 0x0000; + appl_light_hsl_set_actual(0, lightness, hue, saturation, MS_TRUE); + } + break; + + case MS_STATE_LIGHT_HSL_SATURATION_T: + { + appl_light_hsl_set_saturation(0, appl_light_hsl[0].target_hsl_saturation); + appl_light_hsl[0].target_hsl_saturation = 0x0000; + } + break; + + case MS_STATE_LIGHT_HSL_HUE_T: + { + appl_light_hsl_set_hue(0, appl_light_hsl[0].target_hsl_hue); + appl_light_hsl[0].target_hsl_hue = 0x0000; + } + break; + } +} + +static API_RESULT appl_model_light_hsl_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT ret; + UINT8 transition_time; + + switch(state_t) + { + case MS_STATE_LIGHT_HSL_T: + { + MS_STATE_LIGHT_HSL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_hsl[0]; + + if (0 != param_p->transition_time) + { + ret = MS_common_get_remaining_transition_time + ( + param_p->transition_time_handle, + &transition_time + ); + + if (API_SUCCESS == ret) + { + param_p->transition_time = transition_time; + } + } + } + break; + + case MS_STATE_LIGHT_HSL_TARGET_T: + { + MS_STATE_LIGHT_HSL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_hsl[0]; + } + break; + + case MS_STATE_LIGHT_HSL_RANGE_T: + { + MS_STATE_LIGHT_HSL_RANGE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_RANGE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_hsl_range[0]; + } + break; + + case MS_STATE_LIGHT_HSL_DEFAULT_T: + { + MS_STATE_LIGHT_HSL_DEFAULT_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_DEFAULT_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_hsl_default[0]; + } + break; + + case MS_STATE_LIGHT_HSL_HUE_T: + { + MS_STATE_LIGHT_HSL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_hsl[0]; + + if (0 != param_p->transition_time) + { + ret = MS_common_get_remaining_transition_time + ( + param_p->transition_time_handle, + &transition_time + ); + + if (API_SUCCESS == ret) + { + param_p->transition_time = transition_time; + } + } + } + break; + + case MS_STATE_LIGHT_HSL_SATURATION_T: + { + MS_STATE_LIGHT_HSL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_hsl[0]; + + if (0 != param_p->transition_time) + { + ret = MS_common_get_remaining_transition_time + ( + param_p->transition_time_handle, + &transition_time + ); + + if (API_SUCCESS == ret) + { + param_p->transition_time = transition_time; + } + } + } + break; + + default: + break; + } + + return API_SUCCESS; +} + +static API_RESULT appl_model_light_hsl_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_LIGHT_HSL_T: + { + MS_STATE_LIGHT_HSL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_STRUCT*)param; + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + appl_light_hsl[0].target_hsl_hue = param_p->hsl_hue; + appl_light_hsl[0].target_hsl_saturation = param_p->hsl_saturation; + appl_light_hsl[0].target_hsl_lightness = param_p->hsl_lightness; + appl_light_hsl[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = (void*)((intptr_t)state_t); + transition.transition_start_cb = appl_light_hsl_transition_start_cb; + transition.transition_complete_cb = appl_light_hsl_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &appl_light_hsl[0].transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + CONSOLE_OUT("[prior state] current Hue: 0x%04X\n", appl_light_hsl[0].hsl_hue); + CONSOLE_OUT("[prior state] current Saturation: 0x%04X\n", appl_light_hsl[0].hsl_saturation); + CONSOLE_OUT("[prior state] current Lightness: 0x%04X\n", appl_light_hsl[0].hsl_lightness); + #if 0 + appl_light_hsl[0].hsl_lightness = param_p->hsl_lightness; + appl_light_hsl[0].hsl_hue = param_p->hsl_hue; + appl_light_hsl[0].hsl_saturation = param_p->hsl_saturation; + #else + appl_light_hsl_set_actual(0, param_p->hsl_lightness, param_p->hsl_hue, param_p->hsl_saturation, MS_FALSE); + #endif + appl_light_hsl[0].tid = param_p->tid; + /* appl_light_lightness[state_inst].light_lightness_actual.lightness_actual = param_p->hsl_lightness; */ + appl_light_xyl[state_inst].xyl_lightness = param_p->hsl_lightness; + } + + *param_p = appl_light_hsl[0]; + CONSOLE_OUT("[state] current Hue: 0x%04X\n", appl_light_hsl[0].hsl_hue); + CONSOLE_OUT("[state] current Saturation: 0x%04X\n", appl_light_hsl[0].hsl_saturation); + CONSOLE_OUT("[state] current Lightness: 0x%04X\n", appl_light_hsl[0].hsl_lightness); + CONSOLE_OUT("[state] target Hue: 0x%04X\n", appl_light_hsl[0].target_hsl_hue); + CONSOLE_OUT("[state] target Saturation: 0x%04X\n", appl_light_hsl[0].target_hsl_saturation); + CONSOLE_OUT("[state] target Lightness: 0x%04X\n", appl_light_hsl[0].target_hsl_lightness); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_light_hsl[0].transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + case MS_STATE_LIGHT_HSL_RANGE_T: + { + MS_STATE_LIGHT_HSL_RANGE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_RANGE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_light_hsl_set_range(0, param_p->hue_range_min, param_p->hue_range_max, param_p->saturation_range_min, param_p->saturation_range_max); + param_p->status = 0x00; + } + break; + + case MS_STATE_LIGHT_HSL_DEFAULT_T: + { + MS_STATE_LIGHT_HSL_DEFAULT_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_DEFAULT_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_light_hsl_default[0] = *param_p; + } + break; + + case MS_STATE_LIGHT_HSL_HUE_T: + { + MS_STATE_LIGHT_HSL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_STRUCT*)param; + + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + appl_light_hsl[0].target_hsl_hue = param_p->hsl_hue; + appl_light_hsl[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = (void*)((intptr_t)state_t); + transition.transition_start_cb = appl_light_hsl_transition_start_cb; + transition.transition_complete_cb = appl_light_hsl_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &appl_light_hsl[0].transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Ignoring Instance and direction right now */ + appl_light_hsl_set_hue(0, param_p->hsl_hue); + } + + *param_p = appl_light_hsl[0]; + CONSOLE_OUT("[state] current Hue: 0x%04X\n", appl_light_hsl[0].hsl_hue); + CONSOLE_OUT("[state] target Hue: 0x%04X\n", appl_light_hsl[0].target_hsl_hue); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_light_hsl[0].transition_time); + } + break; + + case MS_STATE_LIGHT_HSL_SATURATION_T: + { + MS_STATE_LIGHT_HSL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_STRUCT*)param; + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_hsl[0].target_hsl_saturation = param_p->hsl_saturation; + appl_light_hsl[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = (void*)((intptr_t)state_t); + transition.transition_start_cb = appl_light_hsl_transition_start_cb; + transition.transition_complete_cb = appl_light_hsl_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Ignoring Instance and direction right now */ + appl_light_hsl_set_saturation(0, param_p->hsl_saturation); + } + + *param_p = appl_light_hsl[0]; + CONSOLE_OUT("[state] current Saturation: 0x%04X\n", appl_light_hsl[0].hsl_saturation); + CONSOLE_OUT("[state] target Saturation: 0x%04X\n", appl_light_hsl[0].target_hsl_saturation); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_light_hsl[0].transition_time); + } + break; + + default: + break; + } + + return retval; +} + +/** --------------------- Light - xyL ---- */ +static void appl_model_light_xyl_states_initialization(void) +{ + #if 0 + UINT32 index; + #endif /* 0 */ + EM_mem_set (appl_light_xyl, 0, sizeof(appl_light_xyl)); + EM_mem_set(appl_light_xyl_default, 0, sizeof(appl_light_xyl_default)); + EM_mem_set(appl_light_xyl_range, 0, sizeof(appl_light_xyl_range)); + #if 0 + + for (index = 0; index < MS_MAX_NUM_STATES; index++) + { + appl_light_xyl_set_x(index, 0x0000); + appl_light_xyl_set_y(index, 0x0000); + } + + #endif /* 0 */ +} + +static void appl_light_xyl_set_x(UINT16 state_inst, UINT16 actual) +{ + #if 0 + UINT16 min, max; + min = appl_light_xyl_range[state_inst].xyl_x_range_min; + max = appl_light_xyl_range[state_inst].xyl_x_range_max; + + if ((0 != min) && (actual < min)) + { + actual = min; + } + else if ((0 != max) && (actual > max)) + { + actual = max; + } + + #endif /* 0 */ + appl_light_xyl[state_inst].xyl_x = actual; +} + +static void appl_light_xyl_set_y(UINT16 state_inst, UINT16 actual) +{ + #if 0 + UINT16 min, max; + min = appl_light_xyl_range[state_inst].xyl_y_range_min; + max = appl_light_xyl_range[state_inst].xyl_y_range_max; + + if ((0 != min) && (actual < min)) + { + actual = min; + } + else if ((0 != max) && (actual > max)) + { + actual = max; + } + + #endif /* 0 */ + appl_light_xyl[state_inst].xyl_y = actual; +} + +static void appl_light_xyl_set_actual(UINT16 state_inst, UINT16 xyl_lightness, UINT16 xyl_x, UINT16 xyl_y) +{ + /* if (xyl_lightness != appl_light_xyl[state_inst].xyl_lightness) */ + { + appl_light_xyl[state_inst].xyl_lightness = xyl_lightness; + appl_light_xyl_set_x(state_inst, xyl_x); + appl_light_xyl_set_y(state_inst, xyl_y); + /* Publish */ + appl_light_xyl_server_publish(MS_STATE_LIGHT_XYL_T, 0); + } +} + +static void appl_light_xyl_set_range(UINT16 state_inst, UINT16 x_min, UINT16 x_max, UINT16 y_min, UINT16 y_max) +{ + UINT16 actual_x, actual_y; + appl_light_xyl_range[state_inst].xyl_x_range_min = x_min; + appl_light_xyl_range[state_inst].xyl_x_range_max = x_max; + appl_light_xyl_range[state_inst].xyl_y_range_min = y_min; + appl_light_xyl_range[state_inst].xyl_y_range_max= y_max; + /* Check if actual to be updated */ + actual_x = appl_light_xyl[state_inst].xyl_x; + appl_light_xyl_set_x(state_inst, actual_x); + actual_y = appl_light_xyl[state_inst].xyl_y; + appl_light_xyl_set_y(state_inst, actual_y); +} + +static void appl_light_xyl_transition_start_cb(void* blob) +{ +} + +static void appl_light_xyl_transition_complete_cb(void* blob) +{ + UINT16 state_t; + UINT16 xyl_lightness, xyl_x, xyl_y; + state_t = (UINT16)((intptr_t)(blob)); + appl_light_xyl[0].transition_time = 0x00; + + switch(state_t) + { + case MS_STATE_LIGHT_XYL_T: + { + xyl_x = appl_light_xyl[0].target_xyl_x; + xyl_y = appl_light_xyl[0].target_xyl_y; + xyl_lightness = appl_light_xyl[0].target_xyl_lightness; + appl_light_hsl[0].hsl_lightness = appl_light_xyl[0].xyl_lightness; + appl_light_xyl[0].target_xyl_x = 0x0000; + appl_light_xyl[0].target_xyl_y = 0x0000; + appl_light_xyl[0].target_xyl_lightness = 0x0000; + appl_light_xyl_set_actual(0, xyl_lightness, xyl_x, xyl_y); + } + break; + } +} + +static API_RESULT appl_model_light_xyl_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT ret; + UINT8 transition_time; + + switch(state_t) + { + case MS_STATE_LIGHT_XYL_TARGET_T: + { + MS_STATE_LIGHT_XYL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_XYL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_xyl[0]; + } + break; + + case MS_STATE_LIGHT_XYL_T: + { + MS_STATE_LIGHT_XYL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_XYL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_xyl[0]; + + if (0 != param_p->transition_time) + { + ret = MS_common_get_remaining_transition_time + ( + param_p->transition_time_handle, + &transition_time + ); + + if (API_SUCCESS == ret) + { + param_p->transition_time = transition_time; + } + } + } + break; + + case MS_STATE_LIGHT_XYL_DEFAULT_T: + { + MS_STATE_LIGHT_XYL_DEFAULT_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_XYL_DEFAULT_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_xyl_default[0]; + } + break; + + case MS_STATE_LIGHT_XYL_RANGE_T: + { + MS_STATE_LIGHT_XYL_RANGE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_XYL_RANGE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_xyl_range[0]; + param_p->status = 0x00; + } + break; + + default: + break; + } + + return API_SUCCESS; +} + +static API_RESULT appl_model_light_xyl_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_LIGHT_XYL_T: + { + MS_STATE_LIGHT_XYL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_XYL_STRUCT*)param; + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + appl_light_xyl[0].target_xyl_lightness = param_p->xyl_lightness; + appl_light_xyl[0].target_xyl_x = param_p->xyl_x; + appl_light_xyl[0].target_xyl_y = param_p->xyl_y; + appl_light_xyl[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = (void*)((intptr_t)(state_t)); + transition.transition_start_cb = appl_light_xyl_transition_start_cb; + transition.transition_complete_cb = appl_light_xyl_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &appl_light_xyl[0].transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + appl_light_xyl_set_actual(0, param_p->xyl_lightness, param_p->xyl_x, param_p->xyl_y); + appl_light_hsl[0].hsl_lightness = param_p->xyl_lightness; + } + + *param_p = appl_light_xyl[0]; + CONSOLE_OUT("[state] current X: 0x%04X\n", appl_light_xyl[0].xyl_x); + CONSOLE_OUT("[state] current Y: 0x%04X\n", appl_light_xyl[0].xyl_y); + CONSOLE_OUT("[state] current Lightness: 0x%04X\n", appl_light_xyl[0].xyl_lightness); + CONSOLE_OUT("[state] target X: 0x%04X\n", appl_light_xyl[0].target_xyl_x); + CONSOLE_OUT("[state] target Y: 0x%04X\n", appl_light_xyl[0].target_xyl_y); + CONSOLE_OUT("[state] target Lightness: 0x%04X\n", appl_light_xyl[0].target_xyl_lightness); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_light_xyl[0].transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + case MS_STATE_LIGHT_XYL_DEFAULT_T: + { + MS_STATE_LIGHT_XYL_DEFAULT_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_XYL_DEFAULT_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_light_xyl_default[0] = *param_p; + } + break; + + case MS_STATE_LIGHT_XYL_RANGE_T: + { + MS_STATE_LIGHT_XYL_RANGE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_XYL_RANGE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_light_xyl_set_range(0, param_p->xyl_x_range_min, param_p->xyl_x_range_max, param_p->xyl_y_range_min, param_p->xyl_y_range_max); + param_p->status = 0x00; + } + break; + + default: + break; + } + + return retval; +} + +/** --------------------- Light - LC ---- */ +static void appl_model_light_lc_states_initialization(void) +{ + UINT32 index; + EM_mem_set(appl_light_lc_mode, 0, sizeof(appl_light_lc_mode)); + EM_mem_set(appl_light_lc_om, 0, sizeof(appl_light_lc_om)); + EM_mem_set(appl_light_lc_onoff, 0, sizeof(appl_light_lc_onoff)); + EM_mem_set(appl_light_lc_property, 0, sizeof(appl_light_lc_property)); + + for (index = 0; index < MS_MAX_LC_PROPERTIES; index++) + { + /* TODO: For PTS */ + appl_light_lc_property[0][index].property_id = index + 0x36 /* 1 */; + /* Allocate and keep some property value */ + appl_light_lc_property[0][index].property_value_len = 3 /* 1 */; + appl_light_lc_property[0][index].property_value = EM_alloc_mem(3 /* 1 */); + /* TODO: Not checking for memeory allocation failure */ + EM_mem_set(appl_light_lc_property[0][index].property_value, 0x00, (3 /* 1 */)); + } + + appl_current_property_id_index = 0; +} + +static void appl_light_lc_set_actual(UINT16 state_inst, UINT16 state_t, UCHAR onoff, UCHAR mode) +{ + /* if (xyl_lightness != appl_light_xyl[state_inst].xyl_lightness) */ + switch(state_t) + { + case MS_STATE_LIGHT_LC_MODE_T: + { + appl_light_lc_mode[state_inst].present_mode = mode; + } + break; + + case MS_STATE_LIGHT_LC_OM_T: + { + appl_light_lc_om[state_inst].present_mode = mode; + } + break; + + case MS_STATE_LIGHT_LC_LIGHT_ONOFF_T: + { + appl_light_lc_onoff[state_inst].present_light_onoff = onoff; + } + break; + + default: + return; + } + + /* Publish */ + appl_light_lc_server_publish(state_t, state_inst, 0x0000); +} + +static API_RESULT appl_light_lc_set_actual_propery(UINT16 state_inst, UINT16 property_id, UCHAR* property_value, UINT16 property_value_len) +{ + UINT32 index; + API_RESULT retval; + retval = API_FAILURE; + + for (index = 0; index < MS_MAX_LC_PROPERTIES; index++) + { + if (property_id == appl_light_lc_property[state_inst][index].property_id) + { + if (appl_light_lc_property[state_inst][index].property_value_len == property_value_len) + { + EM_mem_copy + ( + appl_light_lc_property[state_inst][index].property_value, + property_value, + property_value_len + ); + appl_current_property_id_index = index; + retval = API_SUCCESS; + } + + break; + } + } + + if (API_SUCCESS == retval) + { + /* Publish */ + appl_light_lc_server_publish(MS_STATE_LIGHT_LC_PROPERTY_T, state_inst, property_id); + } + + return retval; +} + +static void appl_light_lc_onoff_transition_start_cb(void* blob) +{ + /** + Because binary states cannot support transitions, when changing to 0x01 (On), + the Generic OnOff state shall change immediately when the transition starts, + and when changing to 0x00, the state shall change when the transition finishes. + */ + if (0 == appl_light_lc_onoff[0].present_light_onoff) + { + appl_light_lc_onoff[0].present_light_onoff = appl_light_lc_onoff[0].target_light_onoff; + } +} + +static void appl_light_lc_onoff_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_light_lc_onoff[0].transition_time = 0; + appl_light_lc_onoff[0].present_light_onoff = appl_light_lc_onoff[0].target_light_onoff; + appl_light_lc_onoff[0].target_light_onoff = 0; +} + +API_RESULT appl_model_light_lc_server_set_default_trans_timeout_in_ms(/* IN */ UINT32 time_in_ms) +{ + /* Covert as octet stream and save as Light Control Time Fade property */ + if (MS_DEV_PROP_LIGHT_CONTROL_TIME_FADE == appl_light_lc_property[0][0].property_id) + { + MS_PACK_LE_3_BYTE_VAL(appl_light_lc_property[0][0].property_value, time_in_ms); + } + + return API_SUCCESS; +} + +static API_RESULT appl_model_light_lc_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_LIGHT_LC_MODE_T: + { + MS_STATE_LIGHT_LC_MODE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LC_MODE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + param_p->present_mode = appl_light_lc_mode[0].present_mode; + } + break; + + case MS_STATE_LIGHT_LC_OM_T: + { + MS_STATE_LIGHT_LC_OM_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LC_OM_STRUCT*)param; + /* Ignoring Instance and direction right now */ + param_p->present_mode = appl_light_lc_om[0].present_mode; + } + break; + + case MS_STATE_LIGHT_LC_LIGHT_ONOFF_T: + { + MS_STATE_LIGHT_LC_LIGHT_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LC_LIGHT_ONOFF_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_lc_onoff[0]; + } + break; + + case MS_STATE_LIGHT_LC_PROPERTY_T: + { + MS_STATE_LIGHT_LC_PROPERTY_STRUCT* param_p; + UINT32 index; + param_p = (MS_STATE_LIGHT_LC_PROPERTY_STRUCT*)param; + /* Ignoring Instance and direction right now */ + /* Search for matching property ID */ + param_p->property_value_len = 0x00; + + for (index = 0; index < MS_MAX_LC_PROPERTIES; index++) + { + if (param_p->property_id == appl_light_lc_property[0][index].property_id) + { + param_p->property_value_len = appl_light_lc_property[0][index].property_value_len; + param_p->property_value = appl_light_lc_property[0][index].property_value; + break; + } + } + + /* Else Return Error */ + } + break; + + default: + break; + } + + return retval; +} + +static API_RESULT appl_model_light_lc_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ +// UINT32 index; + API_RESULT retval; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_LIGHT_LC_MODE_T: + { + MS_STATE_LIGHT_LC_MODE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LC_MODE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_light_lc_set_actual(0, MS_STATE_LIGHT_LC_MODE_T, 0x00, param_p->target_mode); + param_p->present_mode = appl_light_lc_mode[0].present_mode; + } + break; + + case MS_STATE_LIGHT_LC_OM_T: + { + MS_STATE_LIGHT_LC_OM_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LC_OM_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_light_lc_set_actual(0, MS_STATE_LIGHT_LC_OM_T, 0x00, param_p->target_mode); + param_p->present_mode = appl_light_lc_om[0].present_mode; + } + break; + + case MS_STATE_LIGHT_LC_LIGHT_ONOFF_T: + { + MS_STATE_LIGHT_LC_LIGHT_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LC_LIGHT_ONOFF_STRUCT*)param; + + if (0 == param_p->transition_time) + { + UINT32 time_in_ms; + UINT8 transition_time; + + /* Check Light Control Time Fade property */ + /* Convert to Transition Time */ + if (MS_DEV_PROP_LIGHT_CONTROL_TIME_FADE == appl_light_lc_property[0][0].property_id) + { + MS_UNPACK_LE_3_BYTE(&time_in_ms, appl_light_lc_property[0][0].property_value); + MS_common_get_transition_time_from_ms + ( + time_in_ms, + &transition_time + ); + param_p->transition_time = transition_time; + param_p->delay = 0; + } + } + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_lc_onoff[0].target_light_onoff = param_p->target_light_onoff; + appl_light_lc_onoff[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_light_lc_onoff_transition_start_cb; + transition.transition_complete_cb = appl_light_lc_onoff_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + /* Ignoring Instance and direction right now */ + appl_light_lc_set_actual(0, MS_STATE_LIGHT_LC_LIGHT_ONOFF_T, param_p->target_light_onoff, 0x00); + appl_set_generic_onoff(state_inst, param_p->target_light_onoff, MS_FALSE); + appl_light_lightness_set_linear(0, param_p->target_light_onoff); + } + + *param_p = appl_light_lc_onoff[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", appl_light_lc_onoff[0].present_light_onoff); + CONSOLE_OUT("[state] target: 0x%02X\n", appl_light_lc_onoff[0].target_light_onoff); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_light_lc_onoff[0].transition_time); + /* TODO: Check for timer and start */ + } + break; + + case MS_STATE_LIGHT_LC_PROPERTY_T: + { + MS_STATE_LIGHT_LC_PROPERTY_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LC_PROPERTY_STRUCT*)param; + retval = appl_light_lc_set_actual_propery(state_inst, param_p->property_id, param_p->property_value, param_p->property_value_len); + + if (API_SUCCESS != retval) + { + param_p->property_value_len = 0x00; + } + + /* TODO: */ + } + break; + + default: + break; + } + + return retval; +} + +/** --------------------------------------------------------------------------------- State Initilization ---- */ +void appl_model_states_initialization(void) +{ + /* Generics - OnOff */ + appl_generic_onoff_states_initialization(); + /* Generics - Level */ + appl_model_generic_level_states_initialization(); + /* Generics - Power OnOff */ + appl_model_generic_power_onoff_states_initialization(); + /* Generics - Power Level */ + appl_model_power_level_states_initialization(); + /* Generics - Battery */ + appl_model_generic_battery_states_initialization(); + /* Generics - Location */ + appl_model_generic_location_states_initialization(); + /* Generics - Properties */ + appl_model_generic_property_states_initialization(); + /* Scene - States */ + EM_mem_set(appl_state_info_vault, 0, sizeof(appl_state_info_vault)); + /* Light - Lightness */ + appl_model_light_lightness_states_initialization(); + /* Light - CTL */ + appl_model_light_ctl_states_initialization(); + /* Light - HSL */ + appl_model_light_hsl_states_initialization(); + /* Light - xyL */ + appl_model_light_xyl_states_initialization(); + /* Light - LC */ + appl_model_light_lc_states_initialization(); + /* Initialize Persistent Storage for application */ + appl_ps_init(); + /* Load from Persistent Storage */ + appl_ps_load(MS_PS_APPL_ALL_RECORDS); + appl_in_transtion = 0x00; + (void)appl_in_transtion; +} + +/** ------------------------------------------------------------------------ Power Cycle - Emulation ---- */ +void appl_model_power_cycle(void) +{ + /* Save the OnPowerUp state and if required other states */ + #if 1 + appl_ps_store(MS_PS_RECORD_APPL_ON_POWER); + #else + appl_ps_store(MS_PS_APPL_ALL_RECORDS); + #endif /* 0 */ + #if 0 + appl_generic_onoff[0].transition_time = 0x00; + appl_generic_onoff[0].target_onoff = 0x00; + + /* */ + if (0x01 == appl_generic_onpower[0].onpowerup) + { + appl_set_generic_onoff(0, 0x01, MS_FALSE); + } + else if (0x00 == appl_generic_onpower[0].onpowerup) + { + appl_set_generic_onoff(0, 0x00, MS_FALSE); + } + else + { + appl_generic_onoff[0].onoff = appl_generic_onoff[0].last_onoff; + } + + /* TODO: Hack */ + if (0x00 != appl_light_lightness[0].light_lightness_actual.transition_time) + { + appl_light_lightness[0].light_lightness_actual.lightness_actual = appl_light_lightness[0].light_lightness_actual.lightness_target; + appl_light_lightness[0].light_lightness_actual.transition_time = 0x00; + appl_light_lightness[0].light_lightness_actual.lightness_target = 0x00; + } + + #endif /* 0 */ +} + +/** ------------------------------------------------------------------------ State Get - Handler ---- */ +API_RESULT appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + CONSOLE_OUT("[State Get] State_T:0x%04X, State_Inst:0x%04X\n", + state_t, state_inst); + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_ONOFF_T: + { + retval = appl_model_generic_onoff_state_get(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_GENERIC_LEVEL_T: + { + retval = appl_model_generic_level_state_get(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_GENERIC_ONPOWERUP_T: + { + retval = appl_model_generic_power_onoff_state_get(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_GENERIC_POWER_ACTUAL_T: + case MS_STATE_GENERIC_POWER_LAST_T: + case MS_STATE_GENERIC_POWER_DEFAULT_T: + case MS_STATE_GENERIC_POWER_RANGE_T: + { + retval = appl_model_generic_power_level_state_get(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_GENERIC_BATTERY_T: + { + retval = appl_model_generic_battery_state_get(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_GENERIC_LOCATION_GLOBAL_T: + case MS_STATE_GENERIC_LOCATION_LOCAL_T: + { + retval = appl_model_generic_location_state_get(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_GENERIC_USER_PROPERTY_IDS_T: + case MS_STATE_GENERIC_ADMIN_PROPERTY_IDS_T: + case MS_STATE_GENERIC_MANUFACTURER_PROPERTY_IDS_T: + case MS_STATE_GENERIC_CLIENT_PROPERTY_IDS_T: + case MS_STATE_GENERIC_USER_PROPERTY_T: + case MS_STATE_GENERIC_ADMIN_PROPERTY_T: + case MS_STATE_GENERIC_MANUFACTURER_PROPERTY_T: + { + retval = appl_model_generic_property_state_get(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + { + retval = appl_model_light_lightness_state_get(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_LIGHT_CTL_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_CTL_T: /* Fall Through */ + case MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_CTL_TEMPERATURE_T: + { + retval = appl_model_light_ctl_state_get(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_LIGHT_HSL_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_TARGET_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_HUE_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_SATURATION_T: + { + retval = appl_model_light_hsl_state_get(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_LIGHT_XYL_T: /* Fall Through */ + case MS_STATE_LIGHT_XYL_TARGET_T: /* Fall Through */ + case MS_STATE_LIGHT_XYL_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_XYL_RANGE_T: + { + retval = appl_model_light_xyl_state_get(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_LIGHT_LC_MODE_T: + case MS_STATE_LIGHT_LC_OM_T: + case MS_STATE_LIGHT_LC_LIGHT_ONOFF_T: + case MS_STATE_LIGHT_LC_PROPERTY_T: + { + retval = appl_model_light_lc_state_get(state_t, state_inst, param, direction); + } + break; + + default: + break; + } + + return retval; +} + +/** ------------------------------------------------------------------------ State Set - Handler ---- */ +API_RESULT appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_ONOFF_T: + { + retval = appl_model_generic_onoff_state_set(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_GENERIC_LEVEL_T: /* Fall Through */ + case MS_STATE_DELTA_LEVEL_T: /* Fall Through */ + case MS_STATE_MOVE_LEVEL_T: + { + retval = appl_model_generic_level_state_set(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_GENERIC_ONPOWERUP_T: + { + retval = appl_model_generic_power_onoff_state_set(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_GENERIC_POWER_ACTUAL_T: + case MS_STATE_GENERIC_POWER_LAST_T: + case MS_STATE_GENERIC_POWER_DEFAULT_T: + case MS_STATE_GENERIC_POWER_RANGE_T: + { + retval = appl_model_generic_power_level_state_set(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_GENERIC_BATTERY_T: + { + retval = appl_model_generic_battery_state_set(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_GENERIC_LOCATION_GLOBAL_T: + case MS_STATE_GENERIC_LOCATION_LOCAL_T: + { + retval = appl_model_generic_location_state_set(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_GENERIC_USER_PROPERTY_T: + case MS_STATE_GENERIC_ADMIN_PROPERTY_T: + case MS_STATE_GENERIC_MANUFACTURER_PROPERTY_T: + { + retval = appl_model_generic_property_state_set(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + { + retval = appl_model_light_lightness_state_set(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_LIGHT_CTL_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_CTL_T: /* Fall Through */ + case MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_CTL_TEMPERATURE_T: + { + retval = appl_model_light_ctl_state_set(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_LIGHT_HSL_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_TARGET_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_HUE_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_SATURATION_T: + { + retval = appl_model_light_hsl_state_set(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_LIGHT_XYL_T: /* Fall Through */ + case MS_STATE_LIGHT_XYL_TARGET_T: /* Fall Through */ + case MS_STATE_LIGHT_XYL_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_XYL_DEFAULT_T: /* Fall Through */ + { + retval = appl_model_light_xyl_state_set(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_LIGHT_LC_MODE_T: + case MS_STATE_LIGHT_LC_OM_T: + case MS_STATE_LIGHT_LC_LIGHT_ONOFF_T: + case MS_STATE_LIGHT_LC_PROPERTY_T: + { + retval = appl_model_light_lc_state_set(state_t, state_inst, param, direction); + } + break; + + default: + break; + } + + return retval; +} + +/** PS Storage Interface for the applicaiton */ +#ifdef MS_STORAGE + +/** Data structure related to persistent storage (PS) load/store */ +typedef struct _MS_PS_APPL_RECORDS +{ + /** Information to load/store */ + void* info; + + /** Start Offset in PS */ + UINT32 start_offset; + + /** Size of Information (in bytes) */ + UINT32 size; + + /** Function Pointer to Store */ + void(*store) (void); + + /** Function Pointer to Load */ + void(*load) (void); + +} MS_PS_APPL_RECORDS; + +/* Store Scene States */ +static void ms_store_appl_scenes(void); +/* Store OnPower States */ +static void ms_store_appl_on_power(void); + +/* Load Scene States */ +static void ms_load_appl_scenes(void); +/* Load OnPower States */ +static void ms_load_appl_on_power(void); + +/** + List of persistent store records. +*/ +static MS_PS_APPL_RECORDS ms_ps_appl_records[] = +{ + /** Information to load/store, Start Offset, Size, Store, Load */ + {NULL, 0, 0, ms_store_appl_scenes, ms_load_appl_scenes}, + {NULL, 0, 0, ms_store_appl_on_power, ms_load_appl_on_power} +}; + +static NVSTO_HANDLE appl_nvsto_handle; + +/* Initialize the access ps store */ +static void appl_ps_init (void) +{ + UINT32 offset; + UINT32 scene_size; + MS_access_ps_get_handle_and_offset(&appl_nvsto_handle, &offset); + scene_size = sizeof(appl_state_info_vault); + /** Information to load/store, Start Offset, Size, Store, Load */ + ms_ps_appl_records[0].start_offset = 0; + ms_ps_appl_records[0].size = scene_size; + ms_ps_appl_records[1].start_offset = scene_size; + ms_ps_appl_records[1].size = 100; /* TODO: See the impact of giving a random value for the size of the last blob in the PS */ + /* Register with the NV Storage */ + nvsto_register_ps + ( + scene_size + 100, + &appl_nvsto_handle + ); +} + +/* Store Scene States */ +static void ms_store_appl_scenes(void) +{ + /* Write Scenes */ + nvsto_write_ps + ( + appl_nvsto_handle, + &appl_state_info_vault[0], + sizeof(appl_state_info_vault) + ); +} + +/* Store OnPower States */ +static void ms_store_appl_on_power(void) +{ + /* Write OnPowerUp state */ + CONSOLE_OUT + ("[APPL_PS]: ms_store_appl_on_power. OnPowerUp 0x%02X\n", + appl_generic_onpower[0].onpowerup); + nvsto_write_ps + ( + appl_nvsto_handle, + &appl_generic_onpower[0].onpowerup, + sizeof(appl_generic_onpower[0].onpowerup) + ); + + /* Write other States, only if OnPowerUp is 0x02 */ + if (0x02 == appl_generic_onpower[0].onpowerup) + { + /* TODO */ + appl_scene_save_current_state_ex(16); + nvsto_write_ps + ( + appl_nvsto_handle, + &appl_state_info_vault[16], + sizeof(appl_state_info_vault[16]) + ); + } +} + +static void appl_ps_store(/* IN */ UINT32 records) +{ + UINT32 index; + INT16 ret; + CONSOLE_OUT + ("[APPL_PS]: PS Store. Records 0x%08X\n", records); + /* Open the storage */ + ret = nvsto_open_pswrite(appl_nvsto_handle); + + if (0 > ret) + { + CONSOLE_OUT + ("[APPL_PS]: PS Open Failed\n"); + return; + } + + /** Store information in listed order */ + for (index = 0; index < MS_PS_APPL_MAX_RECORDS; index++) + { + if (0 != (records & (1 << index))) + { + /* Seek to the corresponding location in PS */ + nvsto_seek_ps(appl_nvsto_handle, ms_ps_appl_records[index].start_offset); + /* Only using the load/store function pointers */ + ms_ps_appl_records[index].store(); + } + } + + /* Close the storage */ + nvsto_close_ps(appl_nvsto_handle); + return; +} + +/* Load Scene States */ +static void ms_load_appl_scenes(void) +{ + /* Read Scenes */ + nvsto_read_ps + ( + appl_nvsto_handle, + &appl_state_info_vault[0], + sizeof(appl_state_info_vault) + ); +} + +/* Load OnPower States */ +static void ms_load_appl_on_power(void) +{ + /* Read OnPowerUp state */ + nvsto_read_ps + ( + appl_nvsto_handle, + &appl_generic_onpower[0].onpowerup, + sizeof(appl_generic_onpower[0].onpowerup) + ); + CONSOLE_OUT + ("[APPL_PS]: ms_load_appl_on_power. OnPowerUp 0x%02X\n", + appl_generic_onpower[0].onpowerup); + + /* Check the status of GenericOnPowerUP */ + /* TODO: Take care of multiple elements */ + /** + Generic OnPowerUp states: + 0x00: Off. + After being powered up, the element is in an off state. + 0x01: Default. + After being powered up, the element is in an On state and uses default state values. + 0x02: Restore. + If a transition was in progress when powered down, the element restores the target state + when powered up. Otherwise the element restores the state it was in when powered down. + */ + switch(appl_generic_onpower[0].onpowerup) + { + case 0x00: + /* Do Nothing */ + break; + + case 0x01: + /* Default State */ + /* Generic OnOff as ON */ + appl_set_generic_onoff(0, 0x01, MS_FALSE); + break; + + case 0x02: + /* Restore */ + nvsto_read_ps + ( + appl_nvsto_handle, + &appl_state_info_vault[16], + sizeof(appl_state_info_vault[16]) + ); + appl_scene_recall_saved_state(16, NULL); + break; + } +} + +static void appl_ps_load(/* IN */ UINT32 records) +{ + UINT32 index; + INT16 ret; + CONSOLE_OUT + ("[APPL_PS]: PS Load. Records 0x%08X\n", records); + /* Open the storage */ + ret = nvsto_open_psread(appl_nvsto_handle); + + if (0 > ret) + { + CONSOLE_OUT + ("[APPL_PS]: PS Open Failed\n"); + return; + } + + /** Load information in listed order */ + for (index = 0; index < MS_PS_APPL_MAX_RECORDS; index++) + { + if (0 != (records & (1 << index))) + { + /* Seek to the corresponding location in PS */ + nvsto_seek_ps(appl_nvsto_handle, ms_ps_appl_records[index].start_offset); + /* Only using the load/store function pointers */ + ms_ps_appl_records[index].load(); + } + } + + /* Close the storage */ + nvsto_close_ps(appl_nvsto_handle); + return; +} +#endif /* MS_STORAGE */ + diff --git a/src/components/ethermind/mesh/export/appl/model/server/appl_model_state_handler.h b/src/components/ethermind/mesh/export/appl/model/server/appl_model_state_handler.h new file mode 100644 index 0000000..c423bf9 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/appl_model_state_handler.h @@ -0,0 +1,30 @@ +/** + \file appl_model_server_state_handler.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_MODEL_SERVER_STATE_HANDLER_ +#define _H_APPL_MODEL_SERVER_STATE_HANDLER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_main.h" +#include "MS_model_states.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void); +API_RESULT appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); +API_RESULT appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +#endif /*_H_APPL_MODEL_SERVER_STATE_HANDLER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_battery_server/appl_generic_battery_server.c b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_battery_server/appl_generic_battery_server.c new file mode 100644 index 0000000..1737af6 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_battery_server/appl_generic_battery_server.c @@ -0,0 +1,153 @@ +/** + \file appl_generic_battery_server.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_generic_battery_server.h" +#include "appl_model_state_handler.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_generic_battery_server_options[] = "\n\ +======== Generic_Battery Server Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_battery_server_model_handle; + + +/* --------------------------------------------- Function */ +/* generic_battery server application entry point */ +void main_generic_battery_server_operations(/* IN */ UINT8 have_menu) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_battery_server_init + ( + element_handle, + &appl_generic_battery_server_model_handle, + appl_generic_battery_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Battery Server Initialized. Model Handle: 0x%04X\n", + appl_generic_battery_server_model_handle); + appl_model_states_initialization(); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Battery Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + if (MS_TRUE != have_menu) + { + CONSOLE_OUT("Not to use menu options\n"); + return; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_generic_battery_server_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + } + } +} + +#if 0 +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Battery server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_battery_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_BATTERY_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_BATTERY] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_BATTERY] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_battery_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} +#endif /* 0 */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_battery_server/appl_generic_battery_server.h b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_battery_server/appl_generic_battery_server.h new file mode 100644 index 0000000..efe3516 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_battery_server/appl_generic_battery_server.h @@ -0,0 +1,56 @@ +/** + \file appl_generic_battery_server.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_GENERIC_BATTERY_SERVER_ +#define _H_APPL_GENERIC_BATTERY_SERVER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_battery_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_battery server application entry point */ +void main_generic_battery_server_operations(/* IN */ UINT8 have_menu); + +/* Get Model Handle */ +void appl_generic_battery_server_get_model_handle(void); + +/* Set Publish Address */ +void appl_generic_battery_server_set_publish_address(void); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Battery server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_battery_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +#endif /*_H_APPL_GENERIC_BATTERY_SERVER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_battery_server/appl_model_state_handler.c b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_battery_server/appl_model_state_handler.c new file mode 100644 index 0000000..bf5c146 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_battery_server/appl_model_state_handler.c @@ -0,0 +1,69 @@ +/** + \file appl_model_state_handler.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_model_state_handler.h" +#include "MS_common.h" + + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ +#define MS_MAX_NUM_STATES 2 + +static MS_STATE_GENERIC_BATTERY_STRUCT appl_generic_battery[MS_MAX_NUM_STATES]; + + + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void) +{ + EM_mem_set(appl_generic_battery, 0, sizeof(appl_generic_battery)); +} + +void appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + switch (state_t) + { + case MS_STATE_GENERIC_BATTERY_T: + { + MS_STATE_GENERIC_BATTERY_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_BATTERY_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_generic_battery[0]; + } + break; + + default: + break; + } +} + +void appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + switch (state_t) + { + case MS_STATE_GENERIC_BATTERY_T: + { + MS_STATE_GENERIC_BATTERY_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_BATTERY_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_generic_battery[0] = *param_p; + } + break; + + default: + break; + } +} diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_battery_server/appl_model_state_handler.h b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_battery_server/appl_model_state_handler.h new file mode 100644 index 0000000..861625a --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_battery_server/appl_model_state_handler.h @@ -0,0 +1,32 @@ +/** + \file appl_model_state_handler.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_MODEL_STATE_HANDLER_ +#define _H_APPL_MODEL_STATE_HANDLER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_main.h" +#include "MS_model_states.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void); + +void appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +void appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +#endif /*_H_APPL_MODEL_STATE_HANDLER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_default_transition_time_server/appl_generic_default_transition_time_server.c b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_default_transition_time_server/appl_generic_default_transition_time_server.c new file mode 100644 index 0000000..8f58193 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_default_transition_time_server/appl_generic_default_transition_time_server.c @@ -0,0 +1,115 @@ +/** + \file appl_generic_default_transition_time_server.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_generic_default_transition_time_server.h" +#include "MS_model_states.h" + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_generic_default_transition_time_server_options[] = "\n\ +======== Generic_Default_Transition_Time Server Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 2. Get Default Transition Time. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_default_transition_time_server_model_handle; + + +/* --------------------------------------------- Function */ +/* generic_default_transition_time server application entry point */ +void main_generic_default_transition_time_server_operations(/* IN */ UINT8 have_menu) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_default_transition_time_server_init + ( + element_handle, + &appl_generic_default_transition_time_server_model_handle, + NULL + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Default Transition Time Server Initialized. Model Handle: 0x%04X\n", + appl_generic_default_transition_time_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Default Transition Time Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + if (MS_TRUE != have_menu) + { + CONSOLE_OUT("Not to use menu options\n"); + return; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_generic_default_transition_time_server_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 2: + { + MS_STATE_GENERIC_DEFAULT_TRANSITION_TIME_STRUCT default_time; + MS_generic_default_transition_time_server_get_time + ( + &default_time + ); + CONSOLE_OUT("Default Transition Steps Resolution: 0x%02X\n", default_time.default_transition_step_resolution); + CONSOLE_OUT("Default Transition Number of Steps: 0x%02X\n", default_time.default_transition_number_of_steps); + } + break; + } + } +} + diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_default_transition_time_server/appl_generic_default_transition_time_server.h b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_default_transition_time_server/appl_generic_default_transition_time_server.h new file mode 100644 index 0000000..0f9edf9 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_default_transition_time_server/appl_generic_default_transition_time_server.h @@ -0,0 +1,36 @@ +/** + \file appl_generic_default_transition_time_server.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_GENERIC_DEFAULT_TRANSITION_TIME_SERVER_ +#define _H_APPL_GENERIC_DEFAULT_TRANSITION_TIME_SERVER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_default_transition_time_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_default_transition_time server application entry point */ +void main_generic_default_transition_time_server_operations(/* IN */ UINT8 have_menu); + +/* Get Model Handle */ +void appl_generic_default_transition_time_server_get_model_handle(void); + +/* Set Publish Address */ +void appl_generic_default_transition_time_server_set_publish_address(void); + +#endif /*_H_APPL_GENERIC_DEFAULT_TRANSITION_TIME_SERVER_ */ + diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_level_server/appl_generic_level_server.c b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_level_server/appl_generic_level_server.c new file mode 100644 index 0000000..2f7eb7d --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_level_server/appl_generic_level_server.c @@ -0,0 +1,271 @@ +/** + \file appl_generic_level_server.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_generic_level_server.h" +#include "appl_model_state_handler.h" +#include "MS_scene_api.h" + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_generic_level_server_options[] = "\n\ +======== Generic_Level Server Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_level_server_model_handle; + +static MS_ACCESS_MODEL_HANDLE appl_scene_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_scene_setup_server_model_handle; + + +/* --------------------------------------------- Function */ +/* generic_level server application entry point */ +void main_generic_level_server_operations(/* IN */ UINT8 have_menu) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_level_server_init + ( + element_handle, + &appl_generic_level_server_model_handle, + appl_generic_level_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Level Server Initialized. Model Handle: 0x%04X\n", + appl_generic_level_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Level Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_scene_server_init + ( + element_handle, + &appl_scene_server_model_handle, + &appl_scene_setup_server_model_handle, + appl_scene_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Scene Server Initialized. Model Handle: 0x%04X\n", + appl_scene_server_model_handle); + CONSOLE_OUT( + "Scene Setup Server Initialized. Model Handle: 0x%04X\n", + appl_scene_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Scene Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + appl_model_states_initialization(); + model_initialized = 0x01; + } + + if (MS_TRUE != have_menu) + { + CONSOLE_OUT("Not to use menu options\n"); + return; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_generic_level_server_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + } + } +} + +#if 0 +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Level server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_level_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_LEVEL_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] SET Request.\n"); + + if ((MS_ACCESS_GENERIC_LEVEL_SET_OPCODE == msg_raw->opcode) || + (MS_ACCESS_GENERIC_LEVEL_SET_UNACKNOWLEDGED_OPCODE == msg_raw->opcode)) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Level SET Request.\n"); + } + else if ((MS_ACCESS_GENERIC_DELTA_SET_OPCODE == msg_raw->opcode) || + (MS_ACCESS_GENERIC_DELTA_SET_UNACKNOWLEDGED_OPCODE == msg_raw->opcode)) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Delta SET Request.\n"); + } + else if ((MS_ACCESS_GENERIC_MOVE_SET_OPCODE == msg_raw->opcode) || + (MS_ACCESS_GENERIC_MOVE_SET_UNACKNOWLEDGED_OPCODE == msg_raw->opcode)) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Move SET Request.\n"); + } + + /* TODO: Right now not handling different type of SET requests separately */ + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_LEVEL_STRUCT*)state_params->state, 0); + current_state_params.state_type = MS_STATE_GENERIC_LEVEL_T; + current_state_params.state = (MS_STATE_GENERIC_LEVEL_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_level_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scene server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. + + TODO: Update +*/ +void* appl_scene_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT8 event_type, + /* IN */ void* event_param, + /* IN */ UINT16 event_length, + /* IN */ void* context +) +{ + void* param_p; + param_p = NULL; + + switch(event_type) + { + case MS_SCENE_EVENT_STORE: + { + param_p = appl_scene_save_current_state(*(UINT32*)event_param); + } + break; + + case MS_SCENE_EVENT_DELETE: + { + param_p = appl_scene_delete_saved_state(*(UINT32*)event_param, context); + } + break; + + case MS_SCENE_EVENT_RECALL_START: + { + } + break; + + case MS_SCENE_EVENT_RECALL_COMPLETE: + { + param_p = appl_scene_recall_saved_state(*(UINT32*)event_param, context); + } + break; + + case MS_SCENE_EVENT_RECALL_IMMEDIATE: + { + param_p = appl_scene_recall_saved_state(*(UINT32*)event_param, context); + } + break; + } + + return param_p; +} + +#endif /* 0 */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_level_server/appl_generic_level_server.h b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_level_server/appl_generic_level_server.h new file mode 100644 index 0000000..757e958 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_level_server/appl_generic_level_server.h @@ -0,0 +1,73 @@ +/** + \file appl_generic_level_server.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_GENERIC_LEVEL_SERVER_ +#define _H_APPL_GENERIC_LEVEL_SERVER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_level_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_level server application entry point */ +void main_generic_level_server_operations(/* IN */ UINT8 have_menu); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Level server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_level_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scene server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. + + TODO: Update +*/ +void* appl_scene_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT8 event_type, + /* IN */ void* event_param, + /* IN */ UINT16 event_length, + /* IN */ void* context +); + +#endif /*_H_APPL_GENERIC_LEVEL_SERVER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_level_server/appl_model_state_handler.c b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_level_server/appl_model_state_handler.c new file mode 100644 index 0000000..f6a278d --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_level_server/appl_model_state_handler.c @@ -0,0 +1,317 @@ +/** + \file appl_model_state_handler.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_model_state_handler.h" +#include "MS_common.h" + +/* --------------------------------------------- Global Definitions */ + +/* --------------------------------------------- Data Types/ Structures */ +#define MS_MAX_NUM_STATES 2 + +typedef struct _APPL_STATE_INFO_VAULT +{ + /* Generic Level state */ + UINT16 level; + +} APPL_STATE_INFO_VAULT; + +typedef struct _APPL_GENENRIC_LEVEL_INFO +{ + MS_STATE_GENERIC_LEVEL_STRUCT generic_level; + + /* Operation Type : 0xFF as initial value (invalid) */ + UINT8 operation_type; + + UINT16 transition_time_handle; + +} APPL_GENERIC_LEVEL_INFO; + +/* static MS_STATE_GENERIC_LEVEL_STRUCT appl_generic_level[MS_MAX_NUM_STATES]; */ +static APPL_GENERIC_LEVEL_INFO appl_generic_level_info[MS_MAX_NUM_STATES]; + +/* For simplicity keeping same number of state info, as the number of max scences */ +static APPL_STATE_INFO_VAULT appl_state_info_vault[16]; + +void appl_set_move_level(UINT16 state_inst, UINT16 move, UINT8 immediate); +void appl_set_level(UINT16 state_inst, UINT16 level); +void appl_set_delta_level(UINT16 state_inst, INT32 delta, UINT8 immediate); + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void) +{ + UINT32 index; + + for (index = 0; index < MS_MAX_NUM_STATES; index++) + { + EM_mem_set(&appl_generic_level_info[index], 0, sizeof(APPL_GENERIC_LEVEL_INFO)); + appl_generic_level_info[index].operation_type = 0xFF; + appl_generic_level_info[index].transition_time_handle = 0xFFFF; + } + + EM_mem_set(appl_state_info_vault, 0, sizeof(appl_state_info_vault)); +} + +static void appl_generic_level_transition_start_cb(void* blob) +{ + UINT16 state_t; + state_t = (UINT16)blob; +} + +static void appl_generic_level_transition_complete_cb(void* blob) +{ + UINT16 state_t; + state_t = (UINT16)blob; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + + switch (state_t) + { + case MS_STATE_GENERIC_LEVEL_T: + { + appl_set_level(0, appl_generic_level_info[0].generic_level.target_level); + } + break; + + case MS_STATE_DELTA_LEVEL_T: + { + appl_set_level(0, appl_generic_level_info[0].generic_level.target_level); + } + break; + + case MS_STATE_MOVE_LEVEL_T: + { + appl_set_move_level(0, appl_generic_level_info[0].generic_level.delta_level, 0x01); + /* TODO: Remove Bad Logic */ + appl_generic_level_info[0].generic_level.move_level = 0; + } + break; + } +} + +void* appl_scene_save_current_state(/* IN */ UINT32 scene_index) +{ + /* Free previous context - if any */ + /* Empty right now - dummy returning the same scene index itself */ + /* Store current state */ + appl_state_info_vault[scene_index].level = appl_generic_level_info[0].generic_level.level; + return (void*)scene_index; +} + +void* appl_scene_delete_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ + /* Free context - if any */ + /* Empty right now - dummy returning NULL */ + /* Invalid value */ + appl_state_info_vault[scene_index].level = 0xFFFF; + return (void*)NULL; +} + +void* appl_scene_recall_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ + /* Recall context - if any */ + /* Empty right now - dummy returning NULL */ + appl_generic_level_info[0].generic_level.level = appl_state_info_vault[scene_index].level; + return (void*)NULL; +} + +API_RESULT appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_LEVEL_T: + { + MS_STATE_GENERIC_LEVEL_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_LEVEL_STRUCT*)param; + /* Ignoting Instance and direction right now */ + *param_p = appl_generic_level_info[0].generic_level; + param_p->level = appl_generic_level_info[0].generic_level.level + appl_generic_level_info[0].generic_level.delta_level; + + /* TODO: hack */ + if (0xFE == appl_generic_level_info[0].generic_level.transition_time) + { + param_p->transition_time = 0x3F; + } + } + break; + + default: + break; + } + + return retval; +} + +void appl_set_level(UINT16 state_inst, UINT16 level) +{ + appl_generic_level_info[state_inst].generic_level.level = level; + appl_generic_level_info[0].generic_level.target_level = 0; + appl_generic_level_info[0].generic_level.delta_level = 0; +} + +void appl_set_delta_level(UINT16 state_inst, INT32 delta, UINT8 immediate) +{ + /* TODO: See if this to be stored */ + if (0x01 == immediate) + { + appl_set_level(state_inst, (appl_generic_level_info[state_inst].generic_level.level + delta)); + } + else if (0x00 == immediate) + { + appl_generic_level_info[0].generic_level.target_level = (appl_generic_level_info[state_inst].generic_level.level + delta); + appl_generic_level_info[state_inst].generic_level.delta_level = delta; + } + else + { + /* Do nothing right now */ + } +} + +void appl_set_move_level(UINT16 state_inst, UINT16 move, UINT8 immediate) +{ + /* TODO: See if this to be stored */ + appl_generic_level_info[state_inst].generic_level.move_level = move; +} + +API_RESULT appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + MS_STATE_GENERIC_LEVEL_STRUCT* param_p; + /** + Transaction State: + 0 : Start of Transaction + 1 : Continue + 2 : End of Transaction + */ + UINT8 transaction_state; + param_p = (MS_STATE_GENERIC_LEVEL_STRUCT*)param; + + switch (state_t) + { + case MS_STATE_GENERIC_LEVEL_T: + { + /* Ignoting Instance and direction right now */ + /* TODO: Not handling transaction state */ + { + MS_common_stop_transition_timer(appl_generic_level_info[0].transition_time_handle); + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + + if (0 == param_p->transition_time) + { + appl_set_level(0, param_p->level); + } + else + { + appl_generic_level_info[0].generic_level.target_level = param_p->level; + param_p->target_level = param_p->level; + } + } + } + break; + + case MS_STATE_DELTA_LEVEL_T: + { + /* Check if a new transaction */ + if (appl_generic_level_info[0].operation_type != state_t) + { + transaction_state = 0x00; + /* Stop associated Transaction Timer, if any */ + MS_common_stop_transition_timer(appl_generic_level_info[0].transition_time_handle); + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + appl_generic_level_info[0].operation_type = state_t; + appl_generic_level_info[0].generic_level.tid = param_p->tid; + } + else if (param_p->tid == appl_generic_level_info[0].generic_level.tid) + { + transaction_state = 0x01; + } + else + { + transaction_state = 0x02; + /* Stop associated Transaction Timer, if any */ + MS_common_stop_transition_timer(appl_generic_level_info[0].transition_time_handle); + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + appl_generic_level_info[0].operation_type = state_t; + appl_generic_level_info[0].generic_level.tid = param_p->tid; + } + + /* Ignoting Instance and direction right now */ + if (0 == param_p->transition_time) + { + if (0x02 == transaction_state) + { + appl_set_delta_level(0, (INT32)appl_generic_level_info[0].generic_level.delta_level, 0x01); + } + + /* Only update delta */ + appl_set_delta_level(0, (INT32)param_p->delta_level, 0x00); + } + else + { + appl_set_delta_level(0, (INT32)param_p->delta_level, 0x00); + } + } + break; + + case MS_STATE_MOVE_LEVEL_T: + { + /* Ignoting Instance and direction right now */ + if (0 == param_p->transition_time) + { + appl_set_move_level(0, param_p->move_level, 0x01); + } + else + { + appl_set_move_level(0, param_p->move_level, 0x00); + /* appl_generic_level_info[0].generic_level.target_level = 0x00; */ + appl_generic_level_info[0].generic_level.target_level = param_p->move_level * (param_p->transition_time & 0x3F); + /* TODO: Hardcoding */ + appl_generic_level_info[0].generic_level.target_level = 0x7FFF; + } + } + break; + + default: + break; + } + + /* TODO: Do we need to check if this is a new transaction? */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + appl_generic_level_info[0].generic_level.transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = (void*)state_t; + transition.transition_start_cb = appl_generic_level_transition_start_cb; + transition.transition_complete_cb = appl_generic_level_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &appl_generic_level_info[0].transition_time_handle + ); + } + + *param_p = appl_generic_level_info[0].generic_level; + param_p->level = appl_generic_level_info[0].generic_level.level + appl_generic_level_info[0].generic_level.delta_level; + + /* TODO: hack */ + if (0xFE == appl_generic_level_info[0].generic_level.transition_time) + { + param_p->transition_time = 0x3F; + } + + return API_SUCCESS; +} diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_level_server/appl_model_state_handler.h b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_level_server/appl_model_state_handler.h new file mode 100644 index 0000000..6522267 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_level_server/appl_model_state_handler.h @@ -0,0 +1,32 @@ +/** + \file appl_model_state_handler.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_MODEL_STATE_HANDLER_ +#define _H_APPL_MODEL_STATE_HANDLER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_main.h" +#include "MS_model_states.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void); + +API_RESULT appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +API_RESULT appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +#endif /*_H_APPL_MODEL_STATE_HANDLER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_location_server/appl_generic_location_server.c b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_location_server/appl_generic_location_server.c new file mode 100644 index 0000000..a24783d --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_location_server/appl_generic_location_server.c @@ -0,0 +1,183 @@ +/** + \file appl_generic_location_server.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_generic_location_server.h" +#include "appl_model_state_handler.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_generic_location_server_options[] = "\n\ +======== Generic_Location Server Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_location_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_location_setup_server_model_handle; + + +/* --------------------------------------------- Function */ +/* generic_location server application entry point */ +void main_generic_location_server_operations(/* IN */ UINT8 have_menu) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_location_server_init + ( + element_handle, + &appl_generic_location_server_model_handle, + appl_generic_location_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Location Server Initialized. Model Handle: 0x%04X\n", + appl_generic_location_server_model_handle); + retval = MS_generic_location_setup_server_init + ( + element_handle, + &appl_generic_location_setup_server_model_handle, + appl_generic_location_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Location Setup Server Initialized. Model Handle: 0x%04X\n", + appl_generic_location_setup_server_model_handle); + appl_model_states_initialization(); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Location Setup Server Initialization Failed. Result: 0x%04X\n", + retval); + } + } + else + { + CONSOLE_OUT( + "[ERR] Generic Location Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + if (MS_TRUE != have_menu) + { + CONSOLE_OUT("Not to use menu options\n"); + return; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_generic_location_server_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + } + } +} + +#if 0 +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Location or Generic_Location_Setup server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_location_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_LOCATION_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_LOCATION] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_LOCATION] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_LOCATION_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_LOCATION_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_LOCATION] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_location_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + + +#endif /* 0 */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_location_server/appl_generic_location_server.h b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_location_server/appl_generic_location_server.h new file mode 100644 index 0000000..c97ffe3 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_location_server/appl_generic_location_server.h @@ -0,0 +1,59 @@ +/** + \file appl_generic_location_server.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_GENERIC_LOCATION_SERVER_ +#define _H_APPL_GENERIC_LOCATION_SERVER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_location_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_location server application entry point */ +void main_generic_location_server_operations(/* IN */ UINT8 have_menu); + +/* Get Model Handle */ +void appl_generic_location_server_get_model_handle(void); +void appl_generic_location_setup_server_get_model_handle(void); + +/* Set Publish Address */ +void appl_generic_location_server_set_publish_address(void); +void appl_generic_location_setup_server_set_publish_address(void); + + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Location or Generic_Location_Setup server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_location_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +#endif /*_H_APPL_GENERIC_LOCATION_SERVER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_location_server/appl_model_state_handler.c b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_location_server/appl_model_state_handler.c new file mode 100644 index 0000000..64de663 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_location_server/appl_model_state_handler.c @@ -0,0 +1,90 @@ +/** + \file appl_model_state_handler.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_model_state_handler.h" +#include "MS_common.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ + + +/* --------------------------------------------- Data Types/Structures */ +#define MS_MAX_NUM_STATES 2 + +static MS_STATE_GENERIC_LOCATION_STRUCT appl_generic_location[MS_MAX_NUM_STATES]; + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void) +{ + EM_mem_set (appl_generic_location, 0, sizeof(appl_generic_location)); +} + +void appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + switch(state_t) + { + case MS_STATE_GENERIC_LOCATION_GLOBAL_T: + { + MS_STATE_GENERIC_LOCATION_GLOBAL_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_LOCATION_GLOBAL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_generic_location[0].global_location; + } + break; + + case MS_STATE_GENERIC_LOCATION_LOCAL_T: + { + MS_STATE_GENERIC_LOCATION_LOCAL_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_LOCATION_LOCAL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_generic_location[0].local_location; + } + break; + + default: + break; + } +} + + +void appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + switch(state_t) + { + case MS_STATE_GENERIC_LOCATION_GLOBAL_T: + { + MS_STATE_GENERIC_LOCATION_GLOBAL_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_LOCATION_GLOBAL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_generic_location[0].global_location = *param_p; + } + break; + + case MS_STATE_GENERIC_LOCATION_LOCAL_T: + { + MS_STATE_GENERIC_LOCATION_LOCAL_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_LOCATION_LOCAL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_generic_location[0].local_location = *param_p; + } + break; + + default: + break; + } +} + + diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_location_server/appl_model_state_handler.h b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_location_server/appl_model_state_handler.h new file mode 100644 index 0000000..861625a --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_location_server/appl_model_state_handler.h @@ -0,0 +1,32 @@ +/** + \file appl_model_state_handler.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_MODEL_STATE_HANDLER_ +#define _H_APPL_MODEL_STATE_HANDLER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_main.h" +#include "MS_model_states.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void); + +void appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +void appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +#endif /*_H_APPL_MODEL_STATE_HANDLER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_onoff_server/appl_generic_onoff_server.c b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_onoff_server/appl_generic_onoff_server.c new file mode 100644 index 0000000..6584242 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_onoff_server/appl_generic_onoff_server.c @@ -0,0 +1,250 @@ +/** + \file appl_generic_onoff_server.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_generic_onoff_server.h" +#include "appl_model_state_handler.h" +#include "MS_generic_onoff_api.h" + +#include "MS_scene_api.h" + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_generic_onoff_server_options[] = "\n\ +======== Generic_Onoff Server Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_onoff_server_model_handle; + +static MS_ACCESS_MODEL_HANDLE appl_scene_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_scene_setup_server_model_handle; + + +/* --------------------------------------------- Function */ +/* generic_onoff server application entry point */ +void main_generic_onoff_server_operations(/* IN */ UINT8 have_menu) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_onoff_server_init + ( + element_handle, + &appl_generic_onoff_server_model_handle, + appl_generic_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Onoff Server Initialized. Model Handle: 0x%04X\n", + appl_generic_onoff_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Onoff Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_scene_server_init + ( + element_handle, + &appl_scene_server_model_handle, + &appl_scene_setup_server_model_handle, + appl_scene_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Scene Server Initialized. Model Handle: 0x%04X\n", + appl_scene_server_model_handle); + CONSOLE_OUT( + "Scene Setup Server Initialized. Model Handle: 0x%04X\n", + appl_scene_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Scene Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + appl_model_states_initialization(); + model_initialized = 0x01; + } + + if (MS_TRUE != have_menu) + { + CONSOLE_OUT("Not to use menu options\n"); + return; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_generic_onoff_server_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + } + } +} + +#if 0 +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONOFF_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + /* Using same as target state and remaining time as 0 */ + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] SET Request.\n"); + retval = appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT("[GENERIC_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scene server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. + + TODO: Update +*/ +void* appl_scene_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT8 event_type, + /* IN */ void* event_param, + /* IN */ UINT16 event_length, + /* IN */ void* context +) +{ + void* param_p; + param_p = NULL; + + switch(event_type) + { + case MS_SCENE_EVENT_STORE: + { + param_p = appl_scene_save_current_state(*(UINT32*)event_param); + } + break; + + case MS_SCENE_EVENT_DELETE: + { + param_p = appl_scene_delete_saved_state(*(UINT32*)event_param, context); + } + break; + + case MS_SCENE_EVENT_RECALL_START: + { + } + break; + + case MS_SCENE_EVENT_RECALL_COMPLETE: + { + param_p = appl_scene_recall_saved_state(*(UINT32*)event_param, context); + } + break; + + case MS_SCENE_EVENT_RECALL_IMMEDIATE: + { + param_p = appl_scene_recall_saved_state(*(UINT32*)event_param, context); + } + break; + } + + return param_p; +} + +#endif /* 0 */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_onoff_server/appl_generic_onoff_server.h b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_onoff_server/appl_generic_onoff_server.h new file mode 100644 index 0000000..269a229 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_onoff_server/appl_generic_onoff_server.h @@ -0,0 +1,73 @@ +/** + \file appl_generic_onoff_server.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_GENERIC_ONOFF_SERVER_ +#define _H_APPL_GENERIC_ONOFF_SERVER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_onoff_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_onoff server application entry point */ +void main_generic_onoff_server_operations(/* IN */ UINT8 have_menu); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scene server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. + + TODO: Update +*/ +void* appl_scene_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT8 event_type, + /* IN */ void* event_param, + /* IN */ UINT16 event_length, + /* IN */ void* context +); + +#endif /*_H_APPL_GENERIC_ONOFF_SERVER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_onoff_server/appl_model_state_handler.c b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_onoff_server/appl_model_state_handler.c new file mode 100644 index 0000000..ddaac08 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_onoff_server/appl_model_state_handler.c @@ -0,0 +1,166 @@ +/** + \file appl_model_state_handler.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_model_state_handler.h" +#include "MS_common.h" + +/* --------------------------------------------- Global Definitions */ + +/* --------------------------------------------- Data Types/ Structures */ +#define MS_MAX_NUM_STATES 2 + +typedef struct _APPL_STATE_INFO_VAULT +{ + /* OnOff state */ + UINT8 onoff; + +} APPL_STATE_INFO_VAULT; + +static MS_STATE_GENERIC_ONOFF_STRUCT appl_generic_onoff[MS_MAX_NUM_STATES]; + +/* For simplicity keeping same number of state info, as the number of max scences */ +static APPL_STATE_INFO_VAULT appl_state_info_vault[16]; + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void) +{ + EM_mem_set(appl_generic_onoff, 0, sizeof(appl_generic_onoff)); + EM_mem_set(appl_state_info_vault, 0, sizeof(appl_state_info_vault)); +} + + +static void appl_generic_onoff_transition_start_cb(void* blob) +{ + /** + Because binary states cannot support transitions, when changing to 0x01 (On), + the Generic OnOff state shall change immediately when the transition starts, + and when changing to 0x00, the state shall change when the transition finishes. + */ + if (0 == appl_generic_onoff[0].onoff) + { + appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; + } +} + +static void appl_generic_onoff_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_generic_onoff[0].transition_time = 0; + appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; + appl_generic_onoff[0].target_onoff = 0; +} + +void* appl_scene_save_current_state(/* IN */ UINT32 scene_index) +{ + /* Free previous context - if any */ + /* Empty right now - dummy returning the same scene index itself */ + /* Store current state */ + appl_state_info_vault[scene_index].onoff = appl_generic_onoff[0].onoff; + return (void*)scene_index; +} + +void* appl_scene_delete_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ + /* Free context - if any */ + /* Empty right now - dummy returning NULL */ + /* Invalid value */ + appl_state_info_vault[scene_index].onoff = 0x02; + return (void*)NULL; +} + +void* appl_scene_recall_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ + /* Recall context - if any */ + /* Empty right now - dummy returning NULL */ + appl_generic_onoff[0].onoff = appl_state_info_vault[scene_index].onoff; + return (void*)NULL; +} + +/* ---- Generic OnOff Get/Set Handlers */ + +/* Generic OnOff Model Get Handlers */ +API_RESULT appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_generic_onoff[0]; + } + break; + + default: + break; + } + + return retval; +} + +/* Generic OnOff Model Set Handlers */ +API_RESULT appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_generic_onoff[0].target_onoff = param_p->onoff; + appl_generic_onoff[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_generic_onoff_transition_start_cb; + transition.transition_complete_cb = appl_generic_onoff_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + appl_generic_onoff[0].onoff = param_p->onoff; + } + + *param_p = appl_generic_onoff[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", appl_generic_onoff[0].onoff); + CONSOLE_OUT("[state] target: 0x%02X\n", appl_generic_onoff[0].target_onoff); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_generic_onoff[0].transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + default: + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_onoff_server/appl_model_state_handler.h b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_onoff_server/appl_model_state_handler.h new file mode 100644 index 0000000..6522267 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_onoff_server/appl_model_state_handler.h @@ -0,0 +1,32 @@ +/** + \file appl_model_state_handler.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_MODEL_STATE_HANDLER_ +#define _H_APPL_MODEL_STATE_HANDLER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_main.h" +#include "MS_model_states.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void); + +API_RESULT appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +API_RESULT appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +#endif /*_H_APPL_MODEL_STATE_HANDLER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_level_server/appl_generic_power_level_server.c b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_level_server/appl_generic_power_level_server.c new file mode 100644 index 0000000..9e6e185 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_level_server/appl_generic_power_level_server.c @@ -0,0 +1,621 @@ +/** + \file appl_generic_power_level_server.c + + Illustration of usage of following model combinations + - Generic Power Level Server + - Generic Power Level Setup Server + - Generic Power OnOff Server + - Generic OnOff Server + - Generic Level Server + - Generic Default Transition Time Server +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_generic_power_level_server.h" +#include "appl_model_state_handler.h" + +#include "MS_scene_api.h" +#include "MS_generic_power_onoff_api.h" +#include "MS_generic_onoff_api.h" +#include "MS_generic_level_api.h" + +/* --------------------------------------------- Global Definitions */ +void appl_model_power_cycle(void); + +/* --------------------------------------------- Static Global Variables */ +static const char main_generic_power_level_server_options[] = "\n\ +======== Generic_Power_Level Server Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 2. Power Cycle. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_power_level_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_power_level_setup_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_power_onoff_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_power_onoff_setup_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_onoff_server_model_handle; +#if 0 + static MS_ACCESS_MODEL_HANDLE appl_generic_default_transition_time_server_model_handle; +#endif /* 0 */ +static MS_ACCESS_MODEL_HANDLE appl_generic_level_server_model_handle; + +static MS_ACCESS_MODEL_HANDLE appl_scene_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_scene_setup_server_model_handle; + + +/* --------------------------------------------- Function */ +/* generic_power_level server application entry point */ +void main_generic_power_level_server_operations(/* IN */ UINT8 have_menu) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_power_level_server_init + ( + element_handle, + &appl_generic_power_level_server_model_handle, + appl_generic_power_level_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Power Level Server Initialized. Model Handle: 0x%04X\n", + appl_generic_power_level_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Power Level Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_power_level_setup_server_init + ( + element_handle, + &appl_generic_power_level_setup_server_model_handle, + appl_generic_power_level_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Power Level Setup Server Initialized. Model Handle: 0x%04X\n", + appl_generic_power_level_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Power Level Setup Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_power_onoff_server_init + ( + element_handle, + &appl_generic_power_onoff_server_model_handle, + appl_generic_power_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Power Onoff Server Initialized. Model Handle: 0x%04X\n", + appl_generic_power_onoff_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Power Onoff Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_power_onoff_setup_server_init + ( + element_handle, + &appl_generic_power_onoff_setup_server_model_handle, + appl_generic_power_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Power Onoff Setup Server Initialized. Model Handle: 0x%04X\n", + appl_generic_power_onoff_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Power Onoff Setup Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_onoff_server_init + ( + element_handle, + &appl_generic_onoff_server_model_handle, + appl_generic_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Onoff Server Initialized. Model Handle: 0x%04X\n", + appl_generic_onoff_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Onoff Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + #if 0 + retval = MS_generic_default_transition_time_server_init + ( + element_handle, + &appl_generic_default_transition_time_server_model_handle, + NULL + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Default Transition Time Server Initialized. Model Handle: 0x%04X\n", + appl_generic_default_transition_time_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Default Transition Time Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + #endif + retval = MS_generic_level_server_init + ( + element_handle, + &appl_generic_level_server_model_handle, + appl_generic_level_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Level Server Initialized. Model Handle: 0x%04X\n", + appl_generic_level_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Level Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_scene_server_init + ( + element_handle, + &appl_scene_server_model_handle, + &appl_scene_setup_server_model_handle, + appl_scene_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Scene Server Initialized. Model Handle: 0x%04X\n", + appl_scene_server_model_handle); + CONSOLE_OUT( + "Scene Setup Server Initialized. Model Handle: 0x%04X\n", + appl_scene_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Scene Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + appl_model_states_initialization(); + model_initialized = 0x01; + } + + if (MS_TRUE != have_menu) + { + CONSOLE_OUT("Not to use menu options\n"); + return; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_generic_power_level_server_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 2: + appl_model_power_cycle(); + break; + } + } +} + +#if 0 +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONOFF_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + /* Using same as target state and remaining time as 0 */ + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] SET Request.\n"); + retval = appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT("[GENERIC_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Level server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_level_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_LEVEL_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] SET Request.\n"); + + if ((MS_ACCESS_GENERIC_LEVEL_SET_OPCODE == msg_raw->opcode) || + (MS_ACCESS_GENERIC_LEVEL_SET_UNACKNOWLEDGED_OPCODE == msg_raw->opcode)) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Level SET Request.\n"); + } + else if ((MS_ACCESS_GENERIC_DELTA_SET_OPCODE == msg_raw->opcode) || + (MS_ACCESS_GENERIC_DELTA_SET_UNACKNOWLEDGED_OPCODE == msg_raw->opcode)) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Delta SET Request.\n"); + } + else if ((MS_ACCESS_GENERIC_MOVE_SET_OPCODE == msg_raw->opcode) || + (MS_ACCESS_GENERIC_MOVE_SET_UNACKNOWLEDGED_OPCODE == msg_raw->opcode)) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Move SET Request.\n"); + } + + /* TODO: Right now not handling different type of SET requests separately */ + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_LEVEL_STRUCT*)state_params->state, 0); + current_state_params.state_type = MS_STATE_GENERIC_LEVEL_T; + current_state_params.state = (MS_STATE_GENERIC_LEVEL_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_level_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_power_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONPOWERUP_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_power_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Level server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_power_level_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_POWER_LEVEL_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_ACCESS_MODEL_EXT_PARAMS ext_param; + MS_EXT_STATUS_STRUCT status; + void* param_p; + API_RESULT retval; + retval = API_SUCCESS; + param_p = NULL; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_POWER_LEVEL] GET Request.\n"); + + switch (state_params->state_type) + { + case MS_STATE_GENERIC_POWER_ACTUAL_T: + { + param_p = (MS_STATE_GENERIC_POWER_ACTUAL_STRUCT*)¶m.generic_power_actual; + } + break; + + case MS_STATE_GENERIC_POWER_LAST_T: + { + param_p = (MS_STATE_GENERIC_POWER_LAST_STRUCT*)¶m.generic_power_last; + } + break; + + case MS_STATE_GENERIC_POWER_DEFAULT_T: + { + param_p = (MS_STATE_GENERIC_POWER_DEFAULT_STRUCT*)¶m.generic_power_default; + } + break; + + case MS_STATE_GENERIC_POWER_RANGE_T: + { + param_p = (MS_STATE_GENERIC_POWER_RANGE_STRUCT*)¶m.generic_power_range; + } + break; + } + + appl_model_state_get(state_params->state_type, 0, param_p, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param_p; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_POWER_LEVEL] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_POWER_LEVEL_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_POWER_LEVEL_STRUCT*)state_params->state; + /* Assign Status */ + ext_param.ext_type = MS_EXT_STATUS_STRUCT_T; + ext_param.ext = &status; + status.status = 0x00; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_POWER_LEVEL] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_power_level_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scene server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. + + TODO: Update +*/ +void* appl_scene_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT8 event_type, + /* IN */ void* event_param, + /* IN */ UINT16 event_length, + /* IN */ void* context +) +{ + void* param_p; + param_p = NULL; + + switch(event_type) + { + case MS_SCENE_EVENT_STORE: + { + param_p = appl_scene_save_current_state(*(UINT32*)event_param); + } + break; + + case MS_SCENE_EVENT_DELETE: + { + param_p = appl_scene_delete_saved_state(*(UINT32*)event_param, context); + } + break; + + case MS_SCENE_EVENT_RECALL_START: + { + } + break; + + case MS_SCENE_EVENT_RECALL_COMPLETE: + { + param_p = appl_scene_recall_saved_state(*(UINT32*)event_param, context); + } + break; + + case MS_SCENE_EVENT_RECALL_IMMEDIATE: + { + param_p = appl_scene_recall_saved_state(*(UINT32*)event_param, context); + } + break; + } + + return param_p; +} + +#endif /* 0 */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_level_server/appl_generic_power_level_server.h b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_level_server/appl_generic_power_level_server.h new file mode 100644 index 0000000..b872fe3 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_level_server/appl_generic_power_level_server.h @@ -0,0 +1,158 @@ +/** + \file appl_generic_power_level_server.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_GENERIC_POWER_LEVEL_SERVER_ +#define _H_APPL_GENERIC_POWER_LEVEL_SERVER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_power_level_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_power_level server application entry point */ +void main_generic_power_level_server_operations(/* IN */ UINT8 have_menu); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Level server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_power_level_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_power_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Level_Setup server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_power_level_setup_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Level server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_level_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scene server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. + + TODO: Update +*/ +void* appl_scene_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT8 event_type, + /* IN */ void* event_param, + /* IN */ UINT16 event_length, + /* IN */ void* context +); + +#endif /*_H_APPL_GENERIC_POWER_LEVEL_SERVER_ */ + diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_level_server/appl_model_state_handler.c b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_level_server/appl_model_state_handler.c new file mode 100644 index 0000000..23ad2d0 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_level_server/appl_model_state_handler.c @@ -0,0 +1,693 @@ +/** + \file appl_model_state_handler.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_model_state_handler.h" +#include "MS_common.h" + +/* --------------------------------------------- Global Definitions */ + +/* --------------------------------------------- Data Types/ Structures */ +#define MS_MAX_NUM_STATES 2 + +typedef struct _APPL_STATE_INFO_VAULT +{ + /* OnOff state */ + UINT8 onoff; + + /* Generic Level state */ + UINT16 level; + + /* Generic Power Level */ + UINT16 power_level; + +} APPL_STATE_INFO_VAULT; + +typedef struct _APPL_GENENRIC_LEVEL_INFO +{ + MS_STATE_GENERIC_LEVEL_STRUCT generic_level; + + /* Operation Type : 0xFF as initial value (invalid) */ + UINT8 operation_type; + + UINT16 transition_time_handle; + +} APPL_GENERIC_LEVEL_INFO; + +static MS_STATE_GENERIC_POWER_LEVEL_STRUCT appl_generic_power_level[MS_MAX_NUM_STATES]; + +static MS_STATE_GENERIC_ONPOWERUP_STRUCT appl_generic_onpower[MS_MAX_NUM_STATES]; + +static MS_STATE_GENERIC_ONOFF_STRUCT appl_generic_onoff[MS_MAX_NUM_STATES]; + +/* static MS_STATE_GENERIC_LEVEL_STRUCT appl_generic_level[MS_MAX_NUM_STATES]; */ +static APPL_GENERIC_LEVEL_INFO appl_generic_level_info[MS_MAX_NUM_STATES]; + +/* For simplicity keeping same number of state info, as the number of max scences */ +static APPL_STATE_INFO_VAULT appl_state_info_vault[16]; + +void appl_set_move_level(UINT16 state_inst, UINT16 move, UINT8 immediate); +void appl_set_level(UINT16 state_inst, UINT16 level); +void appl_set_delta_level(UINT16 state_inst, INT32 delta, UINT8 immediate); + +API_RESULT appl_generic_level_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); +void appl_set_generic_onoff(UINT16 state_inst, UINT8 onoff); +void appl_power_level_set_actual(UINT16 state_inst, UINT16 actual, UINT8 flag); + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void) +{ + UINT32 index; + + for (index = 0; index < MS_MAX_NUM_STATES; index++) + { + EM_mem_set(&appl_generic_level_info[index], 0, sizeof(APPL_GENERIC_LEVEL_INFO)); + appl_generic_level_info[index].operation_type = 0xFF; + appl_generic_level_info[index].transition_time_handle = 0xFFFF; + } + + EM_mem_set(appl_generic_power_level, 0, sizeof(appl_generic_power_level)); + EM_mem_set(appl_generic_onpower, 0, sizeof(appl_generic_onpower)); + EM_mem_set(appl_generic_onoff, 0, sizeof(appl_generic_onoff)); + EM_mem_set(appl_state_info_vault, 0, sizeof(appl_state_info_vault)); +} + +void appl_model_power_cycle(void) +{ + appl_generic_onoff[0].transition_time = 0x00; + appl_generic_onoff[0].target_onoff = 0x00; + + /* */ + if (0x01 == appl_generic_onpower[0].onpowerup) + { + appl_set_generic_onoff(0, 0x01); + } + else if (0x00 == appl_generic_onpower[0].onpowerup) + { + appl_set_generic_onoff(0, 0x00); + } + /* else 0x02. Keep OnOff as before power down */ + /* TODO: Hack */ + else + { + appl_generic_onoff[0].onoff = 0x00; + } + + /* TODO: Hack */ + if (0x00 != appl_generic_power_level[0].generic_power_actual.transition_time) + { + appl_generic_power_level[0].generic_power_actual.power_actual = appl_generic_power_level[0].generic_power_actual.power_target; + appl_generic_power_level[0].generic_power_actual.transition_time = 0x00; + appl_generic_power_level[0].generic_power_actual.power_target = 0x00; + } +} + + +/* ---- State Transition Handlers */ + +static void appl_generic_onoff_transition_start_cb(void* blob) +{ + /** + Because binary states cannot support transitions, when changing to 0x01 (On), + the Generic OnOff state shall change immediately when the transition starts, + and when changing to 0x00, the state shall change when the transition finishes. + */ + #if 0 + if (0 == appl_generic_onoff[0].onoff) + { + appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; + } + + #endif +} + +static void appl_generic_onoff_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_generic_onoff[0].transition_time = 0; + /* appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; */ + appl_set_generic_onoff(0, appl_generic_onoff[0].target_onoff); + appl_generic_onoff[0].target_onoff = 0; +} + +static void appl_generic_power_level_transition_start_cb(void* blob) +{ + /** + Because binary states cannot support transitions, when changing to 0x01 (On), + the Generic OnOff state shall change immediately when the transition starts, + and when changing to 0x00, the state shall change when the transition finishes. + */ + #if 0 + if (0 == appl_generic_onoff[0].onoff) + { + appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; + } + + #endif +} + +static void appl_generic_power_level_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_generic_power_level[0].generic_power_actual.transition_time = 0; + /* appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; */ + appl_power_level_set_actual(0, appl_generic_power_level[0].generic_power_actual.power_target, 1); + appl_generic_power_level[0].generic_power_actual.power_target = 0; +} + +static void appl_generic_level_transition_start_cb(void* blob) +{ + UINT16 state_t; + state_t = (UINT16)blob; +} + +static void appl_generic_level_transition_complete_cb(void* blob) +{ + UINT16 state_t; + state_t = (UINT16)blob; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + + switch (state_t) + { + case MS_STATE_GENERIC_LEVEL_T: + { + appl_set_level(0, appl_generic_level_info[0].generic_level.target_level); + } + break; + + case MS_STATE_DELTA_LEVEL_T: + { + appl_set_level(0, appl_generic_level_info[0].generic_level.target_level); + } + break; + + case MS_STATE_MOVE_LEVEL_T: + { + appl_set_move_level(0, appl_generic_level_info[0].generic_level.delta_level, 0x01); + /* TODO: Remove Bad Logic */ + appl_generic_level_info[0].generic_level.move_level = 0; + } + break; + } +} + +void* appl_scene_save_current_state(/* IN */ UINT32 scene_index) +{ + /* Free previous context - if any */ + /* Empty right now - dummy returning the same scene index itself */ + /* Store current state */ + appl_state_info_vault[scene_index].onoff = appl_generic_onoff[0].onoff; + appl_state_info_vault[scene_index].level = appl_generic_level_info[0].generic_level.level; + appl_state_info_vault[scene_index].power_level = appl_generic_power_level[0].generic_power_actual.power_actual; + return (void*)scene_index; +} + +void* appl_scene_delete_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ + /* Free context - if any */ + /* Empty right now - dummy returning NULL */ + /* Invalid value */ + appl_state_info_vault[scene_index].onoff = 0x02; + appl_state_info_vault[scene_index].level = 0xFFFF; + appl_state_info_vault[scene_index].power_level = 0xFFFF; + return (void*)NULL; +} + +void* appl_scene_recall_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ + /* Recall context - if any */ + /* Empty right now - dummy returning NULL */ + /* appl_generic_onoff[0].onoff = appl_state_info_vault[scene_index].onoff; */ + appl_set_generic_onoff(0, appl_state_info_vault[scene_index].onoff); + appl_generic_level_info[0].generic_level.level = appl_state_info_vault[scene_index].level; + appl_generic_power_level[0].generic_power_actual.power_actual = appl_state_info_vault[0].power_level; + return (void*)NULL; +} + +API_RESULT appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_POWER_ACTUAL_T: + { + MS_STATE_GENERIC_POWER_ACTUAL_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_POWER_ACTUAL_STRUCT*)param; + /* Ignoting Instance and direction right now */ + *param_p = appl_generic_power_level[0].generic_power_actual; + } + break; + + case MS_STATE_GENERIC_POWER_LAST_T: + { + MS_STATE_GENERIC_POWER_LAST_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_POWER_LAST_STRUCT*)param; + /* Ignoting Instance and direction right now */ + *param_p = appl_generic_power_level[0].generic_power_last; + } + break; + + case MS_STATE_GENERIC_POWER_DEFAULT_T: + { + MS_STATE_GENERIC_POWER_DEFAULT_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_POWER_DEFAULT_STRUCT*)param; + /* Ignoting Instance and direction right now */ + *param_p = appl_generic_power_level[0].generic_power_default; + } + break; + + case MS_STATE_GENERIC_POWER_RANGE_T: + { + MS_STATE_GENERIC_POWER_RANGE_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_POWER_RANGE_STRUCT*)param; + /* Ignoting Instance and direction right now */ + *param_p = appl_generic_power_level[0].generic_power_range; + } + break; + + case MS_STATE_GENERIC_ONPOWERUP_T: + { + MS_STATE_GENERIC_ONPOWERUP_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)param; + /* Ignoting Instance and direction right now */ + *param_p = appl_generic_onpower[0]; + } + break; + + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_generic_onoff[0]; + } + break; + + case MS_STATE_GENERIC_LEVEL_T: + { + MS_STATE_GENERIC_LEVEL_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_LEVEL_STRUCT*)param; + /* Ignoting Instance and direction right now */ + *param_p = appl_generic_level_info[0].generic_level; + param_p->level = appl_generic_level_info[0].generic_level.level + appl_generic_level_info[0].generic_level.delta_level; + + /* TODO: hack */ + if (0xFE == appl_generic_level_info[0].generic_level.transition_time) + { + param_p->transition_time = 0x3F; + } + } + break; + + default: + break; + } + + return retval; +} + +void appl_power_level_set_actual(UINT16 state_inst, UINT16 actual, UINT8 flag) +{ + UINT16 min, max; + + /* Generic OnOff binding */ + if (0x0000 == actual) + { + appl_generic_onoff[state_inst].onoff = 0x00; + } + else + { + min = appl_generic_power_level[state_inst].generic_power_range.power_range_min; + max = appl_generic_power_level[state_inst].generic_power_range.power_range_max; + + if ((0 != min) && (actual < min)) + { + actual = min; + } + else if ((0 != max) && (actual > max)) + { + actual = max; + } + + appl_generic_onoff[state_inst].onoff = 0x01; + appl_generic_power_level[state_inst].generic_power_last.power_last = actual; + } + + appl_generic_power_level[state_inst].generic_power_actual.power_actual = actual; + + if (0x00 != flag) + { + appl_generic_level_info[state_inst].generic_level.level = actual - 32768; + } +} + +void appl_generic_power_level_set_range(UINT16 state_inst, UINT16 min, UINT16 max) +{ + UINT16 actual; + appl_generic_power_level[state_inst].generic_power_range.power_range_min = min; + appl_generic_power_level[state_inst].generic_power_range.power_range_max = max; + /* Check if actual to be updated */ + actual = appl_generic_power_level[state_inst].generic_power_actual.power_actual; + #if 1 + appl_power_level_set_actual(state_inst, actual, 1); + #else + + if (actual < min) + { + appl_generic_power_level[state_inst].generic_power_actual.power_actual = min; + } + else if (actual > max) + { + appl_generic_power_level[state_inst].generic_power_actual.power_actual = max; + } + + #endif /* 0 */ +} +void appl_set_level(UINT16 state_inst, UINT16 level) +{ + appl_generic_level_info[state_inst].generic_level.level = level; + appl_generic_level_info[state_inst].generic_level.target_level = 0; + appl_generic_level_info[state_inst].generic_level.delta_level = 0; + appl_power_level_set_actual(0, level + 32768, 0); +} + +void appl_set_delta_level(UINT16 state_inst, INT32 delta, UINT8 immediate) +{ + /* TODO: See if this to be stored */ + if (0x01 == immediate) + { + appl_set_level(state_inst, (appl_generic_level_info[state_inst].generic_level.level + delta)); + } + else if (0x00 == immediate) + { + appl_generic_level_info[0].generic_level.target_level = (appl_generic_level_info[state_inst].generic_level.level + delta); + appl_generic_level_info[state_inst].generic_level.delta_level = delta; + } + else + { + /* Do nothing right now */ + } +} + +void appl_set_move_level(UINT16 state_inst, UINT16 move, UINT8 immediate) +{ + /* TODO: See if this to be stored */ + appl_generic_level_info[state_inst].generic_level.move_level = move; +} + +void appl_set_generic_onoff(UINT16 state_inst, UINT8 onoff) +{ + /* TODO: See if this to be stored */ + appl_generic_onoff[state_inst].onoff = onoff; + + /* Binding */ + if (onoff == 0x00) + { + appl_power_level_set_actual(state_inst, 0x00, 0x01); + } + else + { + if (0x0000 == appl_generic_power_level[state_inst].generic_power_default.power_default) + { + appl_power_level_set_actual(state_inst, appl_generic_power_level[state_inst].generic_power_last.power_last, 0x01); + } + else + { + appl_power_level_set_actual(state_inst, appl_generic_power_level[state_inst].generic_power_default.power_default, 0x01); + } + } +} + +API_RESULT appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_POWER_ACTUAL_T: + { + MS_STATE_GENERIC_POWER_ACTUAL_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_POWER_ACTUAL_STRUCT*)param; + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_generic_power_level[0].generic_power_actual.power_target = param_p->power_actual; + appl_generic_power_level[0].generic_power_actual.transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_generic_power_level_transition_start_cb; + transition.transition_complete_cb = appl_generic_power_level_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + /* Ignoring Instance and direction right now */ + appl_power_level_set_actual(0, param_p->power_actual, 1); + } + + *param_p = appl_generic_power_level[0].generic_power_actual; + CONSOLE_OUT("[state] current: 0x%02X\n", appl_generic_power_level[0].generic_power_actual.power_actual); + CONSOLE_OUT("[state] target: 0x%02X\n", appl_generic_power_level[0].generic_power_actual.power_target); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_generic_power_level[0].generic_power_actual.transition_time); + } + break; + + case MS_STATE_GENERIC_POWER_DEFAULT_T: + { + MS_STATE_GENERIC_POWER_DEFAULT_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_POWER_DEFAULT_STRUCT*)param; + /* Ignoting Instance and direction right now */ + appl_generic_power_level[0].generic_power_default.power_default = param_p->power_default; + } + break; + + case MS_STATE_GENERIC_POWER_RANGE_T: + { + MS_STATE_GENERIC_POWER_RANGE_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_POWER_RANGE_STRUCT*)param; + /* Ignoting Instance and direction right now */ + appl_generic_power_level[0].generic_power_range.power_range_min = param_p->power_range_min; + appl_generic_power_level[0].generic_power_range.power_range_max = param_p->power_range_max; + appl_generic_power_level_set_range(0, param_p->power_range_min, param_p->power_range_max); + param_p->status = 0x00; + } + break; + + case MS_STATE_GENERIC_ONPOWERUP_T: + { + MS_STATE_GENERIC_ONPOWERUP_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)param; + /* Ignoting Instance and direction right now */ + appl_generic_onpower[0] = *param_p; + } + break; + + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_generic_onoff[0].target_onoff = param_p->onoff; + appl_generic_onoff[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_generic_onoff_transition_start_cb; + transition.transition_complete_cb = appl_generic_onoff_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + /* appl_generic_onoff[0].onoff = param_p->onoff; */ + appl_set_generic_onoff(0, param_p->onoff); + } + + *param_p = appl_generic_onoff[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", appl_generic_onoff[0].onoff); + CONSOLE_OUT("[state] target: 0x%02X\n", appl_generic_onoff[0].target_onoff); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_generic_onoff[0].transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + case MS_STATE_GENERIC_LEVEL_T: /* Fall Through */ + case MS_STATE_DELTA_LEVEL_T: /* Fall Through */ + case MS_STATE_MOVE_LEVEL_T: + { + retval = appl_generic_level_model_state_set(state_t, state_inst, param, direction); + } + break; + + default: + break; + } + + return retval; +} + +API_RESULT appl_generic_level_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + MS_STATE_GENERIC_LEVEL_STRUCT* param_p; + /** + Transaction State: + 0 : Start of Transaction + 1 : Continue + 2 : End of Transaction + */ + UINT8 transaction_state; + param_p = (MS_STATE_GENERIC_LEVEL_STRUCT*)param; + + switch (state_t) + { + case MS_STATE_GENERIC_LEVEL_T: + { + /* Ignoting Instance and direction right now */ + /* TODO: Not handling transaction state */ + { + MS_common_stop_transition_timer(appl_generic_level_info[0].transition_time_handle); + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + + if (0 == param_p->transition_time) + { + appl_set_level(0, param_p->level); + } + else + { + appl_generic_level_info[0].generic_level.target_level = param_p->level; + param_p->target_level = param_p->level; + } + } + } + break; + + case MS_STATE_DELTA_LEVEL_T: + { + /* Check if a new transaction */ + if (appl_generic_level_info[0].operation_type != state_t) + { + transaction_state = 0x00; + /* Stop associated Transaction Timer, if any */ + MS_common_stop_transition_timer(appl_generic_level_info[0].transition_time_handle); + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + appl_generic_level_info[0].operation_type = state_t; + appl_generic_level_info[0].generic_level.tid = param_p->tid; + } + else if (param_p->tid == appl_generic_level_info[0].generic_level.tid) + { + transaction_state = 0x01; + } + else + { + transaction_state = 0x02; + /* Stop associated Transaction Timer, if any */ + MS_common_stop_transition_timer(appl_generic_level_info[0].transition_time_handle); + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + appl_generic_level_info[0].operation_type = state_t; + appl_generic_level_info[0].generic_level.tid = param_p->tid; + } + + /* Ignoting Instance and direction right now */ + if (0 == param_p->transition_time) + { + if (0x02 == transaction_state) + { + appl_set_delta_level(0, (INT32)appl_generic_level_info[0].generic_level.delta_level, 0x01); + } + + /* Only update delta */ + appl_set_delta_level(0, (INT32)param_p->delta_level, 0x00); + } + else + { + appl_set_delta_level(0, (INT32)param_p->delta_level, 0x00); + } + } + break; + + case MS_STATE_MOVE_LEVEL_T: + { + /* Ignoting Instance and direction right now */ + if (0 == param_p->transition_time) + { + appl_set_move_level(0, param_p->move_level, 0x01); + } + else + { + appl_set_move_level(0, param_p->move_level, 0x00); + /* appl_generic_level_info[0].generic_level.target_level = 0x00; */ + appl_generic_level_info[0].generic_level.target_level = param_p->move_level * (param_p->transition_time & 0x3F); + /* TODO: Hardcoding */ + appl_generic_level_info[0].generic_level.target_level = 0x7FFF; + } + } + break; + + default: + break; + } + + /* TODO: Do we need to check if this is a new transaction? */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + appl_generic_level_info[0].generic_level.transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = (void*)state_t; + transition.transition_start_cb = appl_generic_level_transition_start_cb; + transition.transition_complete_cb = appl_generic_level_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &appl_generic_level_info[0].transition_time_handle + ); + } + + *param_p = appl_generic_level_info[0].generic_level; + param_p->level = appl_generic_level_info[0].generic_level.level + appl_generic_level_info[0].generic_level.delta_level; + + /* TODO: hack */ + if (0xFE == appl_generic_level_info[0].generic_level.transition_time) + { + param_p->transition_time = 0x3F; + } + + return API_SUCCESS; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_level_server/appl_model_state_handler.h b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_level_server/appl_model_state_handler.h new file mode 100644 index 0000000..6522267 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_level_server/appl_model_state_handler.h @@ -0,0 +1,32 @@ +/** + \file appl_model_state_handler.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_MODEL_STATE_HANDLER_ +#define _H_APPL_MODEL_STATE_HANDLER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_main.h" +#include "MS_model_states.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void); + +API_RESULT appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +API_RESULT appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +#endif /*_H_APPL_MODEL_STATE_HANDLER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_onoff_server/appl_generic_power_onoff_server.c b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_onoff_server/appl_generic_power_onoff_server.c new file mode 100644 index 0000000..469d618 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_onoff_server/appl_generic_power_onoff_server.c @@ -0,0 +1,295 @@ +/** + \file appl_generic_power_onoff_server.c + + Illustration of usage of following model combinations + - Generic Power OnOff Server + - Generic Power OnOff Setup Server + - Generic OnOff Server + - Generic Default Transition Time Server +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_generic_power_onoff_server.h" +#include "appl_model_state_handler.h" +#include "MS_generic_power_onoff_api.h" +#include "MS_generic_onoff_api.h" + + +/* --------------------------------------------- Global Definitions */ +void appl_model_power_cycle(void); + +/* --------------------------------------------- Static Global Variables */ +static const char main_generic_power_onoff_server_options[] = "\n\ +======== Generic_Power_Onoff Server Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 2. Power Cycle. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_power_onoff_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_power_onoff_setup_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_onoff_server_model_handle; +#if 0 + static MS_ACCESS_MODEL_HANDLE appl_generic_default_transition_time_server_model_handle; +#endif /* 0 */ + +/* --------------------------------------------- Function */ +/* generic_power_onoff server application entry point */ +void main_generic_power_onoff_server_operations(/* IN */ UINT8 have_menu) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_power_onoff_server_init + ( + element_handle, + &appl_generic_power_onoff_server_model_handle, + appl_generic_power_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Power Onoff Server Initialized. Model Handle: 0x%04X\n", + appl_generic_power_onoff_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Power Onoff Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_power_onoff_setup_server_init + ( + element_handle, + &appl_generic_power_onoff_setup_server_model_handle, + appl_generic_power_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Power Onoff Setup Server Initialized. Model Handle: 0x%04X\n", + appl_generic_power_onoff_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Power Onoff Setup Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_onoff_server_init + ( + element_handle, + &appl_generic_onoff_server_model_handle, + appl_generic_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Onoff Server Initialized. Model Handle: 0x%04X\n", + appl_generic_onoff_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Onoff Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + #if 0 + retval = MS_generic_default_transition_time_server_init + ( + element_handle, + &appl_generic_default_transition_time_server_model_handle, + NULL + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Default Transition Time Server Initialized. Model Handle: 0x%04X\n", + appl_generic_default_transition_time_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Default Transition Time Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + #endif /* 0 */ + appl_model_states_initialization(); + model_initialized = 0x01; + } + + if (MS_TRUE != have_menu) + { + CONSOLE_OUT("Not to use menu options\n"); + return; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_generic_power_onoff_server_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 2: + appl_model_power_cycle(); + break; + } + } +} + +#if 0 +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONOFF_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + /* Using same as target state and remaining time as 0 */ + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] SET Request.\n"); + retval = appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT("[GENERIC_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_power_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONPOWERUP_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_power_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +#endif /* 0 */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_onoff_server/appl_generic_power_onoff_server.h b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_onoff_server/appl_generic_power_onoff_server.h new file mode 100644 index 0000000..aa8df0b --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_onoff_server/appl_generic_power_onoff_server.h @@ -0,0 +1,94 @@ +/** + \file appl_generic_power_onoff_server.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_GENERIC_POWER_ONOFF_SERVER_ +#define _H_APPL_GENERIC_POWER_ONOFF_SERVER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_power_onoff_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_power_onoff server application entry point */ +void main_generic_power_onoff_server_operations(/* IN */ UINT8 have_menu); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_power_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scene server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. + + TODO: Update +*/ +void* appl_scene_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT8 event_type, + /* IN */ void* event_param, + /* IN */ UINT16 event_length, + /* IN */ void* context +); + +#endif /*_H_APPL_GENERIC_ONOFF_SERVER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_onoff_server/appl_model_state_handler.c b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_onoff_server/appl_model_state_handler.c new file mode 100644 index 0000000..b651e18 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_onoff_server/appl_model_state_handler.c @@ -0,0 +1,209 @@ +/** + \file appl_model_state_handler.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_model_state_handler.h" +#include "MS_common.h" + +/* --------------------------------------------- Global Definitions */ + +/* --------------------------------------------- Data Types/ Structures */ +#define MS_MAX_NUM_STATES 2 + +typedef struct _APPL_STATE_INFO_VAULT +{ + /* OnOff state */ + UINT8 onoff; + +} APPL_STATE_INFO_VAULT; + + +static MS_STATE_GENERIC_ONPOWERUP_STRUCT appl_generic_onpower[MS_MAX_NUM_STATES]; + +static MS_STATE_GENERIC_ONOFF_STRUCT appl_generic_onoff[MS_MAX_NUM_STATES]; +static APPL_STATE_INFO_VAULT appl_state_info_vault[16]; + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void) +{ + EM_mem_set(appl_generic_onpower, 0, sizeof(appl_generic_onpower)); + EM_mem_set(appl_generic_onoff, 0, sizeof(appl_generic_onoff)); + EM_mem_set(appl_state_info_vault, 0, sizeof(appl_state_info_vault)); + /* For Test MMDL/SR/GPOO/BV-03-C */ + appl_generic_onoff[0].onoff = 0x01; +} + +void appl_model_power_cycle(void) +{ + appl_generic_onoff[0].transition_time = 0x00; + appl_generic_onoff[0].target_onoff = 0x00; + + /* */ + if (0x01 == appl_generic_onpower[0].onpowerup) + { + appl_generic_onoff[0].onoff = 0x01; + } + else if (0x00 == appl_generic_onpower[0].onpowerup) + { + appl_generic_onoff[0].onoff = 0x00; + } + /* else 0x02. Keep OnOff as before power down */ + /* TODO: Hack */ + else + { + appl_generic_onoff[0].onoff = 0x00; + } +} + + +static void appl_generic_onoff_transition_start_cb(void* blob) +{ + /** + Because binary states cannot support transitions, when changing to 0x01 (On), + the Generic OnOff state shall change immediately when the transition starts, + and when changing to 0x00, the state shall change when the transition finishes. + */ + #if 0 + if (0 == appl_generic_onoff[0].onoff) + { + appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; + } + + #endif +} + +static void appl_generic_onoff_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_generic_onoff[0].transition_time = 0; + appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; + appl_generic_onoff[0].target_onoff = 0; +} + +void* appl_scene_save_current_state(/* IN */ UINT32 scene_index) +{ + /* Free previous context - if any */ + /* Empty right now - dummy returning the same scene index itself */ + /* Store current state */ + appl_state_info_vault[scene_index].onoff = appl_generic_onoff[0].onoff; + return (void*)scene_index; +} + +void* appl_scene_delete_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ + /* Free context - if any */ + /* Empty right now - dummy returning NULL */ + /* Invalid value */ + appl_state_info_vault[scene_index].onoff = 0x02; + return (void*)NULL; +} + +void* appl_scene_recall_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ + /* Recall context - if any */ + /* Empty right now - dummy returning NULL */ + appl_generic_onoff[0].onoff = appl_state_info_vault[scene_index].onoff; + return (void*)NULL; +} + +API_RESULT appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_GENERIC_ONPOWERUP_T: + { + MS_STATE_GENERIC_ONPOWERUP_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)param; + /* Ignoting Instance and direction right now */ + *param_p = appl_generic_onpower[0]; + } + break; + + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_generic_onoff[0]; + } + break; + + default: + break; + } + + return retval; +} + +API_RESULT appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_ONPOWERUP_T: + { + MS_STATE_GENERIC_ONPOWERUP_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)param; + /* Ignoting Instance and direction right now */ + appl_generic_onpower[0] = *param_p; + } + break; + + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_generic_onoff[0].target_onoff = param_p->onoff; + appl_generic_onoff[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_generic_onoff_transition_start_cb; + transition.transition_complete_cb = appl_generic_onoff_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + appl_generic_onoff[0].onoff = param_p->onoff; + } + + *param_p = appl_generic_onoff[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", appl_generic_onoff[0].onoff); + CONSOLE_OUT("[state] target: 0x%02X\n", appl_generic_onoff[0].target_onoff); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_generic_onoff[0].transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + default: + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_onoff_server/appl_model_state_handler.h b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_onoff_server/appl_model_state_handler.h new file mode 100644 index 0000000..6522267 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_power_onoff_server/appl_model_state_handler.h @@ -0,0 +1,32 @@ +/** + \file appl_model_state_handler.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_MODEL_STATE_HANDLER_ +#define _H_APPL_MODEL_STATE_HANDLER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_main.h" +#include "MS_model_states.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void); + +API_RESULT appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +API_RESULT appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +#endif /*_H_APPL_MODEL_STATE_HANDLER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_property_server/appl_generic_property_server.c b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_property_server/appl_generic_property_server.c new file mode 100644 index 0000000..26a2e8c --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_property_server/appl_generic_property_server.c @@ -0,0 +1,447 @@ +/** + \file appl_generic_property_server.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_generic_property_server.h" +#include "appl_model_state_handler.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_generic_property_server_options[] = "\n\ +======== Generic_Property Server Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_user_property_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_admin_property_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_manufacturer_property_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_client_property_server_model_handle; + +/* --------------------------------------------- Function */ +/* generic_property server application entry point */ +void main_generic_property_server_operations(/* IN */ UINT8 have_menu) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_user_property_server_init + ( + element_handle, + &appl_generic_user_property_server_model_handle, + appl_generic_user_property_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic User Property Server Initialized. Model Handle: 0x%04X\n", + appl_generic_user_property_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic User Property Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_admin_property_server_init + ( + element_handle, + &appl_generic_admin_property_server_model_handle, + appl_generic_admin_property_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Admin Property Server Initialized. Model Handle: 0x%04X\n", + appl_generic_admin_property_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Admin Property Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_manufacturer_property_server_init + ( + element_handle, + &appl_generic_manufacturer_property_server_model_handle, + appl_generic_manufacturer_property_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Manufacturer Property Server Initialized. Model Handle: 0x%04X\n", + appl_generic_manufacturer_property_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Manufacturer Property Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_client_property_server_init + ( + element_handle, + &appl_generic_client_property_server_model_handle, + appl_generic_client_property_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Client Property Server Initialized. Model Handle: 0x%04X\n", + appl_generic_client_property_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Client Property Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + appl_model_states_initialization(); + model_initialized = 0x01; + } + + if (MS_TRUE != have_menu) + { + CONSOLE_OUT("Not to use menu options\n"); + return; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_generic_property_server_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + } + } +} + +#if 0 +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_User_Property server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_user_property_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_USER_PROPERTY_STRUCT user_prop_param; + MS_STATE_GENERIC_PROPERTY_IDS_STRUCT prop_ids; + void* param; + /* As sample example. The array size need to defined, based on the final configuration */ + UINT16 prop_ids_list[10]; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_USER_PROPERTY] GET Request. Type: 0x%02X\n", state_params->state_type); + + if (MS_STATE_GENERIC_USER_PROPERTY_T == state_params->state_type) + { + user_prop_param.property_id = ((MS_STATE_GENERIC_PROPERTY_ID_STRUCT*)state_params->state)->property_id; + param = &user_prop_param; + } + else if (MS_STATE_GENERIC_USER_PROPERTY_IDS_T == state_params->state_type) + { + param = &prop_ids; + prop_ids.property_ids = prop_ids_list; + prop_ids.property_ids_count = sizeof(prop_ids_list) / sizeof(UINT16); + } + + appl_model_state_get(state_params->state_type, 0, param, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_USER_PROPERTY] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_USER_PROPERTY_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_USER_PROPERTY_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_USER_PROPERTY] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_user_property_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Admin_Property server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_admin_property_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ADMIN_PROPERTY_STRUCT prop_param; + MS_STATE_GENERIC_PROPERTY_IDS_STRUCT prop_ids; + void* param; + /* As sample example. The array size need to defined, based on the final configuration */ + UINT16 prop_ids_list[10]; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_ADMIN_PROPERTY] GET Request. Type: 0x%02X\n", state_params->state_type); + + if (MS_STATE_GENERIC_ADMIN_PROPERTY_T == state_params->state_type) + { + prop_param.property_id = ((MS_STATE_GENERIC_PROPERTY_ID_STRUCT*)state_params->state)->property_id; + param = &prop_param; + } + else if (MS_STATE_GENERIC_ADMIN_PROPERTY_IDS_T == state_params->state_type) + { + param = &prop_ids; + prop_ids.property_ids = prop_ids_list; + prop_ids.property_ids_count = sizeof(prop_ids_list) / sizeof(UINT16); + } + + appl_model_state_get(state_params->state_type, 0, param, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_ADMIN_PROPERTY] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ADMIN_PROPERTY_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ADMIN_PROPERTY_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_ADMIN_PROPERTY] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_admin_property_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Manufacturer_Property server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_manufacturer_property_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_MANUFACTURER_PROPERTY_STRUCT prop_param; + MS_STATE_GENERIC_PROPERTY_IDS_STRUCT prop_ids; + void* param; + /* As sample example. The array size need to defined, based on the final configuration */ + UINT16 prop_ids_list[10]; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_MANUFACTURER_PROPERTY] GET Request. Type: 0x%02X\n", state_params->state_type); + + if (MS_STATE_GENERIC_MANUFACTURER_PROPERTY_T == state_params->state_type) + { + prop_param.property_id = ((MS_STATE_GENERIC_PROPERTY_ID_STRUCT*)state_params->state)->property_id; + param = &prop_param; + } + else if (MS_STATE_GENERIC_MANUFACTURER_PROPERTY_IDS_T == state_params->state_type) + { + param = &prop_ids; + prop_ids.property_ids = prop_ids_list; + prop_ids.property_ids_count = sizeof(prop_ids_list) / sizeof(UINT16); + } + + appl_model_state_get(state_params->state_type, 0, param, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_MANUFACTURER_PROPERTY] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_MANUFACTURER_PROPERTY_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_MANUFACTURER_PROPERTY_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_MANUFACTURER_PROPERTY] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_manufacturer_property_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Client_Property server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_client_property_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_PROPERTY_IDS_STRUCT prop_ids; + void* param; + /* As sample example. The array size need to defined, based on the final configuration */ + UINT16 prop_ids_list[10]; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_CLIENT_PROPERTY] GET Request. Type: 0x%02X\n", state_params->state_type); + + if (MS_STATE_GENERIC_CLIENT_PROPERTY_IDS_T == state_params->state_type) + { + param = &prop_ids; + prop_ids.property_ids = prop_ids_list; + prop_ids.property_ids_count = sizeof(prop_ids_list) / sizeof(UINT16); + } + + appl_model_state_get(state_params->state_type, 0, param, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_CLIENT_PROPERTY] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_client_property_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + + +#endif /* 0 */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_property_server/appl_generic_property_server.h b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_property_server/appl_generic_property_server.h new file mode 100644 index 0000000..5c4e0e0 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_property_server/appl_generic_property_server.h @@ -0,0 +1,113 @@ +/** + \file appl_generic_property_server.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_GENERIC_PROPERTY_SERVER_ +#define _H_APPL_GENERIC_PROPERTY_SERVER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_property_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_user_property server application entry point */ +void main_generic_property_server_operations(/* IN */ UINT8 have_menu); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_User_Property server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_user_property_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Admin_Property server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_admin_property_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Manufacturer_Property server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_manufacturer_property_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Client_Property server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_client_property_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +#endif /*_H_APPL_GENERIC_PROPERTY_SERVER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_property_server/appl_model_state_handler.c b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_property_server/appl_model_state_handler.c new file mode 100644 index 0000000..b6fa917 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_property_server/appl_model_state_handler.c @@ -0,0 +1,486 @@ +/** + \file appl_model_state_handler.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_model_state_handler.h" +#include "MS_common.h" +#include "MS_generic_property_api.h" + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ + + +/* --------------------------------------------- Data Types/Structures */ +#define MS_MAX_NUM_STATES 2 + +#define MS_MAX_USER_PROPERTIES 1 /* 3 */ +#define MS_MAX_ADMIN_PROPERTIES 1 /* 3 */ +#define MS_MAX_MANUFACTURER_PROPERTIES 1 /* 3 */ +#define MS_MAX_CLIENT_PROPERTIES 1 /* 3 */ + +static MS_STATE_GENERIC_USER_PROPERTY_STRUCT appl_generic_user_property[MS_MAX_NUM_STATES][MS_MAX_USER_PROPERTIES]; +static MS_STATE_GENERIC_ADMIN_PROPERTY_STRUCT appl_generic_admin_property[MS_MAX_NUM_STATES][MS_MAX_ADMIN_PROPERTIES]; +static MS_STATE_GENERIC_MANUFACTURER_PROPERTY_STRUCT appl_generic_manufacturer_property[MS_MAX_NUM_STATES][MS_MAX_MANUFACTURER_PROPERTIES]; +static MS_STATE_GENERIC_USER_PROPERTY_STRUCT appl_generic_client_property[MS_MAX_NUM_STATES][MS_MAX_CLIENT_PROPERTIES]; + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void) +{ + UINT32 index; + UINT8 access_type; + EM_mem_set (appl_generic_user_property, 0, sizeof(appl_generic_user_property)); + EM_mem_set (appl_generic_admin_property, 0, sizeof(appl_generic_admin_property)); + EM_mem_set (appl_generic_manufacturer_property, 0, sizeof(appl_generic_manufacturer_property)); + EM_mem_set(appl_generic_client_property, 0, sizeof(appl_generic_client_property)); + /* For the PTS testing configure Properies */ + /* Will use all three kinds of user access one after another - for the example configuration */ + /* User Properties */ + access_type = MS_GENERIC_USER_ACCESS_READ; + + for (index = 0; index < MS_MAX_USER_PROPERTIES; index++) + { + appl_generic_user_property[0][index].property_id = index + 1; + appl_generic_user_property[0][index].user_access = access_type; + /* Allocate and keep some property value */ + appl_generic_user_property[0][index].property_value_len = index + 1; + appl_generic_user_property[0][index].property_value = EM_alloc_mem(index + 1); + /* TODO: Not checking for memeory allocation failure */ + EM_mem_set(appl_generic_user_property[0][index].property_value, (index + 1), (index + 1)); + + if (MS_GENERIC_USER_ACCESS_READ_WRITE == access_type) + { + access_type = MS_GENERIC_USER_ACCESS_READ; + } + else + { + access_type++; + } + } + + /* Admin Properties */ + access_type = MS_GENERIC_USER_ACCESS_READ; + + for (index = 0; index < MS_MAX_USER_PROPERTIES; index++) + { + appl_generic_admin_property[0][index].property_id = index + 1; + appl_generic_admin_property[0][index].user_access = access_type; + /* Allocate and keep some property value */ + appl_generic_admin_property[0][index].property_value_len = index + 1; + appl_generic_admin_property[0][index].property_value = EM_alloc_mem(index + 1); + /* TODO: Not checking for memeory allocation failure */ + EM_mem_set(appl_generic_admin_property[0][index].property_value, (index + 1), (index + 1)); + + if (MS_GENERIC_USER_ACCESS_READ_WRITE == access_type) + { + access_type = MS_GENERIC_USER_ACCESS_READ; + } + else + { + access_type++; + } + } + + /* Manufacturer Properties */ + access_type = MS_GENERIC_USER_ACCESS_READ; + + for (index = 0; index < MS_MAX_USER_PROPERTIES; index++) + { + appl_generic_manufacturer_property[0][index].property_id = index + 1; + appl_generic_manufacturer_property[0][index].user_access = access_type; + /* Allocate and keep some property value */ + appl_generic_manufacturer_property[0][index].property_value_len = index + 1; + appl_generic_manufacturer_property[0][index].property_value = EM_alloc_mem(index + 1); + /* TODO: Not checking for memeory allocation failure */ + EM_mem_set(appl_generic_manufacturer_property[0][index].property_value, (index + 1), (index + 1)); + + if (MS_GENERIC_USER_ACCESS_READ_WRITE == access_type) + { + access_type = MS_GENERIC_USER_ACCESS_READ; + } + else + { + access_type++; + } + } + + /* Client Properties */ + /* Manufacturer Properties */ + access_type = MS_GENERIC_USER_ACCESS_READ; + + for (index = 0; index < MS_MAX_CLIENT_PROPERTIES; index++) + { + appl_generic_client_property[0][index].property_id = index + 1; + appl_generic_client_property[0][index].user_access = access_type; + /* Allocate and keep some property value */ + appl_generic_client_property[0][index].property_value_len = index + 1; + appl_generic_client_property[0][index].property_value = EM_alloc_mem(index + 1); + /* TODO: Not checking for memeory allocation failure */ + EM_mem_set(appl_generic_client_property[0][index].property_value, (index + 1), (index + 1)); + + if (MS_GENERIC_USER_ACCESS_READ_WRITE == access_type) + { + access_type = MS_GENERIC_USER_ACCESS_READ; + } + else + { + access_type++; + } + } +} + +void appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + UINT32 index; + + switch(state_t) + { + case MS_STATE_GENERIC_USER_PROPERTY_IDS_T: + { + MS_STATE_GENERIC_PROPERTY_IDS_STRUCT* param_p; + UINT8 count; + param_p = (MS_STATE_GENERIC_PROPERTY_IDS_STRUCT*)param; + count = 0; + + for (index = 0; index < MS_MAX_USER_PROPERTIES; index++) + { + /* Check if Admin Property is not disabled */ + if (MS_GENERIC_USER_ACCESS_PROHIBITED != appl_generic_user_property[0][index].user_access) + { + param_p->property_ids[index] = appl_generic_user_property[0][index].property_id; + count++; + } + } + + /* TODO: Not checking 'property_ids_count' in input */ + param_p->property_ids_count = count; + } + break; + + case MS_STATE_GENERIC_ADMIN_PROPERTY_IDS_T: + { + MS_STATE_GENERIC_PROPERTY_IDS_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_PROPERTY_IDS_STRUCT*)param; + + for (index = 0; index < MS_MAX_ADMIN_PROPERTIES; index++) + { + param_p->property_ids[index] = appl_generic_admin_property[0][index].property_id; + } + + /* TODO: Not checking 'property_ids_count' in input */ + param_p->property_ids_count = MS_MAX_ADMIN_PROPERTIES; + } + break; + + case MS_STATE_GENERIC_MANUFACTURER_PROPERTY_IDS_T: + { + MS_STATE_GENERIC_PROPERTY_IDS_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_PROPERTY_IDS_STRUCT*)param; + + for (index = 0; index < MS_MAX_MANUFACTURER_PROPERTIES; index++) + { + param_p->property_ids[index] = appl_generic_manufacturer_property[0][index].property_id; + } + + /* TODO: Not checking 'property_ids_count' in input */ + param_p->property_ids_count = MS_MAX_MANUFACTURER_PROPERTIES; + } + break; + + case MS_STATE_GENERIC_CLIENT_PROPERTY_IDS_T: + { + MS_STATE_GENERIC_PROPERTY_IDS_STRUCT* param_p; + UINT8 count; + param_p = (MS_STATE_GENERIC_PROPERTY_IDS_STRUCT*)param; + count = 0; + + for (index = 0; index < MS_MAX_CLIENT_PROPERTIES; index++) + { + /* Check if Admin Property is not disabled */ + /* if (MS_GENERIC_USER_ACCESS_PROHIBITED != appl_generic_client_property[0][index].user_access) */ + { + param_p->property_ids[index] = appl_generic_client_property[0][index].property_id; + count++; + } + } + + /* TODO: Not checking 'property_ids_count' in input */ + param_p->property_ids_count = count; + } + break; + + case MS_STATE_GENERIC_USER_PROPERTY_T: + { + MS_STATE_GENERIC_USER_PROPERTY_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_PROPERTY_IDS_STRUCT*)param; + /* Check for property ID match */ + /* Mark the access as prohibited, to indicate invalid Property ID */ + param_p->user_access = MS_GENERIC_USER_ACCESS_PROHIBITED; + + for (index = 0; index < MS_MAX_USER_PROPERTIES; index++) + { + if (appl_generic_user_property[0][index].property_id == param_p->property_id) + { + param_p->user_access = appl_generic_user_property[0][index].user_access; + + if (MS_GENERIC_USER_ACCESS_WRITE == param_p->user_access) + { + param_p->property_value_len = 0; + } + else + { + param_p->property_value = appl_generic_user_property[0][index].property_value; + param_p->property_value_len = appl_generic_user_property[0][index].property_value_len; + } + + printf("GGGGEEETTTTTT::::USER::::: [%d] ID:0x%04X. Access:0x%02X. Len:%d\n", + index, appl_generic_admin_property[0][index].property_id, + appl_generic_admin_property[0][index].user_access, + appl_generic_admin_property[0][index].property_value_len); + break; + } + } + } + break; + + case MS_STATE_GENERIC_ADMIN_PROPERTY_T: + { + MS_STATE_GENERIC_USER_PROPERTY_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_PROPERTY_IDS_STRUCT*)param; + /* Check for property ID match */ + /* Mark the access as prohibited, to indicate invalid Property ID */ + param_p->user_access = MS_GENERIC_USER_ACCESS_PROHIBITED; + param_p->property_value_len = 0; + + for (index = 0; index < MS_MAX_ADMIN_PROPERTIES; index++) + { + if (appl_generic_admin_property[0][index].property_id == param_p->property_id) + { + param_p->user_access = appl_generic_admin_property[0][index].user_access; + + if (MS_GENERIC_USER_ACCESS_WRITE == param_p->user_access) + { + param_p->property_value_len = 0; + } + else + { + param_p->property_value = appl_generic_admin_property[0][index].property_value; + param_p->property_value_len = appl_generic_admin_property[0][index].property_value_len; + } + + printf("GGGGEEETTTTTT::::ADMIN::::: [%d] ID:0x%04X. Access:0x%02X. Len:%d\n", + index, appl_generic_admin_property[0][index].property_id, + appl_generic_admin_property[0][index].user_access, + appl_generic_admin_property[0][index].property_value_len); + break; + } + } + } + break; + + case MS_STATE_GENERIC_MANUFACTURER_PROPERTY_T: + { + MS_STATE_GENERIC_USER_PROPERTY_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_PROPERTY_IDS_STRUCT*)param; + + /* Check for property ID match */ + + for (index = 0; index < MS_MAX_MANUFACTURER_PROPERTIES; index++) + { + if (appl_generic_manufacturer_property[0][index].property_id == param_p->property_id) + { + param_p->user_access = appl_generic_manufacturer_property[0][index].user_access; + + if (MS_GENERIC_USER_ACCESS_WRITE == param_p->user_access) + { + param_p->property_value_len = 0; + } + else + { + param_p->property_value = appl_generic_manufacturer_property[0][index].property_value; + param_p->property_value_len = appl_generic_manufacturer_property[0][index].property_value_len; + } + + printf("GGGGEEETTTTTT::::MANU::::: [%d] ID:0x%04X. Access:0x%02X. Len:%d\n", + index, appl_generic_manufacturer_property[0][index].property_id, + appl_generic_manufacturer_property[0][index].user_access, + appl_generic_manufacturer_property[0][index].property_value_len); + break; + } + } + + /* Mark the access as prohibited, to indicate invalid Property ID */ + if (MS_MAX_MANUFACTURER_PROPERTIES == index) + { + param_p->user_access = MS_GENERIC_USER_ACCESS_INVALID_PROPERTY_ID; + param_p->property_value_len = 0; + } + } + break; + } +} + + +void appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + UINT32 index; + + switch(state_t) + { + case MS_STATE_GENERIC_USER_PROPERTY_T: + { + MS_STATE_GENERIC_USER_PROPERTY_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_PROPERTY_IDS_STRUCT*)param; + /* Check for property ID match */ + /* Mark the access as prohibited, to indicate invalid Property ID */ + param_p->user_access = MS_GENERIC_USER_ACCESS_PROHIBITED; + + for (index = 0; index < MS_MAX_USER_PROPERTIES; index++) + { + if (appl_generic_user_property[0][index].property_id == param_p->property_id) + { + /* Check properties - write is permitted */ + if (MS_GENERIC_USER_ACCESS_READ != appl_generic_user_property[0][index].user_access) + { + /* Update Value */ + /* Free Memory */ + if (NULL != appl_generic_user_property[0][index].property_value) + { + EM_free_mem(appl_generic_user_property[0][index].property_value); + } + + /* Allocate Memory */ + appl_generic_user_property[0][index].property_value_len = param_p->property_value_len; + appl_generic_user_property[0][index].property_value = EM_alloc_mem(param_p->property_value_len); + /* TODO: Not checking memory allocation failure */ + /* Copy */ + EM_mem_copy(appl_generic_user_property[0][index].property_value, param_p->property_value, param_p->property_value_len); + } + + param_p->user_access = appl_generic_user_property[0][index].user_access; + param_p->property_value = appl_generic_user_property[0][index].property_value; + param_p->property_value_len = appl_generic_user_property[0][index].property_value_len; + printf("SSSEEETTTTTT::::USER::::: [%d] ID:0x%04X. Access:0x%02X. Len:%d\n", + index, appl_generic_admin_property[0][index].property_id, + appl_generic_admin_property[0][index].user_access, + appl_generic_admin_property[0][index].property_value_len); + break; + } + } + } + break; + + case MS_STATE_GENERIC_ADMIN_PROPERTY_T: + { + MS_STATE_GENERIC_USER_PROPERTY_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_PROPERTY_IDS_STRUCT*)param; + + /* Check for property ID match */ + /* Mark the access as prohibited, to indicate invalid Property ID */ + /* param_p->user_access = MS_GENERIC_USER_ACCESS_PROHIBITED; */ + + for (index = 0; index < MS_MAX_ADMIN_PROPERTIES; index++) + { + if (appl_generic_admin_property[0][index].property_id == param_p->property_id) + { + appl_generic_admin_property[0][index].user_access = param_p->user_access; + + /* Check properties - write is permitted */ + if (MS_GENERIC_USER_ACCESS_READ != appl_generic_admin_property[0][index].user_access) + { + /* Update Value */ + /* Free Memory */ + if (NULL != appl_generic_admin_property[0][index].property_value) + { + EM_free_mem(appl_generic_admin_property[0][index].property_value); + } + + /* Allocate Memory */ + appl_generic_admin_property[0][index].property_value_len = param_p->property_value_len; + appl_generic_admin_property[0][index].property_value = EM_alloc_mem(param_p->property_value_len); + /* TODO: Not checking memory allocation failure */ + /* Copy */ + EM_mem_copy(appl_generic_admin_property[0][index].property_value, param_p->property_value, param_p->property_value_len); + } + + param_p->user_access = appl_generic_admin_property[0][index].user_access; + param_p->property_value = appl_generic_admin_property[0][index].property_value; + param_p->property_value_len = appl_generic_admin_property[0][index].property_value_len; + printf("SSSSSSSEEETTTTTT::::ADMIN::::: [%d] ID:0x%04X. Access:0x%02X. Len:%d\n", + index, appl_generic_admin_property[0][index].property_id, + appl_generic_admin_property[0][index].user_access, + appl_generic_admin_property[0][index].property_value_len); + break; + } + } + } + break; + + case MS_STATE_GENERIC_MANUFACTURER_PROPERTY_T: + { + MS_STATE_GENERIC_USER_PROPERTY_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_PROPERTY_IDS_STRUCT*)param; + + /* Check for property ID match */ + /* Mark the access as prohibited, to indicate invalid Property ID */ + /* param_p->user_access = MS_GENERIC_USER_ACCESS_PROHIBITED; */ + for (index = 0; index < MS_MAX_MANUFACTURER_PROPERTIES; index++) + { + if (appl_generic_manufacturer_property[0][index].property_id == param_p->property_id) + { + appl_generic_manufacturer_property[0][index].user_access = param_p->user_access; + + /* Check properties - write is permitted */ + if (MS_GENERIC_USER_ACCESS_READ != appl_generic_manufacturer_property[0][index].user_access) + { + /* Update Value */ + /* Free Memory */ + if ((0 != param_p->property_value_len) && (NULL != appl_generic_manufacturer_property[0][index].property_value)) + { + EM_free_mem(appl_generic_manufacturer_property[0][index].property_value); + /* Allocate Memory */ + appl_generic_manufacturer_property[0][index].property_value_len = param_p->property_value_len; + appl_generic_manufacturer_property[0][index].property_value = EM_alloc_mem(param_p->property_value_len); + /* TODO: Not checking memory allocation failure */ + /* Copy */ + EM_mem_copy(appl_generic_manufacturer_property[0][index].property_value, param_p->property_value, param_p->property_value_len); + } + } + + { + appl_generic_user_property[0][index].user_access = param_p->user_access; + } + + param_p->user_access = appl_generic_manufacturer_property[0][index].user_access; + param_p->property_value = appl_generic_manufacturer_property[0][index].property_value; + param_p->property_value_len = appl_generic_manufacturer_property[0][index].property_value_len; + printf("SSSSSSSEEETTTTTT::::MANUFACTURER::::: [%d] ID:0x%04X. Access:0x%02X. Len:%d\n", + index, appl_generic_manufacturer_property[0][index].property_id, + appl_generic_manufacturer_property[0][index].user_access, + appl_generic_manufacturer_property[0][index].property_value_len); + break; + } + } + + /* Mark the access as prohibited, to indicate invalid Property ID */ + if (MS_MAX_MANUFACTURER_PROPERTIES == index) + { + param_p->user_access = MS_GENERIC_USER_ACCESS_INVALID_PROPERTY_ID; + param_p->property_value_len = 0; + } + } + break; + } +} + + diff --git a/src/components/ethermind/mesh/export/appl/model/server/generics/generic_property_server/appl_model_state_handler.h b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_property_server/appl_model_state_handler.h new file mode 100644 index 0000000..861625a --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/generics/generic_property_server/appl_model_state_handler.h @@ -0,0 +1,32 @@ +/** + \file appl_model_state_handler.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_MODEL_STATE_HANDLER_ +#define _H_APPL_MODEL_STATE_HANDLER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_main.h" +#include "MS_model_states.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void); + +void appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +void appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +#endif /*_H_APPL_MODEL_STATE_HANDLER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/health/appl_health_server.c b/src/components/ethermind/mesh/export/appl/model/server/health/appl_health_server.c new file mode 100644 index 0000000..92e3d18 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/health/appl_health_server.c @@ -0,0 +1,259 @@ +/** + \file appl_health_server.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_health_server.h" +#include "MS_health_server_api.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_health_server_options[] = "\n\ +======== Health Server Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 5. Publish No Fault in Master Credential. \n\ + 6. Publish No Fault in Friend Credential. \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_health_server_model_handle; + + +static void appl_health_self_test_00(UINT8 test_id, UINT16 company_id) +{ + UINT8 fault_code; + /* Dummy Function. Reports fault status by default */ + /* Dummy fault code */ + fault_code = (UINT8)(test_id + 1); + MS_health_server_report_fault + ( + &appl_health_server_model_handle, + test_id, + company_id, + fault_code + ); +} + +static void appl_health_self_test_02(UINT8 test_id, UINT16 company_id) +{ + UINT8 fault_code; + /* Dummy Function. Reports fault status by default */ + /* Dummy fault code */ + fault_code = (UINT8)(test_id + 1); + MS_health_server_report_fault + ( + &appl_health_server_model_handle, + test_id, + company_id, + fault_code + ); +} + +static void appl_health_self_test_FF(UINT8 test_id, UINT16 company_id) +{ + UINT8 fault_code; + /* Dummy Function. Reports fault status by default */ + /* Dummy fault code */ + fault_code = (UINT8)(test_id + 1); + MS_health_server_report_fault + ( + &appl_health_server_model_handle, + test_id, + company_id, + fault_code + ); +} + +/* List of Self Tests */ +static MS_HEALTH_SERVER_SELF_TEST appl_health_server_self_tests[] = +{ + { + 0x00, /* Test ID: 0x00 */ + appl_health_self_test_00 + }, + { + 0x02, /* Test ID: 0x02 */ + appl_health_self_test_02 + }, + { + 0xFF, /* Test ID: 0xFF */ + appl_health_self_test_FF + } +}; + +/* --------------------------------------------- Function */ +void appl_health_server_send_status(void) +{ + UCHAR current_status[4] = { 0x00, 0x6A, 0x00, 0x00 }; + MS_health_server_publish_current_status(current_status, sizeof(current_status)); +} + +/* health server application entry point */ +void main_health_server_operations(/* IN */ UINT8 have_menu) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + UINT16 company_id; + MS_HEALTH_SERVER_SELF_TEST* self_tests; + UINT32 num_self_tests; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + company_id = MS_DEFAULT_COMPANY_ID; + self_tests = &appl_health_server_self_tests[0]; + num_self_tests = sizeof(appl_health_server_self_tests)/sizeof(MS_HEALTH_SERVER_SELF_TEST); + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_health_server_init + ( + element_handle, + &appl_health_server_model_handle, + company_id, + self_tests, + num_self_tests, + appl_health_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Health Server Initialized. Model Handle: 0x%04X\n", + appl_health_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Sensor Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + if (MS_TRUE != have_menu) + { + CONSOLE_OUT("Not to use menu options\n"); + return; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_health_server_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 5: + appl_health_server_send_status(); + break; + } + } +} + +API_RESULT main_health_server_log_fault +( + /* IN */ UINT8 test_id, + /* IN */ UINT8 fault +) +{ + API_RESULT retval; + retval = MS_health_server_report_fault + ( + &appl_health_server_model_handle, + test_id, + MS_DEFAULT_COMPANY_ID, + fault + ); + return retval; +} + +/** + \brief Health Server application Asynchronous Notification Callback. + + \par Description + Health Server calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param event_type Health Server Event type. + \param event_param Parameter associated with the event if any or NULL. + \param param_len Size of the event parameter data. 0 if event param is NULL. +*/ +API_RESULT appl_health_server_cb +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT8 event_type, + UINT8* event_param, + UINT16 param_len +) +{ + CONSOLE_OUT( + "[Health Server Callback] Event Type: 0x%02X\n", event_type); + + switch (event_type) + { + case MS_HEALTH_SERVER_ATTENTION_START: + { + CONSOLE_OUT( + "[Health Server Callback] Attention Start. Attention Timeout: 0x%02X\n", + (*event_param)); + } + break; + + case MS_HEALTH_SERVER_ATTENTION_RESTART: + { + CONSOLE_OUT( + "[Health Server Callback] Attention Restart. Attention Timeout: 0x%02X\n", + (*event_param)); + } + break; + + case MS_HEALTH_SERVER_ATTENTION_STOP: + { + CONSOLE_OUT( + "[Health Server Callback] Attention Stop\n"); + } + break; + + default: + CONSOLE_OUT( + "Unhandled Event Type: 0x%02X\n", event_type); + } + + return API_SUCCESS; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/server/health/appl_health_server.h b/src/components/ethermind/mesh/export/appl/model/server/health/appl_health_server.h new file mode 100644 index 0000000..1bec3e9 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/health/appl_health_server.h @@ -0,0 +1,52 @@ +/** + \file appl_health_server.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_HEALTH_SERVER_ +#define _H_APPL_HEALTH_SERVER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_health_server_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* health server application entry point */ +void main_health_server_operations(/* IN */ UINT8 have_menu); + +/** + \brief Health Server application Asynchronous Notification Callback. + + \par Description + Health Server calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param event_type Health Server Event type. + \param event_param Parameter associated with the event if any or NULL. + \param param_len Size of the event parameter data. 0 if event param is NULL. +*/ +API_RESULT appl_health_server_cb +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT8 event_type, + UINT8* event_param, + UINT16 param_len +); + +void appl_health_server_send_status(void); + +#endif /*_H_APPL_HEALTH_SERVER_ */ + diff --git a/src/components/ethermind/mesh/export/appl/model/server/lighting/light_ctl_server/appl_light_ctl_server.c b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_ctl_server/appl_light_ctl_server.c new file mode 100644 index 0000000..8ab6a63 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_ctl_server/appl_light_ctl_server.c @@ -0,0 +1,766 @@ +/** + \file appl_light_ctl_server.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_light_ctl_server.h" +#include "appl_model_state_handler.h" +#include "MS_scene_api.h" +#include "MS_light_lightness_api.h" +#include "MS_generic_power_onoff_api.h" +#include "MS_generic_onoff_api.h" +#include "MS_generic_level_api.h" + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_light_ctl_server_options[] = "\n\ +======== Light_Ctl Server Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 2. Power Cycle. \n\ +\n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_light_ctl_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_light_ctl_setup_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_light_ctl_temperature_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_light_lightness_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_light_lightness_setup_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_power_onoff_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_power_onoff_setup_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_onoff_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_level_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_scene_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_scene_setup_server_model_handle; + +/* --------------------------------------------- Function */ +/* light_ctl server application entry point */ +void main_light_ctl_server_operations(/* IN */ UINT8 have_menu) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_light_ctl_server_init + ( + element_handle, + &appl_light_ctl_server_model_handle, + &appl_light_ctl_setup_server_model_handle, + appl_light_ctl_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Ctl Server Initialized. Model Handle: 0x%04X\n", + appl_light_ctl_server_model_handle); + CONSOLE_OUT( + "Light Ctl Setup Server Initialized. Model Handle: 0x%04X\n", + appl_light_ctl_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Ctl Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_light_ctl_temperature_server_init + ( + element_handle, + &appl_light_ctl_temperature_server_model_handle, + appl_light_ctl_temperature_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Ctl Temperature Server Initialized. Model Handle: 0x%04X\n", + appl_light_ctl_temperature_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Ctl Temperature Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_light_lightness_server_init + ( + element_handle, + &appl_light_lightness_server_model_handle, + appl_light_lightness_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Lightness Server Initialized. Model Handle: 0x%04X\n", + appl_light_lightness_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Lightness Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_light_lightness_setup_server_init + ( + element_handle, + &appl_light_lightness_setup_server_model_handle, + appl_light_lightness_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Lightness Setup Server Initialized. Model Handle: 0x%04X\n", + appl_light_lightness_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Lightness Setup Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_power_onoff_server_init + ( + element_handle, + &appl_generic_power_onoff_server_model_handle, + appl_generic_power_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Power Onoff Server Initialized. Model Handle: 0x%04X\n", + appl_generic_power_onoff_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Power Onoff Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_power_onoff_setup_server_init + ( + element_handle, + &appl_generic_power_onoff_setup_server_model_handle, + appl_generic_power_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Power Onoff Setup Server Initialized. Model Handle: 0x%04X\n", + appl_generic_power_onoff_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Power Onoff Setup Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_onoff_server_init + ( + element_handle, + &appl_generic_onoff_server_model_handle, + appl_generic_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Onoff Server Initialized. Model Handle: 0x%04X\n", + appl_generic_onoff_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Onoff Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + #if 0 + retval = MS_generic_default_transition_time_server_init + ( + element_handle, + &appl_generic_default_transition_time_server_model_handle, + NULL + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Default Transition Time Server Initialized. Model Handle: 0x%04X\n", + appl_generic_default_transition_time_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Default Transition Time Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + #endif + retval = MS_generic_level_server_init + ( + element_handle, + &appl_generic_level_server_model_handle, + appl_generic_level_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Level Server Initialized. Model Handle: 0x%04X\n", + appl_generic_level_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Level Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_scene_server_init + ( + element_handle, + &appl_scene_server_model_handle, + &appl_scene_setup_server_model_handle, + appl_scene_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Scene Server Initialized. Model Handle: 0x%04X\n", + appl_scene_server_model_handle); + CONSOLE_OUT( + "Scene Setup Server Initialized. Model Handle: 0x%04X\n", + appl_scene_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Scene Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + appl_model_states_initialization(); + model_initialized = 0x01; + } + + if (MS_TRUE != have_menu) + { + CONSOLE_OUT("Not to use menu options\n"); + return; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_light_ctl_server_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 2: + appl_model_power_cycle(); + break; + } + } +} + +#if 0 +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONOFF_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + /* Using same as target state and remaining time as 0 */ + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] SET Request.\n"); + retval = appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT("[GENERIC_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Level server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_level_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_LEVEL_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] SET Request.\n"); + + if ((MS_ACCESS_GENERIC_LEVEL_SET_OPCODE == msg_raw->opcode) || + (MS_ACCESS_GENERIC_LEVEL_SET_UNACKNOWLEDGED_OPCODE == msg_raw->opcode)) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Level SET Request.\n"); + } + else if ((MS_ACCESS_GENERIC_DELTA_SET_OPCODE == msg_raw->opcode) || + (MS_ACCESS_GENERIC_DELTA_SET_UNACKNOWLEDGED_OPCODE == msg_raw->opcode)) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Delta SET Request.\n"); + } + else if ((MS_ACCESS_GENERIC_MOVE_SET_OPCODE == msg_raw->opcode) || + (MS_ACCESS_GENERIC_MOVE_SET_UNACKNOWLEDGED_OPCODE == msg_raw->opcode)) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Move SET Request.\n"); + } + + /* TODO: Right now not handling different type of SET requests separately */ + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_LEVEL_STRUCT*)state_params->state, 0); + current_state_params.state_type = MS_STATE_GENERIC_LEVEL_T; + current_state_params.state = (MS_STATE_GENERIC_LEVEL_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_level_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_power_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONPOWERUP_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_power_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scene server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. + + TODO: Update +*/ +void* appl_scene_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT8 event_type, + /* IN */ void* event_param, + /* IN */ UINT16 event_length, + /* IN */ void* context +) +{ + void* param_p; + param_p = NULL; + + switch(event_type) + { + case MS_SCENE_EVENT_STORE: + { + param_p = appl_scene_save_current_state(*(UINT32*)event_param); + } + break; + + case MS_SCENE_EVENT_DELETE: + { + param_p = appl_scene_delete_saved_state(*(UINT32*)event_param, context); + } + break; + + case MS_SCENE_EVENT_RECALL_START: + { + } + break; + + case MS_SCENE_EVENT_RECALL_COMPLETE: + { + param_p = appl_scene_recall_saved_state(*(UINT32*)event_param, context); + } + break; + + case MS_SCENE_EVENT_RECALL_IMMEDIATE: + { + param_p = appl_scene_recall_saved_state(*(UINT32*)event_param, context); + } + break; + } + + return param_p; +} + + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Lightness server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_lightness_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_LIGHT_LIGHTNESS_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_lightness_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Ctl server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_ctl_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_STATE_LIGHT_CTL_STRUCT light_ctl_params; + MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_STRUCT light_ctl_temperature_range_params; + MS_STATE_LIGHT_CTL_DEFAULT_STRUCT light_ctl_default_params; + MS_STATE_LIGHT_CTL_TEMPERATURE_STRUCT light_ctl_temperature_params; + void* param_p; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_CTL] GET Request.\n"); + + switch (state_params->state_type) + { + case MS_STATE_LIGHT_CTL_DEFAULT_T: + { + param_p = &light_ctl_default_params; + } + break; + + case MS_STATE_LIGHT_CTL_T: + { + param_p = &light_ctl_params; + } + break; + + case MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_T: + { + param_p = &light_ctl_temperature_range_params; + } + break; + + case MS_STATE_LIGHT_CTL_TEMPERATURE_T: + { + param_p = &light_ctl_temperature_params; + } + break; + + default: + break; + } + + appl_model_state_get(state_params->state_type, 0, param_p, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param_p; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_CTL] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_CTL] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_ctl_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Ctl_Temperature server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_ctl_temperature_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_LIGHT_CTL_TEMPERATURE_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_CTL_TEMPERATURE] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_CTL_TEMPERATURE] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_LIGHT_CTL_TEMPERATURE_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_LIGHT_CTL_TEMPERATURE_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_CTL_TEMPERATURE] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_ctl_temperature_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +#endif /* 0 */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/lighting/light_ctl_server/appl_light_ctl_server.h b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_ctl_server/appl_light_ctl_server.h new file mode 100644 index 0000000..e8b6763 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_ctl_server/appl_light_ctl_server.h @@ -0,0 +1,186 @@ +/** + \file appl_light_ctl_server.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_LIGHT_CTL_SERVER_ +#define _H_APPL_LIGHT_CTL_SERVER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_light_ctl_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* light_ctl server application entry point */ +void main_light_ctl_server_operations(/* IN */ UINT8 have_menu); + +/* Get Model Handle */ +void appl_light_ctl_server_get_model_handle(void); + +/* Set Publish Address */ +void appl_light_ctl_server_set_publish_address(void); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Ctl server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_ctl_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Ctl_Temperature server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_ctl_temperature_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Lightness server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_lightness_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Level server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_level_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_power_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scene server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. + + TODO: Update +*/ +void* appl_scene_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT8 event_type, + /* IN */ void* event_param, + /* IN */ UINT16 event_length, + /* IN */ void* context +); + +#endif /*_H_APPL_LIGHT_CTL_SERVER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/lighting/light_ctl_server/appl_model_state_handler.c b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_ctl_server/appl_model_state_handler.c new file mode 100644 index 0000000..85c3dd3 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_ctl_server/appl_model_state_handler.c @@ -0,0 +1,1152 @@ +/** + \file appl_model_state_handler.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_model_state_handler.h" +#include "MS_common.h" + +/* --------------------------------------------- Global Definitions */ + +/* --------------------------------------------- Data Types/ Structures */ +#define MS_MAX_NUM_STATES 2 + +typedef struct _APPL_STATE_INFO_VAULT +{ + /* OnOff state */ + UINT8 onoff; + + /* Generic Level state */ + UINT16 level; + + /* Light Lightness Actual */ + UINT16 lightness_actual; + + /* Light Lightness Linear */ + UINT16 lightness_linear; + + /** Light CTL Lightness */ + UINT16 ctl_lightness; + + /** Light CTL Temperature */ + UINT16 ctl_temperature; + + /** Light CTL Delta UV */ + UINT16 ctl_delta_uv; + +} APPL_STATE_INFO_VAULT; + +typedef struct _APPL_GENENRIC_LEVEL_INFO +{ + MS_STATE_GENERIC_LEVEL_STRUCT generic_level; + + /* Operation Type : 0xFF as initial value (invalid) */ + UINT8 operation_type; + + UINT16 transition_time_handle; + +} APPL_GENERIC_LEVEL_INFO; + +static MS_STATE_LIGHT_LIGHTNESS_STRUCT appl_light_lightness[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_LIGHTNESS_STRUCT appl_light_lightness_setup[MS_MAX_NUM_STATES]; + +static MS_STATE_GENERIC_ONPOWERUP_STRUCT appl_generic_onpower[MS_MAX_NUM_STATES]; + +static MS_STATE_GENERIC_ONOFF_STRUCT appl_generic_onoff[MS_MAX_NUM_STATES]; + +/* static MS_STATE_GENERIC_LEVEL_STRUCT appl_generic_level[MS_MAX_NUM_STATES]; */ +static APPL_GENERIC_LEVEL_INFO appl_generic_level_info[MS_MAX_NUM_STATES]; + +static MS_STATE_LIGHT_CTL_STRUCT appl_light_ctl[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_STRUCT appl_light_ctl_temperature_range[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_CTL_DEFAULT_STRUCT appl_light_ctl_default[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_CTL_TEMPERATURE_STRUCT appl_light_ctl_temperature[MS_MAX_NUM_STATES]; + +/* For simplicity keeping same number of state info, as the number of max scences */ +static APPL_STATE_INFO_VAULT appl_state_info_vault[16]; +static UINT8 appl_in_transtion; + +void appl_light_lightness_set_actual(UINT16 state_inst, UINT16 actual); + +void appl_set_move_level(UINT16 state_inst, UINT16 move, UINT8 immediate); +void appl_set_level(UINT16 state_inst, UINT16 level); +void appl_set_delta_level(UINT16 state_inst, INT32 delta, UINT8 immediate); + +API_RESULT appl_generic_level_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); +void appl_set_generic_onoff(UINT16 state_inst, UINT8 onoff); +void appl_light_lightness_set_linear(UINT16 state_inst, UINT16 linear); +API_RESULT appl_model_light_ctl_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); +API_RESULT appl_model_light_ctl_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); +void appl_light_ctl_temp_set_actual(UINT16 state_inst, UINT16 actual); + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void) +{ + UINT32 index; + EM_mem_set (appl_light_lightness, 0, sizeof(appl_light_lightness)); + EM_mem_set (appl_light_lightness_setup, 0, sizeof(appl_light_lightness_setup)); + appl_light_lightness[0].light_lightness_last.lightness_last = 0xFFFF; + appl_light_lightness[1].light_lightness_last.lightness_last = 0xFFFF; + EM_mem_set(appl_generic_onpower, 0, sizeof(appl_generic_onpower)); + EM_mem_set(appl_generic_onoff, 0, sizeof(appl_generic_onoff)); + EM_mem_set(appl_state_info_vault, 0, sizeof(appl_state_info_vault)); + EM_mem_set (appl_light_ctl, 0, sizeof(appl_light_ctl)); + EM_mem_set(appl_light_ctl_temperature_range, 0, sizeof(appl_light_ctl_temperature_range)); + EM_mem_set(appl_light_ctl_default, 0, sizeof(appl_light_ctl_default)); + EM_mem_set (appl_light_ctl_temperature, 0, sizeof(appl_light_ctl_temperature)); + + for (index = 0; index < MS_MAX_NUM_STATES; index++) + { + EM_mem_set(&appl_generic_level_info[index], 0, sizeof(APPL_GENERIC_LEVEL_INFO)); + appl_generic_level_info[index].operation_type = 0xFF; + appl_generic_level_info[index].transition_time_handle = 0xFFFF; + appl_light_ctl_temperature_range[index].ctl_temperature_range_min = 0x320; + appl_light_ctl_temperature_range[index].ctl_temperature_range_max = 0x4E20; + appl_light_ctl_temperature[index].ctl_temperature = appl_light_ctl_temperature_range[index].ctl_temperature_range_min; + /* appl_light_ctl[index].ctl_temperature = appl_light_ctl_temperature[index].ctl_temperature; */ + appl_light_ctl_temp_set_actual(index, appl_light_ctl_temperature[index].ctl_temperature); + } + + appl_in_transtion = 0x00; +} + +void appl_model_power_cycle(void) +{ + appl_generic_onoff[0].transition_time = 0x00; + appl_generic_onoff[0].target_onoff = 0x00; + + /* */ + if (0x01 == appl_generic_onpower[0].onpowerup) + { + appl_set_generic_onoff(0, 0x01); + /* appl_light_ctl_temperature[0]. = appl_light_ctl_default[0].ctl_lightness; */ + appl_light_ctl_temperature[0].ctl_temperature = appl_light_ctl_default[0].ctl_temperature; + appl_light_ctl_temperature[0].ctl_delta_uv = appl_light_ctl_default[0].ctl_delta_uv; + } + else if (0x00 == appl_generic_onpower[0].onpowerup) + { + appl_set_generic_onoff(0, 0x00); + /* appl_light_ctl_temperature[0]. = appl_light_ctl_default[0].ctl_lightness; */ + appl_light_ctl_temperature[0].ctl_temperature = appl_light_ctl_default[0].ctl_temperature; + appl_light_ctl_temperature[0].ctl_delta_uv = appl_light_ctl_default[0].ctl_delta_uv; + } + /* else 0x02. Keep OnOff as before power down */ + /* TODO: Hack */ + else + { + appl_generic_onoff[0].onoff = 0x00; + } + + /* TODO: Hack */ + if (0x00 != appl_light_lightness[0].light_lightness_actual.transition_time) + { + appl_light_lightness[0].light_lightness_actual.lightness_actual = appl_light_lightness[0].light_lightness_actual.lightness_target; + appl_light_lightness[0].light_lightness_actual.transition_time = 0x00; + appl_light_lightness[0].light_lightness_actual.lightness_target = 0x00; + } + + if (0x00 != appl_light_ctl[0].transition_time) + { + /* TODO: Stop timer */ + appl_light_ctl[0].ctl_lightness = appl_light_ctl[0].target_ctl_lightness; + appl_light_ctl[0].ctl_temperature = appl_light_ctl[0].target_ctl_temperature; + appl_light_ctl[0].transition_time = 0x00; + appl_light_ctl[0].target_ctl_lightness = 0x0000; + appl_light_ctl[0].target_ctl_temperature = 0x0000; + } + + if (0x00 != appl_light_ctl_temperature[0].transition_time) + { + /* TODO: Stop timer */ + appl_light_ctl_temperature[0].ctl_temperature = appl_light_ctl_temperature[0].target_ctl_temperature; + appl_light_ctl_temperature[0].ctl_delta_uv = appl_light_ctl_temperature[0].target_ctl_delta_uv; + appl_light_ctl_temperature[0].transition_time = 0x00; + appl_light_ctl_temperature[0].target_ctl_temperature = 0x0000; + appl_light_ctl_temperature[0].target_ctl_delta_uv = 0x0000; + } +} + + +/* ---- State Transition Handlers */ + +static void appl_generic_onoff_transition_start_cb(void* blob) +{ + /** + Because binary states cannot support transitions, when changing to 0x01 (On), + the Generic OnOff state shall change immediately when the transition starts, + and when changing to 0x00, the state shall change when the transition finishes. + */ + #if 0 + if (0 == appl_generic_onoff[0].onoff) + { + appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; + } + + #endif +} + +static void appl_generic_onoff_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_generic_onoff[0].transition_time = 0; + /* appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; */ + appl_set_generic_onoff(0, appl_generic_onoff[0].target_onoff); + appl_generic_onoff[0].target_onoff = 0; +} + +static void appl_generic_level_transition_start_cb(void* blob) +{ + UINT16 state_t; + state_t = (UINT16)blob; +} + +static void appl_generic_level_transition_complete_cb(void* blob) +{ + UINT16 state_t; + state_t = (UINT16)blob; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + + switch (state_t) + { + case MS_STATE_GENERIC_LEVEL_T: + { + appl_set_level(0, appl_generic_level_info[0].generic_level.target_level); + } + break; + + case MS_STATE_DELTA_LEVEL_T: + { + appl_set_level(0, appl_generic_level_info[0].generic_level.target_level); + } + break; + + case MS_STATE_MOVE_LEVEL_T: + { + appl_set_move_level(0, appl_generic_level_info[0].generic_level.delta_level, 0x01); + /* TODO: Remove Bad Logic */ + appl_generic_level_info[0].generic_level.move_level = 0; + } + break; + } +} + +static void appl_light_lightness_transition_start_cb(void* blob) +{ +} + +static void appl_light_lightness_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_light_lightness[0].light_lightness_actual.transition_time = 0; + /* appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; */ + appl_light_lightness_set_actual(0, appl_light_lightness[0].light_lightness_actual.lightness_target); + appl_light_lightness[0].light_lightness_actual.lightness_target = 0; +} + +static void appl_light_lightness_linear_transition_start_cb(void* blob) +{ +} + +static void appl_light_lightness_linear_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_light_lightness[0].light_lightness_linear.transition_time = 0; + /* appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; */ + appl_light_lightness_set_linear(0, appl_light_lightness[0].light_lightness_linear.lightness_target); + appl_light_lightness[0].light_lightness_linear.lightness_target = 0; +} + +static void appl_light_ctl_transition_start_cb(void* blob) +{ +} + +static void appl_light_ctl_transition_complete_cb(void* blob) +{ + appl_light_ctl_temp_set_actual(0, appl_light_ctl[0].target_ctl_temperature); + appl_light_ctl[0].ctl_lightness = appl_light_ctl[0].target_ctl_lightness; + appl_light_lightness[0].light_lightness_actual.lightness_actual = appl_light_ctl[0].ctl_lightness; + appl_light_ctl[0].target_ctl_temperature = 0x0000; + appl_light_ctl[0].target_ctl_lightness = 0x0000; + appl_light_ctl[0].transition_time = 0x0000; +} + +static void appl_light_ctl_temperature_transition_start_cb(void* blob) +{ +} + +static void appl_light_ctl_temperature_transition_complete_cb(void* blob) +{ + appl_light_ctl_temp_set_actual(0, appl_light_ctl_temperature[0].target_ctl_temperature); +// appl_light_ctl_temperature[0].target_ctl_delta_uv = appl_light_ctl_temperature[0].target_ctl_delta_uv; + /* appl_light_lightness[0].light_lightness_actual.lightness_actual = appl_light_ctl[0].ctl_lightness; */ + appl_light_ctl_temperature[0].target_ctl_temperature = 0x0000; + appl_light_ctl_temperature[0].target_ctl_delta_uv= 0x0000; + appl_light_ctl_temperature[0].transition_time = 0x0000; +} + +void* appl_scene_save_current_state(/* IN */ UINT32 scene_index) +{ + /* Free previous context - if any */ + /* Empty right now - dummy returning the same scene index itself */ + /* Store current state */ + appl_state_info_vault[scene_index].onoff = appl_generic_onoff[0].onoff; + appl_state_info_vault[scene_index].level = appl_generic_level_info[0].generic_level.level; + appl_state_info_vault[scene_index].lightness_actual = appl_light_lightness[0].light_lightness_actual.lightness_actual; + appl_state_info_vault[scene_index].lightness_linear = appl_light_lightness[0].light_lightness_linear.lightness_linear; + appl_state_info_vault[scene_index].ctl_lightness = appl_light_ctl[0].ctl_lightness; + appl_state_info_vault[scene_index].ctl_temperature = appl_light_ctl[0].ctl_temperature; + appl_state_info_vault[scene_index].ctl_delta_uv = appl_light_ctl[0].ctl_delta_uv; + return (void*)scene_index; +} + +void* appl_scene_delete_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ + /* Free context - if any */ + /* Empty right now - dummy returning NULL */ + /* Invalid value */ + appl_state_info_vault[scene_index].onoff = 0x02; + appl_state_info_vault[scene_index].level = 0xFFFF; + appl_state_info_vault[scene_index].lightness_actual = 0x0000; + appl_state_info_vault[scene_index].lightness_linear = 0x0000; + appl_state_info_vault[scene_index].ctl_lightness = 0x0000; + appl_state_info_vault[scene_index].ctl_temperature = 0x0000; + appl_state_info_vault[scene_index].ctl_delta_uv = 0x0000; + return (void*)NULL; +} + +void* appl_scene_recall_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ + /* Recall context - if any */ + /* Empty right now - dummy returning NULL */ + /* appl_generic_onoff[0].onoff = appl_state_info_vault[scene_index].onoff; */ + appl_set_generic_onoff(0, appl_state_info_vault[scene_index].onoff); + appl_generic_level_info[0].generic_level.level = appl_state_info_vault[scene_index].level; + appl_light_lightness[0].light_lightness_actual.lightness_actual = appl_state_info_vault[scene_index].lightness_actual; + appl_light_lightness[0].light_lightness_linear.lightness_linear = appl_state_info_vault[scene_index].lightness_linear; + appl_light_ctl[0].ctl_lightness = appl_state_info_vault[scene_index].ctl_lightness; + appl_light_ctl[0].ctl_temperature = appl_state_info_vault[scene_index].ctl_temperature; + appl_light_ctl[0].ctl_delta_uv = appl_state_info_vault[scene_index].ctl_delta_uv; + return (void*)NULL; +} + +API_RESULT appl_model_light_lightness_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + MS_STATE_LIGHT_LIGHTNESS_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)param; + + switch (state_t) + { + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_default = appl_light_lightness[0].light_lightness_default; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_range = appl_light_lightness[0].light_lightness_range; + param_p->range_status = 0x00; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_linear = appl_light_lightness[0].light_lightness_linear; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_last = appl_light_lightness[0].light_lightness_last; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_actual = appl_light_lightness[0].light_lightness_actual; + } + break; + + default: + break; + } + + return API_SUCCESS; +} + +API_RESULT appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_ONPOWERUP_T: + { + MS_STATE_GENERIC_ONPOWERUP_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)param; + /* Ignoting Instance and direction right now */ + *param_p = appl_generic_onpower[0]; + } + break; + + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_generic_onoff[0]; + } + break; + + case MS_STATE_GENERIC_LEVEL_T: + { + MS_STATE_GENERIC_LEVEL_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_LEVEL_STRUCT*)param; + /* Ignoting Instance and direction right now */ + *param_p = appl_generic_level_info[0].generic_level; + param_p->level = appl_generic_level_info[0].generic_level.level + appl_generic_level_info[0].generic_level.delta_level; + + /* TODO: hack */ + if (0xFE == appl_generic_level_info[0].generic_level.transition_time) + { + param_p->transition_time = 0x3F; + } + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + retval = appl_model_light_lightness_state_get(state_t, state_inst, param, direction); + break; + + case MS_STATE_LIGHT_CTL_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_CTL_T: /* Fall Through */ + case MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_CTL_TEMPERATURE_T: + retval = appl_model_light_ctl_state_get(state_t, state_inst, param, direction); + break; + + default: + break; + } + + return retval; +} + +void appl_light_ctl_temp_set_actual(UINT16 state_inst, UINT16 actual) +{ + UINT16 min, max; + min = appl_light_ctl_temperature_range[state_inst].ctl_temperature_range_min; + max = appl_light_ctl_temperature_range[state_inst].ctl_temperature_range_max; + + /* Generic OnOff binding */ + if (0x0000 == actual) + { + /* appl_generic_onoff[state_inst].onoff = 0x00; */ + } + else + { + if ((0 != min) && (actual < min)) + { + actual = min; + } + else if ((0 != max) && (actual > max)) + { + actual = max; + } + + /* appl_generic_onoff[state_inst].onoff = 0x01; */ + /* appl_light_lightness[state_inst].light_lightness_last.lightness_last = actual; */ + } + + appl_light_ctl[state_inst].ctl_temperature = actual; + /* Light Lightness Linear = ((Actual)^2) / 65535 */ + /* appl_light_lightness[state_inst].light_lightness_linear.lightness_linear = ((actual * actual) + 65534) / 65535; */ + /* Generic Level = (Light CTL Temperature - T _MIN) * 65535 / (T_MAX - T_MIN) - 32768 */ + appl_generic_level_info[state_inst].generic_level.level = (((actual - min) * 0xFFFF) / (max - min)) - 32768; +} + +void appl_light_ctl_temp_set_range(UINT16 state_inst, UINT16 min, UINT16 max) +{ + UINT16 actual; + appl_light_ctl_temperature_range[state_inst].ctl_temperature_range_min = min; + appl_light_ctl_temperature_range[state_inst].ctl_temperature_range_max = max; + /* Check if actual to be updated */ + actual = appl_light_ctl[state_inst].ctl_temperature; + + if (actual < min) + { + appl_light_ctl[state_inst].ctl_temperature = min; + } + else if (actual > max) + { + appl_light_ctl[state_inst].ctl_temperature = max; + } +} + +void appl_light_lightness_set_actual(UINT16 state_inst, UINT16 actual) +{ + UINT16 min, max; + + /* Generic OnOff binding */ + if (0x0000 == actual) + { + appl_generic_onoff[state_inst].onoff= 0x00; + } + else + { + min = appl_light_lightness[state_inst].light_lightness_range.lightness_range_min; + max = appl_light_lightness[state_inst].light_lightness_range.lightness_range_max; + + if ((0 != min) && (actual < min)) + { + actual = min; + } + else if ((0 != max) && (actual > max)) + { + actual = max; + } + + appl_generic_onoff[state_inst].onoff = 0x01; + appl_light_lightness[state_inst].light_lightness_last.lightness_last = actual; + } + + appl_light_lightness[state_inst].light_lightness_actual.lightness_actual = actual; + appl_light_ctl[state_inst].ctl_lightness = actual; + /* Light Lightness Linear = ((Actual)^2) / 65535 */ + appl_light_lightness[state_inst].light_lightness_linear.lightness_linear = ((actual * actual) + 65534) / 65535; + appl_generic_level_info[state_inst].generic_level.level = actual - 32768; +} + +void appl_light_lightness_set_range(UINT16 state_inst, UINT16 min, UINT16 max) +{ + UINT16 actual; + appl_light_lightness[state_inst].light_lightness_range.lightness_range_min = min; + appl_light_lightness[state_inst].light_lightness_range.lightness_range_max = max; + /* Check if actual to be updated */ + actual = appl_light_lightness[state_inst].light_lightness_actual.lightness_actual; + + if (actual < min) + { + appl_light_lightness[state_inst].light_lightness_actual.lightness_actual = min; + } + else if (actual > max) + { + appl_light_lightness[state_inst].light_lightness_actual.lightness_actual = max; + } +} + +void appl_set_level(UINT16 state_inst, UINT16 level) +{ + UINT16 min, max; + appl_generic_level_info[state_inst].generic_level.level = level; + appl_generic_level_info[state_inst].generic_level.target_level = 0; + appl_generic_level_info[state_inst].generic_level.delta_level = 0; + appl_light_lightness_set_actual(0, level + 32768); + min = appl_light_ctl_temperature_range[state_inst].ctl_temperature_range_min; + max = appl_light_ctl_temperature_range[state_inst].ctl_temperature_range_max; + /* Light CTL Temperature = T_MIN + (Generic Level + 32768) * (T_MAX - T_MIN) / 65535 */ + appl_light_ctl_temperature[0].ctl_temperature = min + (((level + 32768) * (max - min)) / 65535); +} + +void appl_set_delta_level(UINT16 state_inst, INT32 delta, UINT8 immediate) +{ + /* TODO: See if this to be stored */ + if (0x01 == immediate) + { + appl_set_level(state_inst, (appl_generic_level_info[state_inst].generic_level.level + delta)); + } + else if (0x00 == immediate) + { + appl_generic_level_info[0].generic_level.target_level = (appl_generic_level_info[state_inst].generic_level.level + delta); + appl_generic_level_info[state_inst].generic_level.delta_level = delta; + } + else + { + /* Do nothing right now */ + } +} + +void appl_set_move_level(UINT16 state_inst, UINT16 move, UINT8 immediate) +{ + /* TODO: See if this to be stored */ + appl_generic_level_info[state_inst].generic_level.move_level = move; +} + +/* Todo: Remove the dependency */ +#include "math.h" + +void appl_light_lightness_set_linear(UINT16 state_inst, UINT16 linear) +{ + UINT16 actual; + UINT32 mul_val; + long double d; + /* appl_light_lightness[state_inst].light_lightness_linear.lightness_linear = linear; */ + mul_val = linear * 65535; + actual = (UINT16)sqrt(mul_val); + /* Light Lightness actual = sqrt(Linear * 65535) */ + appl_light_lightness_set_actual(state_inst, actual); +} + + +void appl_set_generic_onoff(UINT16 state_inst, UINT8 onoff) +{ + UINT16 actual; + /* TODO: See if this to be stored */ + appl_generic_onoff[state_inst].onoff = onoff; + + /* Binding */ + if (onoff == 0x00) + { + appl_light_lightness_set_actual(state_inst, 0x00); + } + else + { + if (0x0000 == appl_light_lightness[state_inst].light_lightness_default.lightness_default) + { + actual = appl_light_lightness[state_inst].light_lightness_last.lightness_last; + } + else + { + actual = appl_light_lightness[state_inst].light_lightness_default.lightness_default; + } + + appl_light_lightness_set_actual(state_inst, actual); + } +} + +API_RESULT appl_model_light_lightness_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + MS_STATE_LIGHT_LIGHTNESS_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)param; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: + { + /* Ignoring Instance and direction right now */ + appl_light_lightness[0].light_lightness_default = param_p->light_lightness_default; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: + { + /* Check range min and max */ + if (param_p->light_lightness_range.lightness_range_min > param_p->light_lightness_range.lightness_range_max) + { + /* TODO: add macro define */ + /** + Table 7.2: + 0x00 - Success + 0x01 - Cannot Set Range Min + 0x02 - Cannot Set Range Max + */ + param_p->range_status = 0x01; + #if 0 + appl_light_lightness[0].light_lightness_range = param_p->light_lightness_range; + param_p->light_lightness_range.lightness_range_min = 0x0000; + param_p->light_lightness_range.lightness_range_max = 0x0000; + #endif + } + else + { + /* Ignoring Instance and direction right now */ + appl_light_lightness[0].light_lightness_range = param_p->light_lightness_range; + param_p->range_status = 0x00; + } + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: + { + if (0 != param_p->light_lightness_linear.transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_lightness[0].light_lightness_linear.lightness_target = param_p->light_lightness_linear.lightness_linear; + appl_light_lightness[0].light_lightness_linear.transition_time = param_p->light_lightness_linear.transition_time; + transition.delay = param_p->light_lightness_linear.delay; + transition.transition_time = param_p->light_lightness_linear.transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_light_lightness_linear_transition_start_cb; + transition.transition_complete_cb = appl_light_lightness_linear_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + /* appl_generic_onoff[0].onoff = param_p->onoff; */ + appl_light_lightness_set_linear(0, param_p->light_lightness_linear.lightness_linear); + } + + *param_p = appl_light_lightness[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", param_p->light_lightness_linear.lightness_linear); + CONSOLE_OUT("[state] target: 0x%02X\n", param_p->light_lightness_linear.lightness_target); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", param_p->light_lightness_linear.transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: + { + /* Ignoring Instance and direction right now */ + appl_light_lightness[0].light_lightness_last = param_p->light_lightness_last; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + { + if (0 != param_p->light_lightness_actual.transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_lightness[0].light_lightness_actual.lightness_target = param_p->light_lightness_actual.lightness_actual; + appl_light_lightness[0].light_lightness_actual.transition_time = param_p->light_lightness_actual.transition_time; + transition.delay = param_p->light_lightness_actual.delay; + transition.transition_time = param_p->light_lightness_actual.transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_light_lightness_transition_start_cb; + transition.transition_complete_cb = appl_light_lightness_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + /* appl_generic_onoff[0].onoff = param_p->onoff; */ + appl_light_lightness_set_actual(0, param_p->light_lightness_actual.lightness_actual); + } + + *param_p = appl_light_lightness[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", param_p->light_lightness_actual.lightness_actual); + CONSOLE_OUT("[state] target: 0x%02X\n", param_p->light_lightness_actual.lightness_target); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", param_p->light_lightness_actual.transition_time); + /* Ignoring Instance and direction right now */ + /* param_p->light_lightness_actual.lightness_actual = appl_light_lightness[0].light_lightness_actual.lightness_actual; */ + } + break; + + default: + break; + } + + return retval; +} + +API_RESULT appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_ONPOWERUP_T: + { + MS_STATE_GENERIC_ONPOWERUP_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)param; + /* Ignoting Instance and direction right now */ + appl_generic_onpower[0] = *param_p; + } + break; + + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_generic_onoff[0].target_onoff = param_p->onoff; + appl_generic_onoff[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_generic_onoff_transition_start_cb; + transition.transition_complete_cb = appl_generic_onoff_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + /* appl_generic_onoff[0].onoff = param_p->onoff; */ + appl_set_generic_onoff(0, param_p->onoff); + } + + *param_p = appl_generic_onoff[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", appl_generic_onoff[0].onoff); + CONSOLE_OUT("[state] target: 0x%02X\n", appl_generic_onoff[0].target_onoff); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_generic_onoff[0].transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + case MS_STATE_GENERIC_LEVEL_T: /* Fall Through */ + case MS_STATE_DELTA_LEVEL_T: /* Fall Through */ + case MS_STATE_MOVE_LEVEL_T: + { + retval = appl_generic_level_model_state_set(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + retval = appl_model_light_lightness_state_set(state_t, state_inst, param, direction); + break; + + case MS_STATE_LIGHT_CTL_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_CTL_T: /* Fall Through */ + case MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_CTL_TEMPERATURE_T: + retval = appl_model_light_ctl_state_set(state_t, state_inst, param, direction); + break; + + default: + break; + } + + return retval; +} + +API_RESULT appl_generic_level_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + MS_STATE_GENERIC_LEVEL_STRUCT* param_p; + /** + Transaction State: + 0 : Start of Transaction + 1 : Continue + 2 : End of Transaction + */ + UINT8 transaction_state; + param_p = (MS_STATE_GENERIC_LEVEL_STRUCT*)param; + + switch (state_t) + { + case MS_STATE_GENERIC_LEVEL_T: + { + /* Ignoting Instance and direction right now */ + /* TODO: Not handling transaction state */ + { + MS_common_stop_transition_timer(appl_generic_level_info[0].transition_time_handle); + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + + if (0 == param_p->transition_time) + { + appl_set_level(0, param_p->level); + } + else + { + appl_generic_level_info[0].generic_level.target_level = param_p->level; + param_p->target_level = param_p->level; + } + } + } + break; + + case MS_STATE_DELTA_LEVEL_T: + { + /* Check if a new transaction */ + if (appl_generic_level_info[0].operation_type != state_t) + { + transaction_state = 0x00; + /* Stop associated Transaction Timer, if any */ + MS_common_stop_transition_timer(appl_generic_level_info[0].transition_time_handle); + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + appl_generic_level_info[0].operation_type = state_t; + appl_generic_level_info[0].generic_level.tid = param_p->tid; + } + else if (param_p->tid == appl_generic_level_info[0].generic_level.tid) + { + transaction_state = 0x01; + } + else + { + transaction_state = 0x02; + /* Stop associated Transaction Timer, if any */ + MS_common_stop_transition_timer(appl_generic_level_info[0].transition_time_handle); + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + appl_generic_level_info[0].operation_type = state_t; + appl_generic_level_info[0].generic_level.tid = param_p->tid; + } + + /* Ignoting Instance and direction right now */ + if (0 == param_p->transition_time) + { + if (0x02 == transaction_state) + { + appl_set_delta_level(0, (INT32)appl_generic_level_info[0].generic_level.delta_level, 0x01); + } + + /* Only update delta */ + appl_set_delta_level(0, (INT32)param_p->delta_level, 0x00); + } + else + { + appl_set_delta_level(0, (INT32)param_p->delta_level, 0x00); + } + } + break; + + case MS_STATE_MOVE_LEVEL_T: + { + /* Ignoting Instance and direction right now */ + if (0 == param_p->transition_time) + { + appl_set_move_level(0, param_p->move_level, 0x01); + } + else + { + appl_set_move_level(0, param_p->move_level, 0x00); + /* appl_generic_level_info[0].generic_level.target_level = 0x00; */ + appl_generic_level_info[0].generic_level.target_level = param_p->move_level * (param_p->transition_time & 0x3F); + /* TODO: Hardcoding */ + appl_generic_level_info[0].generic_level.target_level = 0x7FFF; + } + } + break; + + default: + break; + } + + /* TODO: Do we need to check if this is a new transaction? */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + appl_generic_level_info[0].generic_level.transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = (void*)state_t; + transition.transition_start_cb = appl_generic_level_transition_start_cb; + transition.transition_complete_cb = appl_generic_level_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &appl_generic_level_info[0].transition_time_handle + ); + } + + *param_p = appl_generic_level_info[0].generic_level; + param_p->level = appl_generic_level_info[0].generic_level.level + appl_generic_level_info[0].generic_level.delta_level; + + /* TODO: hack */ + if (0xFE == appl_generic_level_info[0].generic_level.transition_time) + { + param_p->transition_time = 0x3F; + } + + return API_SUCCESS; +} + +API_RESULT appl_model_light_ctl_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + switch(state_t) + { + case MS_STATE_LIGHT_CTL_DEFAULT_T: + { + MS_STATE_LIGHT_CTL_DEFAULT_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_CTL_DEFAULT_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_ctl_default[0]; + } + break; + + case MS_STATE_LIGHT_CTL_T: + { + MS_STATE_LIGHT_CTL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_CTL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_ctl[0]; + } + break; + + case MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_T: + { + MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_ctl_temperature_range[0]; + param_p->status = 0x00; + } + break; + + case MS_STATE_LIGHT_CTL_TEMPERATURE_T: + { + MS_STATE_LIGHT_CTL_TEMPERATURE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_CTL_TEMPERATURE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_ctl_temperature[0]; + } + break; + + default: + break; + } + + return API_SUCCESS; +} + +API_RESULT appl_model_light_ctl_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_LIGHT_CTL_DEFAULT_T: + { + MS_STATE_LIGHT_CTL_DEFAULT_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_CTL_DEFAULT_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_light_ctl_default[0] = *param_p; + } + break; + + case MS_STATE_LIGHT_CTL_T: + { + MS_STATE_LIGHT_CTL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_CTL_STRUCT*)param; + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_ctl[0].target_ctl_lightness = param_p->ctl_lightness; + appl_light_ctl[0].target_ctl_temperature = param_p->ctl_temperature; + appl_light_ctl[0].ctl_delta_uv = param_p->ctl_delta_uv; + appl_light_ctl[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_light_ctl_transition_start_cb; + transition.transition_complete_cb = appl_light_ctl_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + appl_light_ctl[0] = *param_p; + appl_light_ctl_temp_set_actual(0, param_p->ctl_temperature); + appl_light_lightness[state_inst].light_lightness_actual.lightness_actual = param_p->ctl_lightness; + } + + *param_p = appl_light_ctl[0]; + CONSOLE_OUT("[state] current Lightness: 0x%02X\n", appl_light_ctl[0].ctl_lightness); + CONSOLE_OUT("[state] target Lightness: 0x%02X\n", appl_light_ctl[0].target_ctl_lightness); + CONSOLE_OUT("[state] current Temperature: 0x%02X\n", appl_light_ctl[0].ctl_temperature); + CONSOLE_OUT("[state] target Temperature: 0x%02X\n", appl_light_ctl[0].target_ctl_temperature); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_light_ctl[0].transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + case MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_T: + { + MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_light_ctl_temp_set_range(0, param_p->ctl_temperature_range_min, param_p->ctl_temperature_range_max); + /* appl_light_ctl_temperature_range[0] = *param_p; */ + param_p->status = 0x00; + } + break; + + case MS_STATE_LIGHT_CTL_TEMPERATURE_T: + { + MS_STATE_LIGHT_CTL_TEMPERATURE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_CTL_TEMPERATURE_STRUCT*)param; + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_ctl_temperature[0].target_ctl_temperature = param_p->ctl_temperature; + appl_light_ctl_temperature[0].target_ctl_delta_uv = param_p->ctl_delta_uv; + appl_light_ctl_temperature[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_light_ctl_temperature_transition_start_cb; + transition.transition_complete_cb = appl_light_ctl_temperature_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + appl_light_ctl_temperature[0] = *param_p; + appl_light_ctl_temp_set_actual(0, param_p->ctl_temperature); + /* appl_light_lightness[state_inst].light_lightness_actual.lightness_actual = param_p->ctl_lightness; */ + } + + *param_p = appl_light_ctl_temperature[0]; + CONSOLE_OUT("[state] current Temperature: 0x%02X\n", appl_light_ctl_temperature[0].ctl_temperature); + CONSOLE_OUT("[state] target Temperature: 0x%02X\n", appl_light_ctl_temperature[0].target_ctl_temperature); + CONSOLE_OUT("[state] current Delta UV: 0x%02X\n", appl_light_ctl_temperature[0].ctl_delta_uv); + CONSOLE_OUT("[state] target Delta UV: 0x%02X\n", appl_light_ctl_temperature[0].ctl_delta_uv); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_light_ctl_temperature[0].transition_time); + } + break; + + default: + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/server/lighting/light_ctl_server/appl_model_state_handler.h b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_ctl_server/appl_model_state_handler.h new file mode 100644 index 0000000..6522267 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_ctl_server/appl_model_state_handler.h @@ -0,0 +1,32 @@ +/** + \file appl_model_state_handler.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_MODEL_STATE_HANDLER_ +#define _H_APPL_MODEL_STATE_HANDLER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_main.h" +#include "MS_model_states.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void); + +API_RESULT appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +API_RESULT appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +#endif /*_H_APPL_MODEL_STATE_HANDLER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/lighting/light_hsl_server/appl_light_hsl_server.c b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_hsl_server/appl_light_hsl_server.c new file mode 100644 index 0000000..5afd15b --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_hsl_server/appl_light_hsl_server.c @@ -0,0 +1,898 @@ +/** + \file appl_light_hsl_server.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_light_hsl_server.h" +#include "appl_model_state_handler.h" +#include "MS_scene_api.h" +#include "MS_light_lightness_api.h" +#include "MS_generic_power_onoff_api.h" +#include "MS_generic_onoff_api.h" +#include "MS_generic_level_api.h" + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_light_hsl_server_options[] = "\n\ +======== Light_Hsl Server Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 2. Power Cycle. \n\ +\n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_light_hsl_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_light_hsl_setup_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_light_hsl_hue_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_light_hsl_saturation_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_light_lightness_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_light_lightness_setup_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_power_onoff_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_power_onoff_setup_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_onoff_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_level_server_model_handle; + +#ifndef HSL_DONT_USE_MULTI_ELEMENTS + static MS_ACCESS_MODEL_HANDLE appl_generic_level_server_hue_model_handle; + static MS_ACCESS_MODEL_HANDLE appl_generic_level_server_saturation_model_handle; +#endif /* HSL_DONT_USE_MULTI_ELEMENTS */ + +static MS_ACCESS_MODEL_HANDLE appl_scene_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_scene_setup_server_model_handle; + +/* --------------------------------------------- Function */ +#ifndef HSL_DONT_USE_MULTI_ELEMENTS + extern MS_ACCESS_ELEMENT_HANDLE sec_element_handle; + extern MS_ACCESS_ELEMENT_HANDLE ter_element_handle; +#endif /* HSL_DONT_USE_MULTI_ELEMENTS */ + +/* light_hsl server application entry point */ +void main_light_hsl_server_operations(/* IN */ UINT8 have_menu) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_light_hsl_server_init + ( + element_handle, + &appl_light_hsl_server_model_handle, + &appl_light_hsl_setup_server_model_handle, + appl_light_hsl_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Hsl Server Initialized. Model Handle: 0x%04X\n", + appl_light_hsl_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Hsl Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + #ifndef HSL_DONT_USE_MULTI_ELEMENTS + /* Hue Element */ + element_handle = sec_element_handle; + #endif /* HSL_DONT_USE_MULTI_ELEMENTS */ + retval = MS_light_hsl_hue_server_init + ( + element_handle, + &appl_light_hsl_hue_server_model_handle, + appl_light_hsl_hue_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Hsl Hue Server Initialized. Model Handle: 0x%04X\n", + appl_light_hsl_hue_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Hsl Hue Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + #ifndef HSL_DONT_USE_MULTI_ELEMENTS + retval = MS_generic_level_server_init + ( + element_handle, + &appl_generic_level_server_hue_model_handle, + appl_generic_level_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Level Server Initialized. Model Handle: 0x%04X\n", + appl_generic_level_server_hue_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Level Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + /* Saturation Element */ + element_handle = ter_element_handle; + #endif /* HSL_DONT_USE_MULTI_ELEMENTS */ + retval = MS_light_hsl_saturation_server_init + ( + element_handle, + &appl_light_hsl_saturation_server_model_handle, + appl_light_hsl_saturation_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Hsl Saturation Server Initialized. Model Handle: 0x%04X\n", + appl_light_hsl_saturation_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Hsl Saturation Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + #ifndef HSL_DONT_USE_MULTI_ELEMENTS + retval = MS_generic_level_server_init + ( + element_handle, + &appl_generic_level_server_saturation_model_handle, + appl_generic_level_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Level Server Initialized. Model Handle: 0x%04X\n", + appl_generic_level_server_saturation_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Level Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + /* Use Default Element Handle (main). Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + #endif /* HSL_DONT_USE_MULTI_ELEMENTS */ + retval = MS_light_lightness_server_init + ( + element_handle, + &appl_light_lightness_server_model_handle, + appl_light_lightness_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Lightness Server Initialized. Model Handle: 0x%04X\n", + appl_light_lightness_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Lightness Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_light_lightness_setup_server_init + ( + element_handle, + &appl_light_lightness_setup_server_model_handle, + appl_light_lightness_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Lightness Setup Server Initialized. Model Handle: 0x%04X\n", + appl_light_lightness_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Lightness Setup Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_power_onoff_server_init + ( + element_handle, + &appl_generic_power_onoff_server_model_handle, + appl_generic_power_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Power Onoff Server Initialized. Model Handle: 0x%04X\n", + appl_generic_power_onoff_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Power Onoff Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_power_onoff_setup_server_init + ( + element_handle, + &appl_generic_power_onoff_setup_server_model_handle, + appl_generic_power_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Power Onoff Setup Server Initialized. Model Handle: 0x%04X\n", + appl_generic_power_onoff_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Power Onoff Setup Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_onoff_server_init + ( + element_handle, + &appl_generic_onoff_server_model_handle, + appl_generic_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Onoff Server Initialized. Model Handle: 0x%04X\n", + appl_generic_onoff_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Onoff Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + #if 0 + retval = MS_generic_default_transition_time_server_init + ( + element_handle, + &appl_generic_default_transition_time_server_model_handle, + NULL + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Default Transition Time Server Initialized. Model Handle: 0x%04X\n", + appl_generic_default_transition_time_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Default Transition Time Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + #endif + retval = MS_generic_level_server_init + ( + element_handle, + &appl_generic_level_server_model_handle, + appl_generic_level_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Level Server Initialized. Model Handle: 0x%04X\n", + appl_generic_level_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Level Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_scene_server_init + ( + element_handle, + &appl_scene_server_model_handle, + &appl_scene_setup_server_model_handle, + appl_scene_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Scene Server Initialized. Model Handle: 0x%04X\n", + appl_scene_server_model_handle); + CONSOLE_OUT( + "Scene Setup Server Initialized. Model Handle: 0x%04X\n", + appl_scene_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Scene Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + appl_model_states_initialization(); + model_initialized = 0x01; + } + + if (MS_TRUE != have_menu) + { + CONSOLE_OUT("Not to use menu options\n"); + return; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_light_hsl_server_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 2: + appl_model_power_cycle(); + break; + } + } +} + +#if 0 +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONOFF_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + /* Using same as target state and remaining time as 0 */ + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] SET Request.\n"); + retval = appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT("[GENERIC_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Level server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_level_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_LEVEL_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] SET Request.\n"); + + if ((MS_ACCESS_GENERIC_LEVEL_SET_OPCODE == msg_raw->opcode) || + (MS_ACCESS_GENERIC_LEVEL_SET_UNACKNOWLEDGED_OPCODE == msg_raw->opcode)) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Level SET Request.\n"); + } + else if ((MS_ACCESS_GENERIC_DELTA_SET_OPCODE == msg_raw->opcode) || + (MS_ACCESS_GENERIC_DELTA_SET_UNACKNOWLEDGED_OPCODE == msg_raw->opcode)) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Delta SET Request.\n"); + } + else if ((MS_ACCESS_GENERIC_MOVE_SET_OPCODE == msg_raw->opcode) || + (MS_ACCESS_GENERIC_MOVE_SET_UNACKNOWLEDGED_OPCODE == msg_raw->opcode)) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Move SET Request.\n"); + } + + /* TODO: Right now not handling different type of SET requests separately */ + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_LEVEL_STRUCT*)state_params->state, 0); + current_state_params.state_type = MS_STATE_GENERIC_LEVEL_T; + current_state_params.state = (MS_STATE_GENERIC_LEVEL_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_level_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_power_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONPOWERUP_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_power_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scene server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. + + TODO: Update +*/ +void* appl_scene_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT8 event_type, + /* IN */ void* event_param, + /* IN */ UINT16 event_length, + /* IN */ void* context +) +{ + void* param_p; + param_p = NULL; + + switch(event_type) + { + case MS_SCENE_EVENT_STORE: + { + param_p = appl_scene_save_current_state(*(UINT32*)event_param); + } + break; + + case MS_SCENE_EVENT_DELETE: + { + param_p = appl_scene_delete_saved_state(*(UINT32*)event_param, context); + } + break; + + case MS_SCENE_EVENT_RECALL_START: + { + } + break; + + case MS_SCENE_EVENT_RECALL_COMPLETE: + { + param_p = appl_scene_recall_saved_state(*(UINT32*)event_param, context); + } + break; + + case MS_SCENE_EVENT_RECALL_IMMEDIATE: + { + param_p = appl_scene_recall_saved_state(*(UINT32*)event_param, context); + } + break; + } + + return param_p; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Lightness server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_lightness_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_LIGHT_LIGHTNESS_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_lightness_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Hsl server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_hsl_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_STATE_LIGHT_HSL_STRUCT param; + MS_STATE_LIGHT_HSL_RANGE_STRUCT param_range; + MS_STATE_LIGHT_HSL_DEFAULT_STRUCT param_default; + void* param_p; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_HSL] GET Request.\n"); + + switch (state_params->state_type) + { + case MS_STATE_LIGHT_HSL_T: + case MS_STATE_LIGHT_HSL_HUE_T: + case MS_STATE_LIGHT_HSL_SATURATION_T: + case MS_STATE_LIGHT_HSL_TARGET_T: + { + param_p = ¶m; + } + break; + + case MS_STATE_LIGHT_HSL_DEFAULT_T: + { + param_p = ¶m_default; + } + break; + + case MS_STATE_LIGHT_HSL_RANGE_T: + { + param_p = ¶m_range; + } + break; + + default: + break; + } + + appl_model_state_get(state_params->state_type, 0, param_p, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param_p; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_HSL] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_HSL] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_hsl_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Hsl_Hue server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_hsl_hue_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_LIGHT_HSL_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_HSL_HUE] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_HSL_HUE] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_HSL_HUE] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_hsl_hue_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Hsl_Saturation server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_hsl_saturation_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_LIGHT_HSL_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_HSL_SATURATION] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_HSL_SATURATION] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_HSL_SATURATION] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_hsl_saturation_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +#endif /* 0 */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/lighting/light_hsl_server/appl_light_hsl_server.h b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_hsl_server/appl_light_hsl_server.h new file mode 100644 index 0000000..b363f44 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_hsl_server/appl_light_hsl_server.h @@ -0,0 +1,228 @@ +/** + \file appl_light_hsl_server.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_LIGHT_HSL_SERVER_ +#define _H_APPL_LIGHT_HSL_SERVER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_light_hsl_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* light_hsl server application entry point */ +void main_light_hsl_server_operations(/* IN */ UINT8 have_menu); + +/* Get Model Handle */ +void appl_light_hsl_server_get_model_handle(void); + +/* Set Publish Address */ +void appl_light_hsl_server_set_publish_address(void); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Hsl server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_hsl_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Hsl_Hue server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_hsl_hue_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Hsl_Saturation server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_hsl_saturation_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Ctl_Temperature server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_ctl_temperature_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Lightness server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_lightness_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Level server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_level_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_power_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scene server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. + + TODO: Update +*/ +void* appl_scene_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT8 event_type, + /* IN */ void* event_param, + /* IN */ UINT16 event_length, + /* IN */ void* context +); + +#endif /*_H_APPL_LIGHT_HSL_SERVER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/lighting/light_hsl_server/appl_model_state_handler.c b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_hsl_server/appl_model_state_handler.c new file mode 100644 index 0000000..b377f91 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_hsl_server/appl_model_state_handler.c @@ -0,0 +1,1301 @@ +/** + \file appl_model_state_handler.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_model_state_handler.h" +#include "MS_common.h" + +/* --------------------------------------------- Global Definitions */ + +/* --------------------------------------------- Data Types/ Structures */ +#define MS_MAX_NUM_STATES 2 + +typedef struct _APPL_STATE_INFO_VAULT +{ + /* OnOff state */ + UINT8 onoff; + + /* Generic Level state */ + UINT16 level; + + /* Light Lightness Actual */ + UINT16 lightness_actual; + + /* Light Lightness Linear */ + UINT16 lightness_linear; + + /** Light CTL Lightness */ + UINT16 ctl_lightness; + + /** Light CTL Temperature */ + UINT16 ctl_temperature; + + /** Light CTL Delta UV */ + UINT16 ctl_delta_uv; + + /** The perceived lightness of a light emitted by the element */ + UINT16 hsl_lightness; + + /** The 16-bit value representing the hue */ + UINT16 hsl_hue; + + /** The saturation of a color light */ + UINT16 hsl_saturation; + +} APPL_STATE_INFO_VAULT; + +typedef struct _APPL_GENENRIC_LEVEL_INFO +{ + MS_STATE_GENERIC_LEVEL_STRUCT generic_level; + + /* Operation Type : 0xFF as initial value (invalid) */ + UINT8 operation_type; + + UINT16 transition_time_handle; + +} APPL_GENERIC_LEVEL_INFO; + +static MS_STATE_LIGHT_LIGHTNESS_STRUCT appl_light_lightness[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_LIGHTNESS_STRUCT appl_light_lightness_setup[MS_MAX_NUM_STATES]; + +static MS_STATE_GENERIC_ONPOWERUP_STRUCT appl_generic_onpower[MS_MAX_NUM_STATES]; + +static MS_STATE_GENERIC_ONOFF_STRUCT appl_generic_onoff[MS_MAX_NUM_STATES]; + +/* static MS_STATE_GENERIC_LEVEL_STRUCT appl_generic_level[MS_MAX_NUM_STATES]; */ +static APPL_GENERIC_LEVEL_INFO appl_generic_level_info[MS_MAX_NUM_STATES]; + +static MS_STATE_LIGHT_HSL_STRUCT appl_light_hsl[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_HSL_RANGE_STRUCT appl_light_hsl_range[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_HSL_DEFAULT_STRUCT appl_light_hsl_default[MS_MAX_NUM_STATES]; + +/* For simplicity keeping same number of state info, as the number of max scences */ +static APPL_STATE_INFO_VAULT appl_state_info_vault[16]; +static UINT8 appl_in_transtion; + +void appl_light_lightness_set_actual(UINT16 state_inst, UINT16 actual); + +void appl_set_move_level(UINT16 state_inst, UINT16 move, UINT8 immediate); +void appl_set_level(UINT16 state_inst, UINT16 level); +void appl_set_delta_level(UINT16 state_inst, INT32 delta, UINT8 immediate); + +API_RESULT appl_generic_level_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); +void appl_set_generic_onoff(UINT16 state_inst, UINT8 onoff); +void appl_light_lightness_set_linear(UINT16 state_inst, UINT16 linear); +API_RESULT appl_model_light_hsl_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); +API_RESULT appl_model_light_hsl_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); +/* void appl_light_ctl_temp_set_actual(UINT16 state_inst, UINT16 actual); */ +void appl_light_hsl_set_hue(UINT16 state_inst, UINT16 actual); +void appl_light_hsl_set_saturation(UINT16 state_inst, UINT16 actual); + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void) +{ + UINT32 index; + EM_mem_set (appl_light_lightness, 0, sizeof(appl_light_lightness)); + EM_mem_set (appl_light_lightness_setup, 0, sizeof(appl_light_lightness_setup)); + appl_light_lightness[0].light_lightness_last.lightness_last = 0xFFFF; + appl_light_lightness[1].light_lightness_last.lightness_last = 0xFFFF; + EM_mem_set(appl_generic_onpower, 0, sizeof(appl_generic_onpower)); + EM_mem_set(appl_generic_onoff, 0, sizeof(appl_generic_onoff)); + EM_mem_set(appl_state_info_vault, 0, sizeof(appl_state_info_vault)); + EM_mem_set (appl_light_hsl, 0, sizeof(appl_light_hsl)); + EM_mem_set(appl_light_hsl_range, 0, sizeof(appl_light_hsl_range)); + EM_mem_set(appl_light_hsl_default, 0, sizeof(appl_light_hsl_default)); + + for (index = 0; index < MS_MAX_NUM_STATES; index++) + { + EM_mem_set(&appl_generic_level_info[index], 0, sizeof(APPL_GENERIC_LEVEL_INFO)); + appl_generic_level_info[index].operation_type = 0xFF; + appl_generic_level_info[index].transition_time_handle = 0xFFFF; + /* appl_light_ctl[index].ctl_temperature = appl_light_ctl_temperature[index].ctl_temperature; */ + /* appl_light_ctl_temp_set_actual(index, appl_light_ctl_temperature[index].ctl_temperature); */ + appl_light_hsl_set_hue(index, 0x0000); + appl_light_hsl_set_saturation(index, 0x0000); + } + + appl_in_transtion = 0x00; +} + +void appl_model_power_cycle(void) +{ + appl_generic_onoff[0].transition_time = 0x00; + appl_generic_onoff[0].target_onoff = 0x00; + + /* */ + if (0x01 == appl_generic_onpower[0].onpowerup) + { + /* appl_light_ctl_temperature[0]. = appl_light_ctl_default[0].ctl_lightness; */ + /* appl_light_ctl_temperature[0].ctl_temperature = appl_light_ctl_default[0].ctl_temperature; */ + /* appl_light_ctl_temperature[0].ctl_delta_uv = appl_light_ctl_default[0].ctl_delta_uv; */ + appl_light_hsl[0].hsl_hue = appl_light_hsl_default[0].hsl_hue; + appl_light_hsl[0].hsl_lightness = appl_light_hsl_default[0].hsl_lightness; + appl_light_hsl[0].hsl_saturation = appl_light_hsl_default[0].hsl_saturation; + appl_set_generic_onoff(0, 0x01); + /* TODO: Hack */ + appl_light_hsl[0].hsl_lightness = 0xFF; + } + else if (0x00 == appl_generic_onpower[0].onpowerup) + { + /* appl_light_ctl_temperature[0]. = appl_light_ctl_default[0].ctl_lightness; */ + /* appl_light_ctl_temperature[0].ctl_temperature = appl_light_ctl_default[0].ctl_temperature; */ + /* appl_light_ctl_temperature[0].ctl_delta_uv = appl_light_ctl_default[0].ctl_delta_uv; */ + appl_light_hsl[0].hsl_hue = appl_light_hsl_default[0].hsl_hue; + appl_light_hsl[0].hsl_lightness = appl_light_hsl_default[0].hsl_lightness; + appl_light_hsl[0].hsl_saturation = appl_light_hsl_default[0].hsl_saturation; + appl_set_generic_onoff(0, 0x00); + } + /* else 0x02. Keep OnOff as before power down */ + /* TODO: Hack */ + else + { + appl_generic_onoff[0].onoff = 0x00; + } + + /* TODO: Hack */ + if (0x00 != appl_light_lightness[0].light_lightness_actual.transition_time) + { + appl_light_lightness[0].light_lightness_actual.lightness_actual = appl_light_lightness[0].light_lightness_actual.lightness_target; + appl_light_lightness[0].light_lightness_actual.transition_time = 0x00; + appl_light_lightness[0].light_lightness_actual.lightness_target = 0x00; + } + + if (0x00 != appl_light_hsl[0].transition_time) + { + /* TODO: Stop timer */ + appl_light_hsl[0].hsl_hue = appl_light_hsl[0].target_hsl_hue; + appl_light_hsl[0].hsl_saturation = appl_light_hsl[0].target_hsl_saturation; + appl_light_hsl[0].hsl_lightness = appl_light_hsl[0].target_hsl_lightness; + appl_light_hsl[0].transition_time = 0x00; + appl_light_hsl[0].target_hsl_hue = 0x0000; + appl_light_hsl[0].target_hsl_saturation = 0x0000; + appl_light_hsl[0].target_hsl_lightness = 0x0000; + } +} + + +/* ---- State Transition Handlers */ + +static void appl_generic_onoff_transition_start_cb(void* blob) +{ + /** + Because binary states cannot support transitions, when changing to 0x01 (On), + the Generic OnOff state shall change immediately when the transition starts, + and when changing to 0x00, the state shall change when the transition finishes. + */ + #if 0 + if (0 == appl_generic_onoff[0].onoff) + { + appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; + } + + #endif +} + +static void appl_generic_onoff_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_generic_onoff[0].transition_time = 0; + /* appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; */ + appl_set_generic_onoff(0, appl_generic_onoff[0].target_onoff); + appl_generic_onoff[0].target_onoff = 0; +} + +static void appl_generic_level_transition_start_cb(void* blob) +{ + UINT16 state_t; + state_t = (UINT16)blob; +} + +static void appl_generic_level_transition_complete_cb(void* blob) +{ + UINT16 state_t; + state_t = (UINT16)blob; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + + switch (state_t) + { + case MS_STATE_GENERIC_LEVEL_T: + { + appl_set_level(0, appl_generic_level_info[0].generic_level.target_level); + } + break; + + case MS_STATE_DELTA_LEVEL_T: + { + appl_set_level(0, appl_generic_level_info[0].generic_level.target_level); + } + break; + + case MS_STATE_MOVE_LEVEL_T: + { + appl_set_move_level(0, appl_generic_level_info[0].generic_level.delta_level, 0x01); + /* TODO: Remove Bad Logic */ + appl_generic_level_info[0].generic_level.move_level = 0; + } + break; + } +} + +static void appl_light_lightness_transition_start_cb(void* blob) +{ +} + +static void appl_light_lightness_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_light_lightness[0].light_lightness_actual.transition_time = 0; + /* appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; */ + appl_light_lightness_set_actual(0, appl_light_lightness[0].light_lightness_actual.lightness_target); + appl_light_lightness[0].light_lightness_actual.lightness_target = 0; +} + +static void appl_light_lightness_linear_transition_start_cb(void* blob) +{ +} + +static void appl_light_lightness_linear_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_light_lightness[0].light_lightness_linear.transition_time = 0; + /* appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; */ + appl_light_lightness_set_linear(0, appl_light_lightness[0].light_lightness_linear.lightness_target); + appl_light_lightness[0].light_lightness_linear.lightness_target = 0; +} + +static void appl_light_hsl_transition_start_cb(void* blob) +{ +} + +static void appl_light_hsl_transition_complete_cb(void* blob) +{ + UINT16 state_t; + state_t = (UINT16)blob; + appl_light_hsl[0].transition_time = 0x00; + + switch(state_t) + { + case MS_STATE_LIGHT_HSL_T: + { + appl_light_hsl[0].hsl_hue = appl_light_hsl[0].target_hsl_hue; + appl_light_hsl[0].hsl_saturation = appl_light_hsl[0].target_hsl_saturation; + appl_light_hsl[0].hsl_lightness = appl_light_hsl[0].target_hsl_lightness; + appl_light_lightness[0].light_lightness_actual.lightness_actual = appl_light_hsl[0].hsl_lightness; + appl_light_hsl[0].target_hsl_hue = 0x0000; + appl_light_hsl[0].target_hsl_saturation = 0x0000; + appl_light_hsl[0].target_hsl_lightness = 0x0000; + } + break; + + case MS_STATE_LIGHT_HSL_SATURATION_T: + { + appl_light_hsl_set_saturation(0, appl_light_hsl[0].target_hsl_saturation); + appl_light_hsl[0].target_hsl_saturation = 0x0000; + } + break; + + case MS_STATE_LIGHT_HSL_HUE_T: + { + appl_light_hsl_set_hue(0, appl_light_hsl[0].target_hsl_hue); + appl_light_hsl[0].target_hsl_hue = 0x0000; + } + break; + } + + #if 0 + appl_light_ctl_temp_set_actual(0, appl_light_ctl[0].target_ctl_temperature); + appl_light_ctl[0].ctl_lightness = appl_light_ctl[0].target_ctl_lightness; + appl_light_lightness[0].light_lightness_actual.lightness_actual = appl_light_ctl[0].ctl_lightness; + appl_light_ctl[0].target_ctl_temperature = 0x0000; + appl_light_ctl[0].target_ctl_lightness = 0x0000; + appl_light_ctl[0].transition_time = 0x0000; + #endif /* 0 */ +} + +void* appl_scene_save_current_state(/* IN */ UINT32 scene_index) +{ + /* Free previous context - if any */ + /* Empty right now - dummy returning the same scene index itself */ + /* Store current state */ + appl_state_info_vault[scene_index].onoff = appl_generic_onoff[0].onoff; + appl_state_info_vault[scene_index].level = appl_generic_level_info[0].generic_level.level; + appl_state_info_vault[scene_index].lightness_actual = appl_light_lightness[0].light_lightness_actual.lightness_actual; + appl_state_info_vault[scene_index].lightness_linear = appl_light_lightness[0].light_lightness_linear.lightness_linear; + appl_state_info_vault[scene_index].hsl_hue = appl_light_hsl[0].hsl_hue; + appl_state_info_vault[scene_index].hsl_saturation = appl_light_hsl[0].hsl_saturation; + appl_state_info_vault[scene_index].hsl_lightness = appl_light_hsl[0].hsl_lightness; + return (void*)scene_index; +} + +void* appl_scene_delete_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ + /* Free context - if any */ + /* Empty right now - dummy returning NULL */ + /* Invalid value */ + appl_state_info_vault[scene_index].onoff = 0x02; + appl_state_info_vault[scene_index].level = 0xFFFF; + appl_state_info_vault[scene_index].lightness_actual = 0x0000; + appl_state_info_vault[scene_index].lightness_linear = 0x0000; + appl_state_info_vault[scene_index].ctl_lightness = 0x0000; + appl_state_info_vault[scene_index].ctl_temperature = 0x0000; + appl_state_info_vault[scene_index].ctl_delta_uv = 0x0000; + return (void*)NULL; +} + +void* appl_scene_recall_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ + /* Recall context - if any */ + /* Empty right now - dummy returning NULL */ + /* appl_generic_onoff[0].onoff = appl_state_info_vault[scene_index].onoff; */ + appl_set_generic_onoff(0, appl_state_info_vault[scene_index].onoff); + appl_generic_level_info[0].generic_level.level = appl_state_info_vault[scene_index].level; + appl_light_lightness[0].light_lightness_actual.lightness_actual = appl_state_info_vault[scene_index].lightness_actual; + appl_light_lightness[0].light_lightness_linear.lightness_linear = appl_state_info_vault[scene_index].lightness_linear; + appl_light_hsl[0].hsl_hue = appl_state_info_vault[scene_index].hsl_hue; + appl_light_hsl[0].hsl_saturation = appl_state_info_vault[scene_index].hsl_saturation; + appl_light_hsl[0].hsl_lightness = appl_state_info_vault[scene_index].hsl_lightness; + return (void*)NULL; +} + +API_RESULT appl_model_light_lightness_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + MS_STATE_LIGHT_LIGHTNESS_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)param; + + switch (state_t) + { + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_default = appl_light_lightness[0].light_lightness_default; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_range = appl_light_lightness[0].light_lightness_range; + param_p->range_status = 0x00; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_linear = appl_light_lightness[0].light_lightness_linear; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_last = appl_light_lightness[0].light_lightness_last; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_actual = appl_light_lightness[0].light_lightness_actual; + } + break; + + default: + break; + } + + return API_SUCCESS; +} + +API_RESULT appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_ONPOWERUP_T: + { + MS_STATE_GENERIC_ONPOWERUP_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)param; + /* Ignoting Instance and direction right now */ + *param_p = appl_generic_onpower[0]; + } + break; + + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_generic_onoff[0]; + } + break; + + case MS_STATE_GENERIC_LEVEL_T: + { + MS_STATE_GENERIC_LEVEL_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_LEVEL_STRUCT*)param; + /* Ignoting Instance and direction right now */ + *param_p = appl_generic_level_info[0].generic_level; + param_p->level = appl_generic_level_info[0].generic_level.level + appl_generic_level_info[0].generic_level.delta_level; + + /* TODO: hack */ + if (0xFE == appl_generic_level_info[0].generic_level.transition_time) + { + param_p->transition_time = 0x3F; + } + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + retval = appl_model_light_lightness_state_get(state_t, state_inst, param, direction); + break; + + case MS_STATE_LIGHT_HSL_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_TARGET_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_HUE_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_SATURATION_T: + retval = appl_model_light_hsl_state_get(state_t, state_inst, param, direction); + break; + + default: + break; + } + + return retval; +} + +void appl_light_hsl_set_hue(UINT16 state_inst, UINT16 actual) +{ + UINT16 min, max; + min = appl_light_hsl_range[state_inst].hue_range_min; + max = appl_light_hsl_range[state_inst].hue_range_max; + + /* Generic OnOff binding */ + if (0x0000 == actual) + { + /* appl_generic_onoff[state_inst].onoff = 0x00; */ + } + else + { + if ((0 != min) && (actual < min)) + { + actual = min; + } + else if ((0 != max) && (actual > max)) + { + actual = max; + } + + /* appl_generic_onoff[state_inst].onoff = 0x01; */ + /* appl_light_lightness[state_inst].light_lightness_last.lightness_last = actual; */ + } + + appl_light_hsl[state_inst].hsl_hue = actual; + /* Light Lightness Linear = ((Actual)^2) / 65535 */ + /* appl_light_lightness[state_inst].light_lightness_linear.lightness_linear = ((actual * actual) + 65534) / 65535; */ + /* Generic Level = (Light CTL Temperature - T _MIN) * 65535 / (T_MAX - T_MIN) - 32768 */ + appl_generic_level_info[state_inst].generic_level.level = actual - 32768; +} + +void appl_light_hsl_set_saturation(UINT16 state_inst, UINT16 actual) +{ + UINT16 min, max; + min = appl_light_hsl_range[state_inst].saturation_range_min; + max = appl_light_hsl_range[state_inst].saturation_range_max; + + /* Generic OnOff binding */ + if (0x0000 == actual) + { + /* appl_generic_onoff[state_inst].onoff = 0x00; */ + } + else + { + if ((0 != min) && (actual < min)) + { + actual = min; + } + else if ((0 != max) && (actual > max)) + { + actual = max; + } + + /* appl_generic_onoff[state_inst].onoff = 0x01; */ + /* appl_light_lightness[state_inst].light_lightness_last.lightness_last = actual; */ + } + + appl_light_hsl[state_inst].hsl_saturation = actual; + /* Light Lightness Linear = ((Actual)^2) / 65535 */ + /* appl_light_lightness[state_inst].light_lightness_linear.lightness_linear = ((actual * actual) + 65534) / 65535; */ + /* Generic Level = (Light CTL Temperature - T _MIN) * 65535 / (T_MAX - T_MIN) - 32768 */ + appl_generic_level_info[state_inst].generic_level.level = actual - 32768; +} + +void appl_light_hsl_set_range(UINT16 state_inst, UINT16 hue_min, UINT16 hue_max, UINT16 saturation_min, UINT16 saturation_max) +{ + UINT16 actual_hue, actual_saturation; + appl_light_hsl_range[state_inst].hue_range_min = hue_min; + appl_light_hsl_range[state_inst].hue_range_max = hue_max; + appl_light_hsl_range[state_inst].saturation_range_min = saturation_min; + appl_light_hsl_range[state_inst].saturation_range_max = saturation_max; + /* Check if actual to be updated */ + actual_hue = appl_light_hsl[state_inst].hsl_hue; + + if (actual_hue < hue_min) + { + appl_light_hsl[state_inst].hsl_hue = hue_min; + } + else if (actual_hue > hue_max) + { + appl_light_hsl[state_inst].hsl_hue = hue_max; + } + + actual_saturation = appl_light_hsl[state_inst].hsl_hue; + + if (actual_saturation < saturation_min) + { + appl_light_hsl[state_inst].hsl_saturation = saturation_min; + } + else if (actual_saturation > saturation_max) + { + appl_light_hsl[state_inst].hsl_saturation = saturation_max; + } +} + +void appl_light_lightness_set_actual(UINT16 state_inst, UINT16 actual) +{ + UINT16 min, max; + + /* Generic OnOff binding */ + if (0x0000 == actual) + { + appl_generic_onoff[state_inst].onoff= 0x00; + } + else + { + min = appl_light_lightness[state_inst].light_lightness_range.lightness_range_min; + max = appl_light_lightness[state_inst].light_lightness_range.lightness_range_max; + + if ((0 != min) && (actual < min)) + { + actual = min; + } + else if ((0 != max) && (actual > max)) + { + actual = max; + } + + appl_generic_onoff[state_inst].onoff = 0x01; + appl_light_lightness[state_inst].light_lightness_last.lightness_last = actual; + } + + appl_light_lightness[state_inst].light_lightness_actual.lightness_actual = actual; + /* appl_light_ctl[state_inst].ctl_lightness = actual; */ + appl_light_hsl[state_inst].hsl_lightness = actual; + /* Light Lightness Linear = ((Actual)^2) / 65535 */ + appl_light_lightness[state_inst].light_lightness_linear.lightness_linear = ((actual * actual) + 65534) / 65535; + appl_generic_level_info[state_inst].generic_level.level = actual - 32768; +} + +void appl_light_lightness_set_range(UINT16 state_inst, UINT16 min, UINT16 max) +{ + UINT16 actual; + appl_light_lightness[state_inst].light_lightness_range.lightness_range_min = min; + appl_light_lightness[state_inst].light_lightness_range.lightness_range_max = max; + /* Check if actual to be updated */ + actual = appl_light_lightness[state_inst].light_lightness_actual.lightness_actual; + + if (actual < min) + { + appl_light_lightness[state_inst].light_lightness_actual.lightness_actual = min; + } + else if (actual > max) + { + appl_light_lightness[state_inst].light_lightness_actual.lightness_actual = max; + } +} + +void appl_set_level(UINT16 state_inst, UINT16 level) +{ + UINT16 min, max; + appl_generic_level_info[state_inst].generic_level.level = level; + appl_generic_level_info[state_inst].generic_level.target_level = 0; + appl_generic_level_info[state_inst].generic_level.delta_level = 0; + appl_light_lightness_set_actual(0, level + 32768); + /* min = appl_light_ctl_temperature_range[state_inst].ctl_temperature_range_min; */ + /* max = appl_light_ctl_temperature_range[state_inst].ctl_temperature_range_max; */ + /* Light CTL Temperature = T_MIN + (Generic Level + 32768) * (T_MAX - T_MIN) / 65535 */ + /* appl_light_ctl_temperature[0].ctl_temperature = min + (((level + 32768) * (max - min)) / 65535); */ + appl_light_hsl[state_inst].hsl_hue = level + 32768; + appl_light_hsl[state_inst].hsl_saturation = level + 32768; +} + +void appl_set_delta_level(UINT16 state_inst, INT32 delta, UINT8 immediate) +{ + /* TODO: See if this to be stored */ + if (0x01 == immediate) + { + appl_set_level(state_inst, (appl_generic_level_info[state_inst].generic_level.level + delta)); + } + else if (0x00 == immediate) + { + appl_generic_level_info[0].generic_level.target_level = (appl_generic_level_info[state_inst].generic_level.level + delta); + appl_generic_level_info[state_inst].generic_level.delta_level = delta; + } + else + { + /* Do nothing right now */ + } +} + +void appl_set_move_level(UINT16 state_inst, UINT16 move, UINT8 immediate) +{ + /* TODO: See if this to be stored */ + appl_generic_level_info[state_inst].generic_level.move_level = move; +} + +/* Todo: Remove the dependency */ +#include "math.h" + +void appl_light_lightness_set_linear(UINT16 state_inst, UINT16 linear) +{ + UINT16 actual; + UINT32 mul_val; + long double d; + /* appl_light_lightness[state_inst].light_lightness_linear.lightness_linear = linear; */ + mul_val = linear * 65535; + actual = (UINT16)sqrt(mul_val); + /* Light Lightness actual = sqrt(Linear * 65535) */ + appl_light_lightness_set_actual(state_inst, actual); +} + + +void appl_set_generic_onoff(UINT16 state_inst, UINT8 onoff) +{ + UINT16 actual; + /* TODO: See if this to be stored */ + appl_generic_onoff[state_inst].onoff = onoff; + + /* Binding */ + if (onoff == 0x00) + { + appl_light_lightness_set_actual(state_inst, 0x00); + } + else + { + if (0x0000 == appl_light_lightness[state_inst].light_lightness_default.lightness_default) + { + actual = appl_light_lightness[state_inst].light_lightness_last.lightness_last; + } + else + { + actual = appl_light_lightness[state_inst].light_lightness_default.lightness_default; + } + + appl_light_lightness_set_actual(state_inst, actual); + } +} + +API_RESULT appl_model_light_lightness_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + MS_STATE_LIGHT_LIGHTNESS_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)param; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: + { + /* Ignoring Instance and direction right now */ + appl_light_lightness[0].light_lightness_default = param_p->light_lightness_default; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: + { + /* Check range min and max */ + if (param_p->light_lightness_range.lightness_range_min > param_p->light_lightness_range.lightness_range_max) + { + /* TODO: add macro define */ + /** + Table 7.2: + 0x00 - Success + 0x01 - Cannot Set Range Min + 0x02 - Cannot Set Range Max + */ + param_p->range_status = 0x01; + #if 0 + appl_light_lightness[0].light_lightness_range = param_p->light_lightness_range; + param_p->light_lightness_range.lightness_range_min = 0x0000; + param_p->light_lightness_range.lightness_range_max = 0x0000; + #endif + } + else + { + /* Ignoring Instance and direction right now */ + appl_light_lightness[0].light_lightness_range = param_p->light_lightness_range; + param_p->range_status = 0x00; + } + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: + { + if (0 != param_p->light_lightness_linear.transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_lightness[0].light_lightness_linear.lightness_target = param_p->light_lightness_linear.lightness_linear; + appl_light_lightness[0].light_lightness_linear.transition_time = param_p->light_lightness_linear.transition_time; + transition.delay = param_p->light_lightness_linear.delay; + transition.transition_time = param_p->light_lightness_linear.transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_light_lightness_linear_transition_start_cb; + transition.transition_complete_cb = appl_light_lightness_linear_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + /* appl_generic_onoff[0].onoff = param_p->onoff; */ + appl_light_lightness_set_linear(0, param_p->light_lightness_linear.lightness_linear); + } + + *param_p = appl_light_lightness[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", param_p->light_lightness_linear.lightness_linear); + CONSOLE_OUT("[state] target: 0x%02X\n", param_p->light_lightness_linear.lightness_target); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", param_p->light_lightness_linear.transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: + { + /* Ignoring Instance and direction right now */ + appl_light_lightness[0].light_lightness_last = param_p->light_lightness_last; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + { + if (0 != param_p->light_lightness_actual.transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_lightness[0].light_lightness_actual.lightness_target = param_p->light_lightness_actual.lightness_actual; + appl_light_lightness[0].light_lightness_actual.transition_time = param_p->light_lightness_actual.transition_time; + transition.delay = param_p->light_lightness_actual.delay; + transition.transition_time = param_p->light_lightness_actual.transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_light_lightness_transition_start_cb; + transition.transition_complete_cb = appl_light_lightness_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + /* appl_generic_onoff[0].onoff = param_p->onoff; */ + appl_light_lightness_set_actual(0, param_p->light_lightness_actual.lightness_actual); + } + + *param_p = appl_light_lightness[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", param_p->light_lightness_actual.lightness_actual); + CONSOLE_OUT("[state] target: 0x%02X\n", param_p->light_lightness_actual.lightness_target); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", param_p->light_lightness_actual.transition_time); + /* Ignoring Instance and direction right now */ + /* param_p->light_lightness_actual.lightness_actual = appl_light_lightness[0].light_lightness_actual.lightness_actual; */ + } + break; + + default: + break; + } + + return retval; +} + +API_RESULT appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_ONPOWERUP_T: + { + MS_STATE_GENERIC_ONPOWERUP_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)param; + /* Ignoting Instance and direction right now */ + appl_generic_onpower[0] = *param_p; + } + break; + + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_generic_onoff[0].target_onoff = param_p->onoff; + appl_generic_onoff[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_generic_onoff_transition_start_cb; + transition.transition_complete_cb = appl_generic_onoff_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + /* appl_generic_onoff[0].onoff = param_p->onoff; */ + appl_set_generic_onoff(0, param_p->onoff); + } + + *param_p = appl_generic_onoff[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", appl_generic_onoff[0].onoff); + CONSOLE_OUT("[state] target: 0x%02X\n", appl_generic_onoff[0].target_onoff); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_generic_onoff[0].transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + case MS_STATE_GENERIC_LEVEL_T: /* Fall Through */ + case MS_STATE_DELTA_LEVEL_T: /* Fall Through */ + case MS_STATE_MOVE_LEVEL_T: + { + retval = appl_generic_level_model_state_set(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + retval = appl_model_light_lightness_state_set(state_t, state_inst, param, direction); + break; + + case MS_STATE_LIGHT_HSL_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_TARGET_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_HUE_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_SATURATION_T: + retval = appl_model_light_hsl_state_set(state_t, state_inst, param, direction); + break; + + default: + break; + } + + return retval; +} + +API_RESULT appl_generic_level_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + MS_STATE_GENERIC_LEVEL_STRUCT* param_p; + /** + Transaction State: + 0 : Start of Transaction + 1 : Continue + 2 : End of Transaction + */ + UINT8 transaction_state; + param_p = (MS_STATE_GENERIC_LEVEL_STRUCT*)param; + + switch (state_t) + { + case MS_STATE_GENERIC_LEVEL_T: + { + /* Ignoting Instance and direction right now */ + /* TODO: Not handling transaction state */ + { + MS_common_stop_transition_timer(appl_generic_level_info[0].transition_time_handle); + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + + if (0 == param_p->transition_time) + { + appl_set_level(0, param_p->level); + } + else + { + appl_generic_level_info[0].generic_level.target_level = param_p->level; + param_p->target_level = param_p->level; + } + } + } + break; + + case MS_STATE_DELTA_LEVEL_T: + { + /* Check if a new transaction */ + if (appl_generic_level_info[0].operation_type != state_t) + { + transaction_state = 0x00; + /* Stop associated Transaction Timer, if any */ + MS_common_stop_transition_timer(appl_generic_level_info[0].transition_time_handle); + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + appl_generic_level_info[0].operation_type = state_t; + appl_generic_level_info[0].generic_level.tid = param_p->tid; + } + else if (param_p->tid == appl_generic_level_info[0].generic_level.tid) + { + transaction_state = 0x01; + } + else + { + transaction_state = 0x02; + /* Stop associated Transaction Timer, if any */ + MS_common_stop_transition_timer(appl_generic_level_info[0].transition_time_handle); + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + appl_generic_level_info[0].operation_type = state_t; + appl_generic_level_info[0].generic_level.tid = param_p->tid; + } + + /* Ignoting Instance and direction right now */ + if (0 == param_p->transition_time) + { + if (0x02 == transaction_state) + { + appl_set_delta_level(0, (INT32)appl_generic_level_info[0].generic_level.delta_level, 0x01); + } + + /* Only update delta */ + appl_set_delta_level(0, (INT32)param_p->delta_level, 0x00); + } + else + { + appl_set_delta_level(0, (INT32)param_p->delta_level, 0x00); + } + } + break; + + case MS_STATE_MOVE_LEVEL_T: + { + /* Ignoting Instance and direction right now */ + if (0 == param_p->transition_time) + { + appl_set_move_level(0, param_p->move_level, 0x01); + } + else + { + appl_set_move_level(0, param_p->move_level, 0x00); + /* appl_generic_level_info[0].generic_level.target_level = 0x00; */ + appl_generic_level_info[0].generic_level.target_level = param_p->move_level * (param_p->transition_time & 0x3F); + /* TODO: Hardcoding */ + appl_generic_level_info[0].generic_level.target_level = 0x7FFF; + } + } + break; + + default: + break; + } + + /* TODO: Do we need to check if this is a new transaction? */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + appl_generic_level_info[0].generic_level.transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = (void*)state_t; + transition.transition_start_cb = appl_generic_level_transition_start_cb; + transition.transition_complete_cb = appl_generic_level_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &appl_generic_level_info[0].transition_time_handle + ); + } + + *param_p = appl_generic_level_info[0].generic_level; + param_p->level = appl_generic_level_info[0].generic_level.level + appl_generic_level_info[0].generic_level.delta_level; + + /* TODO: hack */ + if (0xFE == appl_generic_level_info[0].generic_level.transition_time) + { + param_p->transition_time = 0x3F; + } + + return API_SUCCESS; +} + +API_RESULT appl_model_light_hsl_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + switch(state_t) + { + case MS_STATE_LIGHT_HSL_T: + { + MS_STATE_LIGHT_HSL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_hsl[0]; + } + break; + + case MS_STATE_LIGHT_HSL_TARGET_T: + { + MS_STATE_LIGHT_HSL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_hsl[0]; + } + break; + + case MS_STATE_LIGHT_HSL_RANGE_T: + { + MS_STATE_LIGHT_HSL_RANGE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_RANGE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_hsl_range[0]; + } + break; + + case MS_STATE_LIGHT_HSL_DEFAULT_T: + { + MS_STATE_LIGHT_HSL_DEFAULT_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_DEFAULT_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_hsl_default[0]; + } + break; + + case MS_STATE_LIGHT_HSL_HUE_T: + { + MS_STATE_LIGHT_HSL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_hsl[0]; + } + break; + + case MS_STATE_LIGHT_HSL_SATURATION_T: + { + MS_STATE_LIGHT_HSL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_hsl[0]; + } + break; + + default: + break; + } + + return API_SUCCESS; +} + + +API_RESULT appl_model_light_hsl_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_LIGHT_HSL_T: + { + MS_STATE_LIGHT_HSL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_STRUCT*)param; + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_hsl[0].target_hsl_hue = param_p->hsl_hue; + appl_light_hsl[0].target_hsl_saturation = param_p->hsl_saturation; + appl_light_hsl[0].target_hsl_lightness = param_p->hsl_lightness; + appl_light_hsl[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = (void*)state_t; + transition.transition_start_cb = appl_light_hsl_transition_start_cb; + transition.transition_complete_cb = appl_light_hsl_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + appl_light_hsl[0].hsl_lightness = param_p->hsl_lightness; + appl_light_hsl[0].hsl_hue = param_p->hsl_hue; + appl_light_hsl[0].hsl_saturation = param_p->hsl_saturation; + appl_light_hsl[0].tid = param_p->tid; + /* + appl_light_hsl[0].hsl_lightness = param_p->hsl_lightness; + appl_light_hsl[0].hsl_lightness = param_p->hsl_lightness; + appl_light_hsl[0].hsl_lightness = param_p->hsl_lightness; + */ + appl_light_lightness[state_inst].light_lightness_actual.lightness_actual = param_p->hsl_lightness; + } + + *param_p = appl_light_hsl[0]; + CONSOLE_OUT("[state] current Hue: 0x%04X\n", appl_light_hsl[0].hsl_hue); + CONSOLE_OUT("[state] current Saturation: 0x%04X\n", appl_light_hsl[0].hsl_saturation); + CONSOLE_OUT("[state] current Lightness: 0x%04X\n", appl_light_hsl[0].hsl_lightness); + CONSOLE_OUT("[state] target Hue: 0x%04X\n", appl_light_hsl[0].target_hsl_hue); + CONSOLE_OUT("[state] target Saturation: 0x%04X\n", appl_light_hsl[0].target_hsl_saturation); + CONSOLE_OUT("[state] target Lightness: 0x%04X\n", appl_light_hsl[0].target_hsl_lightness); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_light_hsl[0].transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + case MS_STATE_LIGHT_HSL_RANGE_T: + { + MS_STATE_LIGHT_HSL_RANGE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_RANGE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + /* appl_light_hsl_range[0].hue_range_min = param_p->hue_range_min; */ + /* appl_light_hsl_range[0].hue_range_max = param_p->hue_range_max; */ + /* appl_light_hsl_range[0].saturation_range_min = param_p->saturation_range_min; */ + /* appl_light_hsl_range[0].saturation_range_max = param_p->saturation_range_max; */ + appl_light_hsl_set_range(0, param_p->hue_range_min, param_p->hue_range_max, param_p->saturation_range_min, param_p->saturation_range_max); + param_p->status = 0x00; + } + break; + + case MS_STATE_LIGHT_HSL_DEFAULT_T: + { + MS_STATE_LIGHT_HSL_DEFAULT_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_DEFAULT_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_light_hsl_default[0] = *param_p; + } + break; + + case MS_STATE_LIGHT_HSL_HUE_T: + { + MS_STATE_LIGHT_HSL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_STRUCT*)param; + + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_hsl[0].target_hsl_hue = param_p->hsl_hue; + appl_light_hsl[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = (void*)state_t; + transition.transition_start_cb = appl_light_hsl_transition_start_cb; + transition.transition_complete_cb = appl_light_hsl_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Ignoring Instance and direction right now */ + appl_light_hsl_set_hue(0, param_p->hsl_hue); + /* appl_light_hsl[0].hsl_hue = param_p->hsl_hue; */ + /* param_p->hsl_hue = appl_light_hsl[state_inst].hsl_hue; */ + } + + *param_p = appl_light_hsl[0]; + CONSOLE_OUT("[state] current Hue: 0x%04X\n", appl_light_hsl[0].hsl_hue); + CONSOLE_OUT("[state] target Hue: 0x%04X\n", appl_light_hsl[0].target_hsl_hue); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_light_hsl[0].transition_time); + } + break; + + case MS_STATE_LIGHT_HSL_SATURATION_T: + { + MS_STATE_LIGHT_HSL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_STRUCT*)param; + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_hsl[0].target_hsl_saturation = param_p->hsl_saturation; + appl_light_hsl[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = (void*)state_t; + transition.transition_start_cb = appl_light_hsl_transition_start_cb; + transition.transition_complete_cb = appl_light_hsl_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Ignoring Instance and direction right now */ + appl_light_hsl_set_saturation(0, param_p->hsl_saturation); + /* appl_light_hsl[0].hsl_saturation = param_p->hsl_saturation; */ + /* param_p->hsl_saturation = appl_light_hsl[state_inst].hsl_saturation; */ + } + + *param_p = appl_light_hsl[0]; + CONSOLE_OUT("[state] current Saturation: 0x%04X\n", appl_light_hsl[0].hsl_saturation); + CONSOLE_OUT("[state] target Saturation: 0x%04X\n", appl_light_hsl[0].target_hsl_saturation); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_light_hsl[0].transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + default: + break; + } + + return retval; +} + + diff --git a/src/components/ethermind/mesh/export/appl/model/server/lighting/light_hsl_server/appl_model_state_handler.h b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_hsl_server/appl_model_state_handler.h new file mode 100644 index 0000000..6522267 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_hsl_server/appl_model_state_handler.h @@ -0,0 +1,32 @@ +/** + \file appl_model_state_handler.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_MODEL_STATE_HANDLER_ +#define _H_APPL_MODEL_STATE_HANDLER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_main.h" +#include "MS_model_states.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void); + +API_RESULT appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +API_RESULT appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +#endif /*_H_APPL_MODEL_STATE_HANDLER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lc_server/appl_light_lc_server.c b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lc_server/appl_light_lc_server.c new file mode 100644 index 0000000..ef870f4 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lc_server/appl_light_lc_server.c @@ -0,0 +1,443 @@ +/** + \file appl_light_lc_server.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_light_lc_server.h" +#include "appl_model_state_handler.h" + +#include "MS_scene_api.h" +#include "MS_light_lightness_api.h" +#include "MS_generic_onoff_api.h" + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_light_lc_server_options[] = "\n\ +======== Light_Lc Server Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 2. Set Light Linear \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_light_lc_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_light_lc_setup_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_light_lightness_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_onoff_server_model_handle; + +static MS_ACCESS_MODEL_HANDLE appl_scene_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_scene_setup_server_model_handle; + +void appl_light_lightness_set_linear(UINT16 state_inst, UINT16 linear);; + +/* --------------------------------------------- Function */ +/* light_lc server application entry point */ +void main_light_lc_server_operations(/* IN */ UINT8 have_menu) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_light_lc_server_init + ( + element_handle, + &appl_light_lc_server_model_handle, + &appl_light_lc_setup_server_model_handle, + appl_light_lc_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light LC Server Initialized. Model Handle: 0x%04X\n", + appl_light_lc_server_model_handle); + CONSOLE_OUT( + "Light LC Setup Server Initialized. Model Handle: 0x%04X\n", + appl_light_lc_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Lc Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_light_lightness_server_init + ( + element_handle, + &appl_light_lightness_server_model_handle, + appl_light_lightness_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Lightness Server Initialized. Model Handle: 0x%04X\n", + appl_light_lightness_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Lightness Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_onoff_server_init + ( + element_handle, + &appl_generic_onoff_server_model_handle, + appl_generic_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Onoff Server Initialized. Model Handle: 0x%04X\n", + appl_generic_onoff_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Onoff Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_scene_server_init + ( + element_handle, + &appl_scene_server_model_handle, + &appl_scene_setup_server_model_handle, + appl_scene_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Scene Server Initialized. Model Handle: 0x%04X\n", + appl_scene_server_model_handle); + CONSOLE_OUT( + "Scene Setup Server Initialized. Model Handle: 0x%04X\n", + appl_scene_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Scene Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + appl_model_states_initialization(); + model_initialized = 0x01; + } + + if (MS_TRUE != have_menu) + { + CONSOLE_OUT("Not to use menu options\n"); + return; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_light_lc_server_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 2: + CONSOLE_OUT + ("Enter Light Linerar Value (in HEX)\n"); + CONSOLE_IN("%x", &choice); + appl_light_lightness_set_linear(0, (UINT16)choice);; + break; + } + } +} + +#if 0 +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONOFF_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + /* Using same as target state and remaining time as 0 */ + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] SET Request.\n"); + retval = appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT("[GENERIC_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scene server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. + + TODO: Update +*/ +void* appl_scene_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT8 event_type, + /* IN */ void* event_param, + /* IN */ UINT16 event_length, + /* IN */ void* context +) +{ + void* param_p; + param_p = NULL; + + switch(event_type) + { + case MS_SCENE_EVENT_STORE: + { + param_p = appl_scene_save_current_state(*(UINT32*)event_param); + } + break; + + case MS_SCENE_EVENT_DELETE: + { + param_p = appl_scene_delete_saved_state(*(UINT32*)event_param, context); + } + break; + + case MS_SCENE_EVENT_RECALL_START: + { + } + break; + + case MS_SCENE_EVENT_RECALL_COMPLETE: + { + param_p = appl_scene_recall_saved_state(*(UINT32*)event_param, context); + } + break; + + case MS_SCENE_EVENT_RECALL_IMMEDIATE: + { + param_p = appl_scene_recall_saved_state(*(UINT32*)event_param, context); + } + break; + } + + return param_p; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Lightness server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_lightness_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_LIGHT_LIGHTNESS_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_lightness_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Lc server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_lc_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_LIGHT_LC_MODE_STRUCT param_mode; + MS_STATE_LIGHT_LC_OM_STRUCT param_om; + MS_STATE_LIGHT_LC_LIGHT_ONOFF_STRUCT param_onoff; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + void* param_p; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_LC] GET Request.\n"); + + switch (state_params->state_type) + { + case MS_STATE_LIGHT_LC_MODE_T: + param_p = ¶m_mode; + break; + + case MS_STATE_LIGHT_LC_OM_T: + param_p = ¶m_om; + break; + + case MS_STATE_LIGHT_LC_LIGHT_ONOFF_T: + param_p = ¶m_onoff; + break; + + case MS_STATE_LIGHT_LC_PROPERTY_T: + param_p = state_params->state; + break; + } + + appl_model_state_get(state_params->state_type, 0, param_p, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param_p; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_LC] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_LC] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_lc_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +#endif /* 0 */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lc_server/appl_light_lc_server.h b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lc_server/appl_light_lc_server.h new file mode 100644 index 0000000..5d65675 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lc_server/appl_light_lc_server.h @@ -0,0 +1,124 @@ +/** + \file appl_light_lc_server.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_LIGHT_LC_SERVER_ +#define _H_APPL_LIGHT_LC_SERVER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_light_lc_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* light_lc server application entry point */ +void main_light_lc_server_operations(/* IN */ UINT8 have_menu); + +/* Get Model Handle */ +void appl_light_lc_server_get_model_handle(void); + +/* Set Publish Address */ +void appl_light_lc_server_set_publish_address(void); + +/* Set Default Transition timeout in ms */ +API_RESULT appl_model_light_lc_server_set_default_trans_timeout_in_ms(/* IN */ UINT32 time_in_ms); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Lc server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_lc_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Lightness server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_lightness_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scene server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. + + TODO: Update +*/ +void* appl_scene_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT8 event_type, + /* IN */ void* event_param, + /* IN */ UINT16 event_length, + /* IN */ void* context +); + +#endif /*_H_APPL_LIGHT_LC_SERVER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lc_server/appl_model_state_handler.c b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lc_server/appl_model_state_handler.c new file mode 100644 index 0000000..73c5f6a --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lc_server/appl_model_state_handler.c @@ -0,0 +1,620 @@ +/** + \file appl_model_state_handler.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_model_state_handler.h" +#include "MS_common.h" + +/* --------------------------------------------- Global Definitions */ + +/* --------------------------------------------- Data Types/ Structures */ +#define MS_MAX_NUM_STATES 2 +#define MS_MAX_LC_PROPERTIES 10 + +typedef struct _APPL_STATE_INFO_VAULT +{ + /* OnOff state */ + UINT8 onoff; + + /* LC Mode */ + UINT8 lc_mode; + + MS_STATE_LIGHT_LC_PROPERTY_STRUCT lc_property; + +} APPL_STATE_INFO_VAULT; + + +static MS_STATE_LIGHT_LC_MODE_STRUCT appl_light_lc_mode[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_LIGHTNESS_STRUCT appl_light_lightness[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_LC_OM_STRUCT appl_light_lc_om[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_LC_LIGHT_ONOFF_STRUCT appl_light_lc_onoff[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_LC_PROPERTY_STRUCT appl_light_lc_property[MS_MAX_NUM_STATES][MS_MAX_LC_PROPERTIES]; + +static MS_STATE_GENERIC_ONOFF_STRUCT appl_generic_onoff[MS_MAX_NUM_STATES]; + +/* For simplicity keeping same number of state info, as the number of max scences */ +static APPL_STATE_INFO_VAULT appl_state_info_vault[16]; + +static UINT8 appl_current_property_id_index; +void appl_light_lightness_set_linear(UINT16 state_inst, UINT16 linear); +API_RESULT appl_model_light_lightness_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void) +{ + UINT32 index; + EM_mem_set(appl_light_lc_mode, 0, sizeof(appl_light_lc_mode)); + EM_mem_set(appl_light_lc_om, 0, sizeof(appl_light_lc_om)); + EM_mem_set(appl_light_lc_onoff, 0, sizeof(appl_light_lc_onoff)); + EM_mem_set(appl_light_lc_property, 0, sizeof(appl_light_lc_property)); + + for (index = 0; index < MS_MAX_LC_PROPERTIES; index++) + { + /* TODO: For PTS */ + appl_light_lc_property[0][index].property_id = index + 0x36 /* 1 */; + /* Allocate and keep some property value */ + appl_light_lc_property[0][index].property_value_len = 3 /* 1 */; + appl_light_lc_property[0][index].property_value = EM_alloc_mem(3 /* 1 */); + /* TODO: Not checking for memeory allocation failure */ + EM_mem_set(appl_light_lc_property[0][index].property_value, (index + 3 /* 1 */), (3 /* 1 */)); + } + + EM_mem_set(appl_generic_onoff, 0, sizeof(appl_generic_onoff)); + EM_mem_set(appl_state_info_vault, 0, sizeof(appl_state_info_vault)); + EM_mem_set (appl_light_lightness, 0, sizeof(appl_light_lightness)); + appl_current_property_id_index = 0; +} + + +static void appl_generic_onoff_transition_start_cb(void* blob) +{ + /** + Because binary states cannot support transitions, when changing to 0x01 (On), + the Generic OnOff state shall change immediately when the transition starts, + and when changing to 0x00, the state shall change when the transition finishes. + */ + if (0 == appl_generic_onoff[0].onoff) + { + appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; + } +} + +static void appl_generic_onoff_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_generic_onoff[0].transition_time = 0; + appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; + appl_generic_onoff[0].target_onoff = 0; +} + +static void appl_light_lc_onoff_transition_start_cb(void* blob) +{ + /** + Because binary states cannot support transitions, when changing to 0x01 (On), + the Generic OnOff state shall change immediately when the transition starts, + and when changing to 0x00, the state shall change when the transition finishes. + */ + if (0 == appl_light_lc_onoff[0].present_light_onoff) + { + appl_light_lc_onoff[0].present_light_onoff = appl_light_lc_onoff[0].target_light_onoff; + } +} + +static void appl_light_lc_onoff_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_light_lc_onoff[0].transition_time = 0; + appl_light_lc_onoff[0].present_light_onoff = appl_light_lc_onoff[0].target_light_onoff; + appl_light_lc_onoff[0].target_light_onoff = 0; +} + +void* appl_scene_save_current_state(/* IN */ UINT32 scene_index) +{ + /* Free previous context - if any */ + /* Empty right now - dummy returning the same scene index itself */ + /* Store current state */ + appl_state_info_vault[scene_index].onoff = appl_generic_onoff[0].onoff; + appl_state_info_vault[scene_index].lc_mode = appl_light_lc_mode[0].present_mode; + appl_state_info_vault[scene_index].lc_property.property_id = appl_light_lc_property[0][appl_current_property_id_index].property_id; + appl_state_info_vault[scene_index].lc_property.property_value_len = appl_light_lc_property[0][appl_current_property_id_index].property_value_len; + + if (0 != appl_state_info_vault[scene_index].lc_property.property_value_len) + { + appl_state_info_vault[scene_index].lc_property.property_value = EM_alloc_mem(appl_state_info_vault[scene_index].lc_property.property_value_len); + /* TODO: Not check malloc failure */ + EM_mem_copy(appl_state_info_vault[scene_index].lc_property.property_value, appl_light_lc_property[0][appl_current_property_id_index].property_value, appl_state_info_vault[scene_index].lc_property.property_value_len); + } + + return (void*)scene_index; +} + +void* appl_scene_delete_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ + /* Free context - if any */ + /* Empty right now - dummy returning NULL */ + /* Invalid value */ + appl_state_info_vault[scene_index].onoff = 0x02; + appl_state_info_vault[scene_index].lc_mode = 0x00; + appl_state_info_vault[scene_index].lc_property.property_id = 0x0000; + + if (0 != appl_state_info_vault[scene_index].lc_property.property_value_len) + { + EM_free_mem(appl_state_info_vault[scene_index].lc_property.property_value); + } + + appl_state_info_vault[scene_index].lc_property.property_value = NULL; + appl_state_info_vault[scene_index].lc_property.property_value_len = 0x0000; + return (void*)NULL; +} + +void* appl_scene_recall_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ + /* Recall context - if any */ + /* Empty right now - dummy returning NULL */ + appl_generic_onoff[0].onoff = appl_state_info_vault[scene_index].onoff; + appl_light_lc_mode[0].present_mode = appl_state_info_vault[scene_index].lc_mode; + appl_light_lc_property[0][appl_current_property_id_index].property_id = appl_state_info_vault[scene_index].lc_property.property_id; + appl_light_lc_property[0][appl_current_property_id_index].property_value_len = appl_state_info_vault[scene_index].lc_property.property_value_len; + + if (0 != appl_state_info_vault[scene_index].lc_property.property_value_len) + { + /* appl_state_info_vault[scene_index].lc_property.property_value = EM_alloc_mem(appl_state_info_vault[scene_index].lc_property.property_value_len); */ + /* TODO: Not check malloc failure */ + /* EM_mem_copy(appl_state_info_vault[scene_index].lc_property.property_value, appl_light_lc_property[0][appl_current_property_id_index].property_value, appl_state_info_vault[scene_index].lc_property.property_value_len); */ + appl_light_lc_property[0][appl_current_property_id_index].property_value = appl_state_info_vault[scene_index].lc_property.property_value; + } + + return (void*)NULL; +} + +API_RESULT appl_model_light_lightness_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + MS_STATE_LIGHT_LIGHTNESS_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)param; + + switch (state_t) + { + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_default = appl_light_lightness[0].light_lightness_default; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_range = appl_light_lightness[0].light_lightness_range; + param_p->range_status = 0x00; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_linear = appl_light_lightness[0].light_lightness_linear; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_last = appl_light_lightness[0].light_lightness_last; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_actual = appl_light_lightness[0].light_lightness_actual; + } + break; + + default: + break; + } + + return API_SUCCESS; +} + +API_RESULT appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_LIGHT_LC_MODE_T: + { + MS_STATE_LIGHT_LC_MODE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LC_MODE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + param_p->present_mode = appl_light_lc_mode[0].present_mode; + } + break; + + case MS_STATE_LIGHT_LC_OM_T: + { + MS_STATE_LIGHT_LC_OM_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LC_OM_STRUCT*)param; + /* Ignoring Instance and direction right now */ + param_p->present_mode = appl_light_lc_om[0].present_mode; + } + break; + + case MS_STATE_LIGHT_LC_LIGHT_ONOFF_T: + { + MS_STATE_LIGHT_LC_LIGHT_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LC_LIGHT_ONOFF_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_lc_onoff[0]; + } + break; + + case MS_STATE_LIGHT_LC_PROPERTY_T: + { + MS_STATE_LIGHT_LC_PROPERTY_STRUCT* param_p; + UINT32 index; + param_p = (MS_STATE_LIGHT_LC_PROPERTY_STRUCT*)param; + /* Ignoring Instance and direction right now */ + /* Search for matching property ID */ + param_p->property_value_len = 0x00; + + for (index = 0; index < MS_MAX_LC_PROPERTIES; index++) + { + if (param_p->property_id == appl_light_lc_property[0][index].property_id) + { + param_p->property_value_len = appl_light_lc_property[0][index].property_value_len; + param_p->property_value = appl_light_lc_property[0][index].property_value; + break; + } + } + + /* Else Return Error */ + } + break; + + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_generic_onoff[0]; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + retval = appl_model_light_lightness_state_get(state_t, state_inst, param, direction); + break; + + default: + break; + } + + return retval; +} + +/* Generic OnOff Model Set Handlers */ + +void appl_light_lightness_set_linear(UINT16 state_inst, UINT16 linear) +{ + /* UINT16 actual; */ + /* UINT32 mul_val; */ + /* long double d; */ + /* appl_light_lightness[state_inst].light_lightness_linear.lightness_linear = linear; */ + /* mul_val = linear * 65535; */ + /* actual = (UINT16)sqrt(mul_val); */ + /* Light Lightness actual = sqrt(Linear * 65535) */ + /* appl_light_lightness_set_actual(state_inst, actual); */ + appl_light_lightness[state_inst].light_lightness_linear.lightness_linear = linear; +} + + +API_RESULT appl_model_light_lightness_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + MS_STATE_LIGHT_LIGHTNESS_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)param; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: + { + /* Ignoring Instance and direction right now */ + appl_light_lightness[0].light_lightness_default = param_p->light_lightness_default; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: + { + /* Check range min and max */ + if (param_p->light_lightness_range.lightness_range_min > param_p->light_lightness_range.lightness_range_max) + { + /* TODO: add macro define */ + /** + Table 7.2: + 0x00 - Success + 0x01 - Cannot Set Range Min + 0x02 - Cannot Set Range Max + */ + param_p->range_status = 0x01; + #if 0 + appl_light_lightness[0].light_lightness_range = param_p->light_lightness_range; + param_p->light_lightness_range.lightness_range_min = 0x0000; + param_p->light_lightness_range.lightness_range_max = 0x0000; + #endif + } + else + { + /* Ignoring Instance and direction right now */ + appl_light_lightness[0].light_lightness_range = param_p->light_lightness_range; + param_p->range_status = 0x00; + } + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: + { + if (0 != param_p->light_lightness_linear.transition_time) + { + #if 0 + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_lightness[0].light_lightness_linear.lightness_target = param_p->light_lightness_linear.lightness_linear; + appl_light_lightness[0].light_lightness_linear.transition_time = param_p->light_lightness_linear.transition_time; + transition.delay = param_p->light_lightness_linear.delay; + transition.transition_time = param_p->light_lightness_linear.transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_light_lightness_linear_transition_start_cb; + transition.transition_complete_cb = appl_light_lightness_linear_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + #endif + } + else + { + /* Instantaneous Change */ + /* appl_generic_onoff[0].onoff = param_p->onoff; */ + appl_light_lightness_set_linear(0, param_p->light_lightness_linear.lightness_linear); + } + + *param_p = appl_light_lightness[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", param_p->light_lightness_linear.lightness_linear); + CONSOLE_OUT("[state] target: 0x%02X\n", param_p->light_lightness_linear.lightness_target); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", param_p->light_lightness_linear.transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: + { + /* Ignoring Instance and direction right now */ + appl_light_lightness[0].light_lightness_last = param_p->light_lightness_last; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + { + if (0 != param_p->light_lightness_actual.transition_time) + { + #if 0 + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_lightness[0].light_lightness_actual.lightness_target = param_p->light_lightness_actual.lightness_actual; + appl_light_lightness[0].light_lightness_actual.transition_time = param_p->light_lightness_actual.transition_time; + transition.delay = param_p->light_lightness_actual.delay; + transition.transition_time = param_p->light_lightness_actual.transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_light_lightness_transition_start_cb; + transition.transition_complete_cb = appl_light_lightness_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + #endif + } + else + { + /* Instantaneous Change */ + /* appl_generic_onoff[0].onoff = param_p->onoff; */ + /* appl_light_lightness_set_actual(0, param_p->light_lightness_actual.lightness_actual); */ + } + + *param_p = appl_light_lightness[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", param_p->light_lightness_actual.lightness_actual); + CONSOLE_OUT("[state] target: 0x%02X\n", param_p->light_lightness_actual.lightness_target); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", param_p->light_lightness_actual.transition_time); + /* Ignoring Instance and direction right now */ + /* param_p->light_lightness_actual.lightness_actual = appl_light_lightness[0].light_lightness_actual.lightness_actual; */ + } + break; + + default: + break; + } + + return retval; +} + +API_RESULT appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + UINT32 index; + API_RESULT retval; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_LIGHT_LC_MODE_T: + { + MS_STATE_LIGHT_LC_MODE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LC_MODE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_light_lc_mode[0].present_mode = param_p->target_mode; + param_p->present_mode = appl_light_lc_mode[0].present_mode; + } + break; + + case MS_STATE_LIGHT_LC_OM_T: + { + MS_STATE_LIGHT_LC_OM_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LC_OM_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_light_lc_om[0].present_mode = param_p->target_mode; + param_p->present_mode = appl_light_lc_om[0].present_mode; + } + break; + + case MS_STATE_LIGHT_LC_LIGHT_ONOFF_T: + { + MS_STATE_LIGHT_LC_LIGHT_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LC_LIGHT_ONOFF_STRUCT*)param; + /* TODO: Hack for test case MMDL/SR/LLC/BV-04-C */ + #if 0 + + if (0 == param_p->transition_time) + { + param_p->transition_time = 0x54; + param_p->delay = 0x05; + } + + #endif /* 0 */ + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_lc_onoff[0].target_light_onoff = param_p->target_light_onoff; + appl_light_lc_onoff[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_light_lc_onoff_transition_start_cb; + transition.transition_complete_cb = appl_light_lc_onoff_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + /* Ignoring Instance and direction right now */ + appl_light_lc_onoff[0].present_light_onoff = param_p->target_light_onoff; + appl_generic_onoff[0].onoff = param_p->target_light_onoff; + appl_light_lightness_set_linear(0, param_p->target_light_onoff); + } + + *param_p = appl_light_lc_onoff[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", appl_light_lc_onoff[0].present_light_onoff); + CONSOLE_OUT("[state] target: 0x%02X\n", appl_light_lc_onoff[0].target_light_onoff); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_light_lc_onoff[0].transition_time); + /* TODO: Check for timer and start */ + } + break; + + case MS_STATE_LIGHT_LC_PROPERTY_T: + { + MS_STATE_LIGHT_LC_PROPERTY_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LC_PROPERTY_STRUCT*)param; + + for (index = 0; index < MS_MAX_LC_PROPERTIES; index++) + { + if (param_p->property_id == appl_light_lc_property[0][index].property_id) + { + if (appl_light_lc_property[0][index].property_value_len == param_p->property_value_len) + { + EM_mem_copy(appl_light_lc_property[0][index].property_value, param_p->property_value, param_p->property_value_len); + appl_current_property_id_index = index; + } + else + { + param_p->property_value_len = 0x00; + } + + break; + } + } + + /* TODO: */ + } + break; + + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_generic_onoff[0].target_onoff = param_p->onoff; + appl_generic_onoff[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_generic_onoff_transition_start_cb; + transition.transition_complete_cb = appl_generic_onoff_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + appl_generic_onoff[0].onoff = param_p->onoff; + appl_light_lc_onoff[0].present_light_onoff = param_p->onoff; + } + + *param_p = appl_generic_onoff[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", appl_generic_onoff[0].onoff); + CONSOLE_OUT("[state] target: 0x%02X\n", appl_generic_onoff[0].target_onoff); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_generic_onoff[0].transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + retval = appl_model_light_lightness_state_set(state_t, state_inst, param, direction); + break; + + default: + break; + } + + return retval; +} + + diff --git a/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lc_server/appl_model_state_handler.h b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lc_server/appl_model_state_handler.h new file mode 100644 index 0000000..6522267 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lc_server/appl_model_state_handler.h @@ -0,0 +1,32 @@ +/** + \file appl_model_state_handler.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_MODEL_STATE_HANDLER_ +#define _H_APPL_MODEL_STATE_HANDLER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_main.h" +#include "MS_model_states.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void); + +API_RESULT appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +API_RESULT appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +#endif /*_H_APPL_MODEL_STATE_HANDLER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lightness_server/appl_light_lightness_server.c b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lightness_server/appl_light_lightness_server.c new file mode 100644 index 0000000..4ed4937 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lightness_server/appl_light_lightness_server.c @@ -0,0 +1,572 @@ +/** + \file appl_light_lightness_server.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_light_lightness_server.h" +#include "appl_model_state_handler.h" +#include "MS_scene_api.h" +#include "MS_generic_power_onoff_api.h" +#include "MS_generic_onoff_api.h" +#include "MS_generic_level_api.h" + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_light_lightness_server_options[] = "\n\ +======== Light_Lightness Server Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 2. Power Cycle. \n\ +\n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_light_lightness_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_light_lightness_setup_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_power_onoff_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_power_onoff_setup_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_onoff_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_level_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_scene_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_scene_setup_server_model_handle; + +/* --------------------------------------------- Function */ +/* light_lightness server application entry point */ +void main_light_lightness_server_operations(/* IN */ UINT8 have_menu) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_light_lightness_server_init + ( + element_handle, + &appl_light_lightness_server_model_handle, + appl_light_lightness_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Lightness Server Initialized. Model Handle: 0x%04X\n", + appl_light_lightness_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Lightness Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_light_lightness_setup_server_init + ( + element_handle, + &appl_light_lightness_setup_server_model_handle, + appl_light_lightness_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Lightness Setup Server Initialized. Model Handle: 0x%04X\n", + appl_light_lightness_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Lightness Setup Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_power_onoff_server_init + ( + element_handle, + &appl_generic_power_onoff_server_model_handle, + appl_generic_power_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Power Onoff Server Initialized. Model Handle: 0x%04X\n", + appl_generic_power_onoff_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Power Onoff Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_power_onoff_setup_server_init + ( + element_handle, + &appl_generic_power_onoff_setup_server_model_handle, + appl_generic_power_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Power Onoff Setup Server Initialized. Model Handle: 0x%04X\n", + appl_generic_power_onoff_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Power Onoff Setup Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_onoff_server_init + ( + element_handle, + &appl_generic_onoff_server_model_handle, + appl_generic_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Onoff Server Initialized. Model Handle: 0x%04X\n", + appl_generic_onoff_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Onoff Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + #if 0 + retval = MS_generic_default_transition_time_server_init + ( + element_handle, + &appl_generic_default_transition_time_server_model_handle, + NULL + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Default Transition Time Server Initialized. Model Handle: 0x%04X\n", + appl_generic_default_transition_time_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Default Transition Time Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + #endif + retval = MS_generic_level_server_init + ( + element_handle, + &appl_generic_level_server_model_handle, + appl_generic_level_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Level Server Initialized. Model Handle: 0x%04X\n", + appl_generic_level_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Level Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_scene_server_init + ( + element_handle, + &appl_scene_server_model_handle, + &appl_scene_setup_server_model_handle, + appl_scene_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Scene Server Initialized. Model Handle: 0x%04X\n", + appl_scene_server_model_handle); + CONSOLE_OUT( + "Scene Setup Server Initialized. Model Handle: 0x%04X\n", + appl_scene_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Scene Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + appl_model_states_initialization(); + model_initialized = 0x01; + } + + if (MS_TRUE != have_menu) + { + CONSOLE_OUT("Not to use menu options\n"); + return; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_light_lightness_server_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 2: + appl_model_power_cycle(); + break; + } + } +} + +#if 0 +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONOFF_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + /* Using same as target state and remaining time as 0 */ + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] SET Request.\n"); + retval = appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT("[GENERIC_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Level server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_level_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_LEVEL_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] SET Request.\n"); + + if ((MS_ACCESS_GENERIC_LEVEL_SET_OPCODE == msg_raw->opcode) || + (MS_ACCESS_GENERIC_LEVEL_SET_UNACKNOWLEDGED_OPCODE == msg_raw->opcode)) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Level SET Request.\n"); + } + else if ((MS_ACCESS_GENERIC_DELTA_SET_OPCODE == msg_raw->opcode) || + (MS_ACCESS_GENERIC_DELTA_SET_UNACKNOWLEDGED_OPCODE == msg_raw->opcode)) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Delta SET Request.\n"); + } + else if ((MS_ACCESS_GENERIC_MOVE_SET_OPCODE == msg_raw->opcode) || + (MS_ACCESS_GENERIC_MOVE_SET_UNACKNOWLEDGED_OPCODE == msg_raw->opcode)) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Move SET Request.\n"); + } + + /* TODO: Right now not handling different type of SET requests separately */ + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_LEVEL_STRUCT*)state_params->state, 0); + current_state_params.state_type = MS_STATE_GENERIC_LEVEL_T; + current_state_params.state = (MS_STATE_GENERIC_LEVEL_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_level_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_power_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONPOWERUP_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_power_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scene server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. + + TODO: Update +*/ +void* appl_scene_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT8 event_type, + /* IN */ void* event_param, + /* IN */ UINT16 event_length, + /* IN */ void* context +) +{ + void* param_p; + param_p = NULL; + + switch(event_type) + { + case MS_SCENE_EVENT_STORE: + { + param_p = appl_scene_save_current_state(*(UINT32*)event_param); + } + break; + + case MS_SCENE_EVENT_DELETE: + { + param_p = appl_scene_delete_saved_state(*(UINT32*)event_param, context); + } + break; + + case MS_SCENE_EVENT_RECALL_START: + { + } + break; + + case MS_SCENE_EVENT_RECALL_COMPLETE: + { + param_p = appl_scene_recall_saved_state(*(UINT32*)event_param, context); + } + break; + + case MS_SCENE_EVENT_RECALL_IMMEDIATE: + { + param_p = appl_scene_recall_saved_state(*(UINT32*)event_param, context); + } + break; + } + + return param_p; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Lightness server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_lightness_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_LIGHT_LIGHTNESS_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_lightness_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +#endif /* 0 */ + diff --git a/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lightness_server/appl_light_lightness_server.h b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lightness_server/appl_light_lightness_server.h new file mode 100644 index 0000000..4a1ae13 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lightness_server/appl_light_lightness_server.h @@ -0,0 +1,144 @@ +/** + \file appl_light_lightness_server.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_LIGHT_LIGHTNESS_SERVER_ +#define _H_APPL_LIGHT_LIGHTNESS_SERVER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_light_lightness_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* light_lightness server application entry point */ +void main_light_lightness_server_operations(/* IN */ UINT8 have_menu); + +/* Get Model Handle */ +void appl_light_lightness_server_get_model_handle(void); + +/* Set Publish Address */ +void appl_light_lightness_server_set_publish_address(void); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Lightness server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_lightness_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Level server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_level_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_power_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scene server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. + + TODO: Update +*/ +void* appl_scene_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT8 event_type, + /* IN */ void* event_param, + /* IN */ UINT16 event_length, + /* IN */ void* context +); + +#endif /*_H_APPL_LIGHT_LIGHTNESS_SERVER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lightness_server/appl_model_state_handler.c b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lightness_server/appl_model_state_handler.c new file mode 100644 index 0000000..29ef8a7 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lightness_server/appl_model_state_handler.c @@ -0,0 +1,823 @@ +/** + \file appl_model_state_handler.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_model_state_handler.h" +#include "MS_common.h" + +/* --------------------------------------------- Global Definitions */ + +/* --------------------------------------------- Data Types/ Structures */ +#define MS_MAX_NUM_STATES 2 + +typedef struct _APPL_STATE_INFO_VAULT +{ + /* OnOff state */ + UINT8 onoff; + + /* Generic Level state */ + UINT16 level; + + /* Light Lightness Actual */ + UINT16 lightness_actual; + + /* Light Lightness Linear */ + UINT16 lightness_linear; + +} APPL_STATE_INFO_VAULT; + +typedef struct _APPL_GENENRIC_LEVEL_INFO +{ + MS_STATE_GENERIC_LEVEL_STRUCT generic_level; + + /* Operation Type : 0xFF as initial value (invalid) */ + UINT8 operation_type; + + UINT16 transition_time_handle; + +} APPL_GENERIC_LEVEL_INFO; + +static MS_STATE_LIGHT_LIGHTNESS_STRUCT appl_light_lightness[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_LIGHTNESS_STRUCT appl_light_lightness_setup[MS_MAX_NUM_STATES]; + +static MS_STATE_GENERIC_ONPOWERUP_STRUCT appl_generic_onpower[MS_MAX_NUM_STATES]; + +static MS_STATE_GENERIC_ONOFF_STRUCT appl_generic_onoff[MS_MAX_NUM_STATES]; + +/* static MS_STATE_GENERIC_LEVEL_STRUCT appl_generic_level[MS_MAX_NUM_STATES]; */ +static APPL_GENERIC_LEVEL_INFO appl_generic_level_info[MS_MAX_NUM_STATES]; + +/* For simplicity keeping same number of state info, as the number of max scences */ +static APPL_STATE_INFO_VAULT appl_state_info_vault[16]; +static UINT8 appl_in_transtion; + +void appl_light_lightness_set_actual(UINT16 state_inst, UINT16 actual); + +void appl_set_move_level(UINT16 state_inst, UINT16 move, UINT8 immediate); +void appl_set_level(UINT16 state_inst, UINT16 level); +void appl_set_delta_level(UINT16 state_inst, INT32 delta, UINT8 immediate); + +API_RESULT appl_generic_level_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); +void appl_set_generic_onoff(UINT16 state_inst, UINT8 onoff); +void appl_light_lightness_set_linear(UINT16 state_inst, UINT16 linear); + +/* --------------------------------------------- Function */ + +void appl_model_states_initialization(void) +{ + UINT32 index; + + for (index = 0; index < MS_MAX_NUM_STATES; index++) + { + EM_mem_set(&appl_generic_level_info[index], 0, sizeof(APPL_GENERIC_LEVEL_INFO)); + appl_generic_level_info[index].operation_type = 0xFF; + appl_generic_level_info[index].transition_time_handle = 0xFFFF; + } + + EM_mem_set (appl_light_lightness, 0, sizeof(appl_light_lightness)); + EM_mem_set (appl_light_lightness_setup, 0, sizeof(appl_light_lightness_setup)); + appl_light_lightness[0].light_lightness_last.lightness_last = 0xFFFF; + appl_light_lightness[1].light_lightness_last.lightness_last = 0xFFFF; + EM_mem_set(appl_generic_onpower, 0, sizeof(appl_generic_onpower)); + EM_mem_set(appl_generic_onoff, 0, sizeof(appl_generic_onoff)); + EM_mem_set(appl_state_info_vault, 0, sizeof(appl_state_info_vault)); + appl_in_transtion = 0x00; +} + +void appl_model_power_cycle(void) +{ + appl_generic_onoff[0].transition_time = 0x00; + appl_generic_onoff[0].target_onoff = 0x00; + + /* */ + if (0x01 == appl_generic_onpower[0].onpowerup) + { + appl_set_generic_onoff(0, 0x01); + } + else if (0x00 == appl_generic_onpower[0].onpowerup) + { + appl_set_generic_onoff(0, 0x00); + } + /* else 0x02. Keep OnOff as before power down */ + /* TODO: Hack */ + else + { + appl_generic_onoff[0].onoff = 0x00; + } + + /* TODO: Hack */ + if (0x00 != appl_light_lightness[0].light_lightness_actual.transition_time) + { + appl_light_lightness[0].light_lightness_actual.lightness_actual = appl_light_lightness[0].light_lightness_actual.lightness_target; + appl_light_lightness[0].light_lightness_actual.transition_time = 0x00; + appl_light_lightness[0].light_lightness_actual.lightness_target = 0x00; + } +} + + +/* ---- State Transition Handlers */ + +static void appl_generic_onoff_transition_start_cb(void* blob) +{ + /** + Because binary states cannot support transitions, when changing to 0x01 (On), + the Generic OnOff state shall change immediately when the transition starts, + and when changing to 0x00, the state shall change when the transition finishes. + */ + #if 0 + if (0 == appl_generic_onoff[0].onoff) + { + appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; + } + + #endif +} + +static void appl_generic_onoff_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_generic_onoff[0].transition_time = 0; + /* appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; */ + appl_set_generic_onoff(0, appl_generic_onoff[0].target_onoff); + appl_generic_onoff[0].target_onoff = 0; +} + +static void appl_generic_level_transition_start_cb(void* blob) +{ + UINT16 state_t; + state_t = (UINT16)blob; +} + +static void appl_generic_level_transition_complete_cb(void* blob) +{ + UINT16 state_t; + state_t = (UINT16)blob; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + + switch (state_t) + { + case MS_STATE_GENERIC_LEVEL_T: + { + appl_set_level(0, appl_generic_level_info[0].generic_level.target_level); + } + break; + + case MS_STATE_DELTA_LEVEL_T: + { + appl_set_level(0, appl_generic_level_info[0].generic_level.target_level); + } + break; + + case MS_STATE_MOVE_LEVEL_T: + { + appl_set_move_level(0, appl_generic_level_info[0].generic_level.delta_level, 0x01); + /* TODO: Remove Bad Logic */ + appl_generic_level_info[0].generic_level.move_level = 0; + } + break; + } +} + +static void appl_light_lightness_transition_start_cb(void* blob) +{ +} + +static void appl_light_lightness_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_light_lightness[0].light_lightness_actual.transition_time = 0; + /* appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; */ + appl_light_lightness_set_actual(0, appl_light_lightness[0].light_lightness_actual.lightness_target); + appl_light_lightness[0].light_lightness_actual.lightness_target = 0; +} + +static void appl_light_lightness_linear_transition_start_cb(void* blob) +{ +} + +static void appl_light_lightness_linear_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_light_lightness[0].light_lightness_linear.transition_time = 0; + /* appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; */ + appl_light_lightness_set_linear(0, appl_light_lightness[0].light_lightness_linear.lightness_target); + appl_light_lightness[0].light_lightness_linear.lightness_target = 0; +} + +void* appl_scene_save_current_state(/* IN */ UINT32 scene_index) +{ + /* Free previous context - if any */ + /* Empty right now - dummy returning the same scene index itself */ + /* Store current state */ + appl_state_info_vault[scene_index].onoff = appl_generic_onoff[0].onoff; + appl_state_info_vault[scene_index].level = appl_generic_level_info[0].generic_level.level; + appl_state_info_vault[scene_index].lightness_actual = appl_light_lightness[0].light_lightness_actual.lightness_actual; + appl_state_info_vault[scene_index].lightness_linear = appl_light_lightness[0].light_lightness_linear.lightness_linear; + return (void*)scene_index; +} + +void* appl_scene_delete_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ + /* Free context - if any */ + /* Empty right now - dummy returning NULL */ + /* Invalid value */ + appl_state_info_vault[scene_index].onoff = 0x02; + appl_state_info_vault[scene_index].level = 0xFFFF; + appl_state_info_vault[scene_index].lightness_actual = 0x0000; + appl_state_info_vault[scene_index].lightness_linear = 0x0000; + return (void*)NULL; +} + +void* appl_scene_recall_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ + /* Recall context - if any */ + /* Empty right now - dummy returning NULL */ + /* appl_generic_onoff[0].onoff = appl_state_info_vault[scene_index].onoff; */ + appl_set_generic_onoff(0, appl_state_info_vault[scene_index].onoff); + appl_generic_level_info[0].generic_level.level = appl_state_info_vault[scene_index].level; + appl_light_lightness[0].light_lightness_actual.lightness_actual = appl_state_info_vault[scene_index].lightness_actual; + appl_light_lightness[0].light_lightness_linear.lightness_linear = appl_state_info_vault[scene_index].lightness_linear; + return (void*)NULL; +} + +API_RESULT appl_model_light_lightness_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + MS_STATE_LIGHT_LIGHTNESS_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)param; + + switch (state_t) + { + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_default = appl_light_lightness[0].light_lightness_default; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_range = appl_light_lightness[0].light_lightness_range; + param_p->range_status = 0x00; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_linear = appl_light_lightness[0].light_lightness_linear; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_last = appl_light_lightness[0].light_lightness_last; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_actual = appl_light_lightness[0].light_lightness_actual; + } + break; + + default: + break; + } + + return API_SUCCESS; +} + +API_RESULT appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_ONPOWERUP_T: + { + MS_STATE_GENERIC_ONPOWERUP_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)param; + /* Ignoting Instance and direction right now */ + *param_p = appl_generic_onpower[0]; + } + break; + + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_generic_onoff[0]; + } + break; + + case MS_STATE_GENERIC_LEVEL_T: + { + MS_STATE_GENERIC_LEVEL_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_LEVEL_STRUCT*)param; + /* Ignoting Instance and direction right now */ + *param_p = appl_generic_level_info[0].generic_level; + param_p->level = appl_generic_level_info[0].generic_level.level + appl_generic_level_info[0].generic_level.delta_level; + + /* TODO: hack */ + if (0xFE == appl_generic_level_info[0].generic_level.transition_time) + { + param_p->transition_time = 0x3F; + } + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + retval = appl_model_light_lightness_state_get(state_t, state_inst, param, direction); + break; + + default: + break; + } + + return retval; +} + +void appl_light_lightness_set_actual(UINT16 state_inst, UINT16 actual) +{ + UINT16 min, max; + + /* Generic OnOff binding */ + if (0x0000 == actual) + { + appl_generic_onoff[state_inst].onoff= 0x00; + } + else + { + min = appl_light_lightness[state_inst].light_lightness_range.lightness_range_min; + max = appl_light_lightness[state_inst].light_lightness_range.lightness_range_max; + + if ((0 != min) && (actual < min)) + { + actual = min; + } + else if ((0 != max) && (actual > max)) + { + actual = max; + } + + appl_generic_onoff[state_inst].onoff = 0x01; + appl_light_lightness[state_inst].light_lightness_last.lightness_last = actual; + } + + appl_light_lightness[state_inst].light_lightness_actual.lightness_actual = actual; + /* Light Lightness Linear = ((Actual)^2) / 65535 */ + appl_light_lightness[state_inst].light_lightness_linear.lightness_linear = ((actual * actual) + 65534) / 65535; + appl_generic_level_info[state_inst].generic_level.level = actual - 32768; +} + +void appl_light_lightness_set_range(UINT16 state_inst, UINT16 min, UINT16 max) +{ + UINT16 actual; + appl_light_lightness[state_inst].light_lightness_range.lightness_range_min = min; + appl_light_lightness[state_inst].light_lightness_range.lightness_range_max = max; + /* Check if actual to be updated */ + actual = appl_light_lightness[state_inst].light_lightness_actual.lightness_actual; + + if (actual < min) + { + appl_light_lightness[state_inst].light_lightness_actual.lightness_actual = min; + } + else if (actual > max) + { + appl_light_lightness[state_inst].light_lightness_actual.lightness_actual = max; + } +} +void appl_set_level(UINT16 state_inst, UINT16 level) +{ + appl_generic_level_info[state_inst].generic_level.level = level; + appl_generic_level_info[state_inst].generic_level.target_level = 0; + appl_generic_level_info[state_inst].generic_level.delta_level = 0; + appl_light_lightness_set_actual(0, level + 32768); +} + +void appl_set_delta_level(UINT16 state_inst, INT32 delta, UINT8 immediate) +{ + /* TODO: See if this to be stored */ + if (0x01 == immediate) + { + appl_set_level(state_inst, (appl_generic_level_info[state_inst].generic_level.level + delta)); + } + else if (0x00 == immediate) + { + appl_generic_level_info[0].generic_level.target_level = (appl_generic_level_info[state_inst].generic_level.level + delta); + appl_generic_level_info[state_inst].generic_level.delta_level = delta; + } + else + { + /* Do nothing right now */ + } +} + +void appl_set_move_level(UINT16 state_inst, UINT16 move, UINT8 immediate) +{ + /* TODO: See if this to be stored */ + appl_generic_level_info[state_inst].generic_level.move_level = move; +} + +/* Todo: Remove the dependency */ +#include "math.h" + +void appl_light_lightness_set_linear(UINT16 state_inst, UINT16 linear) +{ + UINT16 actual; + UINT32 mul_val; + long double d; + /* appl_light_lightness[state_inst].light_lightness_linear.lightness_linear = linear; */ + mul_val = linear * 65535; + actual = (UINT16)sqrt(mul_val); + /* Light Lightness actual = sqrt(Linear * 65535) */ + appl_light_lightness_set_actual(state_inst, actual); +} + + +void appl_set_generic_onoff(UINT16 state_inst, UINT8 onoff) +{ + UINT16 actual; + /* TODO: See if this to be stored */ + appl_generic_onoff[state_inst].onoff = onoff; + + /* Binding */ + if (onoff == 0x00) + { + appl_light_lightness_set_actual(state_inst, 0x00); + } + else + { + if (0x0000 == appl_light_lightness[state_inst].light_lightness_default.lightness_default) + { + actual = appl_light_lightness[state_inst].light_lightness_last.lightness_last; + } + else + { + actual = appl_light_lightness[state_inst].light_lightness_default.lightness_default; + } + + appl_light_lightness_set_actual(state_inst, actual); + } +} + +API_RESULT appl_model_light_lightness_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + MS_STATE_LIGHT_LIGHTNESS_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)param; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: + { + /* Ignoring Instance and direction right now */ + appl_light_lightness[0].light_lightness_default = param_p->light_lightness_default; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: + { + /* Check range min and max */ + if (param_p->light_lightness_range.lightness_range_min > param_p->light_lightness_range.lightness_range_max) + { + /* TODO: add macro define */ + /** + Table 7.2: + 0x00 - Success + 0x01 - Cannot Set Range Min + 0x02 - Cannot Set Range Max + */ + param_p->range_status = 0x01; + #if 0 + appl_light_lightness[0].light_lightness_range = param_p->light_lightness_range; + param_p->light_lightness_range.lightness_range_min = 0x0000; + param_p->light_lightness_range.lightness_range_max = 0x0000; + #endif + } + else + { + /* Ignoring Instance and direction right now */ + appl_light_lightness[0].light_lightness_range = param_p->light_lightness_range; + param_p->range_status = 0x00; + } + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: + { + if (0 != param_p->light_lightness_linear.transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_lightness[0].light_lightness_linear.lightness_target = param_p->light_lightness_linear.lightness_linear; + appl_light_lightness[0].light_lightness_linear.transition_time = param_p->light_lightness_linear.transition_time; + transition.delay = param_p->light_lightness_linear.delay; + transition.transition_time = param_p->light_lightness_linear.transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_light_lightness_linear_transition_start_cb; + transition.transition_complete_cb = appl_light_lightness_linear_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + /* appl_generic_onoff[0].onoff = param_p->onoff; */ + appl_light_lightness_set_linear(0, param_p->light_lightness_linear.lightness_linear); + } + + *param_p = appl_light_lightness[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", param_p->light_lightness_linear.lightness_linear); + CONSOLE_OUT("[state] target: 0x%02X\n", param_p->light_lightness_linear.lightness_target); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", param_p->light_lightness_linear.transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: + { + /* Ignoring Instance and direction right now */ + appl_light_lightness[0].light_lightness_last = param_p->light_lightness_last; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + { + if (0 != param_p->light_lightness_actual.transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_lightness[0].light_lightness_actual.lightness_target = param_p->light_lightness_actual.lightness_actual; + appl_light_lightness[0].light_lightness_actual.transition_time = param_p->light_lightness_actual.transition_time; + transition.delay = param_p->light_lightness_actual.delay; + transition.transition_time = param_p->light_lightness_actual.transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_light_lightness_transition_start_cb; + transition.transition_complete_cb = appl_light_lightness_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + /* appl_generic_onoff[0].onoff = param_p->onoff; */ + appl_light_lightness_set_actual(0, param_p->light_lightness_actual.lightness_actual); + } + + *param_p = appl_light_lightness[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", param_p->light_lightness_actual.lightness_actual); + CONSOLE_OUT("[state] target: 0x%02X\n", param_p->light_lightness_actual.lightness_target); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", param_p->light_lightness_actual.transition_time); + /* Ignoring Instance and direction right now */ + /* param_p->light_lightness_actual.lightness_actual = appl_light_lightness[0].light_lightness_actual.lightness_actual; */ + } + break; + + default: + break; + } + + return retval; +} + + +API_RESULT appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_ONPOWERUP_T: + { + MS_STATE_GENERIC_ONPOWERUP_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)param; + /* Ignoting Instance and direction right now */ + appl_generic_onpower[0] = *param_p; + } + break; + + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_generic_onoff[0].target_onoff = param_p->onoff; + appl_generic_onoff[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_generic_onoff_transition_start_cb; + transition.transition_complete_cb = appl_generic_onoff_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + /* appl_generic_onoff[0].onoff = param_p->onoff; */ + appl_set_generic_onoff(0, param_p->onoff); + } + + *param_p = appl_generic_onoff[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", appl_generic_onoff[0].onoff); + CONSOLE_OUT("[state] target: 0x%02X\n", appl_generic_onoff[0].target_onoff); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_generic_onoff[0].transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + case MS_STATE_GENERIC_LEVEL_T: /* Fall Through */ + case MS_STATE_DELTA_LEVEL_T: /* Fall Through */ + case MS_STATE_MOVE_LEVEL_T: + { + retval = appl_generic_level_model_state_set(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + retval = appl_model_light_lightness_state_set(state_t, state_inst, param, direction); + break; + + default: + break; + } + + return retval; +} + +API_RESULT appl_generic_level_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + MS_STATE_GENERIC_LEVEL_STRUCT* param_p; + /** + Transaction State: + 0 : Start of Transaction + 1 : Continue + 2 : End of Transaction + */ + UINT8 transaction_state; + param_p = (MS_STATE_GENERIC_LEVEL_STRUCT*)param; + + switch (state_t) + { + case MS_STATE_GENERIC_LEVEL_T: + { + /* Ignoting Instance and direction right now */ + /* TODO: Not handling transaction state */ + { + MS_common_stop_transition_timer(appl_generic_level_info[0].transition_time_handle); + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + + if (0 == param_p->transition_time) + { + appl_set_level(0, param_p->level); + } + else + { + appl_generic_level_info[0].generic_level.target_level = param_p->level; + param_p->target_level = param_p->level; + } + } + } + break; + + case MS_STATE_DELTA_LEVEL_T: + { + /* Check if a new transaction */ + if (appl_generic_level_info[0].operation_type != state_t) + { + transaction_state = 0x00; + /* Stop associated Transaction Timer, if any */ + MS_common_stop_transition_timer(appl_generic_level_info[0].transition_time_handle); + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + appl_generic_level_info[0].operation_type = state_t; + appl_generic_level_info[0].generic_level.tid = param_p->tid; + } + else if (param_p->tid == appl_generic_level_info[0].generic_level.tid) + { + transaction_state = 0x01; + } + else + { + transaction_state = 0x02; + /* Stop associated Transaction Timer, if any */ + MS_common_stop_transition_timer(appl_generic_level_info[0].transition_time_handle); + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + appl_generic_level_info[0].operation_type = state_t; + appl_generic_level_info[0].generic_level.tid = param_p->tid; + } + + /* Ignoting Instance and direction right now */ + if (0 == param_p->transition_time) + { + if (0x02 == transaction_state) + { + appl_set_delta_level(0, (INT32)appl_generic_level_info[0].generic_level.delta_level, 0x01); + } + + /* Only update delta */ + appl_set_delta_level(0, (INT32)param_p->delta_level, 0x00); + } + else + { + appl_set_delta_level(0, (INT32)param_p->delta_level, 0x00); + } + } + break; + + case MS_STATE_MOVE_LEVEL_T: + { + /* Ignoting Instance and direction right now */ + if (0 == param_p->transition_time) + { + appl_set_move_level(0, param_p->move_level, 0x01); + } + else + { + appl_set_move_level(0, param_p->move_level, 0x00); + /* appl_generic_level_info[0].generic_level.target_level = 0x00; */ + appl_generic_level_info[0].generic_level.target_level = param_p->move_level * (param_p->transition_time & 0x3F); + /* TODO: Hardcoding */ + appl_generic_level_info[0].generic_level.target_level = 0x7FFF; + } + } + break; + + default: + break; + } + + /* TODO: Do we need to check if this is a new transaction? */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + appl_generic_level_info[0].generic_level.transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = (void*)state_t; + transition.transition_start_cb = appl_generic_level_transition_start_cb; + transition.transition_complete_cb = appl_generic_level_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &appl_generic_level_info[0].transition_time_handle + ); + } + + *param_p = appl_generic_level_info[0].generic_level; + param_p->level = appl_generic_level_info[0].generic_level.level + appl_generic_level_info[0].generic_level.delta_level; + + /* TODO: hack */ + if (0xFE == appl_generic_level_info[0].generic_level.transition_time) + { + param_p->transition_time = 0x3F; + } + + return API_SUCCESS; +} + diff --git a/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lightness_server/appl_model_state_handler.h b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lightness_server/appl_model_state_handler.h new file mode 100644 index 0000000..6522267 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_lightness_server/appl_model_state_handler.h @@ -0,0 +1,32 @@ +/** + \file appl_model_state_handler.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_MODEL_STATE_HANDLER_ +#define _H_APPL_MODEL_STATE_HANDLER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_main.h" +#include "MS_model_states.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void); + +API_RESULT appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +API_RESULT appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +#endif /*_H_APPL_MODEL_STATE_HANDLER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/lighting/light_xyl_server/appl_light_xyl_server.c b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_xyl_server/appl_light_xyl_server.c new file mode 100644 index 0000000..f4d792c --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_xyl_server/appl_light_xyl_server.c @@ -0,0 +1,792 @@ +/** + \file appl_light_xyl_server.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_light_xyl_server.h" +#include "appl_model_state_handler.h" +#include "MS_scene_api.h" +#include "MS_light_lightness_api.h" +#include "MS_light_hsl_api.h" +#include "MS_generic_power_onoff_api.h" +#include "MS_generic_onoff_api.h" +#include "MS_generic_level_api.h" + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_light_xyl_server_options[] = "\n\ +======== Light_Xyl Server Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + 2. Power Cycle. \n\ +\n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_light_hsl_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_light_hsl_setup_server_model_handle; + +static MS_ACCESS_MODEL_HANDLE appl_light_xyl_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_light_xyl_setup_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_light_lightness_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_light_lightness_setup_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_power_onoff_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_power_onoff_setup_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_onoff_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_generic_level_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_scene_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_scene_setup_server_model_handle; + +/* --------------------------------------------- Function */ +/* light_xyl server application entry point */ +void main_light_xyl_server_operations(/* IN */ UINT8 have_menu) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_light_xyl_server_init + ( + element_handle, + &appl_light_xyl_server_model_handle, + &appl_light_xyl_setup_server_model_handle, + appl_light_xyl_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Xyl Server Initialized. Model Handle: 0x%04X\n", + appl_light_xyl_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Xyl Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_light_hsl_server_init + ( + element_handle, + &appl_light_hsl_server_model_handle, + &appl_light_hsl_setup_server_model_handle, + appl_light_hsl_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Hsl Server Initialized. Model Handle: 0x%04X\n", + appl_light_hsl_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Hsl Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_light_lightness_server_init + ( + element_handle, + &appl_light_lightness_server_model_handle, + appl_light_lightness_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Lightness Server Initialized. Model Handle: 0x%04X\n", + appl_light_lightness_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Lightness Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_light_lightness_setup_server_init + ( + element_handle, + &appl_light_lightness_setup_server_model_handle, + appl_light_lightness_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Lightness Setup Server Initialized. Model Handle: 0x%04X\n", + appl_light_lightness_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Lightness Setup Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_power_onoff_server_init + ( + element_handle, + &appl_generic_power_onoff_server_model_handle, + appl_generic_power_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Power Onoff Server Initialized. Model Handle: 0x%04X\n", + appl_generic_power_onoff_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Power Onoff Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_power_onoff_setup_server_init + ( + element_handle, + &appl_generic_power_onoff_setup_server_model_handle, + appl_generic_power_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Power Onoff Setup Server Initialized. Model Handle: 0x%04X\n", + appl_generic_power_onoff_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Power Onoff Setup Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_generic_onoff_server_init + ( + element_handle, + &appl_generic_onoff_server_model_handle, + appl_generic_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Onoff Server Initialized. Model Handle: 0x%04X\n", + appl_generic_onoff_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Onoff Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + #if 0 + retval = MS_generic_default_transition_time_server_init + ( + element_handle, + &appl_generic_default_transition_time_server_model_handle, + NULL + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Default Transition Time Server Initialized. Model Handle: 0x%04X\n", + appl_generic_default_transition_time_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Default Transition Time Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + #endif + retval = MS_generic_level_server_init + ( + element_handle, + &appl_generic_level_server_model_handle, + appl_generic_level_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Level Server Initialized. Model Handle: 0x%04X\n", + appl_generic_level_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Level Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_scene_server_init + ( + element_handle, + &appl_scene_server_model_handle, + &appl_scene_setup_server_model_handle, + appl_scene_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Scene Server Initialized. Model Handle: 0x%04X\n", + appl_scene_server_model_handle); + CONSOLE_OUT( + "Scene Setup Server Initialized. Model Handle: 0x%04X\n", + appl_scene_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Scene Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + appl_model_states_initialization(); + model_initialized = 0x01; + } + + if (MS_TRUE != have_menu) + { + CONSOLE_OUT("Not to use menu options\n"); + return; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_light_xyl_server_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + + case 2: + appl_model_power_cycle(); + break; + } + } +} + +#if 0 +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONOFF_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + /* Using same as target state and remaining time as 0 */ + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] SET Request.\n"); + retval = appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT("[GENERIC_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Level server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_level_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_LEVEL_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] SET Request.\n"); + + if ((MS_ACCESS_GENERIC_LEVEL_SET_OPCODE == msg_raw->opcode) || + (MS_ACCESS_GENERIC_LEVEL_SET_UNACKNOWLEDGED_OPCODE == msg_raw->opcode)) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Level SET Request.\n"); + } + else if ((MS_ACCESS_GENERIC_DELTA_SET_OPCODE == msg_raw->opcode) || + (MS_ACCESS_GENERIC_DELTA_SET_UNACKNOWLEDGED_OPCODE == msg_raw->opcode)) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Delta SET Request.\n"); + } + else if ((MS_ACCESS_GENERIC_MOVE_SET_OPCODE == msg_raw->opcode) || + (MS_ACCESS_GENERIC_MOVE_SET_UNACKNOWLEDGED_OPCODE == msg_raw->opcode)) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Move SET Request.\n"); + } + + /* TODO: Right now not handling different type of SET requests separately */ + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_LEVEL_STRUCT*)state_params->state, 0); + current_state_params.state_type = MS_STATE_GENERIC_LEVEL_T; + current_state_params.state = (MS_STATE_GENERIC_LEVEL_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_LEVEL] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_level_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_power_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONPOWERUP_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[GENERIC_POWER_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_power_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scene server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. + + TODO: Update +*/ +void* appl_scene_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT8 event_type, + /* IN */ void* event_param, + /* IN */ UINT16 event_length, + /* IN */ void* context +) +{ + void* param_p; + param_p = NULL; + + switch(event_type) + { + case MS_SCENE_EVENT_STORE: + { + param_p = appl_scene_save_current_state(*(UINT32*)event_param); + } + break; + + case MS_SCENE_EVENT_DELETE: + { + param_p = appl_scene_delete_saved_state(*(UINT32*)event_param, context); + } + break; + + case MS_SCENE_EVENT_RECALL_START: + { + } + break; + + case MS_SCENE_EVENT_RECALL_COMPLETE: + { + param_p = appl_scene_recall_saved_state(*(UINT32*)event_param, context); + } + break; + + case MS_SCENE_EVENT_RECALL_IMMEDIATE: + { + param_p = appl_scene_recall_saved_state(*(UINT32*)event_param, context); + } + break; + } + + return param_p; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Lightness server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_lightness_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_LIGHT_LIGHTNESS_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] GET Request.\n"); + appl_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_lightness_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Hsl server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_hsl_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_STATE_LIGHT_HSL_STRUCT param; + MS_STATE_LIGHT_HSL_RANGE_STRUCT param_range; + MS_STATE_LIGHT_HSL_DEFAULT_STRUCT param_default; + void* param_p; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_HSL] GET Request.\n"); + + switch (state_params->state_type) + { + case MS_STATE_LIGHT_HSL_T: + case MS_STATE_LIGHT_HSL_HUE_T: + case MS_STATE_LIGHT_HSL_SATURATION_T: + case MS_STATE_LIGHT_HSL_TARGET_T: + { + param_p = ¶m; + } + break; + + case MS_STATE_LIGHT_HSL_DEFAULT_T: + { + param_p = ¶m_default; + } + break; + + case MS_STATE_LIGHT_HSL_RANGE_T: + { + param_p = ¶m_range; + } + break; + + default: + break; + } + + appl_model_state_get(state_params->state_type, 0, param_p, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param_p; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_HSL] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_HSL] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_hsl_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Xyl server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_xyl_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + MS_STATE_LIGHT_XYL_STRUCT param; + MS_STATE_LIGHT_XYL_RANGE_STRUCT param_range; + MS_STATE_LIGHT_XYL_DEFAULT_STRUCT param_default; + void* param_p; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_XYL] GET Request.\n"); + + switch (state_params->state_type) + { + case MS_STATE_LIGHT_XYL_T: + case MS_STATE_LIGHT_XYL_TARGET_T: + { + param_p = ¶m; + } + break; + + case MS_STATE_LIGHT_XYL_DEFAULT_T: + { + param_p = ¶m_default; + } + break; + + case MS_STATE_LIGHT_XYL_RANGE_T: + { + param_p = ¶m_range; + } + break; + + default: + break; + } + + appl_model_state_get(state_params->state_type, 0, param_p, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param_p; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_XYL] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_XYL] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_xyl_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +#endif /* 0 */ + diff --git a/src/components/ethermind/mesh/export/appl/model/server/lighting/light_xyl_server/appl_light_xyl_server.h b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_xyl_server/appl_light_xyl_server.h new file mode 100644 index 0000000..37ecf92 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_xyl_server/appl_light_xyl_server.h @@ -0,0 +1,208 @@ +/** + \file appl_light_xyl_server.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_LIGHT_XYL_SERVER_ +#define _H_APPL_LIGHT_XYL_SERVER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_light_xyl_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* light_xyl server application entry point */ +void main_light_xyl_server_operations(/* IN */ UINT8 have_menu); + +/* Get Model Handle */ +void appl_light_xyl_server_get_model_handle(void); + +/* Set Publish Address */ +void appl_light_xyl_server_set_publish_address(void); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Xyl server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_xyl_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Hsl server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_hsl_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Ctl_Temperature server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_ctl_temperature_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Lightness server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_light_lightness_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Level server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_level_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_generic_power_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scene server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. + + TODO: Update +*/ +void* appl_scene_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT8 event_type, + /* IN */ void* event_param, + /* IN */ UINT16 event_length, + /* IN */ void* context +); + +#endif /*_H_APPL_LIGHT_XYL_SERVER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/lighting/light_xyl_server/appl_model_state_handler.c b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_xyl_server/appl_model_state_handler.c new file mode 100644 index 0000000..6c0107e --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_xyl_server/appl_model_state_handler.c @@ -0,0 +1,1648 @@ +/** + \file appl_model_state_handler.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_model_state_handler.h" +#include "MS_common.h" + +/* --------------------------------------------- Global Definitions */ + +/* --------------------------------------------- Data Types/ Structures */ +#define MS_MAX_NUM_STATES 2 + +typedef struct _APPL_STATE_INFO_VAULT +{ + /* OnOff state */ + UINT8 onoff; + + /* Generic Level state */ + UINT16 level; + + /* Light Lightness Actual */ + UINT16 lightness_actual; + + /* Light Lightness Linear */ + UINT16 lightness_linear; + + /** Light CTL Lightness */ + UINT16 ctl_lightness; + + /** Light CTL Temperature */ + UINT16 ctl_temperature; + + /** Light CTL Delta UV */ + UINT16 ctl_delta_uv; + + /** The perceived lightness of a light emitted by the element */ + UINT16 hsl_lightness; + + /** The 16-bit value representing the hue */ + UINT16 hsl_hue; + + /** The saturation of a color light */ + UINT16 hsl_saturation; + + /** The perceived lightness of a light emitted by the element */ + UINT16 xyl_lightness; + + /** The 16-bit value representing the x coordinate of a CIE1931 color light */ + UINT16 xyl_x; + + /** The 16-bit value representing the y coordinate of a CIE1931 color light */ + UINT16 xyl_y; + +} APPL_STATE_INFO_VAULT; + +typedef struct _APPL_GENENRIC_LEVEL_INFO +{ + MS_STATE_GENERIC_LEVEL_STRUCT generic_level; + + /* Operation Type : 0xFF as initial value (invalid) */ + UINT8 operation_type; + + UINT16 transition_time_handle; + +} APPL_GENERIC_LEVEL_INFO; + +static MS_STATE_LIGHT_LIGHTNESS_STRUCT appl_light_lightness[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_LIGHTNESS_STRUCT appl_light_lightness_setup[MS_MAX_NUM_STATES]; + +static MS_STATE_GENERIC_ONPOWERUP_STRUCT appl_generic_onpower[MS_MAX_NUM_STATES]; + +static MS_STATE_GENERIC_ONOFF_STRUCT appl_generic_onoff[MS_MAX_NUM_STATES]; + +/* static MS_STATE_GENERIC_LEVEL_STRUCT appl_generic_level[MS_MAX_NUM_STATES]; */ +static APPL_GENERIC_LEVEL_INFO appl_generic_level_info[MS_MAX_NUM_STATES]; + +static MS_STATE_LIGHT_HSL_STRUCT appl_light_hsl[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_HSL_RANGE_STRUCT appl_light_hsl_range[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_HSL_DEFAULT_STRUCT appl_light_hsl_default[MS_MAX_NUM_STATES]; + +static MS_STATE_LIGHT_XYL_STRUCT appl_light_xyl[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_XYL_DEFAULT_STRUCT appl_light_xyl_default[MS_MAX_NUM_STATES]; +static MS_STATE_LIGHT_XYL_RANGE_STRUCT appl_light_xyl_range[MS_MAX_NUM_STATES]; + +/* For simplicity keeping same number of state info, as the number of max scences */ +static APPL_STATE_INFO_VAULT appl_state_info_vault[16]; +static UINT8 appl_in_transtion; + +void appl_light_lightness_set_actual(UINT16 state_inst, UINT16 actual); + +void appl_set_move_level(UINT16 state_inst, UINT16 move, UINT8 immediate); +void appl_set_level(UINT16 state_inst, UINT16 level); +void appl_set_delta_level(UINT16 state_inst, INT32 delta, UINT8 immediate); + +API_RESULT appl_generic_level_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); +void appl_set_generic_onoff(UINT16 state_inst, UINT8 onoff); +void appl_light_lightness_set_linear(UINT16 state_inst, UINT16 linear); +API_RESULT appl_model_light_hsl_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); +API_RESULT appl_model_light_hsl_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); +API_RESULT appl_model_light_xyl_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); +API_RESULT appl_model_light_xyl_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); +/* void appl_light_ctl_temp_set_actual(UINT16 state_inst, UINT16 actual); */ +void appl_light_hsl_set_hue(UINT16 state_inst, UINT16 actual); +void appl_light_hsl_set_saturation(UINT16 state_inst, UINT16 actual); +void appl_light_xyl_set_x(UINT16 state_inst, UINT16 actual); +void appl_light_xyl_set_y(UINT16 state_inst, UINT16 actual); + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void) +{ + UINT32 index; + EM_mem_set (appl_light_lightness, 0, sizeof(appl_light_lightness)); + EM_mem_set (appl_light_lightness_setup, 0, sizeof(appl_light_lightness_setup)); + appl_light_lightness[0].light_lightness_last.lightness_last = 0xFFFF; + appl_light_lightness[1].light_lightness_last.lightness_last = 0xFFFF; + EM_mem_set(appl_generic_onpower, 0, sizeof(appl_generic_onpower)); + EM_mem_set(appl_generic_onoff, 0, sizeof(appl_generic_onoff)); + EM_mem_set(appl_state_info_vault, 0, sizeof(appl_state_info_vault)); + EM_mem_set (appl_light_hsl, 0, sizeof(appl_light_hsl)); + EM_mem_set(appl_light_hsl_range, 0, sizeof(appl_light_hsl_range)); + EM_mem_set(appl_light_hsl_default, 0, sizeof(appl_light_hsl_default)); + EM_mem_set (appl_light_xyl, 0, sizeof(appl_light_xyl)); + EM_mem_set(appl_light_xyl_default, 0, sizeof(appl_light_xyl_default)); + EM_mem_set(appl_light_xyl_range, 0, sizeof(appl_light_xyl_range)); + + for (index = 0; index < MS_MAX_NUM_STATES; index++) + { + EM_mem_set(&appl_generic_level_info[index], 0, sizeof(APPL_GENERIC_LEVEL_INFO)); + appl_generic_level_info[index].operation_type = 0xFF; + appl_generic_level_info[index].transition_time_handle = 0xFFFF; + /* appl_light_ctl[index].ctl_temperature = appl_light_ctl_temperature[index].ctl_temperature; */ + /* appl_light_ctl_temp_set_actual(index, appl_light_ctl_temperature[index].ctl_temperature); */ + appl_light_hsl_set_hue(index, 0x0000); + appl_light_hsl_set_saturation(index, 0x0000); + appl_light_xyl_set_x(index, 0x0000); + appl_light_xyl_set_y(index, 0x0000); + } + + appl_in_transtion = 0x00; +} + +void appl_model_power_cycle(void) +{ + appl_generic_onoff[0].transition_time = 0x00; + appl_generic_onoff[0].target_onoff = 0x00; + + /* */ + if (0x01 == appl_generic_onpower[0].onpowerup) + { + /* appl_light_ctl_temperature[0]. = appl_light_ctl_default[0].ctl_lightness; */ + /* appl_light_ctl_temperature[0].ctl_temperature = appl_light_ctl_default[0].ctl_temperature; */ + /* appl_light_ctl_temperature[0].ctl_delta_uv = appl_light_ctl_default[0].ctl_delta_uv; */ + appl_light_hsl[0].hsl_hue = appl_light_hsl_default[0].hsl_hue; + appl_light_hsl[0].hsl_lightness = appl_light_hsl_default[0].hsl_lightness; + appl_light_hsl[0].hsl_saturation = appl_light_hsl_default[0].hsl_saturation; + appl_light_xyl[0].xyl_lightness = appl_light_xyl_default[0].xyl_lightness; + appl_light_xyl[0].xyl_x = appl_light_xyl_default[0].xyl_x; + appl_light_xyl[0].xyl_y = appl_light_xyl_default[0].xyl_y; + appl_set_generic_onoff(0, 0x01); + /* TODO: Hack */ + appl_light_hsl[0].hsl_lightness = 0xFF; + appl_light_xyl[0].xyl_lightness = 0xFF; + } + else if (0x00 == appl_generic_onpower[0].onpowerup) + { + /* appl_light_ctl_temperature[0]. = appl_light_ctl_default[0].ctl_lightness; */ + /* appl_light_ctl_temperature[0].ctl_temperature = appl_light_ctl_default[0].ctl_temperature; */ + /* appl_light_ctl_temperature[0].ctl_delta_uv = appl_light_ctl_default[0].ctl_delta_uv; */ + appl_light_hsl[0].hsl_hue = appl_light_hsl_default[0].hsl_hue; + appl_light_hsl[0].hsl_lightness = appl_light_hsl_default[0].hsl_lightness; + appl_light_hsl[0].hsl_saturation = appl_light_hsl_default[0].hsl_saturation; + appl_light_xyl[0].xyl_lightness = appl_light_xyl_default[0].xyl_lightness; + appl_light_xyl[0].xyl_x = appl_light_xyl_default[0].xyl_x; + appl_light_xyl[0].xyl_y = appl_light_xyl_default[0].xyl_y; + appl_set_generic_onoff(0, 0x00); + } + /* else 0x02. Keep OnOff as before power down */ + /* TODO: Hack */ + else + { + appl_generic_onoff[0].onoff = 0x00; + } + + /* TODO: Hack */ + if (0x00 != appl_light_lightness[0].light_lightness_actual.transition_time) + { + appl_light_lightness[0].light_lightness_actual.lightness_actual = appl_light_lightness[0].light_lightness_actual.lightness_target; + appl_light_lightness[0].light_lightness_actual.transition_time = 0x00; + appl_light_lightness[0].light_lightness_actual.lightness_target = 0x00; + } + + if (0x00 != appl_light_hsl[0].transition_time) + { + /* TODO: Stop timer */ + appl_light_hsl[0].hsl_hue = appl_light_hsl[0].target_hsl_hue; + appl_light_hsl[0].hsl_saturation = appl_light_hsl[0].target_hsl_saturation; + appl_light_hsl[0].hsl_lightness = appl_light_hsl[0].target_hsl_lightness; + appl_light_hsl[0].transition_time = 0x00; + appl_light_hsl[0].target_hsl_hue = 0x0000; + appl_light_hsl[0].target_hsl_saturation = 0x0000; + appl_light_hsl[0].target_hsl_lightness = 0x0000; + } + + if (0x00 != appl_light_xyl[0].transition_time) + { + /* TODO: Stop timer */ + appl_light_xyl[0].xyl_x = appl_light_xyl[0].target_xyl_x; + appl_light_xyl[0].xyl_y = appl_light_xyl[0].target_xyl_y; + appl_light_xyl[0].xyl_lightness = appl_light_xyl[0].target_xyl_lightness; + appl_light_xyl[0].transition_time = 0x00; + appl_light_xyl[0].target_xyl_x = 0x0000; + appl_light_xyl[0].target_xyl_y = 0x0000; + appl_light_xyl[0].target_xyl_lightness = 0x0000; + } +} + + +/* ---- State Transition Handlers */ + +static void appl_generic_onoff_transition_start_cb(void* blob) +{ + /** + Because binary states cannot support transitions, when changing to 0x01 (On), + the Generic OnOff state shall change immediately when the transition starts, + and when changing to 0x00, the state shall change when the transition finishes. + */ + #if 0 + if (0 == appl_generic_onoff[0].onoff) + { + appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; + } + + #endif +} + +static void appl_generic_onoff_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_generic_onoff[0].transition_time = 0; + /* appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; */ + appl_set_generic_onoff(0, appl_generic_onoff[0].target_onoff); + appl_generic_onoff[0].target_onoff = 0; +} + +static void appl_generic_level_transition_start_cb(void* blob) +{ + UINT16 state_t; + state_t = (UINT16)blob; +} + +static void appl_generic_level_transition_complete_cb(void* blob) +{ + UINT16 state_t; + state_t = (UINT16)blob; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + + switch (state_t) + { + case MS_STATE_GENERIC_LEVEL_T: + { + appl_set_level(0, appl_generic_level_info[0].generic_level.target_level); + } + break; + + case MS_STATE_DELTA_LEVEL_T: + { + appl_set_level(0, appl_generic_level_info[0].generic_level.target_level); + } + break; + + case MS_STATE_MOVE_LEVEL_T: + { + appl_set_move_level(0, appl_generic_level_info[0].generic_level.delta_level, 0x01); + /* TODO: Remove Bad Logic */ + appl_generic_level_info[0].generic_level.move_level = 0; + } + break; + } +} + +static void appl_light_lightness_transition_start_cb(void* blob) +{ +} + +static void appl_light_lightness_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_light_lightness[0].light_lightness_actual.transition_time = 0; + /* appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; */ + appl_light_lightness_set_actual(0, appl_light_lightness[0].light_lightness_actual.lightness_target); + appl_light_lightness[0].light_lightness_actual.lightness_target = 0; +} + +static void appl_light_lightness_linear_transition_start_cb(void* blob) +{ +} + +static void appl_light_lightness_linear_transition_complete_cb(void* blob) +{ + /* State Transition Complete */ + appl_light_lightness[0].light_lightness_linear.transition_time = 0; + /* appl_generic_onoff[0].onoff = appl_generic_onoff[0].target_onoff; */ + appl_light_lightness_set_linear(0, appl_light_lightness[0].light_lightness_linear.lightness_target); + appl_light_lightness[0].light_lightness_linear.lightness_target = 0; +} + +static void appl_light_xyl_transition_start_cb(void* blob) +{ +} + +static void appl_light_xyl_transition_complete_cb(void* blob) +{ + UINT16 state_t; + state_t = (UINT16)blob; + appl_light_xyl[0].transition_time = 0x00; + + switch(state_t) + { + case MS_STATE_LIGHT_XYL_T: + { + appl_light_xyl[0].xyl_x = appl_light_xyl[0].target_xyl_x; + appl_light_xyl[0].xyl_y = appl_light_xyl[0].target_xyl_y; + appl_light_xyl[0].xyl_lightness = appl_light_xyl[0].target_xyl_lightness; + appl_light_hsl[0].hsl_lightness = appl_light_xyl[0].xyl_lightness; + /* appl_light_lightness[0].light_lightness_actual.lightness_actual = appl_light_hsl[0].hsl_lightness; */ + appl_light_xyl[0].target_xyl_x = 0x0000; + appl_light_xyl[0].target_xyl_y = 0x0000; + appl_light_xyl[0].target_xyl_lightness = 0x0000; + } + break; + #if 0 + + case MS_STATE_LIGHT_HSL_SATURATION_T: + { + appl_light_hsl_set_saturation(0, appl_light_hsl[0].target_hsl_saturation); + appl_light_hsl[0].target_hsl_saturation = 0x0000; + } + break; + + case MS_STATE_LIGHT_HSL_HUE_T: + { + appl_light_hsl_set_hue(0, appl_light_hsl[0].target_hsl_hue); + appl_light_hsl[0].target_hsl_hue = 0x0000; + } + break; + #endif /* 0 */ + } + + #if 0 + appl_light_ctl_temp_set_actual(0, appl_light_ctl[0].target_ctl_temperature); + appl_light_ctl[0].ctl_lightness = appl_light_ctl[0].target_ctl_lightness; + appl_light_lightness[0].light_lightness_actual.lightness_actual = appl_light_ctl[0].ctl_lightness; + appl_light_ctl[0].target_ctl_temperature = 0x0000; + appl_light_ctl[0].target_ctl_lightness = 0x0000; + appl_light_ctl[0].transition_time = 0x0000; + #endif /* 0 */ +} + +static void appl_light_hsl_transition_start_cb(void* blob) +{ +} + +static void appl_light_hsl_transition_complete_cb(void* blob) +{ + UINT16 state_t; + state_t = (UINT16)blob; + appl_light_hsl[0].transition_time = 0x00; + + switch(state_t) + { + case MS_STATE_LIGHT_HSL_T: + { + appl_light_hsl[0].hsl_hue = appl_light_hsl[0].target_hsl_hue; + appl_light_hsl[0].hsl_saturation = appl_light_hsl[0].target_hsl_saturation; + appl_light_hsl[0].hsl_lightness = appl_light_hsl[0].target_hsl_lightness; + appl_light_lightness[0].light_lightness_actual.lightness_actual = appl_light_hsl[0].hsl_lightness; + appl_light_hsl[0].target_hsl_hue = 0x0000; + appl_light_hsl[0].target_hsl_saturation = 0x0000; + appl_light_hsl[0].target_hsl_lightness = 0x0000; + } + break; + + case MS_STATE_LIGHT_HSL_SATURATION_T: + { + appl_light_hsl_set_saturation(0, appl_light_hsl[0].target_hsl_saturation); + appl_light_hsl[0].target_hsl_saturation = 0x0000; + } + break; + + case MS_STATE_LIGHT_HSL_HUE_T: + { + appl_light_hsl_set_hue(0, appl_light_hsl[0].target_hsl_hue); + appl_light_hsl[0].target_hsl_hue = 0x0000; + } + break; + } + + #if 0 + appl_light_ctl_temp_set_actual(0, appl_light_ctl[0].target_ctl_temperature); + appl_light_ctl[0].ctl_lightness = appl_light_ctl[0].target_ctl_lightness; + appl_light_lightness[0].light_lightness_actual.lightness_actual = appl_light_ctl[0].ctl_lightness; + appl_light_ctl[0].target_ctl_temperature = 0x0000; + appl_light_ctl[0].target_ctl_lightness = 0x0000; + appl_light_ctl[0].transition_time = 0x0000; + #endif /* 0 */ +} + +void* appl_scene_save_current_state(/* IN */ UINT32 scene_index) +{ + /* Free previous context - if any */ + /* Empty right now - dummy returning the same scene index itself */ + /* Store current state */ + appl_state_info_vault[scene_index].onoff = appl_generic_onoff[0].onoff; + appl_state_info_vault[scene_index].level = appl_generic_level_info[0].generic_level.level; + appl_state_info_vault[scene_index].lightness_actual = appl_light_lightness[0].light_lightness_actual.lightness_actual; + appl_state_info_vault[scene_index].lightness_linear = appl_light_lightness[0].light_lightness_linear.lightness_linear; + appl_state_info_vault[scene_index].hsl_hue = appl_light_hsl[0].hsl_hue; + appl_state_info_vault[scene_index].hsl_saturation = appl_light_hsl[0].hsl_saturation; + appl_state_info_vault[scene_index].hsl_lightness = appl_light_hsl[0].hsl_lightness; + appl_state_info_vault[scene_index].xyl_lightness = appl_light_xyl[0].xyl_lightness; + appl_state_info_vault[scene_index].xyl_x = appl_light_xyl[0].xyl_x; + appl_state_info_vault[scene_index].xyl_y = appl_light_xyl[0].xyl_y; + return (void*)scene_index; +} + +void* appl_scene_delete_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ + /* Free context - if any */ + /* Empty right now - dummy returning NULL */ + /* Invalid value */ + appl_state_info_vault[scene_index].onoff = 0x02; + appl_state_info_vault[scene_index].level = 0xFFFF; + appl_state_info_vault[scene_index].lightness_actual = 0x0000; + appl_state_info_vault[scene_index].lightness_linear = 0x0000; + appl_state_info_vault[scene_index].ctl_lightness = 0x0000; + appl_state_info_vault[scene_index].ctl_temperature = 0x0000; + appl_state_info_vault[scene_index].ctl_delta_uv = 0x0000; + appl_state_info_vault[scene_index].xyl_lightness = 0x0000; + appl_state_info_vault[scene_index].xyl_x = 0x0000; + appl_state_info_vault[scene_index].xyl_y = 0x0000; + return (void*)NULL; +} + +void* appl_scene_recall_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ + /* Recall context - if any */ + /* Empty right now - dummy returning NULL */ + /* appl_generic_onoff[0].onoff = appl_state_info_vault[scene_index].onoff; */ + appl_set_generic_onoff(0, appl_state_info_vault[scene_index].onoff); + appl_generic_level_info[0].generic_level.level = appl_state_info_vault[scene_index].level; + appl_light_lightness[0].light_lightness_actual.lightness_actual = appl_state_info_vault[scene_index].lightness_actual; + appl_light_lightness[0].light_lightness_linear.lightness_linear = appl_state_info_vault[scene_index].lightness_linear; + appl_light_hsl[0].hsl_hue = appl_state_info_vault[scene_index].hsl_hue; + appl_light_hsl[0].hsl_saturation = appl_state_info_vault[scene_index].hsl_saturation; + appl_light_hsl[0].hsl_lightness = appl_state_info_vault[scene_index].hsl_lightness; + appl_light_xyl[0].xyl_lightness = appl_state_info_vault[scene_index].xyl_lightness; + appl_light_xyl[0].xyl_x = appl_state_info_vault[scene_index].xyl_x; + appl_light_xyl[0].xyl_y = appl_state_info_vault[scene_index].xyl_y; + return (void*)NULL; +} + +API_RESULT appl_model_light_lightness_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + MS_STATE_LIGHT_LIGHTNESS_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)param; + + switch (state_t) + { + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_default = appl_light_lightness[0].light_lightness_default; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_range = appl_light_lightness[0].light_lightness_range; + param_p->range_status = 0x00; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_linear = appl_light_lightness[0].light_lightness_linear; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_last = appl_light_lightness[0].light_lightness_last; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_actual = appl_light_lightness[0].light_lightness_actual; + } + break; + + default: + break; + } + + return API_SUCCESS; +} + +API_RESULT appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_ONPOWERUP_T: + { + MS_STATE_GENERIC_ONPOWERUP_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)param; + /* Ignoting Instance and direction right now */ + *param_p = appl_generic_onpower[0]; + } + break; + + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_generic_onoff[0]; + } + break; + + case MS_STATE_GENERIC_LEVEL_T: + { + MS_STATE_GENERIC_LEVEL_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_LEVEL_STRUCT*)param; + /* Ignoting Instance and direction right now */ + *param_p = appl_generic_level_info[0].generic_level; + param_p->level = appl_generic_level_info[0].generic_level.level + appl_generic_level_info[0].generic_level.delta_level; + + /* TODO: hack */ + if (0xFE == appl_generic_level_info[0].generic_level.transition_time) + { + param_p->transition_time = 0x3F; + } + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + retval = appl_model_light_lightness_state_get(state_t, state_inst, param, direction); + break; + + case MS_STATE_LIGHT_HSL_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_TARGET_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_HUE_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_SATURATION_T: + retval = appl_model_light_hsl_state_get(state_t, state_inst, param, direction); + break; + + case MS_STATE_LIGHT_XYL_T: /* Fall Through */ + case MS_STATE_LIGHT_XYL_TARGET_T: /* Fall Through */ + case MS_STATE_LIGHT_XYL_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_XYL_RANGE_T: + retval = appl_model_light_xyl_state_get(state_t, state_inst, param, direction); + break; + + default: + break; + } + + return retval; +} + + +void appl_light_xyl_set_x(UINT16 state_inst, UINT16 actual) +{ + UINT16 min, max; + min = appl_light_xyl_range[state_inst].xyl_x_range_min; + max = appl_light_xyl_range[state_inst].xyl_x_range_max; + + /* Generic OnOff binding */ + if (0x0000 == actual) + { + /* appl_generic_onoff[state_inst].onoff = 0x00; */ + } + else + { + if ((0 != min) && (actual < min)) + { + actual = min; + } + else if ((0 != max) && (actual > max)) + { + actual = max; + } + + /* appl_generic_onoff[state_inst].onoff = 0x01; */ + /* appl_light_lightness[state_inst].light_lightness_last.lightness_last = actual; */ + } + + appl_light_xyl[state_inst].xyl_x = actual; + /* Light Lightness Linear = ((Actual)^2) / 65535 */ + /* appl_light_lightness[state_inst].light_lightness_linear.lightness_linear = ((actual * actual) + 65534) / 65535; */ + /* Generic Level = (Light CTL Temperature - T _MIN) * 65535 / (T_MAX - T_MIN) - 32768 */ + /* appl_generic_level_info[state_inst].generic_level.level = actual - 32768; */ +} + +void appl_light_xyl_set_y(UINT16 state_inst, UINT16 actual) +{ + UINT16 min, max; + min = appl_light_xyl_range[state_inst].xyl_y_range_min; + max = appl_light_xyl_range[state_inst].xyl_y_range_max; + + /* Generic OnOff binding */ + if (0x0000 == actual) + { + /* appl_generic_onoff[state_inst].onoff = 0x00; */ + } + else + { + if ((0 != min) && (actual < min)) + { + actual = min; + } + else if ((0 != max) && (actual > max)) + { + actual = max; + } + + /* appl_generic_onoff[state_inst].onoff = 0x01; */ + /* appl_light_lightness[state_inst].light_lightness_last.lightness_last = actual; */ + } + + appl_light_xyl[state_inst].xyl_y = actual; + /* Light Lightness Linear = ((Actual)^2) / 65535 */ + /* appl_light_lightness[state_inst].light_lightness_linear.lightness_linear = ((actual * actual) + 65534) / 65535; */ + /* Generic Level = (Light CTL Temperature - T _MIN) * 65535 / (T_MAX - T_MIN) - 32768 */ + /* appl_generic_level_info[state_inst].generic_level.level = actual - 32768; */ +} + +void appl_light_xyl_set_range(UINT16 state_inst, UINT16 x_min, UINT16 x_max, UINT16 y_min, UINT16 y_max) +{ + UINT16 actual_x, actual_y; + appl_light_xyl_range[state_inst].xyl_x_range_min = x_min; + appl_light_xyl_range[state_inst].xyl_x_range_max = x_max; + appl_light_xyl_range[state_inst].xyl_y_range_min = y_min; + appl_light_xyl_range[state_inst].xyl_y_range_max= y_max; + /* Check if actual to be updated */ + actual_x = appl_light_xyl[state_inst].xyl_x; + + if (actual_x < x_min) + { + appl_light_xyl[state_inst].xyl_x = x_min; + } + else if (actual_x > x_max) + { + appl_light_xyl[state_inst].xyl_x = x_max; + } + + actual_y = appl_light_xyl[state_inst].xyl_y; + + if (actual_y < y_min) + { + appl_light_xyl[state_inst].xyl_y = y_min; + } + else if (actual_y > y_max) + { + appl_light_xyl[state_inst].xyl_y = y_max; + } +} + +void appl_light_hsl_set_hue(UINT16 state_inst, UINT16 actual) +{ + UINT16 min, max; + min = appl_light_hsl_range[state_inst].hue_range_min; + max = appl_light_hsl_range[state_inst].hue_range_max; + + /* Generic OnOff binding */ + if (0x0000 == actual) + { + /* appl_generic_onoff[state_inst].onoff = 0x00; */ + } + else + { + if ((0 != min) && (actual < min)) + { + actual = min; + } + else if ((0 != max) && (actual > max)) + { + actual = max; + } + + /* appl_generic_onoff[state_inst].onoff = 0x01; */ + /* appl_light_lightness[state_inst].light_lightness_last.lightness_last = actual; */ + } + + appl_light_hsl[state_inst].hsl_hue = actual; + /* Light Lightness Linear = ((Actual)^2) / 65535 */ + /* appl_light_lightness[state_inst].light_lightness_linear.lightness_linear = ((actual * actual) + 65534) / 65535; */ + /* Generic Level = (Light CTL Temperature - T _MIN) * 65535 / (T_MAX - T_MIN) - 32768 */ + appl_generic_level_info[state_inst].generic_level.level = actual - 32768; +} + +void appl_light_hsl_set_saturation(UINT16 state_inst, UINT16 actual) +{ + UINT16 min, max; + min = appl_light_hsl_range[state_inst].saturation_range_min; + max = appl_light_hsl_range[state_inst].saturation_range_max; + + /* Generic OnOff binding */ + if (0x0000 == actual) + { + /* appl_generic_onoff[state_inst].onoff = 0x00; */ + } + else + { + if ((0 != min) && (actual < min)) + { + actual = min; + } + else if ((0 != max) && (actual > max)) + { + actual = max; + } + + /* appl_generic_onoff[state_inst].onoff = 0x01; */ + /* appl_light_lightness[state_inst].light_lightness_last.lightness_last = actual; */ + } + + appl_light_hsl[state_inst].hsl_saturation = actual; + /* Light Lightness Linear = ((Actual)^2) / 65535 */ + /* appl_light_lightness[state_inst].light_lightness_linear.lightness_linear = ((actual * actual) + 65534) / 65535; */ + /* Generic Level = (Light CTL Temperature - T _MIN) * 65535 / (T_MAX - T_MIN) - 32768 */ + appl_generic_level_info[state_inst].generic_level.level = actual - 32768; +} + +void appl_light_hsl_set_range(UINT16 state_inst, UINT16 hue_min, UINT16 hue_max, UINT16 saturation_min, UINT16 saturation_max) +{ + UINT16 actual_hue, actual_saturation; + appl_light_hsl_range[state_inst].hue_range_min = hue_min; + appl_light_hsl_range[state_inst].hue_range_max = hue_max; + appl_light_hsl_range[state_inst].saturation_range_min = saturation_min; + appl_light_hsl_range[state_inst].saturation_range_max = saturation_max; + /* Check if actual to be updated */ + actual_hue = appl_light_hsl[state_inst].hsl_hue; + + if (actual_hue < hue_min) + { + appl_light_hsl[state_inst].hsl_hue = hue_min; + } + else if (actual_hue > hue_max) + { + appl_light_hsl[state_inst].hsl_hue = hue_max; + } + + actual_saturation = appl_light_hsl[state_inst].hsl_hue; + + if (actual_saturation < saturation_min) + { + appl_light_hsl[state_inst].hsl_saturation = saturation_min; + } + else if (actual_saturation > saturation_max) + { + appl_light_hsl[state_inst].hsl_saturation = saturation_max; + } +} + +void appl_light_lightness_set_actual(UINT16 state_inst, UINT16 actual) +{ + UINT16 min, max; + + /* Generic OnOff binding */ + if (0x0000 == actual) + { + appl_generic_onoff[state_inst].onoff= 0x00; + } + else + { + min = appl_light_lightness[state_inst].light_lightness_range.lightness_range_min; + max = appl_light_lightness[state_inst].light_lightness_range.lightness_range_max; + + if ((0 != min) && (actual < min)) + { + actual = min; + } + else if ((0 != max) && (actual > max)) + { + actual = max; + } + + appl_generic_onoff[state_inst].onoff = 0x01; + appl_light_lightness[state_inst].light_lightness_last.lightness_last = actual; + } + + appl_light_lightness[state_inst].light_lightness_actual.lightness_actual = actual; + /* appl_light_ctl[state_inst].ctl_lightness = actual; */ + appl_light_xyl[state_inst].xyl_lightness = actual; + appl_light_hsl[state_inst].hsl_lightness = actual; + /* Light Lightness Linear = ((Actual)^2) / 65535 */ + appl_light_lightness[state_inst].light_lightness_linear.lightness_linear = ((actual * actual) + 65534) / 65535; + appl_generic_level_info[state_inst].generic_level.level = actual - 32768; +} + +void appl_light_lightness_set_range(UINT16 state_inst, UINT16 min, UINT16 max) +{ + UINT16 actual; + appl_light_lightness[state_inst].light_lightness_range.lightness_range_min = min; + appl_light_lightness[state_inst].light_lightness_range.lightness_range_max = max; + /* Check if actual to be updated */ + actual = appl_light_lightness[state_inst].light_lightness_actual.lightness_actual; + + if (actual < min) + { + appl_light_lightness[state_inst].light_lightness_actual.lightness_actual = min; + } + else if (actual > max) + { + appl_light_lightness[state_inst].light_lightness_actual.lightness_actual = max; + } +} + +void appl_set_level(UINT16 state_inst, UINT16 level) +{ + UINT16 min, max; + appl_generic_level_info[state_inst].generic_level.level = level; + appl_generic_level_info[state_inst].generic_level.target_level = 0; + appl_generic_level_info[state_inst].generic_level.delta_level = 0; + appl_light_lightness_set_actual(0, level + 32768); + /* min = appl_light_ctl_temperature_range[state_inst].ctl_temperature_range_min; */ + /* max = appl_light_ctl_temperature_range[state_inst].ctl_temperature_range_max; */ + /* Light CTL Temperature = T_MIN + (Generic Level + 32768) * (T_MAX - T_MIN) / 65535 */ + /* appl_light_ctl_temperature[0].ctl_temperature = min + (((level + 32768) * (max - min)) / 65535); */ + appl_light_hsl[state_inst].hsl_hue = level + 32768; + appl_light_hsl[state_inst].hsl_saturation = level + 32768; +} + +void appl_set_delta_level(UINT16 state_inst, INT32 delta, UINT8 immediate) +{ + /* TODO: See if this to be stored */ + if (0x01 == immediate) + { + appl_set_level(state_inst, (appl_generic_level_info[state_inst].generic_level.level + delta)); + } + else if (0x00 == immediate) + { + appl_generic_level_info[0].generic_level.target_level = (appl_generic_level_info[state_inst].generic_level.level + delta); + appl_generic_level_info[state_inst].generic_level.delta_level = delta; + } + else + { + /* Do nothing right now */ + } +} + +void appl_set_move_level(UINT16 state_inst, UINT16 move, UINT8 immediate) +{ + /* TODO: See if this to be stored */ + appl_generic_level_info[state_inst].generic_level.move_level = move; +} + +/* Todo: Remove the dependency */ +#include "math.h" + +void appl_light_lightness_set_linear(UINT16 state_inst, UINT16 linear) +{ + UINT16 actual; + UINT32 mul_val; + long double d; + /* appl_light_lightness[state_inst].light_lightness_linear.lightness_linear = linear; */ + mul_val = linear * 65535; + actual = (UINT16)sqrt(mul_val); + /* Light Lightness actual = sqrt(Linear * 65535) */ + appl_light_lightness_set_actual(state_inst, actual); +} + + +void appl_set_generic_onoff(UINT16 state_inst, UINT8 onoff) +{ + UINT16 actual; + /* TODO: See if this to be stored */ + appl_generic_onoff[state_inst].onoff = onoff; + + /* Binding */ + if (onoff == 0x00) + { + appl_light_lightness_set_actual(state_inst, 0x00); + } + else + { + if (0x0000 == appl_light_lightness[state_inst].light_lightness_default.lightness_default) + { + actual = appl_light_lightness[state_inst].light_lightness_last.lightness_last; + } + else + { + actual = appl_light_lightness[state_inst].light_lightness_default.lightness_default; + } + + appl_light_lightness_set_actual(state_inst, actual); + } +} + +API_RESULT appl_model_light_lightness_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + MS_STATE_LIGHT_LIGHTNESS_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)param; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: + { + /* Ignoring Instance and direction right now */ + appl_light_lightness[0].light_lightness_default = param_p->light_lightness_default; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: + { + /* Check range min and max */ + if (param_p->light_lightness_range.lightness_range_min > param_p->light_lightness_range.lightness_range_max) + { + /* TODO: add macro define */ + /** + Table 7.2: + 0x00 - Success + 0x01 - Cannot Set Range Min + 0x02 - Cannot Set Range Max + */ + param_p->range_status = 0x01; + #if 0 + appl_light_lightness[0].light_lightness_range = param_p->light_lightness_range; + param_p->light_lightness_range.lightness_range_min = 0x0000; + param_p->light_lightness_range.lightness_range_max = 0x0000; + #endif + } + else + { + /* Ignoring Instance and direction right now */ + appl_light_lightness[0].light_lightness_range = param_p->light_lightness_range; + param_p->range_status = 0x00; + } + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: + { + if (0 != param_p->light_lightness_linear.transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_lightness[0].light_lightness_linear.lightness_target = param_p->light_lightness_linear.lightness_linear; + appl_light_lightness[0].light_lightness_linear.transition_time = param_p->light_lightness_linear.transition_time; + transition.delay = param_p->light_lightness_linear.delay; + transition.transition_time = param_p->light_lightness_linear.transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_light_lightness_linear_transition_start_cb; + transition.transition_complete_cb = appl_light_lightness_linear_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + /* appl_generic_onoff[0].onoff = param_p->onoff; */ + appl_light_lightness_set_linear(0, param_p->light_lightness_linear.lightness_linear); + } + + *param_p = appl_light_lightness[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", param_p->light_lightness_linear.lightness_linear); + CONSOLE_OUT("[state] target: 0x%02X\n", param_p->light_lightness_linear.lightness_target); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", param_p->light_lightness_linear.transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: + { + /* Ignoring Instance and direction right now */ + appl_light_lightness[0].light_lightness_last = param_p->light_lightness_last; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + { + if (0 != param_p->light_lightness_actual.transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_lightness[0].light_lightness_actual.lightness_target = param_p->light_lightness_actual.lightness_actual; + appl_light_lightness[0].light_lightness_actual.transition_time = param_p->light_lightness_actual.transition_time; + transition.delay = param_p->light_lightness_actual.delay; + transition.transition_time = param_p->light_lightness_actual.transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_light_lightness_transition_start_cb; + transition.transition_complete_cb = appl_light_lightness_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + /* appl_generic_onoff[0].onoff = param_p->onoff; */ + appl_light_lightness_set_actual(0, param_p->light_lightness_actual.lightness_actual); + } + + *param_p = appl_light_lightness[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", param_p->light_lightness_actual.lightness_actual); + CONSOLE_OUT("[state] target: 0x%02X\n", param_p->light_lightness_actual.lightness_target); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", param_p->light_lightness_actual.transition_time); + /* Ignoring Instance and direction right now */ + /* param_p->light_lightness_actual.lightness_actual = appl_light_lightness[0].light_lightness_actual.lightness_actual; */ + } + break; + + default: + break; + } + + return retval; +} + +API_RESULT appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_ONPOWERUP_T: + { + MS_STATE_GENERIC_ONPOWERUP_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONPOWERUP_STRUCT*)param; + /* Ignoting Instance and direction right now */ + appl_generic_onpower[0] = *param_p; + } + break; + + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_generic_onoff[0].target_onoff = param_p->onoff; + appl_generic_onoff[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = NULL; + transition.transition_start_cb = appl_generic_onoff_transition_start_cb; + transition.transition_complete_cb = appl_generic_onoff_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Instantaneous Change */ + /* appl_generic_onoff[0].onoff = param_p->onoff; */ + appl_set_generic_onoff(0, param_p->onoff); + } + + *param_p = appl_generic_onoff[0]; + CONSOLE_OUT("[state] current: 0x%02X\n", appl_generic_onoff[0].onoff); + CONSOLE_OUT("[state] target: 0x%02X\n", appl_generic_onoff[0].target_onoff); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_generic_onoff[0].transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + case MS_STATE_GENERIC_LEVEL_T: /* Fall Through */ + case MS_STATE_DELTA_LEVEL_T: /* Fall Through */ + case MS_STATE_MOVE_LEVEL_T: + { + retval = appl_generic_level_model_state_set(state_t, state_inst, param, direction); + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: /* Fall Through */ + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + retval = appl_model_light_lightness_state_set(state_t, state_inst, param, direction); + break; + + case MS_STATE_LIGHT_HSL_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_TARGET_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_DEFAULT_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_HUE_T: /* Fall Through */ + case MS_STATE_LIGHT_HSL_SATURATION_T: + retval = appl_model_light_hsl_state_set(state_t, state_inst, param, direction); + break; + + case MS_STATE_LIGHT_XYL_T: /* Fall Through */ + case MS_STATE_LIGHT_XYL_TARGET_T: /* Fall Through */ + case MS_STATE_LIGHT_XYL_RANGE_T: /* Fall Through */ + case MS_STATE_LIGHT_XYL_DEFAULT_T: /* Fall Through */ + retval = appl_model_light_xyl_state_set(state_t, state_inst, param, direction); + break; + + default: + break; + } + + return retval; +} + +API_RESULT appl_generic_level_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + MS_STATE_GENERIC_LEVEL_STRUCT* param_p; + /** + Transaction State: + 0 : Start of Transaction + 1 : Continue + 2 : End of Transaction + */ + UINT8 transaction_state; + param_p = (MS_STATE_GENERIC_LEVEL_STRUCT*)param; + + switch (state_t) + { + case MS_STATE_GENERIC_LEVEL_T: + { + /* Ignoting Instance and direction right now */ + /* TODO: Not handling transaction state */ + { + MS_common_stop_transition_timer(appl_generic_level_info[0].transition_time_handle); + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + + if (0 == param_p->transition_time) + { + appl_set_level(0, param_p->level); + } + else + { + appl_generic_level_info[0].generic_level.target_level = param_p->level; + param_p->target_level = param_p->level; + } + } + } + break; + + case MS_STATE_DELTA_LEVEL_T: + { + /* Check if a new transaction */ + if (appl_generic_level_info[0].operation_type != state_t) + { + transaction_state = 0x00; + /* Stop associated Transaction Timer, if any */ + MS_common_stop_transition_timer(appl_generic_level_info[0].transition_time_handle); + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + appl_generic_level_info[0].operation_type = state_t; + appl_generic_level_info[0].generic_level.tid = param_p->tid; + } + else if (param_p->tid == appl_generic_level_info[0].generic_level.tid) + { + transaction_state = 0x01; + } + else + { + transaction_state = 0x02; + /* Stop associated Transaction Timer, if any */ + MS_common_stop_transition_timer(appl_generic_level_info[0].transition_time_handle); + appl_generic_level_info[0].transition_time_handle = 0xFFFF; + appl_generic_level_info[0].generic_level.transition_time = 0x00; + appl_generic_level_info[0].operation_type = state_t; + appl_generic_level_info[0].generic_level.tid = param_p->tid; + } + + /* Ignoting Instance and direction right now */ + if (0 == param_p->transition_time) + { + if (0x02 == transaction_state) + { + appl_set_delta_level(0, (INT32)appl_generic_level_info[0].generic_level.delta_level, 0x01); + } + + /* Only update delta */ + appl_set_delta_level(0, (INT32)param_p->delta_level, 0x00); + } + else + { + appl_set_delta_level(0, (INT32)param_p->delta_level, 0x00); + } + } + break; + + case MS_STATE_MOVE_LEVEL_T: + { + /* Ignoting Instance and direction right now */ + if (0 == param_p->transition_time) + { + appl_set_move_level(0, param_p->move_level, 0x01); + } + else + { + appl_set_move_level(0, param_p->move_level, 0x00); + /* appl_generic_level_info[0].generic_level.target_level = 0x00; */ + appl_generic_level_info[0].generic_level.target_level = param_p->move_level * (param_p->transition_time & 0x3F); + /* TODO: Hardcoding */ + appl_generic_level_info[0].generic_level.target_level = 0x7FFF; + } + } + break; + + default: + break; + } + + /* TODO: Do we need to check if this is a new transaction? */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + appl_generic_level_info[0].generic_level.transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = (void*)state_t; + transition.transition_start_cb = appl_generic_level_transition_start_cb; + transition.transition_complete_cb = appl_generic_level_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &appl_generic_level_info[0].transition_time_handle + ); + } + + *param_p = appl_generic_level_info[0].generic_level; + param_p->level = appl_generic_level_info[0].generic_level.level + appl_generic_level_info[0].generic_level.delta_level; + + /* TODO: hack */ + if (0xFE == appl_generic_level_info[0].generic_level.transition_time) + { + param_p->transition_time = 0x3F; + } + + return API_SUCCESS; +} + +API_RESULT appl_model_light_hsl_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + switch(state_t) + { + case MS_STATE_LIGHT_HSL_T: + { + MS_STATE_LIGHT_HSL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_hsl[0]; + } + break; + + case MS_STATE_LIGHT_HSL_TARGET_T: + { + MS_STATE_LIGHT_HSL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_hsl[0]; + } + break; + + case MS_STATE_LIGHT_HSL_RANGE_T: + { + MS_STATE_LIGHT_HSL_RANGE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_RANGE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_hsl_range[0]; + } + break; + + case MS_STATE_LIGHT_HSL_DEFAULT_T: + { + MS_STATE_LIGHT_HSL_DEFAULT_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_DEFAULT_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_hsl_default[0]; + } + break; + + case MS_STATE_LIGHT_HSL_HUE_T: + { + MS_STATE_LIGHT_HSL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_hsl[0]; + } + break; + + case MS_STATE_LIGHT_HSL_SATURATION_T: + { + MS_STATE_LIGHT_HSL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_hsl[0]; + } + break; + + default: + break; + } + + return API_SUCCESS; +} + + +API_RESULT appl_model_light_hsl_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_LIGHT_HSL_T: + { + MS_STATE_LIGHT_HSL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_STRUCT*)param; + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_hsl[0].target_hsl_hue = param_p->hsl_hue; + appl_light_hsl[0].target_hsl_saturation = param_p->hsl_saturation; + appl_light_hsl[0].target_hsl_lightness = param_p->hsl_lightness; + appl_light_hsl[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = (void*)state_t; + transition.transition_start_cb = appl_light_hsl_transition_start_cb; + transition.transition_complete_cb = appl_light_hsl_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + appl_light_hsl[0].hsl_lightness = param_p->hsl_lightness; + appl_light_xyl[0].xyl_lightness = param_p->hsl_lightness; + appl_light_hsl[0].hsl_hue = param_p->hsl_hue; + appl_light_hsl[0].hsl_saturation = param_p->hsl_saturation; + appl_light_hsl[0].tid = param_p->tid; + /* + appl_light_hsl[0].hsl_lightness = param_p->hsl_lightness; + appl_light_hsl[0].hsl_lightness = param_p->hsl_lightness; + appl_light_hsl[0].hsl_lightness = param_p->hsl_lightness; + */ + appl_light_lightness[state_inst].light_lightness_actual.lightness_actual = param_p->hsl_lightness; + } + + *param_p = appl_light_hsl[0]; + CONSOLE_OUT("[state] current Hue: 0x%04X\n", appl_light_hsl[0].hsl_hue); + CONSOLE_OUT("[state] current Saturation: 0x%04X\n", appl_light_hsl[0].hsl_saturation); + CONSOLE_OUT("[state] current Lightness: 0x%04X\n", appl_light_hsl[0].hsl_lightness); + CONSOLE_OUT("[state] target Hue: 0x%04X\n", appl_light_hsl[0].target_hsl_hue); + CONSOLE_OUT("[state] target Saturation: 0x%04X\n", appl_light_hsl[0].target_hsl_saturation); + CONSOLE_OUT("[state] target Lightness: 0x%04X\n", appl_light_hsl[0].target_hsl_lightness); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_light_hsl[0].transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + case MS_STATE_LIGHT_HSL_RANGE_T: + { + MS_STATE_LIGHT_HSL_RANGE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_RANGE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + /* appl_light_hsl_range[0].hue_range_min = param_p->hue_range_min; */ + /* appl_light_hsl_range[0].hue_range_max = param_p->hue_range_max; */ + /* appl_light_hsl_range[0].saturation_range_min = param_p->saturation_range_min; */ + /* appl_light_hsl_range[0].saturation_range_max = param_p->saturation_range_max; */ + appl_light_hsl_set_range(0, param_p->hue_range_min, param_p->hue_range_max, param_p->saturation_range_min, param_p->saturation_range_max); + param_p->status = 0x00; + } + break; + + case MS_STATE_LIGHT_HSL_DEFAULT_T: + { + MS_STATE_LIGHT_HSL_DEFAULT_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_DEFAULT_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_light_hsl_default[0] = *param_p; + } + break; + + case MS_STATE_LIGHT_HSL_HUE_T: + { + MS_STATE_LIGHT_HSL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_STRUCT*)param; + + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_hsl[0].target_hsl_hue = param_p->hsl_hue; + appl_light_hsl[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = (void*)state_t; + transition.transition_start_cb = appl_light_hsl_transition_start_cb; + transition.transition_complete_cb = appl_light_hsl_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Ignoring Instance and direction right now */ + appl_light_hsl_set_hue(0, param_p->hsl_hue); + /* appl_light_hsl[0].hsl_hue = param_p->hsl_hue; */ + /* param_p->hsl_hue = appl_light_hsl[state_inst].hsl_hue; */ + } + + *param_p = appl_light_hsl[0]; + CONSOLE_OUT("[state] current Hue: 0x%04X\n", appl_light_hsl[0].hsl_hue); + CONSOLE_OUT("[state] target Hue: 0x%04X\n", appl_light_hsl[0].target_hsl_hue); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_light_hsl[0].transition_time); + } + break; + + case MS_STATE_LIGHT_HSL_SATURATION_T: + { + MS_STATE_LIGHT_HSL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_HSL_STRUCT*)param; + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_hsl[0].target_hsl_saturation = param_p->hsl_saturation; + appl_light_hsl[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = (void*)state_t; + transition.transition_start_cb = appl_light_hsl_transition_start_cb; + transition.transition_complete_cb = appl_light_hsl_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + /* Ignoring Instance and direction right now */ + appl_light_hsl_set_saturation(0, param_p->hsl_saturation); + /* appl_light_hsl[0].hsl_saturation = param_p->hsl_saturation; */ + /* param_p->hsl_saturation = appl_light_hsl[state_inst].hsl_saturation; */ + } + + *param_p = appl_light_hsl[0]; + CONSOLE_OUT("[state] current Saturation: 0x%04X\n", appl_light_hsl[0].hsl_saturation); + CONSOLE_OUT("[state] target Saturation: 0x%04X\n", appl_light_hsl[0].target_hsl_saturation); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_light_hsl[0].transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + default: + break; + } + + return retval; +} + + +API_RESULT appl_model_light_xyl_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + switch(state_t) + { + case MS_STATE_LIGHT_XYL_TARGET_T: + { + MS_STATE_LIGHT_XYL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_XYL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_xyl[0]; + } + break; + + case MS_STATE_LIGHT_XYL_T: + { + MS_STATE_LIGHT_XYL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_XYL_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_xyl[0]; + } + break; + + case MS_STATE_LIGHT_XYL_DEFAULT_T: + { + MS_STATE_LIGHT_XYL_DEFAULT_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_XYL_DEFAULT_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_xyl_default[0]; + } + break; + + case MS_STATE_LIGHT_XYL_RANGE_T: + { + MS_STATE_LIGHT_XYL_RANGE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_XYL_RANGE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_light_xyl_range[0]; + param_p->status = 0x00; + } + break; + + default: + break; + } + + return API_SUCCESS; +} + + +API_RESULT appl_model_light_xyl_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_LIGHT_XYL_T: + { + MS_STATE_LIGHT_XYL_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_XYL_STRUCT*)param; + + /* Check if state transition is specified */ + if (0 != param_p->transition_time) + { + MS_ACCESS_STATE_TRANSITION_TYPE transition; + UINT16 transition_time_handle; + appl_light_xyl[0].target_xyl_lightness = param_p->xyl_lightness; + appl_light_xyl[0].target_xyl_x = param_p->xyl_x; + appl_light_xyl[0].target_xyl_y = param_p->xyl_y; + appl_light_xyl[0].transition_time = param_p->transition_time; + transition.delay = param_p->delay; + transition.transition_time = param_p->transition_time; + transition.blob = (void*)state_t; + transition.transition_start_cb = appl_light_xyl_transition_start_cb; + transition.transition_complete_cb = appl_light_xyl_transition_complete_cb; + MS_common_start_transition_timer + ( + &transition, + &transition_time_handle + ); + /* Return value to indicate not sending status right now */ + retval = API_FAILURE; + } + else + { + appl_light_xyl[0].xyl_lightness = param_p->xyl_lightness; + appl_light_hsl[0].hsl_lightness = param_p->xyl_lightness; + appl_light_xyl_set_x(0, param_p->xyl_x); + appl_light_xyl_set_y(0, param_p->xyl_y); + } + + *param_p = appl_light_xyl[0]; + CONSOLE_OUT("[state] current X: 0x%04X\n", appl_light_xyl[0].xyl_x); + CONSOLE_OUT("[state] current Y: 0x%04X\n", appl_light_xyl[0].xyl_y); + CONSOLE_OUT("[state] current Lightness: 0x%04X\n", appl_light_xyl[0].xyl_lightness); + CONSOLE_OUT("[state] target X: 0x%04X\n", appl_light_xyl[0].target_xyl_x); + CONSOLE_OUT("[state] target Y: 0x%04X\n", appl_light_xyl[0].target_xyl_y); + CONSOLE_OUT("[state] target Lightness: 0x%04X\n", appl_light_xyl[0].target_xyl_lightness); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", appl_light_xyl[0].transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + case MS_STATE_LIGHT_XYL_DEFAULT_T: + { + MS_STATE_LIGHT_XYL_DEFAULT_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_XYL_DEFAULT_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_light_xyl_default[0] = *param_p; + } + break; + + case MS_STATE_LIGHT_XYL_RANGE_T: + { + MS_STATE_LIGHT_XYL_RANGE_STRUCT* param_p; + param_p = (MS_STATE_LIGHT_XYL_RANGE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + /* appl_light_xyl_range[0] = *param_p; */ + appl_light_xyl_set_range(0, param_p->xyl_x_range_min, param_p->xyl_x_range_max, param_p->xyl_y_range_min, param_p->xyl_y_range_max); + param_p->status = 0x00; + } + break; + + default: + break; + } + + return retval; +} + + diff --git a/src/components/ethermind/mesh/export/appl/model/server/lighting/light_xyl_server/appl_model_state_handler.h b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_xyl_server/appl_model_state_handler.h new file mode 100644 index 0000000..6522267 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/lighting/light_xyl_server/appl_model_state_handler.h @@ -0,0 +1,32 @@ +/** + \file appl_model_state_handler.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_MODEL_STATE_HANDLER_ +#define _H_APPL_MODEL_STATE_HANDLER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_main.h" +#include "MS_model_states.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void); + +API_RESULT appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +API_RESULT appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +#endif /*_H_APPL_MODEL_STATE_HANDLER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/sensor/sensor_server/appl_model_state_handler.c b/src/components/ethermind/mesh/export/appl/model/server/sensor/sensor_server/appl_model_state_handler.c new file mode 100644 index 0000000..cfc2fd4 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/sensor/sensor_server/appl_model_state_handler.c @@ -0,0 +1,601 @@ +/** + \file appl_model_state_handler.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_model_state_handler.h" +#include "MS_common.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ + + +/* --------------------------------------------- Data Types/Structures */ +#define MS_MAX_NUM_STATES 2 +#define MS_MAX_SENSORS 1 +#define MS_MAX_SENSOR_SETTINGS 1 + +#define MS_PROP_ID_FOR_TEST 0x0042 /* 0x1234 */ + +/* UINT16 value of People Count */ +#define MS_PROP_ID_PEOPLE_COUNT 0x004C + +typedef struct _MS_SENSOR_STRUCT +{ + /** -- Sensor Descriptor -- **/ + /** + Sensor Property ID field is a 2-octet value referencing a device property + that describes the meaning and the format of data reported by a sensor + */ + UINT16 sensor_property_id; + + /** + Sensor Positive Tolerance field is a 12-bit value representing the magnitude + of a possible positive error associated with the measurements that the sensor + is reporting + */ + UINT16 sensor_positive_tolerance; + + /** + Sensor Negative Tolerance field is a 12-bit value representing the magnitude + of a possible negative error associated with the measurements that the sensor + is reporting + */ + UINT16 sensor_negative_tolerance; + + /** + Sensor Sampling Function field specifies the averaging operation or type of + sampling function applied to the measured value + */ + UCHAR sensor_sampling_function; + + /** + Sensor Measurement Period field specifies a uint8 value n that represents the + averaging time span, accumulation time, or measurement period in seconds over + which the measurement is taken + */ + UCHAR sensor_measurement_period; + + /** + measurement reported by a sensor is internally refreshed at the frequency + indicated in the Sensor Update Interval field + */ + UCHAR sensor_update_interval; + + + /** -- Sensor Cadence -- **/ + /** Divisor for the Publish Period */ + UCHAR fast_cadence_period_divisor; + + /** Defines the unit and format of the Status Trigger Delta fields */ + UCHAR status_trigger_type; + + /** Delta down value that triggers a status message */ + UCHAR* status_trigger_delta_down; + UINT16 status_trigger_delta_down_len; + + /** Delta up value that triggers a status message */ + UCHAR* status_trigger_delta_up; + UINT16 status_trigger_delta_up_len; + + /** Minimum interval between two consecutive Status messages */ + UCHAR status_min_interval; + + /** Low value for the fast cadence range */ + UCHAR* fast_cadence_low; + UINT16 fast_cadence_low_len; + + /** High value for the fast cadence range */ + UCHAR* fast_cadence_high; + UINT16 fast_cadence_high_len; + + /** -- Sensor Settings -- **/ + /* Start Index of associated Sensor Settings */ + UINT16 sensor_settings_start_index; + + /* Count of Sensor Settings */ + UINT8 sensor_settings_count; + + /** -- Sensor Data -- **/ + + /* Sensor Data */ + UINT8* sensor_data; + + /* Sensor Data Length */ + UINT8 sensor_data_length; + +} MS_SENSOR_STRUCT; + +typedef struct _MS_SENSOR_SETTING_STRUCT +{ + /** Index of Property of a sensor */ + UINT16 sensor_property_index; + + /** Property ID of a setting within a sensor */ + UINT16 sensor_setting_property_id; + + /** Read/Write access rights for the setting */ + UCHAR sensor_setting_access; + + /** Raw value of a setting within a sensor */ + UCHAR* sensor_setting_raw; + UINT16 sensor_setting_raw_len; + +} MS_SENSOR_SETTING_STRUCT; + + +#if 0 + static MS_STATE_SENSOR_PROPERTY_ID_STRUCT appl_sensor[MS_MAX_NUM_STATES]; + static MS_STATE_SENSOR_DESCRIPTOR_STRUCT appl_sensor_desc[MS_MAX_NUM_STATES]; + static MS_STATE_SENSOR_SERIES_COLUMN_STRUCT appl_sensor_series[MS_MAX_NUM_STATES]; + static MS_STATE_SENSOR_DATA_STRUCT appl_sensor_data[MS_MAX_NUM_STATES]; + static MS_STATE_SENSOR_CADENCE_STRUCT appl_sensor_cadence[MS_MAX_NUM_STATES]; + static MS_STATE_SENSOR_SETTING_STRUCT appl_sensor_setting[MS_MAX_NUM_STATES]; + static MS_STATE_SENSOR_SETTINGS_STRUCT appl_sensor_settings[MS_MAX_NUM_STATES]; +#endif /* 0 */ + +static MS_SENSOR_STRUCT appl_sensors[MS_MAX_NUM_STATES][MS_MAX_SENSORS]; +static MS_SENSOR_SETTING_STRUCT appl_sensor_settings[MS_MAX_NUM_STATES][MS_MAX_SENSOR_SETTINGS]; + +/* For Cadence */ +static UCHAR appl_status_trigger_delta_down[MS_MAX_NUM_STATES][MS_MAX_SENSORS][16]; +static UCHAR appl_status_trigger_delta_up[MS_MAX_NUM_STATES][MS_MAX_SENSORS][16]; +static UCHAR appl_fast_cadence_low[MS_MAX_NUM_STATES][MS_MAX_SENSORS][16]; +static UCHAR appl_fast_cadence_high[MS_MAX_NUM_STATES][MS_MAX_SENSORS][16]; + +/* For Settings */ +static UCHAR appl_sensor_setting_raw[MS_MAX_NUM_STATES][MS_MAX_SENSOR_SETTINGS][16]; + +/* For Data */ +static UCHAR appl_sensor_data[MS_MAX_NUM_STATES][MS_MAX_SENSORS][16]; + +/* Raw Column/Series Values */ +static UINT8 appl_raw_x = 0x00; +static UINT8 appl_raw_width = 0x0F; +static UINT8 appl_raw_y = 0x10; + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void) +{ + UINT32 index; + #if 0 + EM_mem_set (appl_sensor, 0, sizeof(appl_sensor)); + EM_mem_set(appl_sensor_desc, 0, sizeof(appl_sensor_desc)); + EM_mem_set(appl_sensor_series, 0, sizeof(appl_sensor_series)); + EM_mem_set(appl_sensor_data, 0, sizeof(appl_sensor_data)); + EM_mem_set(appl_sensor_cadence, 0, sizeof(appl_sensor_cadence)); + EM_mem_set(appl_sensor_setting, 0, sizeof(appl_sensor_setting)); + EM_mem_set(appl_sensor_settings, 0, sizeof(appl_sensor_settings)); + #else + EM_mem_set(appl_sensors, 0, sizeof(appl_sensors)); + EM_mem_set(appl_sensor_settings, 0, sizeof(appl_sensor_settings)); + + for (index = 0; index < MS_MAX_SENSOR_SETTINGS; index++) + { + appl_sensor_settings[0][index].sensor_property_index = index; + /* Read + Write Permission */ + appl_sensor_settings[0][index].sensor_setting_access = 0x03; + appl_sensor_settings[0][index].sensor_setting_property_id = index + 0x1234; + appl_sensor_settings[0][index].sensor_setting_raw = &appl_sensor_setting_raw[0][index][0]; + appl_sensor_settings[0][index].sensor_setting_raw_len = 1; + } + + /* TODO: only initializing 0-th instance */ + for (index = 0; index < MS_MAX_SENSORS; index++) + { + appl_sensors[0][index].sensor_property_id = MS_PROP_ID_FOR_TEST; + appl_status_trigger_delta_down[0][index][0] = 0x01; + appl_sensors[0][index].status_trigger_delta_down = &appl_status_trigger_delta_down[0][index][0]; + appl_sensors[0][index].status_trigger_delta_down_len = 0x01; + appl_status_trigger_delta_up[0][index][0] = 0xA0; + appl_sensors[0][index].status_trigger_delta_up = &appl_status_trigger_delta_up[0][index][0]; + appl_sensors[0][index].status_trigger_delta_up_len = 0x01; + appl_fast_cadence_low[0][index][0] = 0x00; + appl_sensors[0][index].fast_cadence_low = &appl_fast_cadence_low[0][index][0]; + appl_sensors[0][index].fast_cadence_low_len = 0x01; + appl_fast_cadence_high[0][index][0] = 0xA0; + appl_sensors[0][index].fast_cadence_high = &appl_fast_cadence_high[0][index][0]; + appl_sensors[0][index].fast_cadence_high_len = 0x01; + /* TODO: update example to use more than one settings per sensor property */ + appl_sensors[0][index].sensor_settings_start_index = index; + appl_sensors[0][index].sensor_settings_count = 1; + appl_sensors[0][index].sensor_data = &appl_sensor_data[0][index][0]; + appl_sensors[0][index].sensor_data_length = 1; + appl_sensors[0][index].fast_cadence_period_divisor = 0x01; + appl_sensors[0][index].status_trigger_type = 0x00; + appl_sensors[0][index].status_min_interval = 0x01; + } + + #endif /* 0 */ +} + +API_RESULT appl_search_sensor_property_id(/* IN */ UINT16 state_inst, /* IN */ UINT16 prop_id, /* OUT */ UINT16* prop_index) +{ + UINT16 index; + API_RESULT retval; + retval = API_FAILURE; + + for (index = 0; index < MS_MAX_SENSORS; index ++) + { + if (appl_sensors[state_inst][index].sensor_property_id == prop_id) + { + *prop_index = (UINT16)index; + retval = API_SUCCESS; + break; + } + } + + return retval; +} + +API_RESULT appl_search_sensor_setting_property_id(/* IN */ UINT16 state_inst, /* IN */ UINT16 prop_id, /* IN */ UINT16 setting_prop_id, /* OUT */ UINT16* setting_index) +{ + UINT16 index; + UINT16 sensor_propery_index; + API_RESULT retval; + retval = appl_search_sensor_property_id(state_inst, prop_id, &sensor_propery_index); + + if (API_SUCCESS == retval) + { + UINT32 count; + retval = API_FAILURE; + + for (count = 0; count < appl_sensors[state_inst][sensor_propery_index].sensor_settings_count; count++) + { + if (setting_prop_id == appl_sensor_settings[state_inst][appl_sensors[state_inst][sensor_propery_index].sensor_settings_start_index + count].sensor_setting_property_id) + { + *setting_index = appl_sensors[state_inst][sensor_propery_index].sensor_settings_start_index + count; + retval = API_SUCCESS; + break; + } + } + } + + return retval; +} + +void appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + UINT16 sensor_propery_index; + UINT16 setting_propery_index; + + switch(state_t) + { + case MS_STATE_SENSOR_DESCRIPTOR_T: + { + MS_STATE_SENSOR_DESCRIPTOR_STRUCT* param_p; + param_p = (MS_STATE_SENSOR_DESCRIPTOR_STRUCT*)param; + + if (0x0000 != param_p->sensor_property_id) + { + retval = appl_search_sensor_property_id(state_inst, param_p->sensor_property_id, &sensor_propery_index); + } + else + { + retval = API_SUCCESS; + sensor_propery_index = 0x00; + } + + if (API_SUCCESS == retval) + { + param_p->sensor_property_id = appl_sensors[state_inst][sensor_propery_index].sensor_property_id; + param_p->sensor_measurement_period = appl_sensors[state_inst][sensor_propery_index].sensor_measurement_period; + param_p->sensor_negative_tolerance = appl_sensors[state_inst][sensor_propery_index].sensor_negative_tolerance; + param_p->sensor_positive_tolerance = appl_sensors[state_inst][sensor_propery_index].sensor_positive_tolerance; + param_p->sensor_sampling_function = appl_sensors[state_inst][sensor_propery_index].sensor_sampling_function; + param_p->sensor_update_interval = appl_sensors[state_inst][sensor_propery_index].sensor_update_interval; + param_p->status = 0x01; + } + else + { + param_p->status = 0x00; + } + } + break; + + case MS_STATE_SENSOR_CADENCE_T: + { + MS_STATE_SENSOR_CADENCE_STRUCT* param_p; + param_p = (MS_STATE_SENSOR_CADENCE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + retval = appl_search_sensor_property_id(state_inst, param_p->sensor_property_id, &sensor_propery_index); + param_p->status = 0x00; + + if (API_SUCCESS == retval) + { + param_p->sensor_property_id = appl_sensors[state_inst][sensor_propery_index].sensor_property_id; + param_p->fast_cadence_high = appl_sensors[state_inst][sensor_propery_index].fast_cadence_high; + param_p->fast_cadence_high_len = appl_sensors[state_inst][sensor_propery_index].fast_cadence_high_len; + param_p->fast_cadence_low = appl_sensors[state_inst][sensor_propery_index].fast_cadence_low; + param_p->fast_cadence_low_len = appl_sensors[state_inst][sensor_propery_index].fast_cadence_low_len; + param_p->fast_cadence_period_divisor = appl_sensors[state_inst][sensor_propery_index].fast_cadence_period_divisor; + param_p->status_min_interval = appl_sensors[state_inst][sensor_propery_index].status_min_interval; + param_p->status_trigger_delta_down = appl_sensors[state_inst][sensor_propery_index].status_trigger_delta_down; + param_p->status_trigger_delta_down_len = appl_sensors[state_inst][sensor_propery_index].status_trigger_delta_down_len; + param_p->status_trigger_delta_up = appl_sensors[state_inst][sensor_propery_index].status_trigger_delta_up; + param_p->status_trigger_delta_up_len = appl_sensors[state_inst][sensor_propery_index].status_trigger_delta_up_len; + param_p->status_trigger_type = appl_sensors[state_inst][sensor_propery_index].status_trigger_type; + param_p->status = 0x001; + } + } + break; + + case MS_STATE_SENSOR_SETTINGS_T: + { + MS_STATE_SENSOR_SETTINGS_STRUCT* param_p; + param_p = (MS_STATE_SENSOR_SETTINGS_STRUCT*)param; + param_p->setting_property_ids_count = 0; + retval = appl_search_sensor_property_id(state_inst, param_p->sensor_property_id, &sensor_propery_index); + + if (API_SUCCESS == retval) + { + UINT32 count; + param_p->sensor_property_id = appl_sensors[state_inst][sensor_propery_index].sensor_property_id; + + for (count = 0; count < appl_sensors[state_inst][sensor_propery_index].sensor_settings_count; count ++) + { + param_p->setting_property_ids[count] = appl_sensor_settings[state_inst][appl_sensors[state_inst][sensor_propery_index].sensor_settings_start_index + count].sensor_setting_property_id; + } + + param_p->setting_property_ids_count = appl_sensors[state_inst][sensor_propery_index].sensor_settings_count; + } + } + break; + + case MS_STATE_SENSOR_SETTING_T: + { + MS_STATE_SENSOR_SETTING_STRUCT* param_p; + param_p = (MS_STATE_SENSOR_SETTING_STRUCT*)param; + param_p->sensor_setting_raw_len = 0x00; + retval = appl_search_sensor_setting_property_id(state_inst, param_p->sensor_property_id, param_p->sensor_setting_property_id, &setting_propery_index); + + if (API_SUCCESS == retval) + { + UINT32 count; + /* param_p->sensor_property_id = appl_sensors[state_inst][sensor_propery_index].sensor_property_id; */ + param_p->sensor_setting_access = appl_sensor_settings[state_inst][setting_propery_index].sensor_setting_access; + param_p->sensor_setting_raw = appl_sensor_settings[state_inst][setting_propery_index].sensor_setting_raw; + param_p->sensor_setting_raw_len = appl_sensor_settings[state_inst][setting_propery_index].sensor_setting_raw_len; + param_p->status = 0x01; + } + else + { + param_p->status = 0x00; + } + } + break; + + case MS_STATE_SENSOR_DATA_T: + { + MS_STATE_SENSOR_DATA_STRUCT* param_p; + param_p = (MS_STATE_SENSOR_DATA_STRUCT*)param; + param_p->raw_value_1 = NULL; + param_p->raw_value_1_len = 0; + param_p->status = 0x00; + + if (0x0000 != param_p->property_id_1) + { + retval = appl_search_sensor_property_id(state_inst, param_p->property_id_1, &sensor_propery_index); + + if (API_SUCCESS != retval) + { + /* param_p->property_id_1 = 0x1234; */ + /* param_p->property_id_1 = 0x78; */ + return retval; + } + else + { + param_p->status = 0x01; + } + } + else + { + retval = API_SUCCESS; + sensor_propery_index = 0x00; + param_p->status = 0x01; + } + + param_p->property_id_1 = appl_sensors[state_inst][sensor_propery_index].sensor_property_id; + param_p->raw_value_1 = appl_sensors[state_inst][sensor_propery_index].sensor_data; + param_p->raw_value_1_len = appl_sensors[state_inst][sensor_propery_index].sensor_data_length; + } + break; + + case MS_STATE_SENSOR_SERIES_COLUMN_T: + { + MS_STATE_SENSOR_SERIES_COLUMN_STRUCT* param_p; + param_p = (MS_STATE_SENSOR_SERIES_COLUMN_STRUCT*)param; + /* Ignoring Instance and direction right now */ + /* *param_p = appl_sensor_series[0]; */ + retval = appl_search_sensor_property_id(state_inst, param_p->sensor_property_id, &sensor_propery_index); + param_p->status = 0x00; + + if (API_SUCCESS == retval) + { + param_p->sensor_raw_value_x = &appl_raw_x; + param_p->sensor_raw_value_x_len = sizeof(appl_raw_x); + param_p->sensor_column_width = &appl_raw_width; + param_p->sensor_column_width_len = sizeof(appl_raw_width); + param_p->sensor_raw_value_y = &appl_raw_y; + param_p->sensor_raw_value_y_len = sizeof(appl_raw_y); + param_p->status = 0x001; + } + } + break; + + case MS_STATE_SENSOR_SERIES_T: + { + MS_STATE_SENSOR_SERIES_COLUMN_STRUCT* param_p; + param_p = (MS_STATE_SENSOR_SERIES_COLUMN_STRUCT*)param; + /* Ignoring Instance and direction right now */ + /* *param_p = appl_sensor_series[0]; */ + retval = appl_search_sensor_property_id(state_inst, param_p->sensor_property_id, &sensor_propery_index); + param_p->status = 0x00; + + if (API_SUCCESS == retval) + { + param_p->sensor_raw_value_x = &appl_raw_x; + param_p->sensor_raw_value_x_len = sizeof(appl_raw_x); + param_p->sensor_column_width = &appl_raw_width; + param_p->sensor_column_width_len = sizeof(appl_raw_width); + param_p->sensor_raw_value_y = &appl_raw_y; + param_p->sensor_raw_value_y_len = sizeof(appl_raw_y); + param_p->status = 0x001; + } + } + break; + + default: + break; + } +} + + +void appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + UINT16 sensor_propery_index; + UINT16 setting_propery_index; + + switch(state_t) + { + case MS_STATE_SENSOR_SETTING_T: + { + MS_STATE_SENSOR_SETTING_STRUCT* param_p; + param_p = (MS_STATE_SENSOR_SETTING_STRUCT*)param; + retval = appl_search_sensor_setting_property_id(state_inst, param_p->sensor_property_id, param_p->sensor_setting_property_id, &setting_propery_index); + + if (API_SUCCESS == retval) + { + /* param_p->sensor_property_id = appl_sensors[state_inst][sensor_propery_index].sensor_property_id; */ + param_p->sensor_setting_access = appl_sensor_settings[state_inst][setting_propery_index].sensor_setting_access; + + if (0 != param_p->sensor_setting_raw_len) + { + EM_mem_copy + ( + &appl_sensor_settings[state_inst][setting_propery_index].sensor_setting_raw[0], + param_p->sensor_setting_raw, + param_p->sensor_setting_raw_len + ); + appl_sensor_settings[state_inst][setting_propery_index].sensor_setting_raw_len = param_p->sensor_setting_raw_len; + } + + /* param_p->sensor_setting_raw = appl_sensor_settings[state_inst][setting_propery_index].sensor_setting_raw; */ + /* param_p->sensor_setting_raw_len = appl_sensor_settings[state_inst][setting_propery_index].sensor_setting_raw_len; */ + param_p->status = 0x01; + } + else + { + param_p->status = 0x00; + param_p->sensor_setting_raw_len = 0x00; + } + } + break; + + case MS_STATE_SENSOR_CADENCE_T: + { + MS_STATE_SENSOR_CADENCE_STRUCT* param_p; + param_p = (MS_STATE_SENSOR_CADENCE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + retval = appl_search_sensor_property_id(state_inst, param_p->sensor_property_id, &sensor_propery_index); + param_p->status = 0x00; + + if (API_SUCCESS == retval) + { + /* Check Status Min Interval is in range 0-26 */ + if (26 < param_p->status_trigger_delta_down[2]) + { + param_p->status = 0x02; + break; + } + + /* Copy */ + appl_sensors[state_inst][sensor_propery_index].fast_cadence_period_divisor = param_p->fast_cadence_period_divisor; + appl_sensors[state_inst][sensor_propery_index].status_trigger_type = param_p->status_trigger_type; + appl_sensors[state_inst][sensor_propery_index].status_trigger_delta_down[0] = param_p->status_trigger_delta_down[0]; + appl_sensors[state_inst][sensor_propery_index].status_trigger_delta_up[0] = param_p->status_trigger_delta_down[1]; + appl_sensors[state_inst][sensor_propery_index].status_min_interval = param_p->status_trigger_delta_down[2]; + appl_sensors[state_inst][sensor_propery_index].fast_cadence_low[0] = param_p->status_trigger_delta_down[3]; + appl_sensors[state_inst][sensor_propery_index].fast_cadence_high[0] = param_p->status_trigger_delta_down[4]; + /* Reassign */ + param_p->sensor_property_id = appl_sensors[state_inst][sensor_propery_index].sensor_property_id; + param_p->fast_cadence_high = appl_sensors[state_inst][sensor_propery_index].fast_cadence_high; + param_p->fast_cadence_high_len = appl_sensors[state_inst][sensor_propery_index].fast_cadence_high_len; + param_p->fast_cadence_low = appl_sensors[state_inst][sensor_propery_index].fast_cadence_low; + param_p->fast_cadence_low_len = appl_sensors[state_inst][sensor_propery_index].fast_cadence_low_len; + param_p->fast_cadence_period_divisor = appl_sensors[state_inst][sensor_propery_index].fast_cadence_period_divisor; + param_p->status_min_interval = appl_sensors[state_inst][sensor_propery_index].status_min_interval; + param_p->status_trigger_delta_down = appl_sensors[state_inst][sensor_propery_index].status_trigger_delta_down; + param_p->status_trigger_delta_down_len = appl_sensors[state_inst][sensor_propery_index].status_trigger_delta_down_len; + param_p->status_trigger_delta_up = appl_sensors[state_inst][sensor_propery_index].status_trigger_delta_up; + param_p->status_trigger_delta_up_len = appl_sensors[state_inst][sensor_propery_index].status_trigger_delta_up_len; + param_p->status_trigger_type = appl_sensors[state_inst][sensor_propery_index].status_trigger_type; + param_p->status = 0x01; + } + } + break; + #if 0 + + case MS_STATE_SENSOR_DESCRIPTOR_T: + { + MS_STATE_SENSOR_DESCRIPTOR_STRUCT* param_p; + param_p = (MS_STATE_SENSOR_DESCRIPTOR_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_sensor_desc[0] = *param_p; + } + break; + + case MS_STATE_SENSOR_SERIES_COLUMN_T: + { + MS_STATE_SENSOR_SERIES_COLUMN_STRUCT* param_p; + param_p = (MS_STATE_SENSOR_SERIES_COLUMN_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_sensor_series[0] = *param_p; + } + break; + + case MS_STATE_SENSOR_DATA_T: + { + MS_STATE_SENSOR_DATA_STRUCT* param_p; + param_p = (MS_STATE_SENSOR_DATA_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_sensor_data[0] = *param_p; + } + break; + + case MS_STATE_SENSOR_SETTING_T: + { + MS_STATE_SENSOR_SETTING_STRUCT* param_p; + param_p = (MS_STATE_SENSOR_SETTING_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_sensor_setting[0] = *param_p; + } + break; + + case MS_STATE_SENSOR_SETTINGS_T: + { + MS_STATE_SENSOR_SETTINGS_STRUCT* param_p; + param_p = (MS_STATE_SENSOR_SETTINGS_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_sensor_settings[0] = *param_p; + } + break; + #endif /* 0 */ + + default: + break; + } +} + diff --git a/src/components/ethermind/mesh/export/appl/model/server/sensor/sensor_server/appl_model_state_handler.h b/src/components/ethermind/mesh/export/appl/model/server/sensor/sensor_server/appl_model_state_handler.h new file mode 100644 index 0000000..861625a --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/sensor/sensor_server/appl_model_state_handler.h @@ -0,0 +1,32 @@ +/** + \file appl_model_state_handler.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_MODEL_STATE_HANDLER_ +#define _H_APPL_MODEL_STATE_HANDLER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_main.h" +#include "MS_model_states.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void); + +void appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +void appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +#endif /*_H_APPL_MODEL_STATE_HANDLER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/sensor/sensor_server/appl_sensor_server.c b/src/components/ethermind/mesh/export/appl/model/server/sensor/sensor_server/appl_sensor_server.c new file mode 100644 index 0000000..56e91f4 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/sensor/sensor_server/appl_sensor_server.c @@ -0,0 +1,286 @@ +/** + \file appl_sensor_server.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_sensor_server.h" +#include "appl_model_state_handler.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_sensor_server_options[] = "\n\ +======== Sensor Server Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_sensor_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_sensor_setup_server_model_handle; + +/* --------------------------------------------- Function */ +/* sensor server application entry point */ +void main_sensor_server_operations(/* IN */ UINT8 have_menu) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_sensor_server_init + ( + element_handle, + &appl_sensor_server_model_handle, + appl_sensor_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Sensor Server Initialized. Model Handle: 0x%04X\n", + appl_sensor_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Sensor Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + retval = MS_sensor_setup_server_init + ( + element_handle, + &appl_sensor_setup_server_model_handle, + appl_sensor_setup_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Sensor Setup Server Initialized. Model Handle: 0x%04X\n", + appl_sensor_setup_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Sensor Setup Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + appl_model_states_initialization(); + model_initialized = 0x01; + } + + if (MS_TRUE != have_menu) + { + CONSOLE_OUT("Not to use menu options\n"); + return; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_sensor_server_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + } + } +} + +#if 0 +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Sensor server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_sensor_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_SENSOR_PROPERTY_ID_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + void* param_p; + UINT16 u16[16]; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[SENSOR] GET Request.\n"); + param_p = state_params->state; + + switch (state_params->state_type) + { + case MS_STATE_SENSOR_DESCRIPTOR_T: + break; + + case MS_STATE_SENSOR_CADENCE_T: + break; + + case MS_STATE_SENSOR_SETTINGS_T: + ((MS_STATE_SENSOR_SETTINGS_STRUCT*)param_p)->setting_property_ids = u16; + ((MS_STATE_SENSOR_SETTINGS_STRUCT*)param_p)->setting_property_ids_count = sizeof(u16) / sizeof(UINT16); + break; + + case MS_STATE_SENSOR_SETTING_T: + break; + + case MS_STATE_SENSOR_DATA_T: + break; + + case MS_STATE_SENSOR_SERIES_COLUMN_T: + break; + } + + appl_model_state_get(state_params->state_type, 0, param_p, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param_p; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[SENSOR] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[SENSOR] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_sensor_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Sensor server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_sensor_setup_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_SENSOR_PROPERTY_ID_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + void* param_p; + UINT16 u16[16]; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[SENSOR] GET Request.\n"); + param_p = state_params->state; + + switch (state_params->state_type) + { + case MS_STATE_SENSOR_DESCRIPTOR_T: + break; + + case MS_STATE_SENSOR_CADENCE_T: + break; + + case MS_STATE_SENSOR_SETTINGS_T: + ((MS_STATE_SENSOR_SETTINGS_STRUCT*)param_p)->setting_property_ids = u16; + ((MS_STATE_SENSOR_SETTINGS_STRUCT*)param_p)->setting_property_ids_count = sizeof(u16) / sizeof(UINT16); + break; + + case MS_STATE_SENSOR_SETTING_T: + break; + } + + appl_model_state_get(state_params->state_type, 0, param_p, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param_p; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[SENSOR] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[SENSOR] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_sensor_setup_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +#endif /* 0 */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/sensor/sensor_server/appl_sensor_server.h b/src/components/ethermind/mesh/export/appl/model/server/sensor/sensor_server/appl_sensor_server.h new file mode 100644 index 0000000..b6fd5a5 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/sensor/sensor_server/appl_sensor_server.h @@ -0,0 +1,77 @@ +/** + \file appl_sensor_server.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_SENSOR_SERVER_ +#define _H_APPL_SENSOR_SERVER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_sensor_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* sensor server application entry point */ +void main_sensor_server_operations(/* IN */ UINT8 have_menu); + +/* Get Model Handle */ +void appl_sensor_server_get_model_handle(void); + +/* Set Publish Address */ +void appl_sensor_server_set_publish_address(void); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Sensor server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_sensor_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Sensor server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_sensor_setup_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +#endif /*_H_APPL_SENSOR_SERVER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scene_server/appl_model_state_handler.c b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scene_server/appl_model_state_handler.c new file mode 100644 index 0000000..eb1de1c --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scene_server/appl_model_state_handler.c @@ -0,0 +1,56 @@ +/** + \file appl_model_state_handler.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_model_state_handler.h" +#include "MS_common.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ + + +/* --------------------------------------------- Data Types/Structures */ + +/* ------- Transition Time Data Structures */ + +/* ------- Scene Data Structures */ +#define MS_MAX_SCENE_REGS 16 + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void) +{ +} + +/** Scene Server Handlers */ + +void* appl_scene_save_current_state(/* IN */ UINT32 scene_index) +{ + /* Free previous context - if any */ + /* Empty right now - dummy returning the same scene index itself */ + return (void*)scene_index; +} + +void* appl_scene_delete_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ + /* Free context - if any */ + /* Empty right now - dummy returning NULL */ + return (void*)NULL; +} + +void* appl_scene_recall_saved_state(/* IN */ UINT32 scene_index, /* IN */ void* context) +{ + /* Recall context - if any */ + /* Empty right now - dummy returning NULL */ + return (void*)NULL; +} diff --git a/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scene_server/appl_model_state_handler.h b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scene_server/appl_model_state_handler.h new file mode 100644 index 0000000..83256ce --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scene_server/appl_model_state_handler.h @@ -0,0 +1,32 @@ +/** + \file appl_model_state_handler.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_MODEL_STATE_HANDLER_ +#define _H_APPL_MODEL_STATE_HANDLER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_main.h" +#include "MS_model_states.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void); + +void appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, MS_EXT_TID_AND_TRANSITION_STRUCT* trns, UINT8 direction); + +void appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, MS_EXT_TID_AND_TRANSITION_STRUCT* trns, UINT8 direction); + +#endif /*_H_APPL_MODEL_STATE_HANDLER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scene_server/appl_scene_server.c b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scene_server/appl_scene_server.c new file mode 100644 index 0000000..c1e7ee3 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scene_server/appl_scene_server.c @@ -0,0 +1,171 @@ +/** + \file appl_scene_server.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_scene_server.h" +#include "appl_model_state_handler.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_scene_server_options[] = "\n\ +======== Scene Server Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_scene_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_scene_setup_server_model_handle; + +/* --------------------------------------------- Function */ +/* scene server application entry point */ +void main_scene_server_operations(/* IN */ UINT8 have_menu) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_scene_server_init + ( + element_handle, + &appl_scene_server_model_handle, + &appl_scene_setup_server_model_handle, + appl_scene_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Scene Server Initialized. Model Handle: 0x%04X\n", + appl_scene_server_model_handle); + CONSOLE_OUT( + "Scene Setup Server Initialized. Model Handle: 0x%04X\n", + appl_scene_setup_server_model_handle); + appl_model_states_initialization(); + } + else + { + CONSOLE_OUT( + "[ERR] Scene Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + if (MS_TRUE != have_menu) + { + CONSOLE_OUT("Not to use menu options\n"); + return; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_scene_server_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + } + } +} + +#if 0 +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scene server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. + + TODO: Update +*/ +void* appl_scene_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT8 event_type, + /* IN */ void* event_param, + /* IN */ UINT16 event_length, + /* IN */ void* context +) +{ + void* param_p; + param_p = NULL; + + switch(event_type) + { + case MS_SCENE_EVENT_STORE: + { + param_p = appl_scene_save_current_state(*(UINT32*)event_param); + } + break; + + case MS_SCENE_EVENT_DELETE: + { + param_p = appl_scene_delete_saved_state(*(UINT32*)event_param, context); + } + break; + + case MS_SCENE_EVENT_RECALL_START: + { + } + break; + + case MS_SCENE_EVENT_RECALL_COMPLETE: + { + param_p = appl_scene_recall_saved_state(*(UINT32*)event_param, context); + } + break; + + case MS_SCENE_EVENT_RECALL_IMMEDIATE: + { + param_p = appl_scene_recall_saved_state(*(UINT32*)event_param, context); + } + break; + } + + return param_p; +} + +#endif /* 0 */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scene_server/appl_scene_server.h b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scene_server/appl_scene_server.h new file mode 100644 index 0000000..dbfd068 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scene_server/appl_scene_server.h @@ -0,0 +1,50 @@ +/** + \file appl_scene_server.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_SCENE_SERVER_ +#define _H_APPL_SCENE_SERVER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_scene_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* scene server application entry point */ +void main_scene_server_operations(/* IN */ UINT8 have_menu); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scene server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +void* appl_scene_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT8 event_type, + /* IN */ void* event_param, + /* IN */ UINT16 event_length, + /* IN */ void* context +); + +#endif /*_H_APPL_SCENE_SERVER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scheduler_server/appl_model_state_handler.c b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scheduler_server/appl_model_state_handler.c new file mode 100644 index 0000000..a331ebb --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scheduler_server/appl_model_state_handler.c @@ -0,0 +1,84 @@ +/** + \file appl_model_state_handler.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_model_state_handler.h" +#include "MS_common.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ + + +/* --------------------------------------------- Data Types/Structures */ +#define MS_MAX_NUM_STATES 2 + +static MS_STATE_SCHEDULER_SCHEDULES_STRUCT appl_scheduler_current[MS_MAX_NUM_STATES]; +static MS_STATE_SCHEDULER_ENTRY_STRUCT appl_scheduler[MS_MAX_NUM_STATES]; + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void) +{ + EM_mem_set(appl_scheduler_current, 0, sizeof(appl_scheduler_current)); + EM_mem_set (appl_scheduler, 0, sizeof(appl_scheduler)); +} + + +void appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + switch(state_t) + { + case MS_STATE_SCHEDULER_ENTRY_INDEX_T: + { + MS_STATE_SCHEDULER_ENTRY_STRUCT* param_p; + param_p = (MS_STATE_SCHEDULER_ENTRY_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_scheduler[0]; + } + break; + + case MS_STATE_SCHEDULER_SCHEDULES_T: + { + MS_STATE_SCHEDULER_SCHEDULES_STRUCT* param_p; + param_p = (MS_STATE_SCHEDULER_SCHEDULES_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_scheduler_current[0]; + } + break; + + default: + break; + } +} + + +void appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + switch(state_t) + { + case MS_STATE_SCHEDULER_ENTRY_T: + { + MS_STATE_SCHEDULER_ENTRY_STRUCT* param_p; + param_p = (MS_STATE_SCHEDULER_ENTRY_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_scheduler[0] = *param_p; + } + break; + + default: + break; + } +} + + diff --git a/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scheduler_server/appl_model_state_handler.h b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scheduler_server/appl_model_state_handler.h new file mode 100644 index 0000000..861625a --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scheduler_server/appl_model_state_handler.h @@ -0,0 +1,32 @@ +/** + \file appl_model_state_handler.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_MODEL_STATE_HANDLER_ +#define _H_APPL_MODEL_STATE_HANDLER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_main.h" +#include "MS_model_states.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void); + +void appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +void appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +#endif /*_H_APPL_MODEL_STATE_HANDLER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scheduler_server/appl_scheduler_server.c b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scheduler_server/appl_scheduler_server.c new file mode 100644 index 0000000..76ecaa1 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scheduler_server/appl_scheduler_server.c @@ -0,0 +1,179 @@ +/** + \file appl_scheduler_server.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_scheduler_server.h" +#include "appl_model_state_handler.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_scheduler_server_options[] = "\n\ +======== Scheduler Server Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_scheduler_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_scheduler_setup_server_model_handle; + + +/* --------------------------------------------- Function */ +/* scheduler server application entry point */ +void main_scheduler_server_operations(/* IN */ UINT8 have_menu) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_scheduler_server_init + ( + element_handle, + &appl_scheduler_server_model_handle, + &appl_scheduler_setup_server_model_handle, + appl_scheduler_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Scheduler Server Initialized. Model Handle: 0x%04X\n", + appl_scheduler_server_model_handle); + CONSOLE_OUT( + "Scheduler Setup Server Initialized. Model Handle: 0x%04X\n", + appl_scheduler_setup_server_model_handle); + appl_model_states_initialization(); + } + else + { + CONSOLE_OUT( + "[ERR] Scheduler Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + if (MS_TRUE != have_menu) + { + CONSOLE_OUT("Not to use menu options\n"); + return; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_scheduler_server_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + } + } +} + +#if 0 +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scheduler server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_scheduler_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_SCHEDULER_SCHEDULES_STRUCT param; + MS_STATE_SCHEDULER_ENTRY_STRUCT param_scheduler_entry; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + void* param_p; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[SCHEDULER] GET Request.\n"); + + if (MS_STATE_SCHEDULER_SCHEDULES_T == state_params->state_type) + { + param_p = ¶m; + } + else + { + param_p = state_params->state; + } + + appl_model_state_get(state_params->state_type, 0, param_p, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param_p; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[SCHEDULER_SETUP] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[SCHEDULER] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_scheduler_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +#endif /* 0 */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scheduler_server/appl_scheduler_server.h b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scheduler_server/appl_scheduler_server.h new file mode 100644 index 0000000..775c58f --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/scheduler_server/appl_scheduler_server.h @@ -0,0 +1,56 @@ +/** + \file appl_scheduler_server.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_SCHEDULER_SERVER_ +#define _H_APPL_SCHEDULER_SERVER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_scheduler_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* scheduler server application entry point */ +void main_scheduler_server_operations(/* IN */ UINT8 have_menu); + +/* Get Model Handle */ +void appl_scheduler_server_get_model_handle(void); + +/* Set Publish Address */ +void appl_scheduler_server_set_publish_address(void); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Scheduler server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_scheduler_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +#endif /*_H_APPL_SCHEDULER_SERVER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/time_server/appl_model_state_handler.c b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/time_server/appl_model_state_handler.c new file mode 100644 index 0000000..78a03c8 --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/time_server/appl_model_state_handler.c @@ -0,0 +1,138 @@ +/** + \file appl_model_state_handler.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_model_state_handler.h" +#include "MS_common.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ + + +/* --------------------------------------------- Data Types/Structures */ +#define MS_MAX_NUM_STATES 2 + +static MS_STATE_TIME_STRUCT appl_time[MS_MAX_NUM_STATES]; +static MS_STATE_TIME_TAI_UTC_DELTA_STRUCT appl_time_delta[MS_MAX_NUM_STATES]; +static MS_STATE_TIME_ZONE_STRUCT appl_time_zone[MS_MAX_NUM_STATES]; +static MS_STATE_TIME_ROLE_STRUCT appl_time_role[MS_MAX_NUM_STATES]; + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void) +{ + EM_mem_set (appl_time, 0, sizeof(appl_time)); + EM_mem_set(appl_time_delta, 0, sizeof(appl_time_delta)); + EM_mem_set(appl_time_zone, 0, sizeof(appl_time_zone)); + EM_mem_set(appl_time_role, 0, sizeof(appl_time_role)); +} + + +void appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + switch(state_t) + { + case MS_STATE_TIME_T: + { + MS_STATE_TIME_STRUCT* param_p; + param_p = (MS_STATE_TIME_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_time[0]; + } + break; + + case MS_STATE_TIME_ZONE_T: + { + MS_STATE_TIME_ZONE_STRUCT* param_p; + param_p = (MS_STATE_TIME_ZONE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_time_zone[0]; + } + break; + + case MS_STATE_TIME_TAI_UTC_DELTA_T: + { + MS_STATE_TIME_TAI_UTC_DELTA_STRUCT* param_p; + param_p = (MS_STATE_TIME_TAI_UTC_DELTA_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_time_delta[0]; + } + break; + + case MS_STATE_TIME_ROLE_T: + { + MS_STATE_TIME_ROLE_STRUCT* param_p; + param_p = (MS_STATE_TIME_ROLE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = appl_time_role[0]; + } + break; + + default: + break; + } +} + + +void appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + switch(state_t) + { + case MS_STATE_TIME_T: + { + MS_STATE_TIME_STRUCT* param_p; + param_p = (MS_STATE_TIME_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_time[0] = *param_p; + } + break; + + case MS_STATE_TIME_ZONE_T: + { + MS_STATE_TIME_ZONE_STRUCT* param_p; + param_p = (MS_STATE_TIME_ZONE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + param_p->time_zone_offset_current = appl_time_zone[0].time_zone_offset_current; + appl_time_zone[0].time_zone_offset_current = param_p->time_zone_offset_new; + appl_time_zone[0].time_zone_offset_new = appl_time_zone[0].time_zone_offset_current; + EM_mem_copy(&appl_time_zone[0].tai_of_zone_change[0], ¶m_p->tai_of_zone_change[0], 5); + } + break; + + case MS_STATE_TIME_TAI_UTC_DELTA_T: + { + MS_STATE_TIME_TAI_UTC_DELTA_STRUCT* param_p; + param_p = (MS_STATE_TIME_TAI_UTC_DELTA_STRUCT*)param; + /* Ignoring Instance and direction right now */ + param_p->tai_utc_delta_current = appl_time_delta[0].tai_utc_delta_current; + appl_time_delta[0].tai_utc_delta_current = param_p->tai_utc_delta_new; + appl_time_delta[0].tai_utc_delta_new = appl_time_delta[0].tai_utc_delta_current; + EM_mem_copy(&appl_time_delta[0].tai_of_delta_change[0], ¶m_p->tai_of_delta_change[0], 5); + } + break; + + case MS_STATE_TIME_ROLE_T: + { + MS_STATE_TIME_ROLE_STRUCT* param_p; + param_p = (MS_STATE_TIME_ROLE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + appl_time_role[0] = *param_p; + } + break; + + default: + break; + } +} + + diff --git a/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/time_server/appl_model_state_handler.h b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/time_server/appl_model_state_handler.h new file mode 100644 index 0000000..861625a --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/time_server/appl_model_state_handler.h @@ -0,0 +1,32 @@ +/** + \file appl_model_state_handler.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_MODEL_STATE_HANDLER_ +#define _H_APPL_MODEL_STATE_HANDLER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_main.h" +#include "MS_model_states.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +void appl_model_states_initialization(void); + +void appl_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +void appl_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction); + +#endif /*_H_APPL_MODEL_STATE_HANDLER_ */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/time_server/appl_time_server.c b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/time_server/appl_time_server.c new file mode 100644 index 0000000..adb20cf --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/time_server/appl_time_server.c @@ -0,0 +1,202 @@ +/** + \file appl_time_server.c +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "appl_time_server.h" +#include "appl_model_state_handler.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static const char main_time_server_options[] = "\n\ +======== Time Server Menu ========\n\ + 0. Exit. \n\ + 1. Refresh. \n\ + \n\ + \n\ +Your Option ? \0"; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_time_server_model_handle; +static MS_ACCESS_MODEL_HANDLE appl_time_setup_server_model_handle; + + +/* --------------------------------------------- Function */ +/* time server application entry point */ +void main_time_server_operations(/* IN */ UINT8 have_menu) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + static UCHAR model_initialized = 0x00; + + /** + Register with Access Layer. + */ + if (0x00 == model_initialized) + { + API_RESULT retval; + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_time_server_init + ( + element_handle, + &appl_time_server_model_handle, + &appl_time_setup_server_model_handle, + appl_time_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Time Server Initialized. Model Handle: 0x%04X\n", + appl_time_server_model_handle); + CONSOLE_OUT( + "Time Setup Server Initialized. Model Handle: 0x%04X\n", + appl_time_setup_server_model_handle); + appl_model_states_initialization(); + } + else + { + CONSOLE_OUT( + "[ERR] Time Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + if (MS_TRUE != have_menu) + { + CONSOLE_OUT("Not to use menu options\n"); + return; + } + + MS_LOOP_FOREVER() + { + CONSOLE_OUT + ("%s", main_time_server_options); + CONSOLE_IN + ("%d", &choice); + + if (choice < 0) + { + CONSOLE_OUT + ("*** Invalid Choice. Try Again.\n"); + continue; + } + + switch (choice) + { + case 0: + return; + + case 1: + break; + } + } +} + +#if 0 +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Time server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_time_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_TIME_STRUCT appl_time_param; + MS_STATE_TIME_TAI_UTC_DELTA_STRUCT appl_time_delta_param; + MS_STATE_TIME_ZONE_STRUCT appl_time_zone_param; + MS_STATE_TIME_ROLE_STRUCT appl_time_role_param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + void* param; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[TIME] GET Request.\n"); + + switch (state_params->state_type) + { + case MS_STATE_TIME_T: + { + param = &appl_time_param; + } + break; + + case MS_STATE_TIME_ZONE_T: + { + param = &appl_time_zone_param; + } + break; + + case MS_STATE_TIME_TAI_UTC_DELTA_T: + { + param = &appl_time_delta_param; + } + break; + + case MS_STATE_TIME_ROLE_T: + { + param = &appl_time_role_param; + } + break; + + default: + break; + } + + appl_model_state_get(state_params->state_type, 0, param, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = param; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[TIME] SET Request.\n"); + appl_model_state_set(state_params->state_type, 0, state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[TIME] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_time_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +#endif /* 0 */ diff --git a/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/time_server/appl_time_server.h b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/time_server/appl_time_server.h new file mode 100644 index 0000000..5bf3bcb --- /dev/null +++ b/src/components/ethermind/mesh/export/appl/model/server/time_and_scenes/time_server/appl_time_server.h @@ -0,0 +1,56 @@ +/** + \file appl_time_server.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_APPL_TIME_SERVER_ +#define _H_APPL_TIME_SERVER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_time_api.h" +#include "appl_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* time server application entry point */ +void main_time_server_operations(/* IN */ UINT8 have_menu); + +/* Get Model Handle */ +void appl_time_server_get_model_handle(void); + +/* Set Publish Address */ +void appl_time_server_set_publish_address(void); + +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Time server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT appl_time_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +#endif /*_H_APPL_TIME_SERVER_ */ diff --git a/src/components/ethermind/mesh/export/bearer/blebrr.c b/src/components/ethermind/mesh/export/bearer/blebrr.c new file mode 100644 index 0000000..450f93a --- /dev/null +++ b/src/components/ethermind/mesh/export/bearer/blebrr.c @@ -0,0 +1,1680 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +/** + \file blebrr.c + + This File contains the BLE Bearer interface for the + Mindtree Mesh stack. +*/ + +/* + Copyright (C) 2016. Mindtree Ltd. + All rights reserved. +*/ + +/* ------------------------------- Header File Inclusion */ +#include "MS_brr_api.h" +#include "MS_prov_api.h" +#include "MS_access_api.h" +#include "blebrr.h" +#include "ll.h" +#include "MS_trn_api.h" +#include "pwrmgr.h" +#include "ll_sleep.h" +#include "led_light.h" + + + +/* --------------------------------------------- External Global Variables */ + +/* --------------------------------------------- Global Definitions */ +#define BLEBRR_MAX_ADV_FILTER_LIST_COUNT 100 +#define BLEBRR_MAX_ADV_DATA_SIZE 31 + +#define BLEBRR_BCON_ELEMENTS 2 +#define BLEBRR_ACTIVEADV_TIMEOUT 1 /* Second */ +#define BLEBRR_ADV_SEC_TIMEOUT 3 /* Millisecond */ +#define BLEBRR_ADV_TIMEOUT 5 /* Millisecond */ +#define BLEBRR_ADV_NON_TIMEOUT 3 /* Millisecond */ +#define BLEBRR_SCAN_TIMEOUT (EM_TIMEOUT_MILLISEC | 30) /* Millisecond */ +#define BLEBRR_NCON_ADVTYPE_OFFSET 2 +#define BLEBRR_ADVREPEAT_PRO_COUNT 6 +#define BLEBRR_ADVREPEAT_NET_COUNT 2 +#define BLEBRR_SCAN_ADJ_STEP 30 +#define BLEBRR_SCAN_ADJ_THD_MAX 45//90 +#define BLEBRR_SCAN_ADJ_THD_MIN 15//90 +#define BLEBRR_TURNOFF_RELAY_THD 32 +#define BLEBRR_SKIP_BEACON_QUEUE_DEPTH 0 +#define BLEBRR_BCON_READY_TIME 10 + +/** Bearer Queue defines */ +#define BLEBRR_QTYPE_DATA 0x00 +#define BLEBRR_QTYPE_BEACON 0x01 +#define BLEBRR_NUM_QUEUES 0x02 + +/** Beacon type defines */ +#define BLEBRR_UPROV_ADV_BCON 0x00 +#define BLEBRR_UPROV_ADV_URI 0x01 +#define BLEBRR_UPROV_GATT_BCON 0x02 +#define BLEBRR_UPROV_GATT_URI 0x03 +#define BLEBRR_SECNET_BCON 0x04 +#define BLEBRR_NUM_BCONS 0x05 + +/** GATT Mode GAP Connectable Advertising Service data offset */ +#define BLEBRR_GATT_ADV_SERV_DATA_OFFSET 11 +#define BLEBRR_GATT_ADV_SERV_DATALEN_OFFSET 7 + +/** Advertising data maximum length */ +#define BLEBRR_GAP_ADVDATA_LEN 31 + +/** Advertising data sets MAX */ +#define BLEBRR_GAP_MAX_ADVDATA_SETS 2 + +#ifdef BLEBRR_LP_SUPPORT + UCHAR blebrr_lp_flag = MS_FALSE; + #define BLEBRR_LP_UNPROVISION_TIMEOUT 10*60 //unprovison timeout 10min + #define BLEBRR_LP_PROVISIONED_TIMEOUT 1200 // + #define BLEBRR_LP_PROVISIONED_WKP_TIMEOUT 60 // + #define BLEBRR_LP_PROVISIONED_SLP_TIMEOUT (BLEBRR_LP_PROVISIONED_TIMEOUT-BLEBRR_LP_PROVISIONED_WKP_TIMEOUT) +#endif + + + + +/* --------------------------------------------- Macros */ +#define BLEBRR_MUTEX_INIT() MS_MUTEX_INIT(blebrr_mutex, BRR); +#define BLEBRR_MUTEX_INIT_VOID() MS_MUTEX_INIT_VOID(blebrr_mutex, BRR); +#define BLEBRR_LOCK() MS_MUTEX_LOCK(blebrr_mutex, BRR); +#define BLEBRR_LOCK_VOID() MS_MUTEX_LOCK_VOID(blebrr_mutex, BRR); +#define BLEBRR_UNLOCK() MS_MUTEX_UNLOCK(blebrr_mutex, BRR); +#define BLEBRR_UNLOCK_VOID() MS_MUTEX_UNLOCK_VOID(blebrr_mutex, BRR); + +/* --------------------------------------------- Structures/Data Types */ +/** BLEBRR Data Queue Element */ +typedef struct _BLEBRR_Q_ELEMENT +{ + /* "Allocated" Data Pointer */ + UCHAR* pdata; + + /* + Data Length. If data length is zero, the element is considered + invalid. + */ + UINT16 pdatalen; + + /* Type of data element */ + UCHAR type; + +} BLEBRR_Q_ELEMENT; + +/** BLEBRR Data Queue */ +typedef struct _BLEBRR_Q +{ + /* List of Bearer Queue elements */ + BLEBRR_Q_ELEMENT element[BLEBRR_QUEUE_SIZE]; + + /* Queue start index */ + UINT16 start; + + /* Queue end index */ + UINT16 end; + +} BLEBRR_Q; + +/** Advertising Data type */ +typedef struct _BLEBRR_GAP_ADV_DATA +{ + /** Data */ + UCHAR data[BLEBRR_GAP_ADVDATA_LEN]; + + /** Data Length */ + UCHAR datalen; + +} BLEBRR_GAP_ADV_DATA; + + +/* --------------------------------------------- Global Variables */ +#ifdef BLEBRR_LP_SUPPORT + EM_timer_handle blebrr_lp_thandle; + +#endif +#ifdef BLEBRR_FILTER_DUPLICATE_PACKETS + DECL_STATIC UCHAR blebrr_adv_list[BLEBRR_MAX_ADV_FILTER_LIST_COUNT][BLEBRR_MAX_ADV_DATA_SIZE]; + DECL_STATIC UCHAR blebrr_adv_list_inser_index = 0; +#endif /* BLEBRR_FILTER_DUPLICATE_PACKETS */ + +BRR_BEARER_INFO blebrr_adv; //HZF + +DECL_STATIC BRR_HANDLE blebrr_advhandle; + +DECL_STATIC UCHAR blebrr_bconidx; +#ifdef BLEBRR_LP_SUPPORT + DECL_STATIC UCHAR blebrr_beacon; +#endif +DECL_STATIC UCHAR blebrr_update_advcount = BLEBRR_BCON_READY_TIME; +DECL_STATIC BLEBRR_Q_ELEMENT blebrr_bcon[BRR_BCON_COUNT]; +DECL_STATIC BLEBRR_Q blebrr_queue; + +MS_DEFINE_MUTEX_TYPE(static, blebrr_mutex) +DECL_STATIC EM_timer_handle blebrr_timer_handle = EM_TIMER_HANDLE_INIT_VAL; +UCHAR blebrr_state; // HZF +//DECL_STATIC UCHAR blebrr_state; + +/* Set provision started */ +UCHAR blebrr_prov_started; + +UCHAR blebrr_adv_restart; + + +UINT32 blebrr_scanTimeOut = 100; + +extern UCHAR blebrr_advtype; + + +DECL_STATIC UCHAR blebrr_datacount; + +/* DECL_STATIC UCHAR blebrr_scan_type; */ +DECL_STATIC UCHAR blebrr_advrepeat_count; +DECL_STATIC UCHAR blebrr_scan_interleave; + +BLEBRR_GAP_ADV_DATA blebrr_gap_adv_data[BLEBRR_GAP_MAX_ADVDATA_SETS] = +{ + /* Index 0x00: Mesh Provisioning Service ADV Data */ + { + { + /** + Flags: + 0x01: LE Limited Discoverable Mode + 0x02: LE General Discoverable Mode + 0x04: BR/EDR Not Supported + 0x08: Simultaneous LE and BR/EDR to Same Device + Capable (Controller) + 0x10: Simultaneous LE and BR/EDR to Same Device + Capable (Host) + */ + 0x02, 0x01, 0x06, + + /** + Service UUID List: + Mesh Provisioning Service (0x1827) + */ + 0x03, 0x03, 0x27, 0x18, + + /** + Service Data List: + Mesh Provisioning Service (0x1827) + Mesh UUID (16 Bytes) + Mesh OOB Info (2 Bytes) + */ + 0x15, 0x16, + 0x27, 0x18, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, + 0x00, 0x00 + }, + + /** Advertising Data length */ + 29 + }, + /* Index 0x01: Mesh Proxy Service ADV Data */ + { + { + /** + Flags: + 0x01: LE Limited Discoverable Mode + 0x02: LE General Discoverable Mode + 0x04: BR/EDR Not Supported + 0x08: Simultaneous LE and BR/EDR to Same Device + Capable (Controller) + 0x10: Simultaneous LE and BR/EDR to Same Device + Capable (Host) + */ + 0x02, 0x01, 0x06, + + /** + Service UUID List: + Mesh Proxy Service (0x1828) + */ + 0x03, 0x03, 0x28, 0x18, + + /** + Service Data List: + Mesh Provisioning Service (0x1828) + Type (1 Byte) "0x00 - Network ID; 0x01 - Node Identity" + NetWork ID (8 Bytes) + */ + 0x0C, 0x16, + 0x28, 0x18, + 0x00, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88 + }, + + /** Advertising Data length */ + 20 + } +}; + +DECL_STATIC UCHAR pl_advdata_offset; +UCHAR blebrr_sleep; + + +// ------------ add by HZF +uint32 blebrr_advscan_timeout_count = 0; +extern uint32_t osal_sys_tick; + + +/* ------------------------------- Functions */ +void blebrr_handle_evt_adv_complete (UINT8 enable); +DECL_STATIC void blebrr_timer_start (UINT32 timeout); + +API_RESULT blebrr_queue_depth_check(void); + +/** + \brief + + \par Description + + + \return void +*/ +void blebrr_scan_enable(void) +{ + BLEBRR_LOCK_VOID(); + + if ((BLEBRR_STATE_IDLE == BLEBRR_GET_STATE()) && + (MS_TRUE != blebrr_sleep)) + { + blebrr_scan_pl(MS_TRUE); + /* Update state */ +// BLEBRR_SET_STATE(BLEBRR_STATE_IN_SCAN_ENABLE); + } + + BLEBRR_UNLOCK_VOID(); +} + +/** + \brief + + \par Description + + + \param type + \param bcon + + \return void +*/ +DECL_STATIC UCHAR blebrr_get_beacon_type (UCHAR type, UCHAR bcon) +{ + return (BRR_BCON_PASSIVE == type)? + ((BRR_BCON_TYPE_UNPROV_DEVICE == bcon)? BLEBRR_UPROV_ADV_BCON: BLEBRR_SECNET_BCON): + ((BRR_BCON_TYPE_UNPROV_DEVICE == bcon)? BLEBRR_UPROV_GATT_BCON: BLEBRR_NUM_BCONS); +} + +/** + \brief + + \par Description + + + \param type + + \return void +*/ +DECL_STATIC BLEBRR_Q_ELEMENT* blebrr_enqueue_alloc (void) +{ + BLEBRR_Q_ELEMENT* elt; + UINT16 ei; + /* Get reference to the requested Queue block members */ + elt = blebrr_queue.element; + ei = blebrr_queue.end; + + /* Check if queue end element is free */ + if (0 != (elt + ei)->pdatalen) + { + /* Not free */ + elt = NULL; + } + else + { + /* Set the element to be returned */ + elt = (elt + ei); + /* Update the data availability */ +// blebrr_datacount++; + + /* EM_debug_trace (0, "[BLEBRR] Enqueue at Q Index: %d\n", ei); */ + + /* Update queue end */ + if(ei == BLEBRR_QUEUE_SIZE - 1) + ei = 0; + else + ei++; + +// ei++; +// ei &= (BLEBRR_QUEUE_SIZE - 1); + blebrr_queue.end = ei; + } + + return elt; +} + +DECL_STATIC void blebrr_dequeue_manual (void) +{ + UINT16 ei; + ei = blebrr_queue.end; + + /* Update the data availability */ +// blebrr_datacount--; + + /* EM_debug_trace (0, "[BLEBRR] Enqueue at Q Index: %d\n", ei); */ +// printf ("[BLEBRR] Dequeue at Q Index: __%d\n", ei); + + /* Update queue end */ + if(ei == 0) + ei = BLEBRR_QUEUE_SIZE - 1; + else + ei--; + + blebrr_queue.end = ei; +} + + +/** + \brief + + \par Description + + + \param type + + \return void +*/ +DECL_STATIC BLEBRR_Q_ELEMENT* blebrr_dequeue (void) +{ + BLEBRR_Q_ELEMENT* elt; + UINT16 si; + /* Get reference to the requested Queue block members */ + elt = blebrr_queue.element; + si = blebrr_queue.start; + + /* Check if queue start element is valid */ + if (0 == (elt + si)->pdatalen) + { + /* Not valid */ + elt = NULL; + } + else + { + /* Set the element to be returned */ + elt = (elt + si); + /* EM_debug_trace (0, "[BLEBRR] Dequeue at Q Index: %d\n", si); */ + + /* Is Adv data type in element? */ + if (BRR_BCON_COUNT == elt->type) + { + /* Update the data availability */ + blebrr_datacount--; + } + + /* Update the data availability */ +// blebrr_datacount--; + + /* Update queue start */ + if(si == BLEBRR_QUEUE_SIZE - 1) + si = 0; + else + si++; + +// si++; +// si &= (BLEBRR_QUEUE_SIZE - 1); + blebrr_queue.start = si; + } + + return elt; +} + +/** + \brief + + \par Description + + + \param bcon + + \return void +*/ +DECL_STATIC void blebrr_clear_bcon (UCHAR bconidx) +{ + BLEBRR_Q_ELEMENT* elt; + /* Get reference to the beacon queue element */ + elt = &blebrr_bcon[bconidx]; + + /* Clear the element and the next one for the given type of beacon */ + if (NULL != elt->pdata) + { + EM_free_mem (elt->pdata); + elt->pdata = NULL; + elt->pdatalen = 0; + elt->type = BRR_BCON_COUNT; + + if ((BRR_BCON_TYPE_UNPROV_DEVICE == bconidx) && + (NULL != (elt + 1)->pdata) && + (0 != (elt + 1)->pdatalen)) + { + EM_free_mem((elt + 1)->pdata); + (elt + 1)->pdata = NULL; + (elt + 1)->pdatalen = 0; + (elt + 1)->type = BRR_BCON_COUNT; + } + + blebrr_datacount--; + } +} + +UCHAR blebrr_get_queue_depth(void) +{ + UCHAR depth; + BLEBRR_Q_ELEMENT* elt; + UINT16 ei; + /* Get reference to the requested Queue block members */ + elt = blebrr_queue.element; + ei = blebrr_queue.end; + depth = 0; + + if((blebrr_queue.end == blebrr_queue.start) && (0 != (elt + ei)->pdatalen)) + { + depth = BLEBRR_QUEUE_SIZE; + } + else if(blebrr_queue.end > blebrr_queue.start) + { + depth = blebrr_queue.end-blebrr_queue.start; + } + else if(blebrr_queue.end < blebrr_queue.start) + { + depth = BLEBRR_QUEUE_SIZE-(blebrr_queue.start-blebrr_queue.end); + } + + return depth; +} + +API_RESULT blebrr_queue_depth_check(void) +{ + API_RESULT retval =API_SUCCESS; + uint8_t randData; + UCHAR depth =blebrr_get_queue_depth(); + + if(depth>BLEBRR_TURNOFF_RELAY_THD) + { + LL_Rand(&randData, 1); + randData=randData>>1; + + if( depth > randData) + { + retval= API_FAILURE; + } + + BLEBRR_LOG("[Queue DATA CNT] = %d %d %4X\n", depth,randData,retval); + } + + return retval; +} + +extern uint8 llState, llSecondaryState; +/** + \brief + + \par Description + + * * + * * \param void + + \return void +*/ +DECL_STATIC API_RESULT blebrr_update_advdata(void) +{ + BLEBRR_Q_ELEMENT* elt; + UCHAR type; + elt = NULL; + UCHAR is_proxy_beacon; + is_proxy_beacon = 1; + + //ZQY skip bcon adv when queue is not empty +// printf("blebrr_get_queue_depth:%d\n",blebrr_get_queue_depth()); + + if(blebrr_update_advcount < BLEBRR_BCON_READY_TIME) + { + is_proxy_beacon = 0; + blebrr_update_advcount++; + } + else + { + blebrr_update_advcount = 0; + } + + if(blebrr_get_queue_depth()>BLEBRR_SKIP_BEACON_QUEUE_DEPTH) + { + is_proxy_beacon = 0; + } + + if (is_proxy_beacon) + { + UCHAR bconidx; + bconidx = blebrr_bconidx; + + do + { + if (0 != blebrr_bcon[blebrr_bconidx].pdatalen) + { + elt = &blebrr_bcon[blebrr_bconidx]; + is_proxy_beacon = 0; + } + + if (BRR_BCON_COUNT == ++blebrr_bconidx) + { + blebrr_bconidx = 0; + } + } + while ((blebrr_bconidx != bconidx) && (NULL == elt)); + } + + if (!is_proxy_beacon && NULL == elt) + { + elt = blebrr_dequeue(); + is_proxy_beacon = 1; + } + + if (NULL == elt) + { + return API_FAILURE; + } + + /* Set the type */ + type = (BRR_BCON_COUNT == elt->type) ? BRR_BCON_PASSIVE : elt->type; + /* Set the advertising data */ + blebrr_advrepeat_count = 1; + blebrr_advertise_data_pl(type, elt->pdata, elt->pdatalen); + + /* Is Adv data type in element? */ + if (BRR_BCON_COUNT == elt->type) + { + #ifdef BLEBRR_LP_SUPPORT + blebrr_beacon = 0; + #endif + /* Yes, Free the element */ + EM_free_mem(elt->pdata); + elt->pdatalen = 0; + } + + #ifdef BLEBRR_LP_SUPPORT + else + { + blebrr_beacon = 1; + } + + #endif + return API_SUCCESS; +} + +#if 0 + DECL_STATIC void blebrr_timer_restart (UINT32 timeout); +#endif + + +/** + \brief + + \par Description + + + \param type + \param pdata + \param datalen + \param elt + + \return void +*/ +DECL_STATIC API_RESULT blebrr_send +( + UCHAR type, + void* pdata, + UINT16 datalen, + BLEBRR_Q_ELEMENT* elt +) +{ + API_RESULT retval; + UCHAR* data; + UINT16 packet_len; + UCHAR offset; + data = (UCHAR*)pdata; + /* BLEBRR_LOG("[ADV-Tx >]: "); + BLEBRR_dump_bytes(data, datalen); */ + /* Get the offset based on the type */ + offset = (0 != type)? BLEBRR_NCON_ADVTYPE_OFFSET: 0; + /* Calculate the total length, including Adv Data Type headers */ + packet_len = datalen + offset; + /* Allocate and save the data */ + elt->pdata = EM_alloc_mem(packet_len); + + if (NULL == elt->pdata) + { +// BLEBRR_LOG("Failed to allocate memory!\n"); + return API_FAILURE; + } + + if (offset >= 1) + { + /* Add the Length and Adv type headers */ + elt->pdata[0] = (UCHAR)(datalen + (offset - 1)); + + if (offset - 1) + { + elt->pdata[1] = type; + } + } + + /* Update the data and datalen */ + EM_mem_copy((elt->pdata + offset), data, datalen); + elt->pdatalen = packet_len; + + /* Is the Adv/Scan timer running? */ + if (EM_TIMER_HANDLE_INIT_VAL != blebrr_timer_handle) + { + /* Yes. Do nothing */ + if (BLEBRR_STATE_SCAN_ENABLED == BLEBRR_GET_STATE()) + { + retval = EM_stop_timer(&blebrr_timer_handle); + + if(retval == EM_SUCCESS) + blebrr_scan_pl (MS_FALSE); + } + } + else + { + /* + No. Scan must be enabled. Disable it to trigger alternating + Adv/Scan Procedure + */ + if (BLEBRR_STATE_SCAN_ENABLED == BLEBRR_GET_STATE() + || BLEBRR_STATE_IN_SCAN_ENABLE == BLEBRR_GET_STATE()) + { + blebrr_scan_pl (MS_FALSE); + } + + #if 1 + else if (BLEBRR_STATE_ADV_ENABLED == BLEBRR_GET_STATE()) + { + /* Disable Advertising */ + blebrr_advertise_pl(MS_FALSE); + } + + #endif + else if (BLEBRR_STATE_IDLE == BLEBRR_GET_STATE()) + { + /* No, Enable Advertising with Data */ + retval = blebrr_update_advdata(); + + if (API_SUCCESS != retval) + { + /* Enable Scan */ + blebrr_scan_pl(MS_TRUE); + /* Update state */ +// BLEBRR_SET_STATE(BLEBRR_STATE_IN_SCAN_ENABLE); + } + else + { + /* Update state */ +// BLEBRR_SET_STATE(BLEBRR_STATE_IN_ADV_ENABLE); + } + } + } + + return API_SUCCESS; +} + + +/** + \brief + + \par Description + + + \param handle + \param pdata + \param datalen + + \return void +*/ +DECL_STATIC API_RESULT blebrr_bcon_send(BRR_HANDLE* handle, void* pdata, UINT16 datalen) +{ + BRR_BEACON_INFO* info; + BLEBRR_Q_ELEMENT* elt; + UCHAR op, action, type, bcon, bcontype; + UCHAR bconidx; + /* Get the beacon information */ + info = (BRR_BEACON_INFO*)pdata; + /* Get the Operation and Action */ + op = (info->action & 0x0F); + action = ((info->action & 0xF0) >> 4); + /* Get the Broadcast/Observe type and Beacon type */ + type = (info->type & 0x0F); + bcon = ((info->type & 0xF0) >> 4); + /* Lock */ + BLEBRR_LOCK(); + + /* Check the operations */ + switch (op) + { + case BRR_OBSERVE: + /* blebrr_scan_type = type; */ + break; + + case BRR_BROADCAST: + /* Get the Beacon mapping at the BLEBRR */ + bcontype = blebrr_get_beacon_type (type, bcon); + /* Set the bcon index */ + bconidx = bcon; + + if (BRR_ENABLE == action) + { + /* Update the connectable beacon packet */ + if ((BRR_BCON_ACTIVE == type) && ((NULL != info->bcon_data))) + { + /* Active Beacon (advdata) Source Index */ + UCHAR abs_index; + abs_index = blebrr_gatt_mode_get(); + + if (BLEBRR_GATT_PROV_MODE == abs_index) + { + /* Copy the incoming UUID and OOB info to global connectable ADV data for PB GATT */ + /* TODO have a state to decide about provisioned and unprovisioned state */ + EM_mem_copy + ( + blebrr_gap_adv_data[abs_index].data + BLEBRR_GATT_ADV_SERV_DATA_OFFSET, + info->bcon_data + 1, + 16 + 2 + ); + /** + NOTE: It is not need to calculate assign the Service Data Length as + Service Data length is Fixed for Connectable Provisioning ADV. + This data length is : 1 + 2 + 16 + 2 = 0x15 Bytes, already updated + in the global data strucutre blebrr_gap_adv_data[0]. + */ + /* Disable Interleaving */ + blebrr_scan_interleave = MS_FALSE; + } + /* Assuming that this Active Beacon is for GATT Proxy*/ + else + { + /* Copy the incoming UUID and OOB info to global connectable ADV data for PB GATT */ + /* TODO have a state to decide about provisioned and unprovisioned state */ + abs_index = BLEBRR_GATT_PROXY_MODE; + /* Copy the incoming Proxy ADV data */ + EM_mem_copy + ( + blebrr_gap_adv_data[abs_index].data + BLEBRR_GATT_ADV_SERV_DATA_OFFSET, + info->bcon_data, + info->bcon_datalen + ); + /* Copy the incoming Proxy ADV datalen + the BLEBRR_GATT_ADV_SERV_DATA_OFFSET */ + blebrr_gap_adv_data[abs_index].datalen = BLEBRR_GATT_ADV_SERV_DATA_OFFSET + info->bcon_datalen; + /** + Assign the service data length correctly for Proxy ADVs + Total incoming data + 1 Byte of AD Flags + 2 Bytes of Service UUID + */ + blebrr_gap_adv_data[abs_index].data[BLEBRR_GATT_ADV_SERV_DATALEN_OFFSET] = + info->bcon_datalen + 1 + 2; + } + + /* Re-assign updated ADV data to Info Structure */ + info->bcon_data = blebrr_gap_adv_data[abs_index].data + pl_advdata_offset; + info->bcon_datalen = blebrr_gap_adv_data[abs_index].datalen - pl_advdata_offset; + } + + /* Check if beacon element is free */ + if (0 != blebrr_bcon[bconidx].pdatalen) + { + /* Unlock */ + BLEBRR_UNLOCK(); + BLEBRR_LOG("Beacon Not Free!\n"); + return API_FAILURE; + } + + elt = &blebrr_bcon[bconidx]; + blebrr_datacount++; + /* Update element type */ + elt->type = type; + /* Schedule to send */ + blebrr_send + ( + ((BRR_BCON_TYPE_UNPROV_DEVICE == bcon) && + (BRR_BCON_ACTIVE != type))? MESH_AD_TYPE_BCON : 0, + info->bcon_data, + info->bcon_datalen, + elt + ); + + /* Check if URI data is present for Unprovisioned device */ + if ((BRR_BCON_TYPE_UNPROV_DEVICE == bconidx) && + (NULL != info->uri) && + (NULL != info->uri->payload) && + (0 != info->uri->length)) + { + elt = &blebrr_bcon[bconidx + 1]; + /* Update element type */ + elt->type = bcontype + 1; + /* Schedule to send */ + blebrr_send + ( + 0, + info->uri->payload, + info->uri->length, + elt + ); + } + } + else + { + /* Remove the beacon with type from the queue */ + blebrr_clear_bcon (bconidx); + } + + break; + + default: + break; + } + + /* Unlock */ + BLEBRR_UNLOCK(); + return API_SUCCESS; +} + + +/** + \brief + + \par Description + + + \param handle + \param pdata + \param datalen + + \return void +*/ +extern uint8 llState; +extern uint8 llSecondaryState; + +DECL_STATIC API_RESULT blebrr_adv_send(BRR_HANDLE* handle, UCHAR type, void* pdata, UINT16 datalen) +{ + API_RESULT retval; + BLEBRR_Q_ELEMENT* elt; + + /* Validate handle */ + if (*handle != blebrr_advhandle) + { + return API_FAILURE; + } + + if ((NULL == pdata) || + (0 == datalen)) + { + return API_FAILURE; + } + + /* Enable interleaving */ + blebrr_scan_interleave = MS_TRUE; + blebrr_update_advcount = BLEBRR_BCON_READY_TIME; //send beacon immediately + + /* If beacon type, pass to the handler */ + if (MESH_AD_TYPE_BCON == type) + { + BRR_BEACON_INFO* info; + /* Get reference to the beacon info */ + info = (BRR_BEACON_INFO*)pdata; + + if (BRR_BCON_TYPE_SECURE_NET != (info->type >> 4)) + { + return blebrr_bcon_send(handle, pdata, datalen); + } + else + { + /* Update the data and length reference */ + pdata = info->bcon_data; + datalen = info->bcon_datalen; + } + } + + /* Lock */ + BLEBRR_LOCK(); + /* Allocate the next free element in the data queue */ + elt = blebrr_enqueue_alloc(); + + /* Is any element free? */ + if (NULL == elt) + { + /* Unlock */ + BLEBRR_UNLOCK(); + BLEBRR_LOG("Queue Full! blebrr_advscan_timeout_count = %d, ble state = %d,depth %d llstate %02x llsec %02x\r\n", blebrr_advscan_timeout_count, BLEBRR_GET_STATE(),blebrr_get_queue_depth(),llState,llSecondaryState); + blebrr_scan_pl(FALSE); // HZF + return API_FAILURE; + } + + /* Update element type */ + elt->type = BRR_BCON_COUNT; + /* Schedule to send */ + retval = blebrr_send + ( + type, + pdata, + datalen, + elt + ); + + if(retval == API_FAILURE) + blebrr_dequeue_manual(); + else + blebrr_datacount++; + + /* Unlock */ + BLEBRR_UNLOCK(); + return API_SUCCESS; +} + +#ifdef BLEBRR_LP_SUPPORT +DECL_STATIC void blebrr_adv_sleep(BRR_HANDLE* handle) +{ + BLEBRR_LOCK_VOID(); + /* Set bearer sleep state */ + blebrr_sleep = MS_TRUE; + MS_prov_stop_interleave_timer(); + MS_proxy_server_stop_timer(); + + if (BLEBRR_STATE_SCAN_ENABLED == BLEBRR_GET_STATE() || + BLEBRR_STATE_IDLE == BLEBRR_GET_STATE()) + { + /* Disable Scan */ + blebrr_scan_pl(MS_FALSE); + /* Update state */ + BLEBRR_SET_STATE(BLEBRR_STATE_IDLE); + } + else if(BLEBRR_STATE_ADV_ENABLED == BLEBRR_GET_STATE()) + { + /* Disable Advertising */ + blebrr_advertise_pl(MS_FALSE); + } + + /* Enter platform sleep */ + EM_enter_sleep_pl(); + BLEBRR_UNLOCK_VOID(); +} + +DECL_STATIC void blebrr_adv_wakeup(BRR_HANDLE* handle, UINT8 mode) +{ + BLEBRR_LOCK_VOID(); + /* Exit platform sleep */ + EM_exit_sleep_pl(); + /* Reset bearer sleep state */ + blebrr_sleep = MS_FALSE; + + if (BRR_TX & mode) + { + if (BLEBRR_STATE_IDLE == BLEBRR_GET_STATE()) + { + blebrr_update_advcount = BLEBRR_BCON_READY_TIME; //send beacon immediately + /* Enable Advertise */ + blebrr_lp_flag = MS_TRUE; + blebrr_update_advdata(); + /* Update state */ +// BLEBRR_SET_STATE(BLEBRR_STATE_IN_ADV_ENABLE); + } + } + else if (BRR_RX & mode) + { + if (BLEBRR_STATE_IDLE == BLEBRR_GET_STATE()) + { + /* Enable Scan */ + blebrr_scan_pl(MS_TRUE); + /* Update state */ +// BLEBRR_SET_STATE(BLEBRR_STATE_IN_SCAN_ENABLE); + } + } + + BLEBRR_UNLOCK_VOID(); +} + +API_RESULT blebrr_sleep_handler(void) +{ + API_RESULT retval; + retval=MS_brr_sleep(); + return retval; +} + +API_RESULT blebrr_wakeup_handler(void) +{ + API_RESULT retval; + UCHAR state; + /* Fetch PROXY feature state */ + MS_access_cm_get_features_field(&state, MS_FEATURE_PROXY); + + if(state == MS_TRUE) + { + retval = MS_brr_wakeup(BRR_TX|BRR_RX); + } + else + { + retval = MS_brr_wakeup(BRR_RX); + } + + return retval; +} + +static void enter_lp_sleep_mode (void) +{ + light_timeout_handle(); + hal_pwrmgr_unlock(MOD_USR1); + blebrr_sleep_handler(); + printf("sleep mode:%d\n", isSleepAllow()); +} + + +void blebrr_lp_mode (void* args, UINT16 size) +{ + UCHAR mode; + UCHAR glp_mode; + blebrr_lp_thandle = EM_TIMER_HANDLE_INIT_VAL; + UCHAR state; + /* Fetch PROXY feature state */ + MS_access_cm_get_features_field(&state, MS_FEATURE_PROXY); + MS_IGNORE_UNUSED_PARAM(size); + mode = (*((UCHAR*)args)); + + if(mode == BLEBRR_LP_OFF) + { + pwroff_cfg_t pwr_wkp_cfg[]= {{P14,NEGEDGE}}; + hal_pwrmgr_poweroff( pwr_wkp_cfg, sizeof(pwr_wkp_cfg)/sizeof(pwr_wkp_cfg[0]) ); + } + else if(mode == BLEBRR_LP_SLEEP) + { + blebrr_wakeup_handler(); + + if(state != MS_TRUE) + { + glp_mode = BLEBRR_LP_WKP; + EM_start_timer + ( + &blebrr_lp_thandle, + EM_TIMEOUT_MILLISEC | BLEBRR_LP_PROVISIONED_WKP_TIMEOUT, + blebrr_lp_mode, + (void*)&glp_mode, + sizeof(glp_mode) + ); + } + } + else + { + glp_mode = BLEBRR_LP_SLEEP; + EM_start_timer + ( + &blebrr_lp_thandle, + EM_TIMEOUT_MILLISEC | BLEBRR_LP_PROVISIONED_SLP_TIMEOUT, + blebrr_lp_mode, + (void*)&glp_mode, + sizeof(glp_mode) + ); + enter_lp_sleep_mode(); + } +} + + +API_RESULT blebrr_lp_start(UCHAR mode) +{ + API_RESULT retval; + UCHAR state; + UINT32 timeout; + /* Fetch PROXY feature state */ + MS_access_cm_get_features_field(&state, MS_FEATURE_PROXY); + + switch(mode) + { + case BLEBRR_LP_OFF: + { + timeout = BLEBRR_LP_UNPROVISION_TIMEOUT; + } + break; + + case BLEBRR_LP_SLEEP: + { + timeout = EM_TIMEOUT_MILLISEC | BLEBRR_LP_PROVISIONED_SLP_TIMEOUT; + } + break; + + case BLEBRR_LP_WKP: + { + timeout = EM_TIMEOUT_MILLISEC | BLEBRR_LP_PROVISIONED_WKP_TIMEOUT; + } + break; + + default: + break; + } + + retval = EM_start_timer + ( + &blebrr_lp_thandle, + timeout, + blebrr_lp_mode, + (void*)&mode, + sizeof(mode) + ); + + if(mode == BLEBRR_LP_SLEEP) + enter_lp_sleep_mode(); + + return retval; +} + +void blebrr_lp_stop(void) +{ + EM_stop_timer (&blebrr_lp_thandle); +} + + +#endif /* BLEBRR_LP_SUPPORT */ + +/** + \brief + + \par Description + + + \param args + \param size + + \return void +*/ +DECL_STATIC void blebrr_advscan_timeout_handler (void* args, UINT16 size) +{ + MS_IGNORE_UNUSED_PARAM(args); + MS_IGNORE_UNUSED_PARAM(size); + BLEBRR_LOCK_VOID(); + blebrr_advscan_timeout_count ++; + /* Reset Timer Handler */ + blebrr_timer_handle = EM_TIMER_HANDLE_INIT_VAL; + + /* Check the state of AdvScan procedure */ + switch (BLEBRR_GET_STATE()) + { + case BLEBRR_STATE_ADV_ENABLED: + + /* Disable Adv */ + if (!blebrr_advertise_pl (MS_FALSE)) // HZF + /* Update state */ +// BLEBRR_SET_STATE(BLEBRR_STATE_IN_ADV_DISABLE); + break; + + case BLEBRR_STATE_SCAN_ENABLED: + /* Disable Scan */ + blebrr_scan_pl (MS_FALSE); + /* Update state */ +// BLEBRR_SET_STATE(BLEBRR_STATE_IN_SCAN_DISABLE); + break; + + default: + /* Should not reach here */ + BLEBRR_LOG("=======blebrr_advscan_timeout_handler error: state = %2X, state will not change\r\n", BLEBRR_GET_STATE()); + break; + } + + BLEBRR_UNLOCK_VOID(); +} + + +/** + \brief + + \par Description + + + \param timeout + + \return void +*/ +DECL_STATIC void blebrr_timer_start (UINT32 timeout) +{ + EM_RESULT retval; + + if(blebrr_timer_handle == EM_TIMER_HANDLE_INIT_VAL) + { + retval = EM_start_timer + ( + &blebrr_timer_handle, + timeout, + blebrr_advscan_timeout_handler, + NULL, + 0 + ); + + if (EM_SUCCESS != retval) + { + /* TODO: Log */ + } + } +} + +void blebrr_timer_stop (void) +{ + if(blebrr_timer_handle != EM_TIMER_HANDLE_INIT_VAL) + { + if(EM_stop_timer(&blebrr_timer_handle) != API_SUCCESS) + return; + } + + BLEBRR_SET_STATE(BLEBRR_STATE_IDLE); +} + + +#if 0 +/** + \brief + + \par Description + + + \param timeout + + \return void +*/ +DECL_STATIC void blebrr_timer_restart (UINT32 timeout) +{ + EM_RESULT retval; +// printf("before blebrr_timer_handle:%d\n",blebrr_timer_handle); + retval = EM_restart_timer + ( + blebrr_timer_handle, + timeout + ); +// printf("after blebrr_timer_handle:%d\n",blebrr_timer_handle); + + if (EM_SUCCESS != retval) + { + /* TODO: Log */ + } +} +#endif + + + +/** + \brief + + \par Description + + + \param enable + + \return void +*/ +void blebrr_pl_scan_setup (UCHAR enable) +{ + API_RESULT retval; + BLEBRR_LOCK_VOID(); + #ifdef BLEBRR_ENABLE_SCAN_TRACE + BLEBRR_LOG ("Scan Setup - %d", enable); + #endif /* BLEBRR_ENABLE_SCAN_TRACE */ + + /* Is scan enabled? */ + if (MS_TRUE == enable) + { + /* Yes, Update state */ + BLEBRR_SET_STATE(BLEBRR_STATE_SCAN_ENABLED); + + /* Is data available in queue to be sent? */ + if (0 != blebrr_datacount) + { + UCHAR depth=blebrr_get_queue_depth(); + + if(depth>0) + blebrr_scanTimeOut = BLEBRR_SCAN_ADJ_THD_MIN; + else + blebrr_scanTimeOut = BLEBRR_SCAN_ADJ_THD_MAX; + + /* Yes, Start bearer timer for Scan Timeout */ + blebrr_timer_start ((EM_TIMEOUT_MILLISEC | blebrr_scanTimeOut)); + } + } + else + { + /* No, Enable Advertising with Data */ + retval = blebrr_update_advdata(); + + if (API_SUCCESS != retval) + { + if (MS_TRUE != blebrr_sleep) + { + /* Enale Scan */ + blebrr_scan_pl(MS_TRUE); + /* Update state */ +// BLEBRR_SET_STATE(BLEBRR_STATE_IN_SCAN_ENABLE); + } + else + { + /* Update state */ + BLEBRR_SET_STATE(BLEBRR_STATE_IDLE); + } + } + else + { + /* Update state */ +// BLEBRR_SET_STATE(BLEBRR_STATE_IN_ADV_ENABLE); + } + } + + BLEBRR_UNLOCK_VOID(); +} + +/** + \brief + + \par Description + + + \param type + \param enable + + \return void +*/ +void blebrr_pl_advertise_setup (UCHAR enable) +{ + BLEBRR_LOCK_VOID(); + UCHAR adv_repeat_count; +// API_RESULT retval; + #ifdef BLEBRR_ENABLE_ADV_TRACE + BLEBRR_LOG ("Adv Setup - %d", enable); + #endif /* BLEBRR_ENABLE_ADV_TRACE */ + + /* Is advertise enabled? */ + if (MS_TRUE == enable) + { + /* Yes, Update state */ + BLEBRR_SET_STATE(BLEBRR_STATE_ADV_ENABLED); + + /* Start bearer timer for Adv Timeout */ + if (blebrr_scan_interleave == MS_TRUE) + { + UCHAR timeout,proxy_state; + MS_proxy_fetch_state(&proxy_state); + + if(proxy_state == MS_PROXY_CONNECTED) + timeout = BLEBRR_ADV_SEC_TIMEOUT; + else + timeout= (blebrr_advtype == BRR_BCON_PASSIVE) ? BLEBRR_ADV_NON_TIMEOUT : BLEBRR_ADV_TIMEOUT; + + blebrr_timer_start (EM_TIMEOUT_MILLISEC | timeout); + } + } + else + { + if (MS_TRUE == blebrr_sleep) + { + /* Update state */ + blebrr_adv_restart = MS_FALSE; + BLEBRR_SET_STATE(BLEBRR_STATE_IDLE); + return; + } + +// if(blebrr_adv_restart == MS_TRUE) + { +// blebrr_adv_restart = MS_FALSE; +// blebrr_update_advcount = BLEBRR_BCON_READY_TIME; +// retval = blebrr_update_advdata(); +// if (API_SUCCESS != retval) +// { +// /* Enale Scan */ +// blebrr_scan_pl(MS_TRUE); +// /* Update state */ +// BLEBRR_SET_STATE(BLEBRR_STATE_IN_SCAN_ENABLE); +// } +// else +// { +// /* Update state */ +// BLEBRR_SET_STATE(BLEBRR_STATE_IN_ADV_ENABLE); +// } + } +// else + { + adv_repeat_count = (blebrr_prov_started == MS_TRUE)?BLEBRR_ADVREPEAT_PRO_COUNT:BLEBRR_ADVREPEAT_NET_COUNT; + + if (/*blebrr_beacon && */(adv_repeat_count > blebrr_advrepeat_count)) + { + blebrr_advrepeat_count++; + blebrr_advertise_pl(MS_TRUE); + /* Update state */ +// BLEBRR_SET_STATE(BLEBRR_STATE_IN_ADV_ENABLE); + } + else + { + /* No, Enable Scanning */ + blebrr_scan_pl(MS_TRUE); + #ifdef BLEBRR_LP_SUPPORT + UCHAR glp_mode; + + if((blebrr_lp_flag == MS_TRUE) &&(blebrr_beacon == 1)) + { + blebrr_beacon =0; + blebrr_lp_flag = MS_FALSE; + glp_mode = BLEBRR_LP_WKP; + blebrr_lp_start(glp_mode); + } + + #endif + /* Update state */ +// BLEBRR_SET_STATE(BLEBRR_STATE_IN_SCAN_ENABLE); + } + } + } + + BLEBRR_UNLOCK_VOID(); +} + +/** + \brief + + \par Description + + + \param None + + \return void +*/ +void blebrr_pl_advertise_end (void) +{ + BLEBRR_LOCK_VOID(); + blebrr_advrepeat_count = 0; + BLEBRR_UNLOCK_VOID(); +} + +#ifdef BLEBRR_FILTER_DUPLICATE_PACKETS +/** + \brief + + \par Description + + + \param p_adv_data_with_bd_addr + + \return void +*/ +DECL_STATIC API_RESULT blebrr_adv_duplicate_filter(/* IN */ UCHAR* p_adv_data_with_bd_addr) +{ + UCHAR length, index; + /* Get the ADV data packet length */ + length = p_adv_data_with_bd_addr[1 + BT_BD_ADDR_SIZE]; + + for (index = 0; index < BLEBRR_MAX_ADV_FILTER_LIST_COUNT; index++) + { + /* First Match BD Addr */ + if (0 == EM_mem_cmp + ( + &blebrr_adv_list[index][0], + p_adv_data_with_bd_addr, + 1 + BT_BD_ADDR_SIZE + )) + { + /* Check Data Length */ + if (blebrr_adv_list[index][1 + BT_BD_ADDR_SIZE] == p_adv_data_with_bd_addr[1 + BT_BD_ADDR_SIZE]) + { + if (0 == EM_mem_cmp + ( + &blebrr_adv_list[index][1 + BT_BD_ADDR_SIZE + 1], + &p_adv_data_with_bd_addr[1 + BT_BD_ADDR_SIZE + 1], + length + )) + { + return API_SUCCESS; + } + } + + /* Update Adv data */ + EM_mem_copy + ( + &blebrr_adv_list[index][1 + BT_BD_ADDR_SIZE], + &p_adv_data_with_bd_addr[1 + BT_BD_ADDR_SIZE], + length + 1 + ); + return API_FAILURE; + } + } + + /* Find out the suitable location to save the most recent ADV packet */ + /* New peer device. Add */ + EM_mem_copy + ( + &blebrr_adv_list[blebrr_adv_list_inser_index][0], + p_adv_data_with_bd_addr, + length + 1 + BT_BD_ADDR_SIZE + 1 + ); + /* Increment and Wrap (if required) */ + blebrr_adv_list_inser_index++; + + if (BLEBRR_MAX_ADV_FILTER_LIST_COUNT <= blebrr_adv_list_inser_index) + { + blebrr_adv_list_inser_index = 0; + } + + return API_FAILURE; +} +#endif /* BLEBRR_FILTER_DUPLICATE_PACKETS */ + + +extern uint8 osal_memory_audit(void* ptr); +/** + \brief + + \par Description + + + \param type + \param pdata + \param pdatalen + \param rssi + + \return void +*/ +void blebrr_pl_recv_advpacket (UCHAR type, UCHAR* pdata, UINT16 pdatalen, UCHAR rssi) +{ + MS_BUFFER info; + #ifdef BLEBRR_FILTER_DUPLICATE_PACKETS + /* Duplicate Filtering */ + retval = blebrr_adv_duplicate_filter(p_adv_data_with_bd_addr); + + /* If found the ADV packet as duplicate, drop the ADV packet */ + if (API_SUCCESS == retval) + { + return API_FAILURE; + } + + #endif /* BLEBRR_FILTER_DUPLICATE_PACKETS */ + + /* Handle only if Non-Connectable (Passive) Advertising */ + if (BRR_BCON_PASSIVE != type) + { + return; + } + + /* Pack the RSSI as metadata */ + info.payload = &rssi; + info.length = sizeof(UCHAR); + + /* Deliver the packet to the bearer */ + if (NULL != blebrr_adv.bearer_recv) + { + /* BLEBRR_LOG("[ADV-Rx <]: "); + BLEBRR_dump_bytes(pdata, pdatalen); */ + blebrr_adv.bearer_recv(&blebrr_advhandle, pdata, pdatalen, &info); + } + else + { + BLEBRR_LOG("BEARER RECV Callback Currently NULL !!\n"); + } +} + +/** + \brief + + \par Description + + * * + * * \param void + + \return void +*/ +void blebrr_register(void) +{ + /* Initialize locals */ + BLEBRR_MUTEX_INIT_VOID(); + /* Initialize Timer Handler */ + blebrr_timer_handle = EM_TIMER_HANDLE_INIT_VAL; + /* Initialize the transport */ + blebrr_init_pl(); + /* Get the platform Advdata initial offset if any */ + pl_advdata_offset = blebrr_get_advdata_offset_pl (); + /* Reset the bearer sleep */ + blebrr_sleep = MS_FALSE; + /* Add the Adv Bearer */ + blebrr_adv.bearer_send = blebrr_adv_send; + #ifdef BLEBRR_LP_SUPPORT + blebrr_adv.bearer_sleep = blebrr_adv_sleep; + blebrr_adv.bearer_wakeup = blebrr_adv_wakeup; + blebrr_lp_thandle = EM_TIMER_HANDLE_INIT_VAL; + #endif /* BLEBRR_LP_SUPPORT */ + MS_brr_add_bearer(BRR_TYPE_ADV, &blebrr_adv, &blebrr_advhandle); + /* Enable all Mesh related Module Debugging */ + EM_enable_module_debug_flag + ( + MS_MODULE_ID_APP | + MS_MODULE_ID_ACCESS | + MS_MODULE_ID_TRN | + MS_MODULE_ID_LTRN | + MS_MODULE_ID_NET | + MS_MODULE_ID_COMMON | + MS_MODULE_ID_BRR | + MS_MODULE_ID_STBX | + MS_MODULE_ID_PROV + ); + /* Set Debug Level Trace as default. Enable Information only if required */ + EM_set_debug_level(EM_DEBUG_LEVEL_TRC); + /* Allow the tasks to start and be ready */ + EM_sleep (1); + #if 0 + /* Start Observing */ + BLEBRR_LOG ("Start Observing...\n"); + blebrr_scan_pl (MS_TRUE); + /* Update state */ +// BLEBRR_SET_STATE(BLEBRR_STATE_IN_SCAN_ENABLE); + #else /* 0 */ + BLEBRR_SET_STATE(BLEBRR_STATE_IDLE); + #endif /* 0 */ +} + diff --git a/src/components/ethermind/mesh/export/bearer/blebrr.h b/src/components/ethermind/mesh/export/bearer/blebrr.h new file mode 100644 index 0000000..cfa0ffc --- /dev/null +++ b/src/components/ethermind/mesh/export/bearer/blebrr.h @@ -0,0 +1,148 @@ + +/** + \file blebrr.h + + +*/ + +/* + Copyright (C) 2013. Mindtree Limited. + All rights reserved. +*/ + +#ifndef _H_BLEBRR_ +#define _H_BLEBRR_ + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_common.h" +#include "MS_brr_api.h" +extern UCHAR blebrr_state; + +#define BLEBRR_LOG printf +#define BLEBRR_dump_bytes appl_dump_bytes + +/* --------------------------------------------- Global Definitions */ +/** GATT Modes */ +#define BLEBRR_GATT_PROV_MODE 0x00 +#define BLEBRR_GATT_PROXY_MODE 0x01 + +/** Bearer Client Server Roles */ +#define BLEBRR_CLIENT_ROLE BRR_CLIENT_ROLE +#define BLEBRR_SERVER_ROLE BRR_SERVER_ROLE + +/** Bearer GATT communication Channel setup events */ +#define BLEBRR_COM_CHANNEL_CONNECT 0x00 +#define BLEBRR_COM_CHANNEL_DISCONNECT 0x01 + +/** Bearer GATT MTU related defines */ +#define BLEBRR_GATT_MIN_MTU (23 - 3) + +/* Bearer GATT Service related defines */ +#define BLEBRR_MESH_PRVSNG_SERVICE 0x1827 +#define BLEBRR_MESH_PROXY_SERVICE 0x1828 + +#define BLEBRR_MESH_PRVSNG_DATA_IN_CHAR 0x2ADB +#define BLEBRR_MESH_PRVSNG_DATA_OUT_CHAR 0x2ADC +#define BLEBRR_MESH_PROXY_DATA_IN_CHAR 0x2ADD +#define BLEBRR_MESH_PROXY_DATA_OUT_CHAR 0x2ADE + +/** GATT Interface Events */ +#define BLEBRR_GATT_IFACE_UP 0x00 +#define BLEBRR_GATT_IFACE_DOWN 0x01 +#define BLEBRR_GATT_IFACE_ENABLE 0x02 +#define BLEBRR_GATT_IFACE_DISABLE 0x03 + +/** Bearer state defines */ +#define BLEBRR_STATE_IDLE 0x00 +#define BLEBRR_STATE_IN_SCAN_ENABLE 0x01 +#define BLEBRR_STATE_IN_SCAN_DISABLE 0x02 +#define BLEBRR_STATE_SCAN_ENABLED 0x04 +#define BLEBRR_STATE_IN_ADV_ENABLE 0x10 +#define BLEBRR_STATE_IN_ADV_DISABLE 0x20 +#define BLEBRR_STATE_ADV_ENABLED 0x40 + +/*define Queue Size*/ +#define BLEBRR_QUEUE_SIZE 64 + +#define BLEBRR_SET_STATE(x) blebrr_state = (x) +#define BLEBRR_GET_STATE() blebrr_state + +//#define BLEBRR_LP_SUPPORT + +#ifdef BLEBRR_LP_SUPPORT + #define BLEBRR_LP_OFF 1 + #define BLEBRR_LP_SLEEP 2 + #define BLEBRR_LP_WKP 3 + #define BLEBRR_LP_PROXY 4 +#endif + + + + +/* --------------------------------------------- Structures/Data Types */ +/* Call Back to Inform Application Layer about GATT Bearer Iface Events */ +typedef void (* BLEBRR_GATT_IFACE_EVENT_PL_CB) +( + UCHAR ev_name, + UCHAR ev_param +); +/* --------------------------------------------- Macros */ + +/* --------------------------------------------- Internal Functions */ +void blebrr_adv_idle (void); +void blebrr_scan_enable (void); + +/* --------------------------------------------- API Declarations */ +void blebrr_init_pl (void); +void blebrr_register(void); + +void blebrr_scan_pl (UCHAR enable); +void blebrr_advertise_data_pl (CHAR type, UCHAR* pdata, UINT16 pdatalen); +//void blebrr_advertise_pl(UCHAR state); // HZF +API_RESULT blebrr_advertise_pl(UCHAR state); // HZF + +UCHAR blebrr_get_advdata_offset_pl (void); +void blebrr_set_gattmode_pl (UCHAR flag); + +void blebrr_pl_scan_setup (UCHAR enable); +void blebrr_pl_advertise_setup (UCHAR enable); +void blebrr_pl_recv_advpacket(UCHAR type, UCHAR* pdata, UINT16 pdatalen, UCHAR rssi); + +API_RESULT blebrr_gatt_send_pl(BRR_HANDLE* handle, UCHAR* data, UINT16 datalen); +API_RESULT blebrr_pl_gatt_connection (BRR_HANDLE* handle, UCHAR role, UCHAR mode, UINT16 mtu); +API_RESULT blebrr_pl_gatt_disconnection (BRR_HANDLE* handle); +API_RESULT blebrr_pl_recv_gattpacket (BRR_HANDLE* handle, UCHAR* pdata, UINT16 pdatalen); +UCHAR blebrr_gatt_mode_get(void); +API_RESULT blebrr_create_gatt_conn_pl +( + UCHAR p_bdaddr_type, + UCHAR* p_bdaddr +); +API_RESULT blebrr_disconnect_pl(void); +API_RESULT blebrr_discover_service_pl(UCHAR serv); +API_RESULT blebrr_confige_ntf_pl(UCHAR config_ntf, UCHAR mode); +API_RESULT blebrr_set_adv_scanrsp_data_pl +( + UCHAR* srp_data, + UCHAR srp_datalen +); +void blebrr_gatt_mode_set(UCHAR flag); +UCHAR blebrr_gatt_mode_get(void); +void blebrr_pl_advertise_end (void); +void blebrr_timer_stop (void); + + +API_RESULT blebrr_register_gatt_iface_event_pl +( + BLEBRR_GATT_IFACE_EVENT_PL_CB gatt_iface_evt_cb +); +API_RESULT blebrr_sleep_handler(void); +API_RESULT blebrr_wakeup_handler(void); +API_RESULT blebrr_lp_start(UCHAR mode); +void blebrr_lp_stop(void); + + +UCHAR blebrr_get_queue_depth(void); + +#endif /* _H_BLEBRR_ */ + diff --git a/src/components/ethermind/mesh/export/bearer/blebrr_gatt.c b/src/components/ethermind/mesh/export/bearer/blebrr_gatt.c new file mode 100644 index 0000000..f0cbfbc --- /dev/null +++ b/src/components/ethermind/mesh/export/bearer/blebrr_gatt.c @@ -0,0 +1,241 @@ + +/** + \file blebrr_gatt.c + + This File contains the BLE Bearer interface for the GATT bearer over + Mindtree Mesh stack. +*/ + +/* + Copyright (C) 2016. Mindtree Ltd. + All rights reserved. +*/ + +/* ------------------------------- Header File Inclusion */ +#include "MS_brr_api.h" +#include "MS_prov_api.h" +#include "blebrr.h" + +/* --------------------------------------------- External Global Variables */ + +/* --------------------------------------------- Global Definitions */ + +/* GATT Proxy Segmentation and Reassembly related states */ +#define BLEBRR_GATT_SAR_COMPLETE_PKT 0x00 +#define BLEBRR_GATT_SAR_START_PKT 0x01 +#define BLEBRR_GATT_SAR_CONTINUE_PKT 0x02 +#define BLEBRR_GATT_SAR_END_PKT 0x03 + +/* GATT Proxy Segmentation and Reassembly related state values */ +#define BLEBRR_GATT_SAR_INIT_STATE 0x00 +#define BLEBRR_GATT_SAR_TX_PROGRESS 0x01 + +/* GATT PDU Size in octets */ +#define BLEBRR_GATT_PDU_SIZE 75 + +/* --------------------------------------------- Macros */ + +/* --------------------------------------------- Structures/Data Types */ + +/* --------------------------------------------- Global Variables */ +/** GATT bearer Information */ +DECL_STATIC BRR_BEARER_INFO blebrr_gatt; + +/* TODO: Check if the MTU be global or part of specific context */ +/** GATT bearer specific identifiers */ +DECL_STATIC BRR_BEARER_CH_INFO blebrr_gatt_ch_info; + +/** GATT Current mode identifier - PROV or PROXY */ +DECL_STATIC UCHAR blebrr_gatt_mode = 0xFF; + +/* ------------------------------- Functions */ +/** + \brief + + \par Description + + + \param flag + + \return void +*/ +void blebrr_gatt_mode_set(UCHAR flag) +{ + /** + The valid values for 'flag' are: + 0x00: BLEBRR_GATT_PROV_MODE GATT Provisioning Mode + 0x01: BLEBRR_GATT_PROXY_MODE GATT Proxy Mode + All other values are RFU. + */ + blebrr_gatt_mode = ((flag == BLEBRR_GATT_PROV_MODE) || (flag == BLEBRR_GATT_PROXY_MODE))? + flag: 0xFF; + /* Notify GATT mode setting to blebrr pl */ + blebrr_set_gattmode_pl (blebrr_gatt_mode); +} + +/** + \brief + + \par Description + + * * + * * \param void + + \return void +*/ +UCHAR blebrr_gatt_mode_get(void) +{ + /** + The valid return values are: + 0x00: BLEBRR_GATT_PROV_MODE GATT Provisioning Mode + 0x01: BLEBRR_GATT_PROXY_MODE GATT Proxy Mode + All other values are RFU. + */ + return blebrr_gatt_mode; +} + +/** + \brief + + \par Description + + + \param handle + \param type + \param pdata + \param datalen + + \return void +*/ +DECL_STATIC API_RESULT blebrr_gatt_send +( + BRR_HANDLE* handle, + UCHAR type, + void* pdata, + UINT16 datalen +) +{ + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(type); + retval = blebrr_gatt_send_pl + ( + handle, + pdata, + datalen + ); + return retval; +} + +/** + \brief + + \par Description + + + \param handle + \param type + \param pdata + \param pdatalen + + \return void +*/ +API_RESULT blebrr_pl_recv_gattpacket +( + BRR_HANDLE* handle, + UCHAR* pdata, + UINT16 pdatalen +) +{ + if (NULL != blebrr_gatt.bearer_recv) + { + blebrr_gatt.bearer_recv + ( + handle, + pdata, + pdatalen, + NULL + ); + } + + return API_SUCCESS; +} + +/** + \brief + + \par Description + + + \param type + \param uuid + \param handle + + \return void +*/ +API_RESULT blebrr_pl_gatt_connection +( + BRR_HANDLE* handle, + UCHAR role, + UCHAR mode, + UINT16 mtu +) +{ + MS_BUFFER buffer; + API_RESULT retval; + /* Initialize */ + retval = API_FAILURE; + /* Populate the Bearer GATT Channel info */ + blebrr_gatt_ch_info.role = role; + blebrr_gatt_ch_info.mtu = mtu; + /* Add bearer to the mesh network */ + blebrr_gatt.bearer_send = blebrr_gatt_send; + blebrr_gatt.binfo = &buffer; + buffer.payload = (UCHAR*)&blebrr_gatt_ch_info; + buffer.length = sizeof(blebrr_gatt_ch_info); + retval = MS_brr_add_bearer(BRR_TYPE_GATT, &blebrr_gatt, handle); + + /* Check the PDU type received and Add bearer to Mesh stack */ + if (BLEBRR_SERVER_ROLE == role) + { + blebrr_pl_advertise_end(); + + if (BLEBRR_GATT_PROXY_MODE == mode) + { + /* Start observing */ + blebrr_scan_enable(); + } + } + else if (BLEBRR_CLIENT_ROLE == role) + { + /* Do Nothing */ + /** + Currently, not enabling scan for Proxy Client. + Typically, Proxy Client supports only GATT Bearer. + Hence, not initiating 'SCAN' on Bearer UP event. + */ + } + + return retval; +} + +/** + \brief + + \par Description + + + \param type + \param handle + + \return void +*/ +API_RESULT blebrr_pl_gatt_disconnection +( + BRR_HANDLE* handle +) +{ + API_RESULT retval; + retval = MS_brr_remove_bearer(BRR_TYPE_GATT, handle); + return retval; +} + diff --git a/src/components/ethermind/mesh/export/cbtimer/EXT_cbtimer.c b/src/components/ethermind/mesh/export/cbtimer/EXT_cbtimer.c new file mode 100644 index 0000000..a98ef0e --- /dev/null +++ b/src/components/ethermind/mesh/export/cbtimer/EXT_cbtimer.c @@ -0,0 +1,1106 @@ + +/** + \file EM_timer.c + + This File contains source codes for the EtherMind + Timer Library Implementation for FreeRTOS. +*/ + + + +/* ----------------------------------------------- Header File Inclusion */ +#include "EXT_cbtimer.h" +//#include "EM_timer_internal.h" //todo +//#include "EXT_cbtimer.h" +#include "OSAL_Clock.h" +#include "gpio.h" + +#include "OSAL_Tasks.h" + +/* ----------------------------------------------- Global Definitions */ +/* Timer Elements */ +EXT_CBTIMER_ENTITY ext_cbtimer_entity[EXT_CBTIMER_MAX_ENTITIES]; +EXT_CBTIMER_ENTITY* ext_cbtimer_q_start = NULL; +EXT_CBTIMER_ENTITY* ext_cbtimer_q_end = NULL; + +#if 0 + /* Timer Library Mutex */ + EM_thread_mutex_type timer_mutex; +#endif /* 0 */ + +#if 1 +/* Timer */ +#if defined ( CBTIMER_NUM_TASKS ) + #include "cbTimer.h" +#endif + + +/* ----------------------------------------------- Static Global Variables */ +/********************************************************************* + CONSTANTS +*/ +// Number of callback timers supported per task (limited by the number of OSAL event timers) +#define EXT_NUM_CBTIMERS_PER_TASK 16 + +// Total number of callback timers +#define EXT_NUM_CBTIMERS ( CBTIMER_NUM_TASKS * EXT_NUM_CBTIMERS_PER_TASK ) + +#define ext_timer_malloc EM_alloc_mem +#define ext_timer_free EM_free_mem + + +typedef struct +{ + extpfnCbTimer_t pfnCbTimer; // callback function to be called when timer expires + uint8* pData; // data to be passed in to callback function +} ext_cbTimer_t; + +ext_cbTimer_t ext_cbTimers[EXT_NUM_CBTIMERS]; +uint16 extbaseTaskID = TASK_NO_TASK; + +#define EXT_EVENT_ID( timerId ) ( 0x0001 << ( ( timerId ) % EXT_NUM_CBTIMERS_PER_TASK ) ) + +// Find out task id using timer id +#define EXT_TASK_ID( timerId ) ( ( ( timerId ) / EXT_NUM_CBTIMERS_PER_TASK ) + extbaseTaskID ) + +// Find out bank task id using task id +#define EXT_BANK_TASK_ID( taskId ) ( ( ( taskId ) - extbaseTaskID ) * EXT_NUM_CBTIMERS_PER_TASK ) + +/********************************************************************* + LOCAL FUNCTIONS +*/ + + +/********************************************************************* + API FUNCTIONS +*/ +EM_RESULT ext_timer_init_entity (EXT_CBTIMER_ENTITY* timer); + +EM_RESULT ext_timer_search_entity_timer_id +( + EXT_CBTIMER_ENTITY** timer, + UINT8 handle +); +EM_RESULT ext_timer_del_entity +( + EXT_CBTIMER_ENTITY* timer, + UCHAR free +); +EM_RESULT ext_timer_search_entity ( EXT_CBTIMER_ENTITY* timer ); + +EM_RESULT ext_timer_add_entity ( EXT_CBTIMER_ENTITY* timer ); + +#ifdef EXT_CBTIMER_SUPPORT_REMAINING_TIME + + /* + This function returns elapsed time in microsecond since system power on. + */ + UINT64 ext_cbtimer_get_ms_timestamp(void); +#endif + +/********************************************************************* + @fn CbTimerInit + + @brief Callback Timer task initialization function. This function + can be called more than once (CBTIMER_NUM_TASKS times). + + @param taskId - Message Timer task ID. + + @return void +*/ +void CbTimerInit( uint8 taskId ) +{ + if ( extbaseTaskID == TASK_NO_TASK ) + { + // Only initialize the base task id + extbaseTaskID = taskId; + // Initialize all timer structures + osal_memset( ext_cbTimers, 0, sizeof( ext_cbTimers ) ); + } +} + +/********************************************************************* + @fn CbTimerProcessEvent + + @brief Callback Timer task event processing function. + + @param taskId - task ID. + @param events - events. + + @return events not processed +*/ +uint16 CbTimerProcessEvent( uint8 taskId, uint16 events ) +{ + if ( events ) + { + uint8 i; + uint16 event; + + // Process event timers + for ( i = 0; i < EXT_NUM_CBTIMERS_PER_TASK; i++ ) + { + if ( ( events >> i ) & 0x0001 ) + { + ext_cbTimer_t* pTimer = &ext_cbTimers[EXT_BANK_TASK_ID( taskId )+i]; + // Found the first event + event = 0x0001 << i; + + // Timer expired, call the registered callback function + if(pTimer->pData != NULL) + { + pTimer->pfnCbTimer( pTimer->pData ); + } + + // Mark entry as free + pTimer->pfnCbTimer = NULL; + // Null out data pointer + pTimer->pData = NULL; + // We only process one event at a time + break; + } + } + + // return unprocessed events + return ( events ^ event ); + } + + // If reach here, the events are unknown + // Discard or make more handlers + return 0; +} + +/********************************************************************* + @fn CbTimerStart + + @brief This function is called to start a callback timer to expire + in n mSecs. When the timer expires, the registered callback + function will be called. + + @param pfnCbTimer - callback function to be called when timer expires + @param pData - data to be passed in to callback function + @param timeout - in milliseconds. + @param pTimerId - will point to new timer Id (if not null) + + @return Success, or Failure. +*/ +Status_t CbTimerStart( extpfnCbTimer_t pfnCbTimer, uint8* pData, + uint16 timeout, uint8* pTimerId ) +{ + uint8 i; + + // Validate input parameters + if ( pfnCbTimer == NULL ) + { + return ( INVALIDPARAMETER ); + } + + // Look for an unused timer first + for ( i = 0; i < EXT_NUM_CBTIMERS; i++ ) + { + if ( ext_cbTimers[i].pfnCbTimer == NULL ) + { + // Start the OSAL event timer first + if ( osal_start_timerEx( EXT_TASK_ID( i ), EXT_EVENT_ID( i ), timeout ) == SUCCESS ) + { + // Set up the callback timer + ext_cbTimers[i].pfnCbTimer = pfnCbTimer; + ext_cbTimers[i].pData = pData; + + if ( pTimerId != NULL ) + { + // Caller is intreseted in the timer id + *pTimerId = i; + } + + return ( SUCCESS ); + } + } + } + + // No timer available + return ( NO_TIMER_AVAIL ); +} + +/********************************************************************* + @fn CbTimerUpdate + + @brief This function is called to update a message timer that has + already been started. If SUCCESS, the function will update + the timer's timeout value. If INVALIDPARAMETER, the timer + either doesn't exit. + + @param timerId - identifier of the timer that is to be updated + @param timeout - new timeout in milliseconds. + + @return SUCCESS or INVALIDPARAMETER if timer not found +*/ +Status_t CbTimerUpdate( uint8 timerId, uint16 timeout ) +{ + // Look for the existing timer + if ( timerId < EXT_NUM_CBTIMERS ) + { + if ( ext_cbTimers[timerId].pfnCbTimer != NULL ) + { + // Make sure the corresponding OSAL event timer is still running + if ( osal_get_timeoutEx( EXT_TASK_ID( timerId ), EXT_EVENT_ID( timerId ) ) != 0 ) + { + // Timer exists; update it + osal_start_timerEx( EXT_TASK_ID( timerId ), EXT_EVENT_ID( timerId ), timeout ); + return ( SUCCESS ); + } + } + } + + // Timer not found + return ( INVALIDPARAMETER ); +} + + +/********************************************************************* + @fn CbTimerStop + + @brief This function is called to stop a timer that has already been + started. If SUCCESS, the function will cancel the timer. If + INVALIDPARAMETER, the timer doesn't exit. + + @param timerId - identifier of the timer that is to be stopped + + @return SUCCESS or INVALIDPARAMETER if timer not found +*/ +Status_t CbTimerStop( uint8 timerId ) +{ + // Look for the existing timer + if ( timerId < EXT_NUM_CBTIMERS ) + { + if ( ext_cbTimers[timerId].pfnCbTimer != NULL ) + { + // Timer exists; stop the OSAL event timer first + osal_stop_timerEx( EXT_TASK_ID( timerId ), EXT_EVENT_ID( timerId ) ); + // Mark entry as free + ext_cbTimers[timerId].pfnCbTimer = NULL; + // Null out data pointer + ext_cbTimers[timerId].pData = NULL; + return ( SUCCESS ); + } + } + + // Timer not found + return ( INVALIDPARAMETER ); +} + + + +#endif + +#undef EM_RESTART_TIMER + +/* ----------------------------------------------- Functions */ + +void EXT_cbtimer_init (void) +{ + UINT16 index; +// EM_TIMER_TRC( +// "Initializing EtherMind Timer Library Module ...\n"); + #if 0 + /* Initialize Timer Mutex */ + EM_thread_mutex_init(&timer_mutex, NULL); + #endif /* 0 */ + + /* Initialize Timer Elements */ + for (index = 0; index < EXT_CBTIMER_MAX_ENTITIES; index ++) + { + ext_timer_init_entity(&ext_cbtimer_entity[index]); + ext_cbtimer_entity[index].timer_id = EXT_PHYOS_INVALID_TIMER_ID; + ext_cbtimer_entity[index].handle = index; + } + + return; +} + + +void ext_cbtimer_em_init ( void ) +{ + EXT_CBTIMER_ENTITY* timer; + UINT16 index; + + /* Lock Timer */ +// timer_lock(); + +// EM_TIMER_TRC( +// "Stack ON Initialization for Timer Library ...\n"); + + /* Initialize Timer Entities */ + for (index = 0; index < EXT_CBTIMER_MAX_ENTITIES; index ++) + { + timer = &ext_cbtimer_entity[index]; + timer->timer_id = EXT_PHYOS_INVALID_TIMER_ID; + } + + /* Initialize Timer Q */ + ext_cbtimer_q_start = ext_cbtimer_q_end = NULL; +// timer_unlock(); + return; +} + +EM_RESULT EXT_cbtimer_start_timer +( + EXT_cbtimer_handle* handle, + UINT32 timeout, + void (* callback) (void*, UINT16), + void* data, + UINT16 data_length +) +{ + UCHAR* data_ptr = NULL; + EM_RESULT retval; + EXT_CBTIMER_ENTITY current_timer; + // HZF + osalTimeUpdate(); + + if (NULL == handle) + { +// EM_TIMER_ERR( +// "NULL Argument Unacceptable for Timer Handles.\n"); + return EXT_CBTIMER_HANDLE_IS_NULL; + } + +// EM_TIMER_TRC( +// "Preparing to Add New Timer Entity. Timeout = %d, Data Size = %d.\n", +// timeout, data_length); + + /* Timer Library expects to have a valid callback */ + if (NULL == callback) + { +// EM_TIMER_ERR( +// "FAILED to Add New Timer Element. NULL Callback.\n"); + return EXT_CBTIMER_CALLBACK_IS_NULL; + } + + if (0 != data_length) + { + if (data_length > EXT_CBTIMER_STATIC_DATA_SIZE) + { + data_ptr = (UCHAR*) ext_timer_malloc (data_length); + + if (NULL == data_ptr) + { +// EM_TIMER_ERR( +// "FAILED to allocate Memory for Timer Handler Argument.\n"); + return EXT_CBTIMER_MEMORY_ALLOCATION_FAILED; + } + + current_timer.allocated_data = data_ptr; + } + else + { + data_ptr = current_timer.static_data; + } + + /* Copy the Data to be passed to the Timer Handler */ + EM_mem_copy(data_ptr, data, data_length); + } + + /* Store Timer Data Length, Callback & Timeout */ + current_timer.callback = callback; + current_timer.data_length = data_length; + current_timer.timeout = timeout; + /* Lock Timer */ +// timer_lock(); + /* Insert this Timer Entity into the List */ + retval = ext_timer_add_entity(¤t_timer); + + if (EM_SUCCESS != retval) + { +// EM_TIMER_ERR( +// "FAILED to Add New Timer to Timer Queue. Error Code = 0x%04X\n", +// retval); + if (current_timer.data_length > EXT_CBTIMER_STATIC_DATA_SIZE) + { + ext_timer_free (current_timer.allocated_data); + } + +// timer_unlock(); + return retval; + } + + /* Store the Handle */ + *handle = current_timer.handle; +// printf( +// "Successfully Added EXT New Timer to Timer Queue. Handle = 0x%02X\n", +// *handle); +// timer_unlock(); + return EM_SUCCESS; +} + + + +void ext_cbtimer_em_shutdown ( void ) +{ + UINT16 index; + EXT_CBTIMER_ENTITY* timer; + /* Lock Timer */ +// timer_lock(); + /* Initialize Timer Q */ + ext_cbtimer_q_start = ext_cbtimer_q_end = NULL; + + /* Initialize Timer Entities */ + for (index = 0; index < EXT_CBTIMER_MAX_ENTITIES; index++) + { + timer = &ext_cbtimer_entity[index]; + + if (EXT_CBTIMER_ENTITY_IN_USE == timer->in_use) + { + /* Stop Timer */ + CbTimerStop(timer->timer_id); + + if (timer->data_length > EXT_CBTIMER_STATIC_DATA_SIZE) + { + ext_timer_free(timer->allocated_data); + } + + ext_timer_init_entity(timer); + timer->timer_id = EXT_PHYOS_INVALID_TIMER_ID; + } + } + +// EM_TIMER_TRC( +// "Stack OFF on Timer Library Module ...\n"); +// timer_unlock(); + return; +} + +//Status_t osal_CbTimerStart32( pfnCbTimer_t pfnCbTimer, uint8 *pData, +// uint32 timeout, uint8 *pTimerId ) +//{ +// uint8 i; +// +// // Validate input parameters +// if ( pfnCbTimer == NULL ) +// { +// return ( INVALIDPARAMETER ); +// } + +// // Look for an unused timer first +// for ( i = 0; i < NUM_CBTIMERS32; i++ ) +// { +// if ( cbTimers[i].pfnCbTimer == NULL ) +// { +// // Start the OSAL event timer first +// if ( osal_start_timerEx( TASK_ID32( i ), EVENT_ID32( i ), timeout ) == SUCCESS ) +// { +// // Set up the callback timer +// cbTimers[i].pfnCbTimer = pfnCbTimer; +// cbTimers[i].pData = pData; + +// if ( pTimerId != NULL ) +// { +// // Caller is intreseted in the timer id +// *pTimerId = i; +// } + +// return ( SUCCESS ); +// } +// } +// } + +// // No timer available +// return ( NO_TIMER_AVAIL ); +//} + + +/* Callback registered with timer module */ +void ext_cbtimer_timeout_handler (UINT8* handle) +{ + EM_RESULT retval; + EXT_CBTIMER_ENTITY* timer; +// EM_TIMER_TRC ( +// "In Timer handler (Timer Handle: 0x%02X)\n", *handle); + /* Lock Timer */ +// timer_lock(); + /* Get the appropriate timer entity */ + retval = ext_timer_search_entity_timer_id (&timer, *handle); + + if (EM_SUCCESS != retval) + { +// EM_TIMER_ERR( +// "*** UNKNOWN Spurious Timeout Callback?!?!\n"); + /* Unlock Timer */ +// timer_unlock (); + return; + } + + /* Unlock Timer */ +// timer_unlock (); + + if (timer->data_length > EXT_CBTIMER_STATIC_DATA_SIZE) + { + /* Call the registered timeout handler */ + timer->callback (timer->allocated_data, timer->data_length); + } + else + { + /* Use Static Data */ + timer->callback (timer->static_data, timer->data_length); + } + + /* Lock Timer */ +// timer_lock (); + #if 0 + /* Stop Timer */ + xTimerStop (timer->timer_id, 0); + #endif /* 0 */ + /* Free the Timer */ + retval = ext_timer_del_entity (timer, 1); + + if (EM_SUCCESS != retval) + { +// EM_TIMER_ERR( +// "FAILED to find Timer Element. Handle = 0x%02X. Error Code = 0x%04X\n", +// handle, retval); + printf( + "FAILED to find Timer Element. Handle = 0x%02X. Error Code = 0x%04X\n", + *handle, retval); + } + + /* Unlock Timer */ +// timer_unlock (); + return; +} + + +EM_RESULT EXT_cbtimer_stop_timer +( + EXT_cbtimer_handle handle +) +{ + EXT_CBTIMER_ENTITY* timer; + EM_RESULT retval; + UINT8 timer_id; + UINT32 new_timeout; + Status_t status; + + if (EXT_CBTIMER_MAX_ENTITIES <= handle) + { +// EM_TIMER_ERR( +// "NULL Argument Unacceptable for Timer Handles.\r\n"); + /* TODO: Use appropriate error value */ + return EXT_CBTIMER_HANDLE_IS_NULL; + } + + osalTimeUpdate(); + retval = EM_FAILURE; + /* Lock Timer */ +// timer_lock(); + timer = &ext_cbtimer_entity[handle]; + /* Store the timer id before deleting entity */ + timer_id = timer->timer_id; + new_timeout = 0x10; + + if(ext_timer_search_entity(timer) == EM_SUCCESS) + { + if(CbTimerUpdate(timer_id,new_timeout) == EM_SUCCESS + ||(osalFindTimer(EXT_TASK_ID( timer->timer_id ),EXT_EVENT_ID( timer->timer_id )) == NULL)) + { + retval = ext_timer_del_entity(timer, 0x01); + + if (EM_SUCCESS != retval) + { + // EM_TIMER_ERR( + // "FAILED to find Timer Element. Handle = 0x%02X. Error Code = 0x%04X\n", + // handle, retval); + printf( + "FAILED to find Timer Element. Handle = 0x%02X. Error Code = 0x%04X\n", + handle, retval); + } + else + { + // EM_TIMER_TRC( + // "Successfully Deleted Timer Element for Handle 0x%02X.\n", + // handle); + /* Stop Timer */ + status = CbTimerStop(timer_id); + osal_clear_event(EXT_TASK_ID( timer->timer_id ),EXT_EVENT_ID( timer->timer_id )); + + if (SUCCESS != status) + { + retval = EM_FAILURE; + } + + // EM_TIMER_TRC("*** Stopped Timer [ID: %04X]\n", + // timer_id); + } + } + } + + /* Unlock Timer */ +// timer_unlock(); + return retval; +} + + +UINT32 EXT_cbtimer_get_remain_timer +( + EXT_cbtimer_handle handle +) +{ + EXT_CBTIMER_ENTITY* timer; + UINT32 remain_timeout; + + if (EXT_CBTIMER_MAX_ENTITIES <= handle) + { +// EM_TIMER_ERR( +// "NULL Argument Unacceptable for Timer Handles.\r\n"); + /* TODO: Use appropriate error value */ + return EXT_CBTIMER_HANDLE_IS_NULL; + } + + /* Lock Timer */ +// timer_lock(); + timer = &ext_cbtimer_entity[handle]; + remain_timeout = osal_get_timeoutEx(EXT_TASK_ID( timer->timer_id ),EXT_EVENT_ID( timer->timer_id )); + /* Unlock Timer */ +// timer_unlock(); + return remain_timeout; +} + + + +EM_RESULT EXT_cbtimer_restart_timer +( + EXT_cbtimer_handle handle, + UINT32 new_timeout +) +{ + EXT_CBTIMER_ENTITY* timer; + EM_RESULT retval; + + if (EXT_CBTIMER_MAX_ENTITIES <= handle) + { +// EM_TIMER_ERR( +// "NULL Argument Unacceptable for Timer Handles.\n"); + /* TODO: Use appropriate error value */ + return EXT_CBTIMER_HANDLE_IS_NULL; + } + +// timer_lock(); + timer = &ext_cbtimer_entity[handle]; + retval = ext_timer_search_entity(timer); + + if (EM_SUCCESS != retval) + { +// EM_TIMER_ERR( +// "FAILED to Find Timer ELement for Handle 0x%02X. Error Code = 0x%04X\n", +// handle, retval); + } + else + { + if(CbTimerUpdate(timer->timer_id,new_timeout) == EM_SUCCESS) + { + return ( SUCCESS ); + } + } + + // No timer available + return ( NO_TIMER_AVAIL ); +} + +EM_RESULT EXT_cbtimer_is_active_timer +( + EXT_cbtimer_handle handle +) +{ + EXT_CBTIMER_ENTITY* timer; + EM_RESULT retval; + + if (EXT_CBTIMER_MAX_ENTITIES <= handle) + { +// EM_TIMER_ERR( +// "NULL Argument Unacceptable for Timer Handles.\n"); + /* TODO: Use appropriate error value */ + return EXT_CBTIMER_HANDLE_IS_NULL; + } + + /* Lock Timer */ +// timer_lock(); + timer = &ext_cbtimer_entity[handle]; + retval = ext_timer_search_entity(timer); + + if (EM_SUCCESS != retval) + { +// EM_TIMER_ERR( +// "FAILED to Find the Timer Entity for Handle 0x%02X. Error Code = 0x%04X\n", +// handle, retval); + } + +// timer_unlock(); + return retval; +} + + +EM_RESULT ext_timer_search_entity ( EXT_CBTIMER_ENTITY* timer ) +{ + EXT_CBTIMER_ENTITY* current_timer; + + /* Is Queue Empty */ + if (NULL == ext_cbtimer_q_start) + { + return EXT_CBTIMER_QUEUE_EMPTY; + } + + /* Handle the first Element */ + if (timer == ext_cbtimer_q_start) + { + return EM_SUCCESS; + } + + current_timer = ext_cbtimer_q_start->next; + + while (NULL != current_timer) + { + if (timer == current_timer) + { + return EM_SUCCESS; + } + + current_timer = current_timer->next; + } + + return EXT_CBTIMER_ENTITY_SEARCH_FAILED; +} + +/* Get the timer based on obtained timer id */ +EM_RESULT ext_timer_search_entity_timer_id +( + EXT_CBTIMER_ENTITY** timer, + UINT8 handle +) +{ + EXT_CBTIMER_ENTITY* current_timer; + + /* Is Queue Empty */ + if (NULL == ext_cbtimer_q_start) + { + return EXT_CBTIMER_QUEUE_EMPTY; + } + + /* Handle the first Element */ + if (handle == ext_cbtimer_q_start->handle) + { + /* Note the timer entity */ + *timer = ext_cbtimer_q_start; + return EM_SUCCESS; + } + + current_timer = ext_cbtimer_q_start->next; + + while (NULL != current_timer) + { + if (handle == current_timer->handle) + { + /* Note the timer entity */ + *timer = current_timer; + return EM_SUCCESS; + } + + current_timer = current_timer->next; + } + + return EXT_CBTIMER_ENTITY_SEARCH_FAILED; +} + +EM_RESULT ext_timer_add_entity ( EXT_CBTIMER_ENTITY* timer ) +{ + UINT16 index; + Status_t ret; + EXT_CBTIMER_ENTITY* new_timer; + new_timer = NULL; + + for (index = 0; index < EXT_CBTIMER_MAX_ENTITIES; index++) + { + new_timer = &ext_cbtimer_entity[index]; + + if (EXT_CBTIMER_ENTITY_FREE == new_timer->in_use) + { + new_timer->in_use = EXT_CBTIMER_ENTITY_IN_USE; + break; + } + else + { + new_timer = NULL; + } + } + + if (NULL == new_timer) + { + printf( + "FAILED to Allocate EXT New Timer Entity. Timer List FULL !\n"); + #ifdef EM_STATUS + /* Timer List Full: Update EtherMind Status Flag */ + EM_status_set_bit (STATUS_BIT_TIMER_ENTITY_FULL, STATUS_BIT_SET); + #endif /* EM_STATUS */ + return EXT_CBTIMER_QUEUE_FULL; + } + + new_timer->next = NULL; + new_timer->timeout = timer->timeout; + new_timer->callback = timer->callback; + new_timer->data_length = timer->data_length; + + if (new_timer->data_length > EXT_CBTIMER_STATIC_DATA_SIZE) + { + new_timer->allocated_data = timer->allocated_data; + } + else + { + EM_mem_copy + ( + new_timer->static_data, + timer->static_data, + new_timer->data_length + ); + } + + /* Start the timer */ + #ifdef EXT_CBTIMER_SUPPORT_REMAINING_TIME + new_timer->start_timestamp = ext_cbtimer_get_ms_timestamp(); + #endif /* EM_TIMER_SUPPORT_REMAINING_TIME */ + /* Start timer. Set Timeout. This will also start the timer. */ + ret = CbTimerStart + ( + ext_cbtimer_timeout_handler, + &new_timer->handle, + ((EXT_CBTIMEOUT_MILLISEC & new_timer->timeout) ? + (new_timer->timeout & (UINT32)~(EXT_CBTIMEOUT_MILLISEC)): + (new_timer->timeout * 1000)), + &new_timer->timer_id + ); + + if (SUCCESS != ret) + { +// EM_TIMER_ERR("*** FAILED to Start timer\n"); +// printf("*** FAILED to Start timer, ret = %d\r\n", ret); + return EXT_CBTIMER_FAILED_SET_TIME_EVENT; + } + +// EM_TIMER_TRC("Successfully started Timer [ID: %02X]. Handle: 0x%02X\n", +// new_timer->timer_id, timer->handle); + timer->handle = new_timer->handle; + timer->timer_id = new_timer->timer_id; + + /* If the Timer Q Empty */ + if (NULL == ext_cbtimer_q_start) + { + ext_cbtimer_q_start = ext_cbtimer_q_end = new_timer; + return EM_SUCCESS; + } + + ext_cbtimer_q_end->next = new_timer; + ext_cbtimer_q_end = new_timer; + return EM_SUCCESS; +} + + +EM_RESULT ext_timer_del_entity +( + EXT_CBTIMER_ENTITY* timer, + UCHAR free +) +{ + EXT_CBTIMER_ENTITY* current_timer, *previous_timer; + + /* Either None or One Element */ + if (ext_cbtimer_q_start == ext_cbtimer_q_end) + { + if (NULL == ext_cbtimer_q_start) + { + /* Queue is Empty */ + return EXT_CBTIMER_QUEUE_EMPTY; + } + else + { + if (timer == ext_cbtimer_q_start) + { + /* Queue has One Element */ + ext_cbtimer_q_start = ext_cbtimer_q_end = NULL; + } + else + { + /* Match NOT found in the Only element in Timer Queue */ + return EXT_CBTIMER_ENTITY_SEARCH_FAILED; + } + } + } + else + { + /* Queue has more than One Element */ + if (timer == ext_cbtimer_q_start) + { + /* Match in the First Element */ + ext_cbtimer_q_start = ext_cbtimer_q_start->next; + } + else + { + previous_timer = ext_cbtimer_q_start; + current_timer = ext_cbtimer_q_start->next; + + while (NULL != current_timer) + { + if (timer == current_timer) + { + previous_timer->next = current_timer->next; + + if (current_timer == ext_cbtimer_q_end) + { + ext_cbtimer_q_end = previous_timer; + } + + break; + } + + previous_timer = current_timer; + current_timer = current_timer->next; + } + + if (NULL == current_timer) + { + return EXT_CBTIMER_ENTITY_SEARCH_FAILED; + } + } + } + + /* Free Allocated Data */ + if ((0x01 == free) && + (timer->data_length > EXT_CBTIMER_STATIC_DATA_SIZE)) + { + ext_timer_free (timer->allocated_data); + } + + ext_timer_init_entity(timer); + return EM_SUCCESS; +} + + +EM_RESULT ext_timer_init_entity (EXT_CBTIMER_ENTITY* timer) +{ + timer->in_use = EXT_CBTIMER_ENTITY_FREE; + timer->timeout = 0; + timer->callback = NULL; + timer->allocated_data = NULL; + timer->data_length = 0; + timer->next = NULL; + #ifdef EM_TIMER_SUPPORT_REMAINING_TIME + timer->start_timestamp = 0; + #endif /* EM_TIMER_SUPPORT_REMAINING_TIME */ + return EM_SUCCESS; +} + + +#ifdef EXT_CBTIMER_SUPPORT_REMAINING_TIME + +/* + This function returns elapsed time in microsecond since system power on. +*/ +UINT64 ext_cbtimer_get_ms_timestamp(void) +{ + return osal_GetSystemClock(); +} + +EM_RESULT EXT_cbtimer_get_remaining_time +( + EXT_cbtimer_handle handle, + UINT32* remaining_time_ms +) +{ + EXT_CBTIMER_ENTITY* timer; + EM_RESULT retval; + UINT64 current_timestamp; + UINT32 time_ms; + + if (NULL == handle) + { +// EM_TIMER_ERR( +// "NULL Argument Unacceptable for Timer Handles.\n"); + return EXT_CBTIMER_HANDLE_IS_NULL; + } + + /* Lock Timer */ +// timer_lock(); + timer = (EXT_CBTIMER_ENTITY*)handle; + retval = ext_timer_search_entity(timer); + + if (EM_SUCCESS != retval) + { +// EM_TIMER_ERR( +// "FAILED to Find Timer ELement for Handle %p. Error Code = 0x%04X\n", +// (void *)handle, retval); + } + else + { + time_ms = ((EXT_CBTIMEOUT_MILLISEC & timer->timeout) ? + (timer->timeout & (UINT32)~(EXT_CBTIMEOUT_MILLISEC)) : + (timer->timeout * 1000)); + /* Get Current Time */ + /* Remaining Time = (Timeout in ms) - (Current Time - Timer Start Time) */ + current_timestamp = ext_cbtimer_get_ms_timestamp(); + + if ((current_timestamp < timer->start_timestamp) || + (time_ms < (current_timestamp - timer->start_timestamp)) + ) + { +// EM_TIMER_ERR( +// "FAILED to Find Remaining Time.TO:%d < (CurT:%lld - StartT:%lld\n", +// time_ms, current_timestamp, timer->start_timestamp); + } + else + { + time_ms -= (UINT32)(current_timestamp - timer->start_timestamp); + *remaining_time_ms = time_ms; +// EM_TIMER_TRC( +// "[EM_TIMER] Remaining Time (ms): %d\n", time_ms); + retval = EM_SUCCESS; + } + } + +// timer_unlock(); + return retval; +} +#endif /* EM_TIMER_SUPPORT_REMAINING_TIME */ + +EM_RESULT EXT_cbtimer_list_timer ( void ) +{ + #ifdef EM_TIMERL_DEBUG + UINT16 index, free; + EXT_CBTIMER_ENTITY* timer; + timer_lock(); + EM_TIMERL_TRC("\n"); + EM_TIMERL_TRC("========================================= \n"); + EM_TIMERL_TRC("Start Q = %p\n", ext_cbtimer_q_start); + timer = ext_cbtimer_q_start; + + while(NULL != timer) + { + EM_TIMERL_TRC(" Handle = 0x%02X", + timer->handle); + timer = timer->next; + } + + EM_TIMERL_TRC("End Q = %p\n", ext_cbtimer_q_end); + free = 0; + + for (index = 0; index < EXT_CBTIMER_MAX_ENTITIES; index ++) + { + if (EXT_CBTIMER_ENTITY_FREE == ext_cbtimer_entity[index].in_use) + { + free ++; + } + } + + EM_TIMERL_TRC("Max Q Entity = %d, Free = %d\n", + EXT_CBTIMER_MAX_ENTITIES, free); + EM_TIMERL_TRC("========================================= \n"); + EM_TIMERL_TRC("\n"); + timer_unlock(); + #endif /* EM_TIMERL_DEBUG */ + return EM_SUCCESS; +} + diff --git a/src/components/ethermind/mesh/export/cbtimer/EXT_cbtimer.h b/src/components/ethermind/mesh/export/cbtimer/EXT_cbtimer.h new file mode 100644 index 0000000..0e48445 --- /dev/null +++ b/src/components/ethermind/mesh/export/cbtimer/EXT_cbtimer.h @@ -0,0 +1,166 @@ + +/** + \file EM_timer.h + + This Header File contains the APIs and the ADTs exported by the + EtherMind Timer Library for Windows (User-mode). +*/ + +/* + Copyright (C) 2013. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_EXT_CBTIMER_ +#define _H_EXT_CBTIMER_ + +/* --------------------------------------------------- Header File Inclusion */ +#include "EM_os.h" +#include "cbtimer.h" + +/* Enable support to get remaining time to expire of a timer entity */ +#define EXT_CBTIMER_SUPPORT_REMAINING_TIME + +/* --------------------------------------------------- Global Definitions */ +/* Maximum number of timer entities */ +#define EXT_CBTIMER_MAX_ENTITIES 10 + +/* Mask to indicate millisecond timeout */ +#define EXT_CBTIMEOUT_MILLISEC 0x80000000 + +/* Timer Handles must be initialized to this value */ +#define EXT_CBTIMER_HANDLE_INIT_VAL 0xFF + +#define EXT_CBTIMER_STATIC_DATA_SIZE 32 + +/* Flag: Timer Entity State */ +#define EXT_CBTIMER_ENTITY_FREE 0x00 +#define EXT_CBTIMER_ENTITY_IN_USE 0x01 +#define EXT_CBTIMER_ENTITY_IN_FREE 0x02 + +/* Flag: Timer Entity Data to be freed or not */ +#define EXT_CBTIMER_ENTITY_HOLD_ALLOC_DATA 0x00 +#define EXT_CBTIMER_ENTITY_FREE_ALLOC_DATA 0x01 + +/* Timer module ID and Error codes */ +#define EXT_CBTIMER_ERR_ID 0xC000 + +#define EXT_CBTIMER_MUTEX_INIT_FAILED (0x0001 | EXT_CBTIMER_ERR_ID) +#define EXT_CBTIMER_COND_INIT_FAILED (0x0002 | EXT_CBTIMER_ERR_ID) +#define EXT_CBTIMER_MUTEX_LOCK_FAILED (0x0003 | EXT_CBTIMER_ERR_ID) +#define EXT_CBTIMER_MUTEX_UNLOCK_FAILED (0x0004 | EXT_CBTIMER_ERR_ID) +#define EXT_CBTIMER_MEMORY_ALLOCATION_FAILED (0x0005 | EXT_CBTIMER_ERR_ID) + +#define EXT_CBTIMER_HANDLE_IS_NULL (0x0011 | EXT_CBTIMER_ERR_ID) +#define EXT_CBTIMER_CALLBACK_IS_NULL (0x0012 | EXT_CBTIMER_ERR_ID) +#define EXT_CBTIMER_QUEUE_EMPTY (0x0013 | EXT_CBTIMER_ERR_ID) +#define EXT_CBTIMER_QUEUE_FULL (0x0014 | EXT_CBTIMER_ERR_ID) +#define EXT_CBTIMER_ENTITY_SEARCH_FAILED (0x0015 | EXT_CBTIMER_ERR_ID) +#define EXT_CBTIMER_NULL_PARAMETER_NOT_ALLOWED (0x0016 | EXT_CBTIMER_ERR_ID) +#define EXT_CBTIMER_TIMEOUT_ZERO_NOT_ALLOWED (0x0017 | EXT_CBTIMER_ERR_ID) +#define EXT_CBTIMER_FAILED_SET_TIME_EVENT (0x0018 | EXT_CBTIMER_ERR_ID) + +/** + Invalid Timer ID for PhyOS. + NUM_CBTIMERS is not exposed from osal_cbtimer.c +*/ +#define EXT_PHYOS_INVALID_TIMER_ID 0xFF + +/* ----------------------------------------------- Structures/Data Types */ + +/* Timer Entity */ +typedef struct ext_cbtimer_entity_struct +{ + /* The Timer Handle - Index of the timer entity */ + UINT8 handle; + + /* Callback to call when Timer expires */ + void (* callback) (void*, UINT16); + + /** + Timer Callback Parameter if + data_length > EM_TIMER_STATIC_DATA_SIZE + */ + UCHAR* allocated_data; + + /* Next Element in the Timer Q */ + struct ext_cbtimer_entity_struct* next; + + /** + Timer Callback Parameter if + data_length <= EM_TIMER_STATIC_DATA_SIZE + */ + UCHAR static_data[EXT_CBTIMER_STATIC_DATA_SIZE]; + + /* Timeout Value asked by the User */ + UINT32 timeout; + + #ifdef EXT_CBTIMER_SUPPORT_REMAINING_TIME + /* Start Time Stamp - used to calculate remaining time */ + UINT64 start_timestamp; + #endif /* EM_TIMER_SUPPORT_REMAINING_TIME */ + + /* Length of the data */ + UINT16 data_length; + + /* Is this Entity Allocated ? */ + UCHAR in_use; + + /* PhyOS Timer ID */ + UINT8 timer_id; + +} EXT_CBTIMER_ENTITY; + +typedef UINT8 EXT_cbtimer_handle; + + + +/* --------------------------------------------------- Function Declarations */ + +#ifdef __cplusplus +extern "C" { +#endif + +void EXT_cbtimer_init ( void ); +void ext_cbtimer_em_init ( void ); +void ext_cbtimer_em_shutdown ( void ); + +EM_RESULT EXT_cbtimer_start_timer +( + EXT_cbtimer_handle* handle, + UINT32 timeout, + void (* callback) (void*, UINT16), + void* args, UINT16 size_args +); + +EM_RESULT EXT_cbtimer_restart_timer +( + EXT_cbtimer_handle handle, + UINT32 new_timeout +); + +EM_RESULT EXT_cbtimer_stop_timer ( EXT_cbtimer_handle handle ); + +UINT32 EXT_cbtimer_get_remain_timer +( + EXT_cbtimer_handle handle +); + + +EM_RESULT EXT_cbtimer_get_remaining_time +( + EXT_cbtimer_handle handle, + UINT32* remaining_time_ms +); + +EM_RESULT EXT_cbtimer_is_active_timer ( EXT_cbtimer_handle handle ); + +/* Debug Routine - Internal Use Only */ +EM_RESULT EXT_cbtimer_list_timer ( void ); + +#ifdef __cplusplus +}; +#endif + +#endif /* _H_EM_TIMER_ */ + diff --git a/src/components/ethermind/mesh/export/cbtimer/cbtimer.h b/src/components/ethermind/mesh/export/cbtimer/cbtimer.h new file mode 100644 index 0000000..fccbb9a --- /dev/null +++ b/src/components/ethermind/mesh/export/cbtimer/cbtimer.h @@ -0,0 +1,134 @@ +/************************************************************************************************** + + Wuxi CMOSTEK Microelectronics Co., Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Wuxi CMOSTEK Microelectronics Co., + Limited ("CMOSTEK"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of CMOSTEK. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a CMOSTEK Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + CMOSTEK OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************** + Filename: osal_cbtimer.h + Revised: + Revision: + + Description: This file contains the Callback Timer definitions. + + + **************************************************************************************************/ + +#ifndef CBTIMER_H +#define CBTIMER_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + CONSTANTS +*/ +// Invalid timer id +#define INVALID_TIMER_ID 0xFF + +// Timed out timer +#define TIMEOUT_TIMER_ID 0xFE + +/********************************************************************* + VARIABLES +*/ + +/********************************************************************* + MACROS +*/ +#define CBTIMER_NUM_TASKS 1 // set by HZF, align to project setting +#if ( CBTIMER_NUM_TASKS == 0 ) +#error Callback Timer module shouldn't be included (no callback timer is needed)! +#elif ( CBTIMER_NUM_TASKS == 1 ) +#define CBTIMER_PROCESS_EVENT( a ) ( a ) +#elif ( CBTIMER_NUM_TASKS == 2 ) +#define CBTIMER_PROCESS_EVENT( a ) ( a ), ( a ) +#else +#error Maximum of 2 callback timer tasks are supported! Modify it here. +#endif + +/********************************************************************* + TYPEDEFS +*/ + +// Callback Timer function prototype. Callback function will be called +// when the associated timer expires. +// +// pData - pointer to data registered with timer +// +typedef void (*extpfnCbTimer_t)( uint8* pData ); + +/********************************************************************* + VARIABLES +*/ + +/********************************************************************* + FUNCTIONS +*/ + +/* + Callback Timer task initialization function. +*/ +void CbTimerInit( uint8 taskId ); + +/* + Callback Timer task event processing function. +*/ +uint16 CbTimerProcessEvent( uint8 taskId, uint16 events ); + +/* + Function to start a timer to expire in n mSecs. +*/ +Status_t CbTimerStart( extpfnCbTimer_t pfnCbTimer, uint8* pData, + uint16 timeout, uint8* pTimerId ); + +/* + Function to update a timer that has already been started. +*/ +Status_t CbTimerUpdate( uint8 timerId, uint16 timeout ); + +/* + Function to stop a timer that has already been started. +*/ +Status_t CbTimerStop( uint8 timerId ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* CBTIMER_H */ diff --git a/src/components/ethermind/mesh/export/cli/cli_brr.c b/src/components/ethermind/mesh/export/cli/cli_brr.c new file mode 100644 index 0000000..17e48a0 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/cli_brr.c @@ -0,0 +1,157 @@ +/** + \file cli_brr.c + + This File contains the "main" function for the CLI application, + to exercise various functionalities of the Mindtree Mesh stack. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* ------------------------------- Header File Inclusion */ +#include "cli_main.h" +#include "blebrr.h" + +/* --------------------------------------------- External Global Variables */ + +/* ------------------------------- Global Variables */ + +DECL_CONST CLI_COMMAND cli_core_client_menu_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Create GATT Connection to Peer */ + { "connect", "Create GATT Connection", cli_create_gatt_conn}, + + /* Initiate GATT Disconnection with Peer */ + { "disconnect", "Terminate GATT Connection", cli_terminate_gatt_conn }, + + /* Start or Stop Scan in Bearer */ + { "scan", "Enable/Disable Scanning", cli_scan_feature}, + + /* Set Scan Response Data */ + { "srsp_set", "Set Scan Response Data", cli_scan_rsp_data_set}, + + /* Discover GATT Bearer Services */ + {"discover", "Discover GATT Service", cli_discover_service}, + + /* Enable/Disable GATT Bearer Services for Notfications */ + {"config_ntf", "Enable/Disable Notification", cli_config_ntf}, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root } +}; + +/* ------------------------------- Functions */ +API_RESULT cli_brr(UINT32 argc, UCHAR* argv[]) +{ + cli_cmd_stack_push((CLI_COMMAND*)cli_core_client_menu_cmd_list, sizeof(cli_core_client_menu_cmd_list) / sizeof(CLI_COMMAND)); + cli_help(argc, argv); + return API_SUCCESS; +} + +API_RESULT cli_create_gatt_conn(UINT32 argc, UCHAR* argv[]) +{ + UCHAR peer_bd_addr_type; + UCHAR peer_bd_addr[6]; + API_RESULT retval; + + if (2 != argc) + { + CONSOLE_OUT("Usage: connect \n"); + return API_FAILURE; + } + + peer_bd_addr_type = (UCHAR)CLI_strtoi(argv[0], (UINT8)CLI_strlen(argv[0]), 16); + CLI_strtoarray + ( + argv[1], + CLI_strlen(argv[1]), + &peer_bd_addr[0], + 6 + ); + retval = blebrr_create_gatt_conn_pl(peer_bd_addr_type, peer_bd_addr); + CONSOLE_OUT("retval = 0x%04X\n", retval); + return retval; +} + +API_RESULT cli_scan_feature(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("\n Scan Start Stop Feature to be extended for CLI\n"); + return API_FAILURE; +} + +API_RESULT cli_scan_rsp_data_set(UINT32 argc, UCHAR* argv[]) +{ + /** + Currently setting MT-MESH-DEMO as Complete Device Name! + This can be updated to each individual devices as per requirement. + */ + UCHAR cli_brr_scanrsp_data[] = + { + /** + Shortened Device Name: MT-MESH-DEMO + */ + 0x0D, 0x09, 'M', 'T', '-', 'M', 'E', 'S', 'H', '-', 'D', 'E', 'M', 'O' + }; + CONSOLE_OUT("\n Setting MT-MESH-DEMO as Complete Device Name!\n"); + /* Set the Scan Response Data at the Bearer Layer */ + blebrr_set_adv_scanrsp_data_pl + ( + cli_brr_scanrsp_data, + sizeof(cli_brr_scanrsp_data) + ); + return API_SUCCESS; +} + +API_RESULT cli_terminate_gatt_conn(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + retval = blebrr_disconnect_pl(); + + if (API_SUCCESS != retval) + { + CONSOLE_OUT("Failed to stop Adv"); + return retval; + } + + CONSOLE_OUT("Disconnected successfully\n\n"); + return retval; +} + +API_RESULT cli_discover_service(UINT32 argc, UCHAR* argv[]) +{ + UCHAR service; + + if (1 != argc) + { + CONSOLE_OUT("Usage: discover \n"); + return API_FAILURE; + } + + service = (UCHAR)CLI_strtoi(argv[0], (UINT8)CLI_strlen(argv[0]), 16); + return blebrr_discover_service_pl(service); +} + +API_RESULT cli_config_ntf(UINT32 argc, UCHAR* argv[]) +{ + UCHAR config_ntf; + UCHAR mode; + + if (2 != argc) + { + CONSOLE_OUT("Usage: config_ntf < 0 - Disable, 1 - Enable> \n"); + return API_FAILURE; + } + + config_ntf = (UCHAR)CLI_strtoi(argv[0], (UINT8)CLI_strlen(argv[0]), 16); + mode = (UCHAR)CLI_strtoi(argv[1], (UINT8)CLI_strlen(argv[1]), 16); + return blebrr_confige_ntf_pl(config_ntf, mode); +} + diff --git a/src/components/ethermind/mesh/export/cli/cli_core.c b/src/components/ethermind/mesh/export/cli/cli_core.c new file mode 100644 index 0000000..6adfd12 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/cli_core.c @@ -0,0 +1,192 @@ + +/** + \file cli_core.c + + This File contains the "Core" Layer handlers for the CLI application, + to exercise various functionalities of the Mindtree Mesh stack. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* ------------------------------- Header File Inclusion */ +#include "cli_main.h" +#include "nvsto.h" +#include "blebrr.h" +#include "access_extern.h" + +/* ------------------------------- Global Variables */ +/* Level - Core */ +DECL_CONST CLI_COMMAND cli_core_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Setup */ + { "setup", "Setup", cli_core_setup }, + + #ifdef CLI_PROVISION + /* Provision */ + { "provision", "Provisioning Menu", cli_core_provision }, + #endif /* CLI_PROVISION */ + + #ifdef CLI_PROXY + /* Proxy */ + { "proxy", "Start Proxy", cli_core_proxy }, + #endif /* CLI_PROXY */ + + #ifdef CLI_TRANSPORT + /* Transport */ + { "transport", "Transport Menu", cli_core_transport }, + #endif /* CLI_TRANSPORT */ + + #ifdef CLI_NETWORK + /* Network */ + { "network", "Network Menu", cli_core_network }, + #endif /* CLI_NETWORK */ + + /* Enable */ + { "enable", "Enable relay/proxy/friend/lpn", cli_core_enable_feature }, + + /* Enable */ + { "disable", "Disable relay/proxy/friend/lpn", cli_core_disable_feature }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root } + +}; + +/* ------------------------------- Functions */ +/* CLI Command Handlers. Level - Root */ + +/* Core */ +API_RESULT cli_core(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Core\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_core_cmd_list, sizeof(cli_core_cmd_list) / sizeof(CLI_COMMAND)); + cli_help(argc, argv); + return API_SUCCESS; +} + +/* CLI Command Handlers. Level - Core */ +/* Setup */ +API_RESULT cli_core_setup(UINT32 argc, UCHAR* argv[]) +{ + MS_CONFIG* config_ptr; + #ifdef MS_HAVE_DYNAMIC_CONFIG + MS_CONFIG config; + /* Initialize dynamic configuration */ + MS_INIT_CONFIG(config); + config_ptr = &config; + #else + config_ptr = NULL; + #endif /* MS_HAVE_DYNAMIC_CONFIG */ + #ifdef MEMWATCH + mwInit(); + #endif /* MEMWATCH */ + CONSOLE_OUT("In Core Setup\n"); + /* Initialize OSAL */ + EM_os_init(); + /* Initialize Debug Module */ + EM_debug_init(); + /* Initialize Timer Module */ + EM_timer_init(); + timer_em_init(); + /* Initialize utilities */ + nvsto_init(NVS_FLASH_BASE1,NVS_FLASH_BASE2); + /* Initialize Mesh Stack */ + MS_init(config_ptr); + /* Register with underlying BLE stack */ + blebrr_register(); + /* Register GATT Bearer Connection/Disconnection Event Hook */ + blebrr_register_gatt_iface_event_pl(cli_gatt_bearer_iface_event_pl_cb); + + /* Enable bearer scan if device provisioned and configured */ + if (API_SUCCESS == appl_is_configured()) + { + CONSOLE_OUT ("Device Provisioned and Configured\n"); + blebrr_scan_enable(); + } + else + { + CONSOLE_OUT ("Provision and Configure the Device!\n"); + } + + return API_SUCCESS; +} + +/* Enable Feature */ +API_RESULT cli_core_enable_feature(UINT32 argc, UCHAR* argv[]) +{ + UINT32 index; + UCHAR* features[4] = { "relay", "proxy", "friend", "lpn" }; + CONSOLE_OUT("In Enable Feature\n"); + + if (1 == argc) + { + for (index = 0; index < 4; index++) + { + if (0 == CLI_STR_COMPARE(argv[0], features[index])) + { + break; + } + } + + if (index < 4) + { + MS_access_cm_set_features_field(MS_ENABLE, index); + CONSOLE_OUT("Enable Feature:%s\n", features[index]); + } + else + { + CONSOLE_OUT("Invalid Argument: %s\n", argv[0]); + } + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X\n", argc); + } + + return API_SUCCESS; +} + +/* Disable Feature */ +API_RESULT cli_core_disable_feature(UINT32 argc, UCHAR* argv[]) +{ + UINT32 index; + UCHAR* features[4] = { "relay", "proxy", "friend", "lpn" }; + CONSOLE_OUT("In Disable Feature\n"); + + if (1 == argc) + { + for (index = 0; index < 4; index++) + { + if (0 == CLI_STR_COMPARE(argv[0], features[index])) + { + break; + } + } + + if (index < 4) + { + MS_access_cm_set_features_field(MS_DISABLE, index); + CONSOLE_OUT("Disable Feature:%s\n", features[index]); + } + else + { + CONSOLE_OUT("Invalid Argument: %s\n", argv[0]); + } + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X\n", argc); + } + + return API_SUCCESS; +} + diff --git a/src/components/ethermind/mesh/export/cli/cli_core_network.c b/src/components/ethermind/mesh/export/cli/cli_core_network.c new file mode 100644 index 0000000..b29e3eb --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/cli_core_network.c @@ -0,0 +1,238 @@ + +/** + \file cli_core_network.c + + This File contains the Network function for the CLI application, + to exercise various functionalities of the Network layer. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* ------------------------------- Header File Inclusion */ +#include "cli_main.h" + +#ifdef CLI_NETWORK +/* ------------------------------- Global Variables */ +/* Level - Core - Network */ +DECL_CONST CLI_COMMAND cli_core_network_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Transmit a Network Packet */ + { "send", "Transmit a Network Packet", cli_core_network_send_packet }, + + { "set_hdr", "Set Network Packet Header", cli_core_network_set_pkt_hdr}, + + /* Transmit a secure network beacon */ + /* Transmit a secure network beacon with IV update */ + /* Trasmit secure network beacon with key refresh update */ + /* Use this option when peer device initiated key refresh procedure */ + /* Use this option when local device needs to initiate Key refresh procedure */ + /* Transmit a secure network beacon with both IV update and Key Refresh */ + { "snb", "Transmit a Secure Network Beacon", cli_core_network_snb }, + + /* get the Current IV Index */ + {"get_ivindex", "Get Current IV Index", cli_core_network_get_ivindex}, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root } +}; + +/* Global Network Packet Header */ +MS_NET_HEADER g_hdr; +UCHAR g_hdr_flag = MS_FALSE; + +/* ------------------------------- Functions */ +/* Network */ +API_RESULT cli_core_network(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Core Network\n"); + cli_cmd_stack_push + ( + (CLI_COMMAND*)cli_core_network_cmd_list, + sizeof(cli_core_network_cmd_list) / sizeof(CLI_COMMAND) + ); + cli_help(argc, argv); + return API_SUCCESS; +} + +/* CLI Command Handlers. Level - Core - Network */ +/* Network transmit packet */ +API_RESULT cli_core_network_send_packet(UINT32 argc, UCHAR* argv[]) +{ + UINT16 dst_addr; + UCHAR mode; + MS_BUFFER buffer; + API_RESULT retval; + UINT16 len; + UCHAR* trans_pdu; + /* Un-Segmented Data of 5 Bytes */ + DECL_CONST UCHAR unseg_trans_pdu[] = { 0x01, 0x02, 0x03, 0x04, 0x05 }; + /* Segmented Data of 15 Bytes */ + DECL_CONST UCHAR seg_trans_pdu[] = { 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0A, + 0x0B, 0x0C, 0x0D, 0x0E, 0x0F + }; + + if (2 != argc) + { + CONSOLE_OUT("Usage: send \n"); + return API_FAILURE; + } + + dst_addr = (UINT16)CLI_strtoi(argv[0], (UINT8)CLI_strlen(argv[0]), 16); + mode = (UCHAR) CLI_strtoi(argv[1], (UINT8)CLI_strlen(argv[1]), 16); + + if (MS_FALSE == g_hdr_flag) + { + /* Initialize */ + EM_mem_set(&g_hdr, 0x0, sizeof(g_hdr)); + MS_access_cm_get_primary_unicast_address(&g_hdr.saddr); + g_hdr.daddr = dst_addr; + g_hdr.ttl = 0x01; + g_hdr.ctl = 0x00; + } + + /* Update Sequence Number irrespective of g_hdr_flag */ + MS_net_alloc_seq_num(&g_hdr.seq_num); + + /* Set PDU */ + if (0 == mode) + { + trans_pdu = (UCHAR*)unseg_trans_pdu; + len = sizeof(unseg_trans_pdu); + } + else + { + trans_pdu = (UCHAR*)seg_trans_pdu; + len = sizeof(seg_trans_pdu); + } + + buffer.payload = trans_pdu; + buffer.length = len; + retval = MS_net_send_pdu(&g_hdr, 0x0000, &buffer,MS_FALSE); + return retval; +} + +API_RESULT cli_core_network_set_pkt_hdr(UINT32 argc, UCHAR* argv[]) +{ + if (4 != argc) + { + CONSOLE_OUT("Usage: set_hdr \n"); + return API_FAILURE; + } + + /* Initialize */ + EM_mem_set(&g_hdr, 0x0, sizeof(g_hdr)); + /* Fetch the Sequence Number */ + MS_net_alloc_seq_num(&g_hdr.seq_num); + /* Populate the Network Packet Header Flags */ + g_hdr.ttl = (UCHAR)CLI_strtoi(argv[0], (UINT8)CLI_strlen(argv[0]), 16); + g_hdr.ctl = (UCHAR)CLI_strtoi(argv[1], (UINT8)CLI_strlen(argv[1]), 16); + g_hdr.saddr = (MS_NET_ADDR) CLI_strtoi(argv[2], (UINT16)CLI_strlen(argv[2]), 16); + g_hdr.daddr = (MS_NET_ADDR) CLI_strtoi(argv[3], (UINT16)CLI_strlen(argv[3]), 16); + /* Set the global Header Flag Set as TRUE */ + g_hdr_flag = MS_TRUE; + return API_SUCCESS; +} + +API_RESULT cli_core_network_get_ivindex(UINT32 argc, UCHAR* argv[]) +{ + UINT32 ivindex; + UINT8 ivstate; + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + /* Get the current IV Index */ + retval = MS_access_cm_get_iv_index(&ivindex, &ivstate); + CONSOLE_OUT("Current IV Index: 0x%08X\n", ivindex); + CONSOLE_OUT("Current IV Update state: 0x%02X\n", ivstate); + return retval; +} + +/* Network transmit secure network beacon */ +/** + This CLI command has following sets of parameters: + Option 1: snb + Option 2: snb + Option 3: snb + Also, there could be a scenario as stated below which is + currently not catered to. + Option 4: snb + + Depending on the number of parameters, we can choose the mode of SNB + to be sent appropriately. +*/ +API_RESULT cli_core_network_snb(UINT32 argc, UCHAR* argv[]) +{ + MS_SUBNET_HANDLE handle; + UINT32 ivindex; + UINT8 ivstate; + UINT8 krstate; + CONSOLE_OUT("In Core Network SNB\n"); + + if ((1 > argc) || (4 < argc)) + { + CONSOLE_OUT("Mandatory Usage: snb \n"); + CONSOLE_OUT("Usage: snb {[Optional]}\n"); + CONSOLE_OUT("Usage: snb {[Optional] \n"); + CONSOLE_OUT("Usage: snb "); + return API_FAILURE; + } + + /* Extract the Subnet Handle from Param 1 */ + handle = (UINT16) CLI_strtoi(argv[0], (UINT16) CLI_strlen(argv[0]), 16); + + if (2 == argc) + { + /* Extract Key Refresh State from Param 2 */ + krstate = ((UINT8)CLI_strtoi(argv[1], (UINT8)CLI_strlen(argv[1]), 16) & 0x01) + ? MS_ACCESS_KEY_REFRESH_PHASE_3 : MS_ACCESS_KEY_REFRESH_PHASE_2; + MS_access_cm_set_key_refresh_phase(handle, &krstate); + } + else if (3 == argc) + { + /* Extract IV state from Param 2 */ + ivstate = (UINT8)CLI_strtoi(argv[1], (UINT8)CLI_strlen(argv[1]), 16); + ivstate |= 0x80; + /* Extract IV Index from Param 3 */ + ivindex = (UINT32)CLI_strtoi(argv[2], (UINT16)CLI_strlen(argv[2]), 16); + MS_access_cm_set_iv_index(ivindex, ivstate); + } + else if (4 == argc) + { + /* Extract Key Refresh State from Param 2 */ + krstate = ((UINT8)CLI_strtoi(argv[1], (UINT8)CLI_strlen(argv[1]), 16) & 0x01) + ? MS_ACCESS_KEY_REFRESH_PHASE_3 : MS_ACCESS_KEY_REFRESH_PHASE_2; + /* Extract IV state from Param 2 */ + ivstate = (UINT8)CLI_strtoi(argv[2], (UINT8)CLI_strlen(argv[2]), 16); + ivstate |= 0x80; + /* Extract IV Index from Param 3 */ + ivindex = (UINT32)CLI_strtoi(argv[3], (UINT16)CLI_strlen(argv[3]), 16); + MS_access_cm_set_key_refresh_phase(handle, &krstate); + MS_access_cm_set_iv_index(ivindex, ivstate); + } + + /* Send the Secure Network Beacon */ + MS_net_broadcast_secure_beacon((MS_SUBNET_HANDLE)handle); + + if ((3 == argc) || (4 == argc)) + { + /** + To get the iv state to normal state from In Progess state + and send secure network beacons with new IVIndex value. + */ + MS_access_cm_set_iv_index(ivindex, 0); + } + + return API_SUCCESS; +} + +#endif /* CLI_NETWORK */ diff --git a/src/components/ethermind/mesh/export/cli/cli_core_provision.c b/src/components/ethermind/mesh/export/cli/cli_core_provision.c new file mode 100644 index 0000000..8842738 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/cli_core_provision.c @@ -0,0 +1,269 @@ + +/** + \file cli_main.c + + This File contains the "main" function for the CLI application, + to exercise various functionalities of the Mindtree Mesh stack. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* ------------------------------- Header File Inclusion */ +#include "cli_main.h" + +#ifdef CLI_PROVISION + +/* ------------------------------- Global Variables */ +/* Level - Core - Provision */ +DECL_CONST CLI_COMMAND cli_core_provision_cmd_list[] = +{ + /* Help */ + { "help", "\tHelp", cli_help }, + + /* Help */ + { "uuid", "\tUpdate 1st octet of UUID", cli_provision_uuid }, + + /* Provision Setup */ + { "setup", "\tSetup", cli_core_provision_setup }, + + /* Provision Bind */ + { "bind", "\tBind", cli_core_provision_bind }, + + /* Provision Input Auth Val */ + { "auth_val", "\tInput Authentication Value", cli_core_provision_input_auth_val}, + + /* Provision Set Authentication Action */ + { "auth_act", "\tSet Authentication Action", cli_core_provision_set_auth_action}, + + /* Provision Set Dev Public Key */ + { "dev_pkey", "\tSet Device P256 ECDH Public Key", cli_core_provision_set_dev_pkey}, + + /* Provision Get Local Public Key */ + { "get_pkey", "\tGet Local P256 ECDH Public Key", cli_core_provision_get_pkey}, + + /* Get List of Provisioned Devices */ + { "dev_list", "\tGet List of Provisioned Devices", cli_core_provision_get_dev_list}, + + /* Remove all Device Keys */ + { "rm_devkeys", "Delete All Device Keys", cli_core_provision_delete_all_dev_keys}, + + /* Back */ + { "back", "\tOne Level Up", cli_back }, + + /* Root */ + { "root", "\tBack to Root", cli_root } +}; + +/* ------------------------------- Functions */ +/* Provision */ +API_RESULT cli_core_provision(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Core Provision\n"); + appl_prov_register(); + cli_cmd_stack_push((CLI_COMMAND*)cli_core_provision_cmd_list, sizeof(cli_core_provision_cmd_list) / sizeof(CLI_COMMAND)); + cli_help(argc, argv); + return API_SUCCESS; +} + +/* CLI Command Handlers. Level - Core - Provision */ +API_RESULT cli_provision_uuid(UINT32 argc, UCHAR* argv[]) +{ + UCHAR octet; + CONSOLE_OUT("In Core Provision UUID\n"); + + if (1 != argc) + { + CONSOLE_OUT("Usage: uuid \n"); + return API_FAILURE; + } + + octet = (UCHAR)CLI_strtoi(argv[0], (UINT8)CLI_strlen(argv[0]), 16); + appl_prov_update_uuid(octet); + return API_SUCCESS; +} + +/* Provision Setup */ +API_RESULT cli_core_provision_setup(UINT32 argc, UCHAR* argv[]) +{ + UCHAR role, brr; + CONSOLE_OUT("In Core Provision Setup\n"); + + if (2 != argc) + { + CONSOLE_OUT("Usage: setup \n"); + return API_FAILURE; + } + + role = (UCHAR)CLI_strtoi(argv[0], (UINT8)CLI_strlen(argv[0]), 16); + brr = (UCHAR)CLI_strtoi(argv[1], (UINT8)CLI_strlen(argv[1]), 16); + appl_prov_setup(role, brr); + return API_SUCCESS; +} + +/* Provision Bind */ +API_RESULT cli_core_provision_bind(UINT32 argc, UCHAR* argv[]) +{ + UCHAR brr, indx; + CONSOLE_OUT("In Core Provision Bind\n"); + + if (2 != argc) + { + CONSOLE_OUT("Usage: bind \n"); + return API_FAILURE; + } + + brr = (UCHAR)CLI_strtoi(argv[0], (UINT8)CLI_strlen(argv[0]), 16); + indx = (UCHAR)CLI_strtoi(argv[1], (UINT8)CLI_strlen(argv[1]), 16); + appl_prov_bind(brr, indx); + return API_SUCCESS; +} + +/* Provision Input Auth Val */ +API_RESULT cli_core_provision_input_auth_val(UINT32 argc, UCHAR* argv[]) +{ + UCHAR mode; + UINT32 auth_val_num; + + if (2 != argc) + { + CONSOLE_OUT("Usage: auth_val \n"); + return API_FAILURE; + } + + /** + MODE = 0 -> Numeric + MODE = 1 -> Alphanumeric + */ + /* Copy "Mode" from the CLI stream */ + mode = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + + if (0x00 != mode) + { + appl_prov_input_auth_val(mode, argv[1], CLI_strlen(argv[1])); + } + else + { + /* Copy the Numeric Value */ + auth_val_num = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 10); + appl_prov_input_auth_val(mode, &auth_val_num, sizeof(auth_val_num)); + } + + return API_SUCCESS; +} + +/* Provision Set Authentication Action */ +API_RESULT cli_core_provision_set_auth_action(UINT32 argc, UCHAR* argv[]) +{ + UCHAR mode, oob_act, oob_sz; + UCHAR s_oob_val[16]; + + if ((3 > argc) || (4 < argc)) + { + CONSOLE_OUT("Usage: auth_act \n"); + return API_FAILURE; + } + + /** + Valid Values of Mode for OOB usage are: + 0x00 - None + 0x01 - Static + 0x02 - Output + 0x03 - Input + */ + /* Copy "Mode" from the CLI stream */ + mode = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + /* Copy "OOB Action" from the CLI stream */ + oob_act = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + /* Copy "OOB size" from the CLI stream */ + oob_sz = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + EM_mem_set(s_oob_val, 0x0, sizeof(s_oob_val)); + + if (4 == argc) + { + CLI_strtoarray + ( + argv[3], + CLI_strlen(argv[3]), + &s_oob_val[0], + sizeof(s_oob_val) + ); + } + + appl_prov_set_auth_action + ( + mode, + s_oob_val, + oob_act, + oob_sz + ); + return API_SUCCESS; +} + +/* Provision Set Dev Public Key */ +API_RESULT cli_core_provision_set_dev_pkey(UINT32 argc, UCHAR* argv[]) +{ + /** + TODO: Extended the CLI to have values for generic Peer Device + Currently, this CLI command is making use of PTS provided + PublicKeys by default. + */ + appl_prov_set_dev_public_key(); + return API_SUCCESS; +} + +/* Provision Get Local Public Key */ +API_RESULT cli_core_provision_get_pkey(UINT32 argc, UCHAR* argv[]) +{ + appl_prov_get_local_public_key(); + return API_SUCCESS; +} + +/* Get List of Provisioned Devices */ +API_RESULT cli_core_provision_get_dev_list(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + UINT32 index; + MS_PROV_DEV_ENTRY cli_prov_dev_list[MS_MAX_DEV_KEYS]; + UINT16 cli_req_entries; + UINT16 cli_pointer_entries; + cli_req_entries = MS_MAX_DEV_KEYS; + retval = MS_access_cm_get_prov_devices_list + ( + &cli_prov_dev_list[0], + &cli_req_entries, + &cli_pointer_entries + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT("\r\n=============================================\r\n"); + CONSOLE_OUT(" PROVISONED DEVICE LIST:-\r\n"); + + for (index = 0; index < cli_req_entries; index++) + { + CONSOLE_OUT( + " %02d Device : Primary Element Addr 0x%04X [%d elements]\r\n", + (index + 1), + cli_prov_dev_list[index].uaddr, + cli_prov_dev_list[index].num_elements); + } + + CONSOLE_OUT("=============================================\r\n"); + } + + return retval; +} + +/* Delete all Device Keys */ +API_RESULT cli_core_provision_delete_all_dev_keys(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + retval = MS_access_cm_remove_all_device_keys(); + CONSOLE_OUT("\n Deleting ALL Device Keys, retval 0x%04X\n", retval); + return retval; +} + +#endif /* CLI_PROVISION */ diff --git a/src/components/ethermind/mesh/export/cli/cli_core_proxy.c b/src/components/ethermind/mesh/export/cli/cli_core_proxy.c new file mode 100644 index 0000000..57bc6f2 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/cli_core_proxy.c @@ -0,0 +1,305 @@ + +/** + \file cli_core_proxy.c + + This File contains the "main" function for the CLI application, + to exercise various functionalities of the Mindtree Mesh stack. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* ------------------------------- Header File Inclusion */ +#include "cli_main.h" + +#ifdef CLI_PROXY + +/* --------------------------------------------- External Global Variables */ +#ifdef MS_PROXY_SUPPORT +extern NETIF_HANDLE g_appl_netif_hndl; + +/* ------------------------------- Global Variables */ +/** Macro to hold configurabile limit of Address from CLI command */ +#define CLI_PROXY_MAX_PROXY_ADDR_CNT 5 + +DECL_CONST CLI_COMMAND cli_core_proxy_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Proxy Server Operation Setup */ + { "proxys", "Proxy Server Operation", cli_core_proxy_server_op}, + + /* Proxy Client Opeartion Setup */ + { "proxyc", "Proxy Client Operation", cli_core_proxy_client_op }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root } +}; + +DECL_CONST CLI_COMMAND cli_core_proxy_server_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Start Advertising Proxy Service */ + {"start", "Start Proxy ADV", cli_core_start_proxy_adv}, + + /* Stop Advertising proxy Service */ + { "stop", "Stop Proxy ADV", cli_core_stop_proxy_adv }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root } +}; + +DECL_CONST CLI_COMMAND cli_core_proxy_client_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Set WhiteList Filter Type */ + { "setwl", "Set White List Filter", cli_core_set_wl_filter }, + + /* Set BlackList Filter Type */ + { "setbl", "Set Black List Filter", cli_core_set_bl_filter }, + + /* Add Address to Filter */ + { "add_addr", "Add Address to Filter", cli_core_add_addr_to_filter }, + + /* Remove Address from Filter */ + { "rm_addr", "Remove Address to Filter", cli_core_rm_addr_to_filter }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root } +}; +#endif /* MS_PROXY_SUPPORT */ +/* ------------------------------- Functions */ +API_RESULT cli_core_proxy(UINT32 argc, UCHAR* argv[]) +{ + #ifdef MS_PROXY_SUPPORT + /* Register with Proxy */ + appl_proxy_register(); + cli_cmd_stack_push((CLI_COMMAND*)cli_core_proxy_cmd_list, sizeof(cli_core_proxy_cmd_list) / sizeof(CLI_COMMAND)); + cli_help(argc, argv); + return API_SUCCESS; + #else /* MS_PROXY_SUPPORT */ + CONSOLE_OUT( + "Proxy Support Feature Currently Disabled!!!\n"); + return API_FAILURE; + #endif /* MS_PROXY_SUPPORT */ +} + +#ifdef MS_PROXY_SUPPORT +API_RESULT cli_core_proxy_server_op(UINT32 argc, UCHAR* argv[]) +{ + cli_cmd_stack_push((CLI_COMMAND*)cli_core_proxy_server_cmd_list, sizeof(cli_core_proxy_server_cmd_list) / sizeof(CLI_COMMAND)); + cli_help(argc, argv); + return API_SUCCESS; +} + +API_RESULT cli_core_proxy_client_op(UINT32 argc, UCHAR* argv[]) +{ + cli_cmd_stack_push((CLI_COMMAND*)cli_core_proxy_client_cmd_list, sizeof(cli_core_proxy_client_cmd_list) / sizeof(CLI_COMMAND)); + cli_help(argc, argv); + return API_SUCCESS; +} + +API_RESULT cli_core_start_proxy_adv(UINT32 argc, UCHAR* argv[]) +{ + #ifdef MS_PROXY_SERVER + UCHAR idtfn_type; + MS_SUBNET_HANDLE sub_hndl; + CONSOLE_OUT("Start Proxy ADV....\n"); + + if (2 != argc) + { + CONSOLE_OUT("Usage: start \n"); + return API_FAILURE; + } + + idtfn_type = (UCHAR) CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + sub_hndl = (MS_SUBNET_HANDLE) CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + appl_proxy_adv(idtfn_type, sub_hndl); + return API_SUCCESS; + #else /* MS_PROXY_SERVER */ + CONSOLE_OUT( + "Proxy Server Feature Currently Disabled!!!\n"); + return API_FAILURE; + #endif /* MS_PROXY_SERVER */ +} + +API_RESULT cli_core_stop_proxy_adv(UINT32 argc, UCHAR* argv[]) +{ + #ifdef MS_PROXY_SERVER + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + retval = MS_proxy_server_adv_stop(); + + if (API_SUCCESS != retval) + { + CONSOLE_OUT("Failed to stop Adv\n"); + return retval; + } + + CONSOLE_OUT("ADV Stopped successfully!\n"); + return retval; + #else /* MS_PROXY_SERVER */ + CONSOLE_OUT( + "Proxy Server Feature Currently Disabled!!!\n"); + return API_FAILURE; + #endif /* MS_PROXY_SERVER */ +} + +API_RESULT cli_core_set_wl_filter(UINT32 argc, UCHAR* argv[]) +{ + #ifdef MS_PROXY_CLIENT + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + retval = MS_proxy_set_whitelist_filter(&g_appl_netif_hndl, 0x0000); + + if (API_SUCCESS != retval) + { + CONSOLE_OUT("Failed to stop Adv"); + return retval; + } + + CONSOLE_OUT("Set WhiteList filter Successfully\n\n"); + return retval; + #else /* MS_PROXY_CLIENT */ + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + CONSOLE_OUT( + "Proxy Client Feature Currently Disabled!!!\n"); + return API_FAILURE; + #endif /* MS_PROXY_CLIENT */ +} + +API_RESULT cli_core_set_bl_filter(UINT32 argc, UCHAR* argv[]) +{ + #ifdef MS_PROXY_CLIENT + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + retval = MS_proxy_set_blacklist_filter(&g_appl_netif_hndl, 0x0000); + + if (API_SUCCESS != retval) + { + CONSOLE_OUT("Failed to stop Adv"); + return retval; + } + + CONSOLE_OUT("Set BlackList filter Successfully\n\n"); + return retval; + #else /* MS_PROXY_CLIENT */ + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + CONSOLE_OUT( + "Proxy Client Feature Currently Disabled!!!\n"); + return API_FAILURE; + #endif /* MS_PROXY_CLIENT */ +} + +API_RESULT cli_core_add_addr_to_filter(UINT32 argc, UCHAR* argv[]) +{ + #ifdef MS_PROXY_CLIENT + PROXY_ADDR appl_proxy_addr_list[CLI_PROXY_MAX_PROXY_ADDR_CNT]; + UINT32 i; + MS_SUBNET_HANDLE sub_hndl; + UCHAR appl_proxy_addr_count; + + if ((0 == argc) || (argc > (CLI_PROXY_MAX_PROXY_ADDR_CNT + 1))) + { + CONSOLE_OUT("Usage : add_addr \n"); + CONSOLE_OUT("Example: add_addr 0 1001 1002 ... 1005]>\n"); + return API_FAILURE; + } + + /* Initialize */ + EM_mem_set(appl_proxy_addr_list, 0x0, sizeof(appl_proxy_addr_list)); + appl_proxy_addr_count = 0; + sub_hndl = 0xFFFF; + sub_hndl = (MS_SUBNET_HANDLE)CLI_strtoi(argv[0], (UINT16)CLI_strlen(argv[0]), 16); + appl_proxy_addr_count = argc - 1; + + for (i = 0; i < appl_proxy_addr_count; i++) + { + appl_proxy_addr_list[i] = CLI_strtoi(argv[i + 1], CLI_strlen(argv[i + 1]), 16); + } + + MS_proxy_add_to_list + ( + &g_appl_netif_hndl, + sub_hndl, + appl_proxy_addr_list, + appl_proxy_addr_count + ); + return API_SUCCESS; + #else /* MS_PROXY_CLIENT */ + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + CONSOLE_OUT( + "Proxy Client Feature Currently Disabled!!!\n"); + return API_FAILURE; + #endif /* MS_PROXY_CLIENT */ +} + +API_RESULT cli_core_rm_addr_to_filter(UINT32 argc, UCHAR* argv[]) +{ + #ifdef MS_PROXY_CLIENT + PROXY_ADDR appl_proxy_addr_list[CLI_PROXY_MAX_PROXY_ADDR_CNT]; + UINT32 i; + MS_SUBNET_HANDLE sub_hndl; + UCHAR appl_proxy_addr_count; + + if ((0 == argc) || (argc > (CLI_PROXY_MAX_PROXY_ADDR_CNT + 1))) + { + CONSOLE_OUT("Usage : rm_addr \n"); + CONSOLE_OUT("Example: rm_addr 0 1001 1002 ... 1005]>\n"); + return API_FAILURE; + } + + /* Initialize */ + EM_mem_set(appl_proxy_addr_list, 0x0,sizeof(appl_proxy_addr_list)); + appl_proxy_addr_count = 0; + sub_hndl = 0xFFFF; + sub_hndl = (MS_SUBNET_HANDLE)CLI_strtoi(argv[0], (UINT16)CLI_strlen(argv[0]), 16); + appl_proxy_addr_count = argc - 1; + + for (i = 0; i < appl_proxy_addr_count; i++) + { + appl_proxy_addr_list[i] = CLI_strtoi(argv[i + 1], CLI_strlen(argv[i + 1]), 16); + } + + MS_proxy_del_from_list + ( + &g_appl_netif_hndl, + sub_hndl, + appl_proxy_addr_list, + appl_proxy_addr_count + ); + return API_SUCCESS; + #else /* MS_PROXY_CLIENT */ + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + CONSOLE_OUT( + "Proxy Client Feature Currently Disabled!!!\n"); + return API_FAILURE; + #endif /* MS_PROXY_CLIENT */ +} + +#endif /* MS_PROXY_SUPPORT */ + +#endif /* CLI_PROXY */ diff --git a/src/components/ethermind/mesh/export/cli/cli_core_transport.c b/src/components/ethermind/mesh/export/cli/cli_core_transport.c new file mode 100644 index 0000000..705f099 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/cli_core_transport.c @@ -0,0 +1,300 @@ + +/** + \file cli_core_transport.c + + This File contains the transport function for the CLI application, + to exercise various functionalities of the transport layer. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* ------------------------------- Header File Inclusion */ +#include "cli_main.h" +#include "MS_trn_api.h" + +#ifdef CLI_TRANSPORT + +/* From "sec_tbx.h" */ +void ms_stbx_va +( + /* IN */ UCHAR* l, + /* IN */ UINT16 llen, + /* OUT */ UINT16* va +); + +/* ------------------------------- Global Variables */ +/* Level - Core - Transport */ +DECL_CONST CLI_COMMAND cli_core_transport_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Transmit a Transport Packet */ + { "send", "Transmit a Transport Packet", cli_core_transport_send_packet }, + + /* Trasmit Friend Request */ + { "frndreq", "Friendship Request broadcast", cli_core_transport_frndreq }, + + /* Send Transport Control Message */ + { "ctrlmsg", "Send Transport Control Message", cli_core_transport_ctrlmsg }, + + /* Clear Replay Cache */ + { "clrreplaycache", "Clear Replay Cache", cli_core_transport_clrreplaycache }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root } +}; + +void cli_frnd_cb(MS_SUBNET_HANDLE subnet, UCHAR event_type, UINT16 status); + +/* ------------------------------- Functions */ +/* Transport */ +API_RESULT cli_core_transport(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Core Transport\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_core_transport_cmd_list, sizeof(cli_core_transport_cmd_list) / sizeof(CLI_COMMAND)); + cli_help(argc, argv); + return API_SUCCESS; +} + +/* CLI Command Handlers. Level - Core - Transport */ +/* Transport Send Packet */ +API_RESULT cli_core_transport_send_packet(UINT32 argc, UCHAR* argv[]) +{ + MS_NET_ADDR saddr; + MS_NET_ADDR daddr; + MS_BUFFER buffer; + API_RESULT retval; + UINT8 ttl; + MS_SUBNET_HANDLE subnet_handle; + MS_APPKEY_HANDLE appkey_handle; + UCHAR pdu[] = { 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10 + }; + UINT8 label[16]; + UINT8* a; + UCHAR is_segmented; + CONSOLE_OUT("In Core Transport Send Packet\n"); + + if (6 != argc) + { + CONSOLE_OUT("Usage: send \n"); + return API_FAILURE; + } + + is_segmented = (UCHAR)CLI_strtoi(argv[0], (UINT16)CLI_strlen(argv[0]), 16); + subnet_handle = (MS_SUBNET_HANDLE)CLI_strtoi(argv[1], (UINT16)CLI_strlen(argv[1]), 16); + appkey_handle = (MS_APPKEY_HANDLE)CLI_strtoi(argv[2], (UINT16)CLI_strlen(argv[2]), 16); + ttl = (UINT8)CLI_strtoi(argv[3], (UINT16)CLI_strlen(argv[3]), 16); + saddr = (MS_NET_ADDR)CLI_strtoi(argv[4], (UINT16)CLI_strlen(argv[4]), 16); + + if (4 >= CLI_strlen(argv[5])) + { + daddr = (MS_NET_ADDR)CLI_strtoi(argv[5], (UINT16)CLI_strlen(argv[5]), 16); + CONSOLE_OUT("Destination Address: non-Virtual Address: 0x%04X\n", daddr); + a = NULL; + } + else + { + CONSOLE_OUT("Destination Address is Virtual Address\n"); + CLI_strtoarray + ( + argv[5], + (UINT16)CLI_strlen(argv[5]), + label, + MS_LABEL_UUID_LENGTH + ); + /* Calculate corresponding virtual address */ + ms_stbx_va + ( + label, + MS_LABEL_UUID_LENGTH, + &daddr + ); + a = &label[0]; + CONSOLE_OUT("Calculated Destination Address:0x%04X\n", daddr); + } + + /* Set PDU */ + buffer.payload = pdu; + /** + If the PDU to be transmitted is Un-segmented then currently we are + sending "5" Bytes of Access message otherwise it is "16" Bytes. + */ + buffer.length = (0 == is_segmented) ? 5 : sizeof(pdu); + retval = MS_trn_send_access_pdu + ( + saddr, + daddr, + a, + subnet_handle, + appkey_handle, + ttl, + &buffer, + MS_FALSE + ); + return retval; +} + +/* Transport FrndReq */ +API_RESULT cli_core_transport_frndreq(UINT32 argc, UCHAR* argv[]) +{ + #ifdef MS_LPN_SUPPORT + int val; + API_RESULT retval; + MS_SUBNET_HANDLE subnet; + UCHAR criteria, rx_delay; + UINT32 poll_to, setup_to; + CONSOLE_OUT("In Core Transport FrndReq\n"); + + if (5 != argc) + { + CONSOLE_OUT("Usage: frndreq "); + return API_FAILURE; + } + + val = CLI_strtoi(argv[0], (UINT16)CLI_strlen(argv[0]), 16); + subnet = (MS_SUBNET_HANDLE)val; + val = CLI_strtoi(argv[1], (UINT16)CLI_strlen(argv[1]), 16); + criteria = (UCHAR)val; + val = CLI_strtoi(argv[2], (UINT16)CLI_strlen(argv[2]), 10); + rx_delay = (UCHAR)val; + val = CLI_strtoi(argv[3], (UINT16)CLI_strlen(argv[3]), 10); + poll_to = (UINT32)val; + val = CLI_strtoi(argv[4], (UINT16)CLI_strlen(argv[4]), 10); + setup_to = (UINT32)val; + retval = MS_trn_lpn_setup_friendship + ( + subnet, + criteria, + rx_delay, + poll_to, + setup_to, + cli_frnd_cb + ); + CONSOLE_OUT ("Retval - 0x%04X\n", retval); + return retval; + #else /* MS_LPN_SUPPORT */ + CONSOLE_OUT("MS_LPN_SUPPORT not defined."); + return API_FAILURE; + #endif /* MS_LPN_SUPPORT */ +} + +void cli_frnd_cb(MS_SUBNET_HANDLE subnet, UCHAR event_type, UINT16 status) +{ + API_RESULT retval; + UINT16 num_subaddr; + UINT16 subaddr[5]; + CONSOLE_OUT("\nFriendship Event 0x%02X on Subnet 0x%04X - 0x%04X\n", + event_type, subnet, status); + + switch (event_type) + { + case MS_TRN_FRIEND_SETUP_CNF: + CONSOLE_OUT("Recvd MS_TRN_FRIEND_SETUP_CNF - 0x%04X\n", status); + + if (API_SUCCESS == status) + { + /* Get the subscription list */ + num_subaddr = sizeof(subaddr) / sizeof(UINT16); + MS_access_cm_get_all_model_subscription_list(&num_subaddr, subaddr); + + if (0 < num_subaddr) + { + CONSOLE_OUT("Initiating FriendSubscriptionListAdd - %d addr\n", num_subaddr); + retval = MS_trn_lpn_subscrn_list_add(subaddr, num_subaddr); + CONSOLE_OUT("Retval - 0x%04X\n", retval); + } + } + + break; + + case MS_TRN_FRIEND_SUBSCRNLIST_CNF: + CONSOLE_OUT("Recvd MS_TRN_FRIEND_SUBSCRNLIST_CNF - 0x%04X\n", status); + break; + + case MS_TRN_FRIEND_CLEAR_CNF: + CONSOLE_OUT("Recvd MS_TRN_FRIEND_CLEAR_CNF - 0x%04X\n", status); + break; + + case MS_TRN_FRIEND_TERMINATE_IND: + CONSOLE_OUT("Recvd MS_TRN_FRIEND_TERMINATE_IND - 0x%04X\n", status); + break; + + default: + break; + } +} + +API_RESULT cli_core_transport_ctrlmsg(UINT32 argc, UCHAR* argv[]) +{ + #ifdef MS_LPN_SUPPORT + API_RESULT retval; + MS_NET_ADDR addr[1]; + UCHAR ctrlmsg_type; + retval = API_FAILURE; + + if (1 > argc) + { + CONSOLE_OUT("Usage: ctrlmsg <0 - FriendSubscriptionListAdd\n 1 - FriendSubscriptionListRemove\n 2- FriendClear>\n"); + return retval; + } + + ctrlmsg_type = (UCHAR)CLI_strtoi(argv[0], (UINT16)CLI_strlen(argv[0]), 16); + + if (0 == ctrlmsg_type) + { + if (2 != argc) + { + CONSOLE_OUT("Usage: ctrlmsg 0 \n"); + return retval; + } + + addr[0] = (UINT16)CLI_strtoi(argv[1], (UINT16)CLI_strlen(argv[1]), 16); + CONSOLE_OUT("In Core Transport FriendSubscriptionListAdd\n"); + retval = MS_trn_lpn_subscrn_list_add(addr, (sizeof(addr) / sizeof(MS_NET_ADDR))); + } + else if (1 == ctrlmsg_type) + { + if (2 != argc) + { + CONSOLE_OUT("Usage: ctrlmsg 1 \n"); + return retval; + } + + addr[0] = (UINT16)CLI_strtoi(argv[1], (UINT16)CLI_strlen(argv[1]), 16); + CONSOLE_OUT("In Core Transport FriendSubscriptionListRemove\n"); + retval = MS_trn_lpn_subscrn_list_remove(addr, (sizeof(addr) / sizeof(MS_NET_ADDR))); + } + else + { + CONSOLE_OUT("In Core Transport FriendClear\n"); + retval = MS_trn_lpn_clear_friendship(); + } + + CONSOLE_OUT("Retval - 0x%04X\n", retval); + return retval; + #else /* MS_LPN_SUPPORT */ + CONSOLE_OUT("MS_LPN_SUPPORT not defined.\n"); + return API_FAILURE; + #endif /* MS_LPN_SUPPORT */ +} + +API_RESULT cli_core_transport_clrreplaycache(UINT32 argc, UCHAR* argv[]) +{ + /* No parameter */ + ltrn_init_replay_cache(); + CONSOLE_OUT("Replay Cache cleared...\n"); + return API_SUCCESS; +} + +#endif /* CLI_TRANSPORT */ + diff --git a/src/components/ethermind/mesh/export/cli/cli_demo.c b/src/components/ethermind/mesh/export/cli/cli_demo.c new file mode 100644 index 0000000..8078a30 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/cli_demo.c @@ -0,0 +1,263 @@ + +/** + \file cli_demo.c + + This File contains the "main" function for the Demo application. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifdef DEMO + +/* ------------------------------- Header File Inclusion */ +#include "MS_access_api.h" +#include "MS_config_api.h" + +#include "MS_generic_onoff_api.h" + +#include "cliface.h" +#include "blebrr.h" + + +/* ------------------------------- Global Variables */ +/* Console Input/Output */ +#define CONSOLE_OUT(...) printf(__VA_ARGS__) +#define CONSOLE_IN(...) scanf(__VA_ARGS__) + +/* Macro to declare a CLI Command Handler */ +#define CLI_CMD_HANDLER_DECL(x) \ + API_RESULT (x) (UINT32 arc, UCHAR * arv[]) + +/* Macro to define an empty CLI Command Handler */ +#define CLI_CMD_HANDLER_EMPTY_DEF(x) \ + API_RESULT (x) (UINT32 argc, UCHAR * argv[]) \ + { \ + UINT32 index; \ + \ + CLI_APP_TRC(#x ". Argc %d\n", argc); \ + \ + for (index = 0; index < argc; index++) \ + { \ + CLI_APP_TRC("Argv[%d]: %s\n", index, argv[index]); \ + } \ + \ + return API_SUCCESS; \ + } + +/* CLI Command Handler declaration for configuration client */ +CLI_CMD_HANDLER_DECL( cli_help ); + +CLI_CMD_HANDLER_DECL( cli_provisioning_mode_adv_set ); +CLI_CMD_HANDLER_DECL( cli_provisioning_mode_gatt_set ); + +CLI_CMD_HANDLER_DECL( cli_proxy_mode_set ); + +CLI_CMD_HANDLER_DECL( cli_provisioner_mode_set ); +CLI_CMD_HANDLER_DECL( cli_start_provisioning ); + +CLI_CMD_HANDLER_DECL( cli_clear_persistent ); +CLI_CMD_HANDLER_DECL( cli_switchon ); +CLI_CMD_HANDLER_DECL( cli_switchoff ); + +/* CLI Server command table */ +DECL_STATIC CLI_COMMAND cli_server_cmd_list[] = +{ + /* Help */ + { "help", "Help Menu", cli_help }, + + /* Set in provisioning mode */ + { "provadv", "Device for Provisioning over ADV", cli_provisioning_mode_adv_set }, + { "provgatt", "Device for Provisioning over GATT", cli_provisioning_mode_gatt_set }, + + /* Switch to Proxy */ + { "proxy", "Device for Proxy", cli_proxy_mode_set}, + + #ifdef DEMO_CLIENT + { "on", "Switch ON Light", cli_switchon}, + { "off", "Switch OFF Light", cli_switchoff}, + #endif /* DEMO_CLIENT */ + + /* Clear the Mesh Database from persistent store */ + { "reset", "Clear Persistent storage", cli_clear_persistent } +}; + +/* Debug Macros */ +/* TBD: Mapped with debug sub-system */ +#define CLI_APP_ERR(...) printf(__VA_ARGS__) +#define CLI_APP_TRC(...) printf(__VA_ARGS__) +#define CLI_APP_INF(...) printf(__VA_ARGS__) + +/* TODO: Remove */ +/* Current Test Case ID */ +UINT32 appl_mesh_test_id; + +#ifdef DEMO_CLIENT +static MS_ACCESS_MODEL_HANDLE appl_generic_onoff_client_model_handle; + +API_RESULT appl_generic_onoff_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); +#endif /* DEMO_CLIENT */ + +/* ------------------------------- Functions */ +void cli_input (char* cmd, int size) +{ + CLI_process_line + ( + cmd, + size, + cli_server_cmd_list, + (sizeof(cli_server_cmd_list) / sizeof(CLI_COMMAND)) + ); +} + +/* CLI Command Handler Defines */ +API_RESULT cli_help(UINT32 argc, UCHAR* argv[]) +{ + UINT32 index; + + /* Print all the available commands */ + for (index = 0; index < (sizeof(cli_server_cmd_list) / sizeof(CLI_COMMAND)); index++) + { + CONSOLE_OUT(" %s\n", cli_server_cmd_list[index].cmd); + } + + return API_SUCCESS; +} + +API_RESULT cli_demo_init(void) +{ + MS_ACCESS_NODE_ID node_id; + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + /* Create Node */ + retval = MS_access_create_node(&node_id); + + if (API_SUCCESS == retval) + { + /* Register the Models */ + main_register_models(); + #ifndef DEMO_CLIENT + /* Initialize Generic ON/OFF Server */ + main_generic_onoff_server_operations(MS_FALSE); + #else /* DEMO_CLIENT */ + cli_modelc_generic_onoff_setup(0, NULL); + #endif /* DEMO_CLIENT */ + } + + CONSOLE_OUT("Model Registration Status: 0x%04X\n", retval); + return API_SUCCESS; +} + +API_RESULT cli_provisioning_mode_adv_set(UINT32 argc, UCHAR* argv[]) +{ + appl_prov_register(); + appl_prov_setup(PROV_ROLE_DEVICE, PROV_BRR_ADV); + return API_SUCCESS; +} + +API_RESULT cli_provisioning_mode_gatt_set(UINT32 argc, UCHAR* argv[]) +{ + appl_prov_register(); + /* Set the role to Prov with bearer */ + blebrr_gatt_mode_set(BLEBRR_GATT_PROV_MODE); + appl_prov_setup(PROV_ROLE_DEVICE, PROV_BRR_GATT); + return API_SUCCESS; +} + +API_RESULT cli_proxy_mode_set(UINT32 argc, UCHAR* argv[]) +{ + appl_proxy_register(); + appl_proxy_start_net_id_adv(); + return API_SUCCESS; +} + +void appl_prov_register(void); +void appl_prov_setup_provisioner(void); +API_RESULT cli_provisioner_mode_set(UINT32 argc, UCHAR* argv[]) +{ + appl_prov_register(); + appl_prov_setup_provisioner(); + return API_SUCCESS; +} + +void appl_prov_start_provisioning(void); +API_RESULT cli_start_provisioning(UINT32 argc, UCHAR* argv[]) +{ + appl_prov_start_provisioning(); + return API_SUCCESS; +} + +API_RESULT cli_config_gatt_proxy_get(UINT32 argc, UCHAR* argv[]) +{ + return MS_config_client_gatt_proxy_get(); +} + +API_RESULT cli_config_gatt_proxy_set(UINT32 argc, UCHAR* argv[]) +{ + ACCESS_CONFIG_GATT_PROXY_SET_PARAM proxy; + proxy.proxy = 0x01; + return MS_config_client_gatt_proxy_set(&proxy); +} + +API_RESULT cli_clear_persistent(UINT32 argc, UCHAR* argv[]) +{ + nvs_reset(); + printf ("Persistent database Reset Success!"); + /* appl_set_prov_state(false); */ + return API_SUCCESS; +} + + +API_RESULT cli_switchon(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + MS_GENERIC_ONOFF_SET_STRUCT param; + param.onoff= 0x01; + param.tid= 0; + param.optional_fields_present = 0x00; + printf ("Switch ON!"); + retval = MS_generic_onoff_set_unacknowledged(¶m); + printf ("Retval = 0x%04X\n", retval); + return API_SUCCESS; +} + +API_RESULT cli_switchoff(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + MS_GENERIC_ONOFF_SET_STRUCT param; + param.onoff= 0x00; + param.tid= 0; + param.optional_fields_present = 0x00; + printf ("Switch OFF!"); + retval = MS_generic_onoff_set_unacknowledged(¶m); + printf ("Retval = 0x%04X\n", retval); + return API_SUCCESS; +} + +void appl_indicate_provisioning_state (void) +{ + MS_NET_ADDR addr; + MS_access_cm_get_primary_unicast_address (&addr); + + if (0x0000 == addr) + { + printf ("Device Not Provisioned!"); + /* Put device in provisioning over GATT */ + cli_provisioning_mode_gatt_set(0, NULL); + } + else + { + printf ("Device Provisioned!"); + /* Put device in Proxy over GATT */ + /* cli_proxy_mode_set(0, NULL); */ + } +} +#endif /* DEMO */ diff --git a/src/components/ethermind/mesh/export/cli/cli_inclusion_flags.txt b/src/components/ethermind/mesh/export/cli/cli_inclusion_flags.txt new file mode 100644 index 0000000..e0393e5 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/cli_inclusion_flags.txt @@ -0,0 +1,49 @@ +== CLI Flags for Mesh Core layers == +------------------------------------ +CLI_PROVISION -> Enables provisioning related CLI menu +CLI_PROXY -> Enables proxy related CLI menu +CLI_TRANSPORT -> Enables transport layer related CLI menu +CLI_NETWORK -> Enables network layer related CLI menu + +== CLI Flags for Mesh Model layers == +------------------------------------- +CLI_CONFIG_SERVER_MODEL -> Enables setup of configuration server model *** THIS IS MANDATORY FOR ANY CIENT/SERVER SPECIFIC MODEL OPERATION *** + +CLI_CONFIG_CLIENT_MODEL -> Enables configuration client related CLI menu +CLI_HEALTH_CLIENT_MODEL -> Enables health client related CLI menu +CLI_GENERICS_CLIENT_MODEL -> Enables generics client related CLI menu and submodel client menu with beow flags + - CLI_GENERICS_ONOFF_CLIENT_MODEL + - CLI_GENERICS_LEVEL_CLIENT_MODEL + - CLI_GENERICS_TRANSITIONTIME_CLIENT_MODEL + - CLI_GENERICS_PWRONOFF_CLIENT_MODEL + - CLI_GENERICS_PWRLEVEL_CLIENT_MODEL + - CLI_GENERICS_BATTERY_CLIENT_MODEL + - CLI_GENERICS_LOCATION_CLIENT_MODEL + - CLI_GENERICS_PROPERTY_CLIENT_MODEL + +CLI_LIGHTINGS_CLIENT_MODEL -> Enables lightings client related CLI menu and submodel client menu with beow flags + - CLI_LIGHTINGS_LIGHTNESS_CLIENT_MODEL + - CLI_LIGHTINGS_CTL_CLIENT_MODEL + - CLI_LIGHTINGS_HSL_CLIENT_MODEL + - CLI_LIGHTINGS_XYL_CLIENT_MODEL + - CLI_LIGHTINGS_LC_CLIENT_MODEL + +CLI_HEALTH_SERVER_MODEL -> Enables setup of health server model +CLI_GENERICS_SERVER_MODEL -> Enables setup of generics server model and submodel with below flags + - CLI_GENERICS_ONOFF_SERVER_MODEL + - CLI_GENERICS_LEVEL_SERVER_MODEL + - CLI_GENERICS_TRANSITIONTIME_SERVER_MODEL + - CLI_GENERICS_PWRONOFF_SERVER_MODEL + - CLI_GENERICS_PWRLEVEL_SERVER_MODEL + - CLI_GENERICS_BATTERY_SERVER_MODEL + - CLI_GENERICS_LOCATION_SERVER_MODEL + - CLI_GENERICS_PROPERTY_SERVER_MODEL + +CLI_LIGHTINGS_SERVER_MODEL -> Enables setup of lightings server model and submodel with below flags + - CLI_LIGHTINGS_LIGHTNESS_SERVER_MODEL + - CLI_LIGHTINGS_CTL_SERVER_MODEL + - CLI_LIGHTINGS_HSL_SERVER_MODEL + - CLI_LIGHTINGS_XYL_SERVER_MODEL + - CLI_LIGHTINGS_LC_SERVER_MODEL + + diff --git a/src/components/ethermind/mesh/export/cli/cli_main.c b/src/components/ethermind/mesh/export/cli/cli_main.c new file mode 100644 index 0000000..3adfee4 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/cli_main.c @@ -0,0 +1,279 @@ + +/** + \file cli_main.c + + This File contains the "main" function for the CLI application, + to exercise various functionalities of the Mindtree Mesh stack. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef DEMO + +/* ------------------------------- Header File Inclusion */ +#include "cli_main.h" +#include "nvs.h" + +/* ------------------------------- Global Variables */ +#ifndef CLI_NO_MAIN + DECL_STATIC UCHAR r_buf[1024]; +#else + void cli_input (char* cmd, int size); +#endif /* CLI_NO_MAIN */ + +/* Level - Root */ +DECL_CONST CLI_COMMAND cli_root_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Core */ + { "core", "Core Options", cli_core }, + + /* Model */ + { "model", "Model Options", cli_model }, + + /* Reset */ + { "reset", "Reset Node", cli_reset }, + + /* Persistent Storage */ + { "ps", "Persistent Storage", cli_ps }, + + /* Mesh ADV/GATT bearer Operations */ + { "brr", "Mesh bearer Operations", cli_brr }, + + /* Set Log Level */ + { "loglevel", "Set Log Level ", cli_set_log_level } +}; + +/* Command List Stack */ +typedef struct _CLI_COMMAND_STACK_FRAME +{ + CLI_COMMAND* cmd_list; + UINT16 cmd_list_len; + +} CLI_COMMAND_STACK_FRAME; + +#define CLI_CMD_LIST_MAX_DEPTH 10 +DECL_STATIC UINT16 cli_cmd_list_sp; +DECL_STATIC CLI_COMMAND_STACK_FRAME cli_cmd_list_stack[CLI_CMD_LIST_MAX_DEPTH]; + +/* ------------------------------- Functions */ +/* Common Utility Routines */ +void cli_cmd_stack_push(/* IN */ CLI_COMMAND* cmd_list, /* IN */ UINT16 cmd_list_len) +{ + cli_cmd_list_sp++; + cli_cmd_list_stack[cli_cmd_list_sp].cmd_list = cmd_list; + cli_cmd_list_stack[cli_cmd_list_sp].cmd_list_len = cmd_list_len; +} + +void cli_cmd_stack_pop(void) +{ + /* Check if the Stack point in not 0. Decrement by one */ + if (0 != cli_cmd_list_sp) + { + cli_cmd_list_sp--; + } + else + { + CONSOLE_OUT("Already at Root Level\n"); + } +} + +API_RESULT cli_reset(UINT32 argc, UCHAR* argv[]) +{ + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + CONSOLE_OUT ("Clearing Storage\n"); + nvs_reset(NVS_BANK_PERSISTENT); + return API_SUCCESS; +} +extern uint8 llState; +extern uint8 llSecondaryState; +extern UCHAR blebrr_state; +extern uint32 blebrr_advscan_timeout_count; + +/* Help */ +API_RESULT cli_help(UINT32 argc, UCHAR* argv[]) +{ + UINT32 index; + UINT32 sum = 0; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + CONSOLE_OUT("In Help\n"); + + /* Print all the available commands */ + for (index = 0; index < cli_cmd_list_stack[cli_cmd_list_sp].cmd_list_len; index++) + { + CONSOLE_OUT(" %s: %s\n", + cli_cmd_list_stack[cli_cmd_list_sp].cmd_list[index].cmd, + cli_cmd_list_stack[cli_cmd_list_sp].cmd_list[index].desc); + } + + printf("osal_memory sum = %d\r\n", sum); + printf("\r\n===== internal status ============\r\n"); + printf("llState = %d, llSecondaryState = %d\r\n", llState, llSecondaryState); + printf("blebrr_state = %d\r\n", blebrr_state); + printf("blebrr_advscan_timeout_count = %d\r\n", blebrr_advscan_timeout_count); + return API_SUCCESS; +} + +/* Back */ +API_RESULT cli_back(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("Going Back \n"); + cli_cmd_stack_pop(); + /* Print Help of the new level */ + cli_help(argc, argv); + return API_SUCCESS; +} + +/* Root */ +API_RESULT cli_root(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("Level - Root\n"); + /* Set Stack Pointer to Root */ + cli_cmd_list_sp = 0; + cli_cmd_list_stack[cli_cmd_list_sp].cmd_list = (CLI_COMMAND*)cli_root_cmd_list; + cli_cmd_list_stack[cli_cmd_list_sp].cmd_list_len = sizeof(cli_root_cmd_list) / sizeof(CLI_COMMAND); + /* Print Help of the Root level */ + cli_help(argc, argv); + return API_SUCCESS; +} + +/* Log Level */ +API_RESULT cli_set_log_level(UINT32 argc, UCHAR* argv[]) +{ + UINT32 index; + UCHAR* log_levels[4] = { "ERR", "TRC", "INF", "ALL" }; + CONSOLE_OUT("In Set Log Level\n"); + + if (1 == argc) + { + for (index = 0; index < 4; index++) + { + if (0 == CLI_STR_COMPARE(argv[0], log_levels[index])) + { + break; + } + } + + if (index > 3) + { + CONSOLE_OUT("Invalid Argument:%s\n", argv[0]); + return API_FAILURE; + } + + if (index < 3) + { + index += 1; + } + + EM_set_debug_level((UCHAR)index); + CONSOLE_OUT("Set Log Level:0x%02X\n", (UCHAR)index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X\n", argc); + } + + return API_SUCCESS; +} + +/* Module related Utility Routines */ +void cli_gatt_bearer_iface_event_pl_cb +( + UCHAR ev_name, + UCHAR ev_param +) +{ + switch(ev_name) + { + /* GATT Bearer BLE Link Layer Disconnected */ + case BLEBRR_GATT_IFACE_DOWN: + CONSOLE_OUT("\r\n >> GATT Bearer BLE Link Layer Disconnection Event Received!\r\n"); + CONSOLE_OUT("Invoke relevant CLI Commands! \r\n"); + break; + + /* GATT Bearer BLE Link Layer Connected */ + case BLEBRR_GATT_IFACE_UP: + CONSOLE_OUT("\r\n >> GATT Bearer BLE Link Layer Connection Event Received!\r\n"); + /** + TODO: + Check if this only when DUT is Unprovisioned Device! + also check if this needs to be done. + */ + MS_prov_stop_interleave_timer(); + MS_brr_bcast_end(BRR_BCON_TYPE_UNPROV_DEVICE, BRR_BCON_ACTIVE); + break; + + /* GATT Bearer Service Enabled for Communication */ + case BLEBRR_GATT_IFACE_ENABLE: + CONSOLE_OUT("\r\n >> GATT Bearer Active Event Received!\r\n"); + { + if (BLEBRR_GATT_PROV_MODE == ev_param) + { + /* Call to bind with the selected device */ + /** + TODO: + This needs to be made role Specific. + For Provisioner role, this below function needs to be + updated. Typically for Provisioner Role, "Bind" needs + to happen from the CLI command pointing to the desired + PROV_DEVICE_S of Remote Unprovisioned Device. + */ + appl_prov_bind_device(PROV_BRR_GATT); + } + } + break; + + /* GATT Bearer Service Disabled for Communication */ + case BLEBRR_GATT_IFACE_DISABLE: + CONSOLE_OUT("\r\n >> GATT Bearer Inactive Event Received!\r\n"); + CONSOLE_OUT("Invoke relevant CLI Commands! \r\n"); + break; + + /* Unknown Event! */ + default: + CONSOLE_OUT("\r\n >> GATT Bearer BLE Link Layer Unknown Event 0x%02X Received!\r\n", ev_name); + break; + } +} + +#ifndef CLI_NO_MAIN +int main (int argc, char** argv) +{ + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + /* Initialize CLI */ + CLI_init(); + /* Set Root Command List and Length */ + cli_root(0, NULL); + MS_LOOP_FOREVER() + { + /* */ + fgets(r_buf, sizeof(r_buf), stdin); + CLI_process_line + ( + r_buf, + CLI_strlen(r_buf), + cli_cmd_list_stack[cli_cmd_list_sp].cmd_list, + cli_cmd_list_stack[cli_cmd_list_sp].cmd_list_len + ); + } + return 0; +} +#else /* CLI_NO_MAIN */ +void cli_input (char* cmd, int size) +{ + CLI_process_line + ( + (UCHAR*) cmd, + size + ); +} +#endif /* CLI_NO_MAIN */ +#endif /* DEMO */ diff --git a/src/components/ethermind/mesh/export/cli/cli_main.h b/src/components/ethermind/mesh/export/cli/cli_main.h new file mode 100644 index 0000000..c0ac59f --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/cli_main.h @@ -0,0 +1,300 @@ + +/** + \file cli_main.h + + Header File for the CLI application to test the Mindtree + Mesh stack. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_CLI_MAIN_ +#define _H_CLI_MAIN_ + +/* --------------------------------------------- Header File Inclusion */ +#include "cliface.h" +#include "MS_access_api.h" +#include "MS_config_api.h" +#include "MS_health_server_api.h" +#include "appl_main.h" +#include "blebrr.h" + +/* --------------------------------------------- Global Definitions */ + +/* --------------------------------------------- Structures/Data Types */ + +// ---------------- add by HZF, CLI options +#define CLI_NO_MAIN +//#define CLI_PROVISION +//#define CLI_PROXY +//#define CLI_TRANSPORT +//#define CLI_NETWORK + +//#define CLI_GENERICS_SERVER_MODEL +//#define CLI_GENERICS_CLIENT_MODEL + +//#define CLI_GENERICS_ONOFF_SERVER_MODEL +//#define CLI_GENERICS_ONOFF_CLIENT_MODEL + +//#define CLI_CONFIG_SERVER_MODEL +//#define CLI_CONFIG_CLIENT_MODEL + +//#define CLI_HEALTH_SERVER_MODEL +//#define CLI_HEALTH_CLIENT_MODEL + +/* + - CLI_GENERICS_ONOFF_CLIENT_MODEL + - CLI_GENERICS_LEVEL_CLIENT_MODEL + - CLI_GENERICS_TRANSITIONTIME_CLIENT_MODEL + - CLI_GENERICS_PWRONOFF_CLIENT_MODEL + - CLI_GENERICS_PWRLEVEL_CLIENT_MODEL + - CLI_GENERICS_BATTERY_CLIENT_MODEL + - CLI_GENERICS_LOCATION_CLIENT_MODEL + - CLI_GENERICS_PROPERTY_CLIENT_MODEL + + CLI_LIGHTINGS_CLIENT_MODEL -> Enables lightings client related CLI menu and submodel client menu with beow flags + - CLI_LIGHTINGS_LIGHTNESS_CLIENT_MODEL + - CLI_LIGHTINGS_CTL_CLIENT_MODEL + - CLI_LIGHTINGS_HSL_CLIENT_MODEL + - CLI_LIGHTINGS_XYL_CLIENT_MODEL + - CLI_LIGHTINGS_LC_CLIENT_MODEL + + - CLI_GENERICS_LEVEL_SERVER_MODEL + - CLI_GENERICS_TRANSITIONTIME_SERVER_MODEL + - CLI_GENERICS_PWRONOFF_SERVER_MODEL + - CLI_GENERICS_PWRLEVEL_SERVER_MODEL + - CLI_GENERICS_BATTERY_SERVER_MODEL + - CLI_GENERICS_LOCATION_SERVER_MODEL + - CLI_GENERICS_PROPERTY_SERVER_MODEL + + CLI_LIGHTINGS_SERVER_MODEL -> Enables setup of lightings server model and submodel with below flags + - CLI_LIGHTINGS_LIGHTNESS_SERVER_MODEL + - CLI_LIGHTINGS_CTL_SERVER_MODEL + - CLI_LIGHTINGS_HSL_SERVER_MODEL + - CLI_LIGHTINGS_XYL_SERVER_MODEL + - CLI_LIGHTINGS_LC_SERVER_MODEL +*/ + +/* --------------------------------------------- Macros */ + +/* Debug Macros */ +/* TBD: Mapped with debug sub-system */ +#define CLI_APP_ERR(...) printf(__VA_ARGS__) +#define CLI_APP_TRC(...) printf(__VA_ARGS__) +#define CLI_APP_INF(...) printf(__VA_ARGS__) + +/* Console Input/Output */ +#define CONSOLE_OUT(...) printf(__VA_ARGS__) +#define CONSOLE_IN(...) scanf(__VA_ARGS__) + +/* Macro to declare a CLI Command Handler */ +#define CLI_CMD_HANDLER_DECL(x) \ + API_RESULT (x) (UINT32 arc, UCHAR * arv[]) + +/* Macro to define an empty CLI Command Handler */ +#define CLI_CMD_HANDLER_EMPTY_DEF(x) \ + API_RESULT (x) (UINT32 argc, UCHAR * argv[]) \ + { \ + UINT32 index; \ + \ + CLI_APP_TRC(#x ". Argc %d\n", argc); \ + \ + for (index = 0; index < argc; index++) \ + { \ + CLI_APP_TRC("Argv[%d]: %s\n", index, argv[index]); \ + } \ + \ + return API_SUCCESS; \ + } + +/* --------------------------------------------- Internal Functions */ +/* CLI Command Handler declaration for configuration client */ +/* Level - Root */ +CLI_CMD_HANDLER_DECL( cli_help ); +CLI_CMD_HANDLER_DECL( cli_core ); +CLI_CMD_HANDLER_DECL( cli_model ); +CLI_CMD_HANDLER_DECL( cli_reset ); +CLI_CMD_HANDLER_DECL( cli_ps ); +CLI_CMD_HANDLER_DECL( cli_brr ); +CLI_CMD_HANDLER_DECL( cli_set_log_level ); + +CLI_CMD_HANDLER_DECL(cli_back); +CLI_CMD_HANDLER_DECL(cli_root); + +/* Level - Core */ +CLI_CMD_HANDLER_DECL( cli_core_setup ); +CLI_CMD_HANDLER_DECL( cli_core_provision ); +CLI_CMD_HANDLER_DECL( cli_core_proxy ); +CLI_CMD_HANDLER_DECL( cli_core_transport ); +CLI_CMD_HANDLER_DECL( cli_core_network ); +CLI_CMD_HANDLER_DECL( cli_core_enable_feature ); +CLI_CMD_HANDLER_DECL( cli_core_disable_feature ); + +/* Level - Core - Network */ +CLI_CMD_HANDLER_DECL(cli_core_network_send_packet); +CLI_CMD_HANDLER_DECL(cli_core_network_set_pkt_hdr); +CLI_CMD_HANDLER_DECL(cli_core_network_snb); +CLI_CMD_HANDLER_DECL(cli_core_network_get_ivindex); + +/* Level - Core - Transport */ +CLI_CMD_HANDLER_DECL(cli_core_transport_send_packet); +CLI_CMD_HANDLER_DECL(cli_core_transport_frndreq); +CLI_CMD_HANDLER_DECL(cli_core_transport_ctrlmsg); +CLI_CMD_HANDLER_DECL(cli_core_transport_clrreplaycache); + +/* Level - Core - Provision */ +CLI_CMD_HANDLER_DECL(cli_provision_uuid); +CLI_CMD_HANDLER_DECL(cli_core_provision_setup); +CLI_CMD_HANDLER_DECL(cli_core_provision_bind); +CLI_CMD_HANDLER_DECL(cli_core_provision_input_auth_val); +CLI_CMD_HANDLER_DECL(cli_core_provision_set_auth_action); +CLI_CMD_HANDLER_DECL(cli_core_provision_set_dev_pkey); +CLI_CMD_HANDLER_DECL(cli_core_provision_get_pkey); +CLI_CMD_HANDLER_DECL(cli_core_provision_get_dev_list); +CLI_CMD_HANDLER_DECL(cli_core_provision_delete_all_dev_keys); + +/* Level - Core - Proxy */ +CLI_CMD_HANDLER_DECL(cli_core_proxy_server_op); +CLI_CMD_HANDLER_DECL(cli_core_proxy_client_op); +CLI_CMD_HANDLER_DECL(cli_core_start_proxy_adv); +CLI_CMD_HANDLER_DECL(cli_core_stop_proxy_adv); +CLI_CMD_HANDLER_DECL(cli_core_set_wl_filter); +CLI_CMD_HANDLER_DECL(cli_core_set_bl_filter); +CLI_CMD_HANDLER_DECL(cli_core_add_addr_to_filter); +CLI_CMD_HANDLER_DECL(cli_core_rm_addr_to_filter); + +/* Level - Model */ +CLI_CMD_HANDLER_DECL(cli_model_server); +CLI_CMD_HANDLER_DECL(cli_model_client); + +/* Level - Persistent Storage */ +CLI_CMD_HANDLER_DECL(cli_ps_get_device_key); +CLI_CMD_HANDLER_DECL(cli_ps_get_app_key); +CLI_CMD_HANDLER_DECL(cli_ps_get_net_key); +CLI_CMD_HANDLER_DECL(cli_ps_get_primary_unicast_addr); + +/* Level - Bearer Layer */ +CLI_CMD_HANDLER_DECL(cli_create_gatt_conn); +CLI_CMD_HANDLER_DECL(cli_terminate_gatt_conn); +CLI_CMD_HANDLER_DECL(cli_discover_service); +CLI_CMD_HANDLER_DECL(cli_config_ntf); +CLI_CMD_HANDLER_DECL(cli_scan_feature); +CLI_CMD_HANDLER_DECL(cli_scan_rsp_data_set); + +/* Model Server - Foundation Models */ +CLI_CMD_HANDLER_DECL(cli_models_foundation); + +/* Model Server - Health */ +CLI_CMD_HANDLER_DECL(cli_models_health); + +/* Model Server - Health - Log Fault */ +CLI_CMD_HANDLER_DECL(cli_models_health_log_fault); + +/* Health - TODO: Temporary till model publication period is triggered */ +CLI_CMD_HANDLER_DECL(cli_health_status_publish); + +/* Level - Model - Server */ +/* Generics */ +CLI_CMD_HANDLER_DECL(cli_models_generics); + +/* Model Server - Generics - OnOff */ +CLI_CMD_HANDLER_DECL(cli_models_generics_onoff); + +/* Model Server - Generics - Level */ +CLI_CMD_HANDLER_DECL(cli_models_generics_level); + +/* Model Server - Generics - Default Transition Time */ +CLI_CMD_HANDLER_DECL(cli_models_generics_default_transition_time); + +/* Model Server - Generics - Power OnOff */ +CLI_CMD_HANDLER_DECL(cli_models_generics_power_onoff); + +/* Model Server - Generics - Power Level */ +CLI_CMD_HANDLER_DECL(cli_models_generics_power_level); + +/* Model Server - Generics - Battery */ +CLI_CMD_HANDLER_DECL(cli_models_generics_battery); + +/* Model Server - Generics - Location */ +CLI_CMD_HANDLER_DECL(cli_models_generics_location); + +/* Model Server - Generics - Property */ +CLI_CMD_HANDLER_DECL(cli_models_generics_property); + +/* Sensors */ +CLI_CMD_HANDLER_DECL(cli_models_sensor); + +/* Time and Scene */ +/* Time */ +CLI_CMD_HANDLER_DECL(cli_models_time); + +/* Scene */ +CLI_CMD_HANDLER_DECL(cli_models_scene); + +/* Scheduler */ +CLI_CMD_HANDLER_DECL(cli_models_scheduler); + +/* Light */ +CLI_CMD_HANDLER_DECL(cli_models_light); + +/* Model Server - Light Lightness */ +CLI_CMD_HANDLER_DECL(cli_models_light_lightness); + +/* Model Server - Light CTL */ +CLI_CMD_HANDLER_DECL(cli_models_light_ctl); + +/* Model Server - Light HSL */ +CLI_CMD_HANDLER_DECL(cli_models_light_hsl); + +/* Model Server - Light xyL */ +CLI_CMD_HANDLER_DECL(cli_models_light_xyl); + +/* Model Server - Light LC */ +CLI_CMD_HANDLER_DECL(cli_models_light_lc); + +/* Model Server - Vendor */ +CLI_CMD_HANDLER_DECL(cli_models_vendor); + +/* Model Server - Set Default Transition Time in ms */ +CLI_CMD_HANDLER_DECL(cli_models_light_lc_set_default_trans_timeout_in_ms); + +/* Reset */ +/* TODO: Shall be part of common reset called from root */ +CLI_CMD_HANDLER_DECL(cli_models_reset); + +/* Level - Model - Client */ +CLI_CMD_HANDLER_DECL(cli_modelc_config); +CLI_CMD_HANDLER_DECL(cli_modelc_health); +CLI_CMD_HANDLER_DECL(cli_modelc_generic_onoff); +CLI_CMD_HANDLER_DECL(cli_modelc_generic_level); +CLI_CMD_HANDLER_DECL(cli_modelc_generic_default_transition_time); +CLI_CMD_HANDLER_DECL(cli_modelc_generic_power_onoff); +CLI_CMD_HANDLER_DECL(cli_modelc_generic_power_level); +CLI_CMD_HANDLER_DECL(cli_modelc_generic_battery); +CLI_CMD_HANDLER_DECL(cli_modelc_generic_location); +CLI_CMD_HANDLER_DECL(cli_modelc_generic_property); +CLI_CMD_HANDLER_DECL(cli_modelc_sensor); +CLI_CMD_HANDLER_DECL(cli_modelc_time); +CLI_CMD_HANDLER_DECL(cli_modelc_scene); +CLI_CMD_HANDLER_DECL(cli_modelc_scheduler); +CLI_CMD_HANDLER_DECL(cli_modelc_light_lightness); +CLI_CMD_HANDLER_DECL(cli_modelc_light_ctl); +CLI_CMD_HANDLER_DECL(cli_modelc_light_hsl); +CLI_CMD_HANDLER_DECL(cli_modelc_light_xyl); +CLI_CMD_HANDLER_DECL(cli_modelc_light_lc); + +/* Common Utility Routines */ +void cli_cmd_stack_push(/* IN */ CLI_COMMAND* cmd_list, /* IN */ UINT16 cmd_list_len); +void cli_cmd_stack_pop(void); + +/* Module related Utility Routines */ +void cli_gatt_bearer_iface_event_pl_cb +( + UCHAR ev_name, + UCHAR ev_param +); +#endif /* _H_CLI_MAIN_ */ + diff --git a/src/components/ethermind/mesh/export/cli/cli_model.c b/src/components/ethermind/mesh/export/cli/cli_model.c new file mode 100644 index 0000000..9ff0498 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/cli_model.c @@ -0,0 +1,47 @@ + +/** + \file cli_main.c + + This File contains the "model" handlers for the CLI application, + to exercise various functionalities of the Mindtree Mesh stack. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* ------------------------------- Header File Inclusion */ +#include "cli_main.h" + +/* ------------------------------- Global Variables */ +/* Level - Model */ +DECL_CONST CLI_COMMAND cli_model_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Model Server */ + { "models", "Model Server Options", cli_model_server }, + + /* Model Client */ + { "modelc", "Model Client Options", cli_model_client }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root } + +}; + +/* ------------------------------- Functions */ +/* Model */ +API_RESULT cli_model(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_model_cmd_list, sizeof(cli_model_cmd_list) / sizeof(CLI_COMMAND)); + cli_help(argc, argv); + return API_SUCCESS; +} + diff --git a/src/components/ethermind/mesh/export/cli/cli_model_client.c b/src/components/ethermind/mesh/export/cli/cli_model_client.c new file mode 100644 index 0000000..4b56889 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/cli_model_client.c @@ -0,0 +1,97 @@ + +/** + \file cli_model_client.c + + This File contains the "model client" handlers for the CLI application, + to exercise various functionalities of the Mindtree Mesh stack. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* ------------------------------- Header File Inclusion */ +#include "cli_main.h" + +/* ------------------------------- Global Variables */ +/* Level - Model - Client */ +DECL_CONST CLI_COMMAND cli_modelc_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + #ifdef CLI_CONFIG_CLIENT_MODEL + { "config", "Config Client Operations", cli_modelc_config }, + #endif /* CLI_CONFIG_CLIENT_MODEL */ + + #ifdef CLI_HEALTH_CLIENT_MODEL + { "health", "Health Client Operations", cli_modelc_health }, + #endif /* CLI_HEALTH_CLIENT_MODEL */ + + #ifdef CLI_GENERICS_CLIENT_MODEL + #ifdef CLI_GENERICS_ONOFF_CLIENT_MODEL + { "onoff", "Generic Onoff Client Operations", cli_modelc_generic_onoff }, + #endif /* CLI_GENERICS_ONOFF_CLIENT_MODEL */ + #ifdef CLI_GENERICS_LEVEL_CLIENT_MODEL + { "level", "Generic Level Client Operations", cli_modelc_generic_level }, + #endif /* CLI_GENERICS_LEVEL_CLIENT_MODEL */ + #ifdef CLI_GENERICS_TRANSITIONTIME_CLIENT_MODEL + { "transitiontime", "Generic Default Transition Time Client Operations", cli_modelc_generic_default_transition_time }, + #endif /* CLI_GENERICS_TRANSITIONTIME_CLIENT_MODEL */ + #ifdef CLI_GENERICS_PWRONOFF_CLIENT_MODEL + { "poweronoff", "Generic Power OnOff Client Operations", cli_modelc_generic_power_onoff }, + #endif /* CLI_GENERICS_PWRONOFF_CLIENT_MODEL */ + #ifdef CLI_GENERICS_PWRLEVEL_CLIENT_MODEL + { "powerlevel", "Generic Power Level Client Operations", cli_modelc_generic_power_level }, + #endif /* CLI_GENERICS_PWRLEVEL_CLIENT_MODEL */ + #ifdef CLI_GENERICS_BATTERY_CLIENT_MODEL + { "battery", "Generic Battery Client Operations", cli_modelc_generic_battery }, + #endif /* CLI_GENERICS_BATTERY_CLIENT_MODEL */ + #ifdef CLI_GENERICS_LOCATION_CLIENT_MODEL + { "location", "Generic Location Client Operations", cli_modelc_generic_location }, + #endif /* CLI_GENERICS_LOCATION_CLIENT_MODEL */ + #ifdef CLI_GENERICS_PROPERTY_CLIENT_MODEL + { "property", "Generic Property Client Operations", cli_modelc_generic_property }, + #endif /* CLI_GENERICS_PROPERTY_CLIENT_MODEL */ + #endif /* CLI_GENERICS_CLIENT_MODEL */ + + #if (defined CLI_GENERICS_CLIENT_MODEL || defined CLI_LIGHTINGS_CLIENT_MODEL) + { "scene", "Scene Client Operations", cli_modelc_scene }, + #endif /* (defined CLI_GENERICS_CLIENT_MODEL || defined CLI_LIGHTINGS_CLIENT_MODEL) */ + + #ifdef CLI_LIGHTINGS_CLIENT_MODEL + #ifdef CLI_LIGHTINGS_LIGHTNESS_CLIENT_MODEL + { "lightness", "Light Lightness Client Operations", cli_modelc_light_lightness }, + #endif /* CLI_LIGHTINGS_LIGHTNESS_CLIENT_MODEL */ + #ifdef CLI_LIGHTINGS_CTL_CLIENT_MODEL + { "ctl", "Light CTL Client Operations", cli_modelc_light_ctl }, + #endif /* CLI_LIGHTINGS_CTL_CLIENT_MODEL */ + #ifdef CLI_LIGHTINGS_HSL_CLIENT_MODEL + { "hsl", "Light HSL Client Operations", cli_modelc_light_hsl }, + #endif /* CLI_LIGHTINGS_HSL_CLIENT_MODEL */ + #ifdef CLI_LIGHTINGS_XYL_CLIENT_MODEL + { "xyl", "Light xyL Client Operations", cli_modelc_light_xyl }, + #endif /* CLI_LIGHTINGS_XYL_CLIENT_MODEL */ + #ifdef CLI_LIGHTINGS_LC_CLIENT_MODEL + { "lc", "Light LC Client Operations", cli_modelc_light_lc }, + #endif /* CLI_LIGHTINGS_LC_CLIENT_MODEL */ + #endif /* CLI_LIGHTINGS_CLIENT_MODEL */ +}; + +/* ------------------------------- Functions */ +/* Model Client */ +API_RESULT cli_model_client(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model Client \n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_modelc_cmd_list, sizeof(cli_modelc_cmd_list) / sizeof(CLI_COMMAND)); + cli_help(argc, argv); + return API_SUCCESS; +} + diff --git a/src/components/ethermind/mesh/export/cli/cli_model_server.c b/src/components/ethermind/mesh/export/cli/cli_model_server.c new file mode 100644 index 0000000..81cc768 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/cli_model_server.c @@ -0,0 +1,519 @@ + +/** + \file cli_model_server.c + + This File contains the "model server" handlers for the CLI application, + to exercise various functionalities of the Mindtree Mesh stack. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* ------------------------------- Header File Inclusion */ +#include "cli_main.h" + +/* Model server application entry point */ +void main_generic_battery_server_operations(/* IN */ UINT8 have_menu); +void main_generic_default_transition_time_server_operations(/* IN */ UINT8 have_menu); +void main_generic_level_server_operations(/* IN */ UINT8 have_menu); +void main_generic_location_server_operations(/* IN */ UINT8 have_menu); +void main_generic_onoff_server_operations(/* IN */ UINT8 have_menu); +void main_generic_power_level_server_operations(/* IN */ UINT8 have_menu); +void main_generic_power_onoff_server_operations(/* IN */ UINT8 have_menu); +void main_generic_property_server_operations(/* IN */ UINT8 have_menu); +void main_health_server_operations(/* IN */ UINT8 have_menu); +API_RESULT main_health_server_log_fault +( + /* IN */ UINT8 test_id, + /* IN */ UINT8 fault +); +void main_light_ctl_server_operations(/* IN */ UINT8 have_menu); +void main_light_hsl_server_operations(/* IN */ UINT8 have_menu); +void main_light_lc_server_operations(/* IN */ UINT8 have_menu); +void main_light_lightness_server_operations(/* IN */ UINT8 have_menu); +void main_light_xyl_server_operations(/* IN */ UINT8 have_menu); +void main_scene_server_operations(/* IN */ UINT8 have_menu); +API_RESULT appl_model_light_lc_server_set_default_trans_timeout_in_ms(/* IN */ UINT32 time_in_ms); + +/* ------------------------------- Global Variables */ +/* Level - Model - Server */ +DECL_CONST CLI_COMMAND cli_models_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + /* Reset */ + { "reset", "Emulate Reset", cli_models_reset }, + + /* Foundation Model Setup */ + { "foundation", "Foundation Server Models Initialization", cli_models_foundation }, + + #ifdef CLI_HEALTH_SERVER_MODEL + /* Health Server Model Setup */ + { "health", "Health Server Options", cli_models_health }, + #endif /* CLI_HEALTH_SERVER_MODEL */ + + #ifdef CLI_GENERICS_SERVER_MODEL + /* Generics */ + { "generics", "Generic Server Options", cli_models_generics }, + #endif /* CLI_GENERICS_SERVER_MODEL */ + + #if (defined CLI_GENERICS_SERVER_MODEL || defined CLI_LIGHTINGS_SERVER_MODEL) + /* Scene */ + { "scene", "Scene Server Model Initialization", cli_models_scene }, + #endif /* (defined CLI_GENERICS_SERVER_MODEL || defined CLI_LIGHTINGS_SERVER_MODEL) */ + + #ifdef CLI_LIGHTINGS_SERVER_MODEL + /* Light */ + { "light", "Light Server Options", cli_models_light }, + #endif /* CLI_LIGHTINGS_SERVER_MODEL */ + + #ifdef HAVE_VENDOR_MODEL_EXAMPLE_1 + /* Vendor Specific */ + { "vendor", "Vendor Specific", cli_models_vendor }, + #endif /* HAVE_VENDOR_MODEL_EXAMPLE_1 */ +}; + +#ifdef CLI_HEALTH_SERVER_MODEL +/* Level - Model = Server - Health */ +DECL_CONST CLI_COMMAND cli_models_health_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + /* Model Server - Health - Log Fault */ + { "logfault", "Log Fault Values", cli_models_health_log_fault }, + + /* Health - TODO: Temporary till model publication period is triggered */ + { "publishstatus", "Publish Health status", cli_health_status_publish } +}; +#endif /* CLI_HEALTH_SERVER_MODEL */ + +#ifdef CLI_GENERICS_SERVER_MODEL +/* Level - Model = Server - Generics */ +DECL_CONST CLI_COMMAND cli_models_generics_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + #ifdef CLI_GENERICS_ONOFF_SERVER_MODEL + /* Model Server - Generics - OnOff */ + { "onoff", "OnOff Server Model Initialization", cli_models_generics_onoff }, + #endif /* CLI_GENERICS_ONOFF_SERVER_MODEL */ + + #ifdef CLI_GENERICS_LEVEL_SERVER_MODEL + /* Model Server - Generics - Level */ + { "level", "Level Server Model Initialization", cli_models_generics_level }, + #endif /* CLI_GENERICS_LEVEL_SERVER_MODEL */ + + #ifdef CLI_GENERICS_TRANSITIONTIME_SERVER_MODEL + /* Model Server - Generics - Default Transition Time */ + { "transitiontime", "Default Transition Time Server Model Initialization", cli_models_generics_default_transition_time }, + #endif /* CLI_GENERICS_TRANSITIONTIME_SERVER_MODEL */ + + #ifdef CLI_GENERICS_PWRONOFF_SERVER_MODEL + /* Model Server - Generics - Power OnOff */ + { "poweronoff", "Power OnOff Server Model Initialization", cli_models_generics_power_onoff }, + #endif /* CLI_GENERICS_PWRONOFF_SERVER_MODEL */ + + #ifdef CLI_GENERICS_PWRLEVEL_SERVER_MODEL + /* Model Server - Generics - Power Level */ + { "powerlevel", "Power Level Server Model Initialization", cli_models_generics_power_level }, + #endif /* CLI_GENERICS_PWRLEVEL_SERVER_MODEL */ + + #ifdef CLI_GENERICS_BATTERY_SERVER_MODEL + /* Model Server - Generics - Battery */ + { "battery", "Battery Server Model Initialization", cli_models_generics_battery }, + #endif /* CLI_GENERICS_BATTERY_SERVER_MODEL */ + + #ifdef CLI_GENERICS_LOCATION_SERVER_MODEL + /* Model Server - Generics - Location */ + { "location", "Location Server Model Initialization", cli_models_generics_location }, + #endif /* CLI_GENERICS_LOCATION_SERVER_MODEL */ + + #ifdef CLI_GENERICS_PROPERTY_SERVER_MODEL + /* Model Server - Generics - Property */ + { "property", "Property Server Model Initialization", cli_models_generics_property }, + #endif /* CLI_GENERICS_PROPERTY_SERVER_MODEL */ +}; +#endif /* CLI_GENERICS_SERVER_MODEL */ + +#ifdef CLI_LIGHTINGS_SERVER_MODEL +/* Level - Model = Server - Light */ +DECL_CONST CLI_COMMAND cli_models_light_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + #ifdef CLI_LIGHTINGS_LIGHTNESS_SERVER_MODEL + /* Model Server - Light Lightness */ + { "lightness", "Lightness Server Model Initialization", cli_models_light_lightness }, + #endif /* CLI_LIGHTINGS_LIGHTNESS_SERVER_MODEL */ + + #ifdef CLI_LIGHTINGS_CTL_SERVER_MODEL + /* Model Server - Light CTL */ + { "ctl", "CTL Server Model Initialization", cli_models_light_ctl }, + #endif /* CLI_LIGHTINGS_CTL_SERVER_MODEL */ + + #ifdef CLI_LIGHTINGS_HSL_SERVER_MODEL + /* Model Server - Light HSL */ + { "hsl", "HSL Server Model Initialization", cli_models_light_hsl }, + #endif /* CLI_LIGHTINGS_HSL_SERVER_MODEL */ + + #ifdef CLI_LIGHTINGS_XYL_SERVER_MODEL + /* Model Server - Light xyL */ + { "xyl", "xyL Server Model Initialization", cli_models_light_xyl }, + #endif /* CLI_LIGHTINGS_XYL_SERVER_MODEL */ + + #ifdef CLI_LIGHTINGS_LC_SERVER_MODEL + /* Model Server - Light LC */ + { "lc", "LC Server Model Initialization", cli_models_light_lc }, + + /* Model Server - Set Default Transition Time in ms */ + { "lcsettranstime", "LC Set Default Transition time in ms", cli_models_light_lc_set_default_trans_timeout_in_ms} + #endif /* CLI_LIGHTINGS_LC_SERVER_MODEL */ +}; +#endif /* CLI_LIGHTINGS_SERVER_MODEL */ + +/* ------------------------------- Functions */ +/* Model Server */ +API_RESULT cli_model_server(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model Server\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_models_cmd_list, sizeof(cli_models_cmd_list) / sizeof(CLI_COMMAND)); + cli_help(argc, argv); + return API_SUCCESS; +} + +/* Model Server - Foundation Models */ + +#ifndef HSL_DONT_USE_MULTI_ELEMENTS + /* Two additional elements are registerd for HSL Server */ + MS_ACCESS_ELEMENT_HANDLE sec_element_handle; + MS_ACCESS_ELEMENT_HANDLE ter_element_handle; +#endif /* HSL_DONT_USE_MULTI_ELEMENTS */ + +API_RESULT cli_models_foundation(UINT32 argc, UCHAR* argv[]) +{ + MS_ACCESS_NODE_ID node_id; + MS_ACCESS_ELEMENT_DESC element; + MS_ACCESS_ELEMENT_HANDLE element_handle; + MS_ACCESS_MODEL_HANDLE config_server_model_handle; + API_RESULT retval; + CONSOLE_OUT("In Model Server - Foundation Models\n"); + /* Create Node */ + retval = MS_access_create_node(&node_id); + /* Register Element */ + /** + TBD: Define GATT Namespace Descriptions from + https://www.bluetooth.com/specifications/assigned-numbers/gatt-namespace-descriptors + + Using 'main' (0x0106) as Location temporarily. + */ + element.loc = 0x0106; + retval = MS_access_register_element + ( + node_id, + &element, + &element_handle + ); + #ifdef CLI_CONFIG_SERVER_MODEL + + if (API_SUCCESS == retval) + { + retval = MS_config_server_init(element_handle, &config_server_model_handle); + } + + #endif /* CLI_CONFIG_SERVER_MODEL */ + CONSOLE_OUT("Model Registration Status: 0x%04X\n", retval); + #ifdef CLI_HEALTH_SERVER_MODEL + /* Health Server */ + main_health_server_operations(MS_FALSE); + #endif /* CLI_HEALTH_SERVER_MODEL */ + #ifndef HSL_DONT_USE_MULTI_ELEMENTS + /* Two additional elements are registerd for HSL Server */ + retval = MS_access_register_element + ( + node_id, + &element, + &sec_element_handle + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT("Secondary Element Handle Registered @: 0x%04X\n", sec_element_handle); + } + + retval = MS_access_register_element + ( + node_id, + &element, + &ter_element_handle + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT("Tertiary Element Handle Registered @: 0x%04X\n", ter_element_handle); + } + + #endif /* HSL_DONT_USE_MULTI_ELEMENTS */ + (void) config_server_model_handle; + return API_SUCCESS; +} + +#ifdef CLI_HEALTH_SERVER_MODEL +/* Model Server - Health */ +API_RESULT cli_models_health(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model Server - Health\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_models_health_cmd_list, sizeof(cli_models_health_cmd_list) / sizeof(CLI_COMMAND)); + cli_help(argc, argv); + return API_SUCCESS; +} + +/* Model Server - Health - Log Fault */ +API_RESULT cli_models_health_log_fault(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + UINT8 test_id, fault; + CONSOLE_OUT("In Model Server - Health - Log Fault\n"); + retval = API_FAILURE; + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + test_id = (UINT8)choice; + CONSOLE_OUT("Test ID (8-bit in HEX): 0x%02X\n", test_id); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + fault = (UINT8)choice; + CONSOLE_OUT("Fault Value (8-bit in HEX): 0x%02X\n", fault); + retval = main_health_server_log_fault(test_id, fault); + } + else + { + CONSOLE_OUT("Usage: logfault \n"); + retval = API_FAILURE; + } + + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Health - TODO: Temporary till model publication period is triggered */ +API_RESULT cli_health_status_publish(UINT32 argc, UCHAR* argv[]) +{ + UCHAR current_status[4] = { 0x00, 0x6A, 0x00, 0x00 }; + + if (1 != argc) + { + CONSOLE_OUT("Usage: publishstatus \n"); + return API_FAILURE; + } + + current_status[0] = (UCHAR)CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + return MS_health_server_publish_current_status(current_status, sizeof(current_status)); +} +#endif /* CLI_HEALTH_SERVER_MODEL */ + +#ifdef CLI_GENERICS_SERVER_MODEL +/* Model Server - Generics */ +API_RESULT cli_models_generics(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model Server - Generics\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_models_generics_cmd_list, sizeof(cli_models_generics_cmd_list) / sizeof(CLI_COMMAND)); + cli_help(argc, argv); + return API_SUCCESS; +} + +/* Model Server - Generics - OnOff */ +API_RESULT cli_models_generics_onoff(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model Server - Generics - OnOff\n"); + main_generic_onoff_server_operations(MS_FALSE); + return API_SUCCESS; +} + +/* Model Server - Generics - Level */ +API_RESULT cli_models_generics_level(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model Server - Generics - Level\n"); + main_generic_level_server_operations(MS_FALSE); + return API_SUCCESS; +} + +/* Model Server - Generics - Default Transition Time */ +API_RESULT cli_models_generics_default_transition_time(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model Server - Generics - Default Transition Time\n"); + main_generic_default_transition_time_server_operations(MS_FALSE); + return API_SUCCESS; +} + +/* Model Server - Generics - Power OnOff */ +API_RESULT cli_models_generics_power_onoff(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model Server - Generics - Power OnOff\n"); + main_generic_power_onoff_server_operations(MS_FALSE); + return API_SUCCESS; +} + +/* Model Server - Generics - Power Level */ +API_RESULT cli_models_generics_power_level(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model Server - Generics - Power Level\n"); + main_generic_power_level_server_operations(MS_FALSE); + return API_SUCCESS; +} + +/* Model Server - Generics - Battery */ +API_RESULT cli_models_generics_battery(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model Server - Generics - Battery\n"); + main_generic_battery_server_operations(MS_FALSE); + return API_SUCCESS; +} + +/* Model Server - Generics - Location */ +API_RESULT cli_models_generics_location(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model Server - Generics - Location\n"); + main_generic_location_server_operations(MS_FALSE); + return API_SUCCESS; +} + +/* Model Server - Generics - Property */ +API_RESULT cli_models_generics_property(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model Server - Generics - Property\n"); + main_generic_property_server_operations(MS_FALSE); + return API_SUCCESS; +} +#endif /* CLI_GENERICS_SERVER_MODEL */ + +#if (defined CLI_GENERICS_SERVER_MODEL || defined CLI_LIGHTINGS_SERVER_MODEL) +/* Model Server - Time and Scene */ +/* Model Server - Scene */ +API_RESULT cli_models_scene(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model Server - Scene\n"); + main_scene_server_operations(MS_FALSE); + return API_SUCCESS; +} +#endif /* (defined CLI_GENERICS_SERVER_MODEL || defined CLI_LIGHTINGS_SERVER_MODEL) */ + +#ifdef CLI_LIGHTINGS_SERVER_MODEL +/* Model Server - Light */ +API_RESULT cli_models_light(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model Server - Light\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_models_light_cmd_list, sizeof(cli_models_light_cmd_list) / sizeof(CLI_COMMAND)); + cli_help(argc, argv); + return API_SUCCESS; +} + +/* Model Server - Light Lightness */ +API_RESULT cli_models_light_lightness(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model Server - Light - Lightness\n"); + main_light_lightness_server_operations(MS_FALSE); + return API_SUCCESS; +} + +/* Model Server - Light CTL */ +API_RESULT cli_models_light_ctl(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model Server - Light - CTL\n"); + main_light_ctl_server_operations(MS_FALSE); + return API_SUCCESS; +} + +/* Model Server - Light HSL */ +API_RESULT cli_models_light_hsl(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model Server - Light - HSL\n"); + main_light_hsl_server_operations(MS_FALSE); + return API_SUCCESS; +} + +/* Model Server - Light xyL */ +API_RESULT cli_models_light_xyl(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model Server - Light - xyL\n"); + main_light_xyl_server_operations(MS_FALSE); + return API_SUCCESS; +} + +/* Model Server - Light LC */ +API_RESULT cli_models_light_lc(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model Server - Light - LC\n"); + main_light_lc_server_operations(MS_FALSE); + return API_SUCCESS; +} + +/* Model Server - Set Default Transition Time in ms */ +API_RESULT cli_models_light_lc_set_default_trans_timeout_in_ms(UINT32 argc, UCHAR* argv[]) +{ + UINT32 time_in_ms; + CONSOLE_OUT("In Model Server - Light - LC - Set Default Timeout in ms\n"); + CONSOLE_OUT("In Core Provision Setup\n"); + + if (1 != argc) + { + CONSOLE_OUT("Usage: lcsettranstime \n"); + return API_FAILURE; + } + + time_in_ms = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + appl_model_light_lc_server_set_default_trans_timeout_in_ms(time_in_ms); + return API_SUCCESS; +} +#endif /* CLI_LIGHTINGS_SERVER_MODEL */ + +#ifdef HAVE_VENDOR_MODEL_EXAMPLE_1 +/* Model Server - Vendor Example 1 */ +API_RESULT cli_models_vendor(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model Server - Vendor\n"); + main_vendor_example_1_server_operations(MS_FALSE); + return API_SUCCESS; +} +#endif /* HAVE_VENDOR_MODEL_EXAMPLE_1 */ + +/* Reset */ +/* TODO: Shall be part of common reset called from root */ +API_RESULT cli_models_reset(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Model Server - calling RESET\n"); + appl_model_power_cycle(); + return API_SUCCESS; +} + diff --git a/src/components/ethermind/mesh/export/cli/cli_ps.c b/src/components/ethermind/mesh/export/cli/cli_ps.c new file mode 100644 index 0000000..05d1e37 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/cli_ps.c @@ -0,0 +1,185 @@ + +/** + \file cli_ps.c + + This File contains the "Persistent Storage" handlers for the CLI application, + to exercise various functionalities of the Mindtree Mesh stack. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +/* ------------------------------- Header File Inclusion */ +#include "cli_main.h" + +/* ------------------------------- Global Variables */ +/* Level - Persistent Storage */ +DECL_STATIC CLI_COMMAND cli_ps_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Get Device Key */ + { "getdevkey", "Get Device Key", cli_ps_get_device_key }, + + /* Get App Key */ + { "getappkey", "Get App Key", cli_ps_get_app_key }, + + /* Get Network Key */ + { "getnetkey", "Get Network Key", cli_ps_get_net_key }, + + /* Get Primary Unicast Address */ + { "getprimunicastaddr", "Get Primary Unicast Address", cli_ps_get_primary_unicast_addr }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root } + +}; + +/* ------------------------------- Functions */ +/* Persistent Storage */ +API_RESULT cli_ps(UINT32 argc, UCHAR* argv[]) +{ + CONSOLE_OUT("In Persistent Storage\n"); + cli_cmd_stack_push(cli_ps_cmd_list, sizeof(cli_ps_cmd_list) / sizeof(CLI_COMMAND)); + cli_help(argc, argv); + return API_SUCCESS; +} + +/* Get Device Key */ +API_RESULT cli_ps_get_device_key(UINT32 argc, UCHAR* argv[]) +{ + UINT8 index; + UINT8* key; + API_RESULT retval; + CONSOLE_OUT("In PS Get Device Key\n"); + + if (1 != argc) + { + CONSOLE_OUT("Usage: getdevkey \n"); + return API_FAILURE; + } + + index = (UINT8)CLI_strtoi(argv[0], (UINT8)CLI_strlen(argv[0]), 16); + retval = MS_access_cm_get_device_key + ( + index, + &key + ); + + /* Check Retval. Print Device Key */ + if (API_SUCCESS == retval) + { + CONSOLE_OUT("Device Key[0x%02X]: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + index, key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7], + key[8], key[9], key[10], key[11], key[12], key[13], key[14], key[15]); + } + else + { + CONSOLE_OUT("FAILED. Reason: 0x%04X\n", retval); + } + + return API_SUCCESS; +} + +/* Get App Key */ +API_RESULT cli_ps_get_app_key(UINT32 argc, UCHAR* argv[]) +{ + MS_APPKEY_HANDLE handle; + UINT8* key; + UINT8 aid; + API_RESULT retval; + CONSOLE_OUT("In PS Get App Key\n"); + + if (1 != argc) + { + CONSOLE_OUT("Usage: getappkey \n"); + return API_FAILURE; + } + + handle = (MS_APPKEY_HANDLE)CLI_strtoi(argv[0], (UINT16)CLI_strlen(argv[0]), 16); + retval = MS_access_cm_get_app_key + ( + handle, + &key, + &aid + ); + + /* Check Retval. Print App Key */ + if (API_SUCCESS == retval) + { + CONSOLE_OUT("App Key[0x%02X]: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + handle, key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7], + key[8], key[9], key[10], key[11], key[12], key[13], key[14], key[15]); + } + else + { + CONSOLE_OUT("FAILED. Reason: 0x%04X\n", retval); + } + + return API_SUCCESS; +} + +/* Get Network Key */ +API_RESULT cli_ps_get_net_key(UINT32 argc, UCHAR* argv[]) +{ + MS_SUBNET_HANDLE handle; + UINT8 key[16]; + API_RESULT retval; + CONSOLE_OUT("In PS Get Network Key\n"); + + if (1 != argc) + { + CONSOLE_OUT("Usage: getnetkey \n"); + return API_FAILURE; + } + + handle = (MS_SUBNET_HANDLE)CLI_strtoi(argv[0], (UINT16)CLI_strlen(argv[0]), 16); + retval = MS_access_cm_get_netkey_at_offset + ( + handle, + 0, + key + ); + + /* Check Retval. Print Network Key */ + if (API_SUCCESS == retval) + { + CONSOLE_OUT("Net Key[0x%02X]: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + handle, key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7], + key[8], key[9], key[10], key[11], key[12], key[13], key[14], key[15]); + } + else + { + CONSOLE_OUT("FAILED. Reason: 0x%04X\n", retval); + } + + return API_SUCCESS; +} + +/* Get Primary Unicast Address */ +API_RESULT cli_ps_get_primary_unicast_addr(UINT32 argc, UCHAR* argv[]) +{ + MS_NET_ADDR addr; + API_RESULT retval; + CONSOLE_OUT("In PS Get Primary Unicast Address\n"); + retval = MS_access_cm_get_primary_unicast_address(&addr); + + /* Check Retval. Print Primary Unicast Address */ + if (API_SUCCESS == retval) + { + CONSOLE_OUT("Primary Unicast Address: 0x%04X\n", addr); + } + else + { + CONSOLE_OUT("FAILED. Reason: 0x%04X\n", retval); + } + + return API_SUCCESS; +} + diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_config_client.c b/src/components/ethermind/mesh/export/cli/model/client/cli_config_client.c new file mode 100644 index 0000000..6e4d617 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_config_client.c @@ -0,0 +1,2126 @@ +/** + \file cli_config_client.c + + \brief This file defines the Mesh Configuration Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "cli_config_client.h" + +#ifdef CLI_CONFIG_CLIENT_MODEL + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +DECL_CONST CLI_COMMAND cli_modelc_configuration_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + /* Setup */ + { "setup", "Model Configuration Setup", cli_modelc_configuration_setup }, + + /* Get Model Handle */ + { "gethandle", "Get Model Handle", cli_modelc_configuration_get_model_handle }, + + /* Set Publish Address */ + { "publishaddr", "Set Publish Address ", cli_modelc_configuration_set_publish_address }, + + /* Send Config Beacon Set */ + { "beaconset", "Send Config Beacon Set", cli_modelc_config_beacon_set}, + + /* Send Config Beacon Get */ + { "beaconget", "Send Config Beacon Get", cli_modelc_config_beacon_get}, + + /* Send Config Composition Data Get */ + { "compositiondataget", "Send Config Composition Data Get", cli_modelc_config_composition_data_get}, + + /* Send Config Default Ttl Set */ + { "defaultttlset", "Send Config Default Ttl Set", cli_modelc_config_default_ttl_set}, + + /* Send Config Default Ttl Get */ + { "defaultttlget", "Send Config Default Ttl Get", cli_modelc_config_default_ttl_get}, + + /* Send Config Gatt Proxy Set */ + { "proxyset", "Send Config Gatt Proxy Set", cli_modelc_config_gatt_proxy_set}, + + /* Send Config Gatt Proxy Get */ + { "proxyget", "Send Config Gatt Proxy Get", cli_modelc_config_gatt_proxy_get}, + + /* Send Config Friend Set */ + { "friendset", "Send Config Friend Set", cli_modelc_config_friend_set}, + + /* Send Config Friend Get */ + { "friendget", "Send Config Friend Get", cli_modelc_config_friend_get}, + + /* Send Config Relay Set */ + { "relayset", "Send Config Relay Set", cli_modelc_config_relay_set}, + + /* Send Config Relay Get */ + { "relayget", "Send Config Relay Get", cli_modelc_config_relay_get}, + + /* Send Config Model Publication Set */ + { "modelpublicationset", "Send Config Model Publication Set", cli_modelc_config_model_publication_set}, + + /* Send Config Model Publication Virtual Address Set */ + { "modelpublicationvirtualaddressset", "Send Config Model Publication Virtual Address Set", cli_modelc_config_model_publication_virtual_address_set}, + + /* Send Config Model Publication Get */ + { "modelpublicationget", "Send Config Model Publication Get", cli_modelc_config_model_publication_get}, + + /* Send Config Model Subscription Add */ + { "modelsubscriptionadd", "Send Config Model Subscription Add", cli_modelc_config_model_subscription_add}, + + /* Send Config Model Subscription Virtual Address Add */ + { "modelsubscriptionvirtualaddressadd", "Send Config Model Subscription Virtual Address Add", cli_modelc_config_model_subscription_virtual_address_add}, + + /* Send Config Model Subscription Overwrite */ + { "modelsubscriptionoverwrite", "Send Config Model Subscription Overwrite", cli_modelc_config_model_subscription_overwrite}, + + /* Send Config Model Subscription Virtual Address Overwrite */ + { "modelsubscriptionvirtualaddressoverwrite", "Send Config Model Subscription Virtual Address Overwrite", cli_modelc_config_model_subscription_virtual_address_overwrite}, + + /* Send Config Model Subscription Delete */ + { "modelsubscriptiondelete", "Send Config Model Subscription Delete", cli_modelc_config_model_subscription_delete}, + + /* Send Config Model Subscription Virtual Address Delete */ + { "modelsubscriptionvirtualaddressdelete", "Send Config Model Subscription Virtual Address Delete", cli_modelc_config_model_subscription_virtual_address_delete}, + + /* Send Config Model Subscription Delete All */ + { "modelsubscriptiondeleteall", "Send Config Model Subscription Delete All", cli_modelc_config_model_subscription_delete_all}, + + /* Send Config Sig Model Subscription Get */ + { "sigmodelsubscriptionget", "Send Config Sig Model Subscription Get", cli_modelc_config_sig_model_subscription_get}, + + /* Send Config Vendor Model Subscription Get */ + { "vendormodelsubscriptionget", "Send Config Vendor Model Subscription Get", cli_modelc_config_vendor_model_subscription_get}, + + /* Send Config Netkey Add */ + { "netkeyadd", "Send Config Netkey Add", cli_modelc_config_netkey_add}, + + /* Send Config Netkey Update */ + { "netkeyupdate", "Send Config Netkey Update", cli_modelc_config_netkey_update}, + + /* Send Config Netkey Delete */ + { "netkeydelete", "Send Config Netkey Delete", cli_modelc_config_netkey_delete}, + + /* Send Config Netkey Get */ + { "netkeyget", "Send Config Netkey Get", cli_modelc_config_netkey_get}, + + /* Send Config Appkey Add */ + { "appkeyadd", "Send Config Appkey Add", cli_modelc_config_appkey_add}, + + /* Send Config Appkey Update */ + { "appkeyupdate", "Send Config Appkey Update", cli_modelc_config_appkey_update}, + + /* Send Config Appkey Delete */ + { "appkeydelete", "Send Config Appkey Delete", cli_modelc_config_appkey_delete}, + + /* Send Config Appkey Get */ + { "appkeyget", "Send Config Appkey Get", cli_modelc_config_appkey_get}, + + /* Send Config Model App Bind */ + { "bind", "Send Config Model App Bind", cli_modelc_config_model_app_bind}, + + /* Send Config Model App Unbind */ + { "unbind", "Send Config Model App Unbind", cli_modelc_config_model_app_unbind}, + + /* Send Config Sig Model App Get */ + { "sigmodelappget", "Send Config Sig Model App Get", cli_modelc_config_sig_model_app_get}, + + /* Send Config Vendor Model App Get */ + { "vendormodelappget", "Send Config Vendor Model App Get", cli_modelc_config_vendor_model_app_get}, + + /* Send Config Node Identity Set */ + { "nodeidentityset", "Send Config Node Identity Set", cli_modelc_config_node_identity_set}, + + /* Send Config Node Identity Get */ + { "nodeidentityget", "Send Config Node Identity Get", cli_modelc_config_node_identity_get}, + + /* Send Config Node Reset */ + { "nodereset", "Send Config Node Reset", cli_modelc_config_node_reset}, + + /* Send Config Heartbeat Publication Set */ + { "heartbeatpublicationset", "Send Config Heartbeat Publication Set", cli_modelc_config_heartbeat_publication_set}, + + /* Send Config Heartbeat Publication Get */ + { "heartbeatpublicationget", "Send Config Heartbeat Publication Get", cli_modelc_config_heartbeat_publication_get}, + + /* Send Config Heartbeat Subscription Set */ + { "heartbeatsubscriptionset", "Send Config Heartbeat Subscription Set", cli_modelc_config_heartbeat_subscription_set}, + + /* Send Config Heartbeat Subscription Get */ + { "heartbeatsubscriptionget", "Send Config Heartbeat Subscription Get", cli_modelc_config_heartbeat_subscription_get}, + + /* Send Config Network Transmit Set */ + { "networktransmitset", "Send Config Network Transmit Set", cli_modelc_config_network_transmit_set}, + + /* Send Config Network Transmit Get */ + { "networktransmitget", "Send Config Network Transmit Get", cli_modelc_config_network_transmit_get}, + + /* Send Config Low Power Node Polltimeout Get */ + { "lpnpolltimeoutget", "Send Config Low Power Node Polltimeout Get", cli_modelc_config_low_power_node_polltimeout_get}, + + /* Send Config Key Refresh Phase Set */ + { "keyrefreshphaseset", "Send Config Key Refresh Phase Set", cli_modelc_config_key_refresh_phase_set}, + + /* Send Config Key Refresh Phase Get */ + { "keyrefreshphaseget", "Send Config Key Refresh Phase Get", cli_modelc_config_key_refresh_phase_get}, + +}; + + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_configuration_client_model_handle; + + +/* --------------------------------------------- Function */ +API_RESULT cli_modelc_config(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT("In Model Client - Configuration\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_modelc_configuration_cmd_list, sizeof(cli_modelc_configuration_cmd_list) / sizeof(CLI_COMMAND)); + retval = cli_help(argc, argv); + return retval; +} + +/* configuration client CLI entry point */ +API_RESULT cli_modelc_configuration_setup(UINT32 argc, UCHAR* argv[]) +{ + int choice; + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + static UCHAR model_initialized = 0x00; + /** + Register with Access Layer. + */ + retval = API_FAILURE; + + if (0x00 == model_initialized) + { + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_config_client_init + ( + element_handle, + &appl_configuration_client_model_handle, + appl_configuration_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Configuration Client Initialized. Model Handle: 0x%04X\n", + appl_configuration_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Configuration Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + return retval; +} + +/* Send Config Model App Unbind */ +API_RESULT cli_modelc_config_model_app_unbind(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODEL_APP_UNBIND_PARAM param; + CONSOLE_OUT + (">> Send Config Model App Unbind\n"); + + if (4 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.element_address = (UINT16)choice; + CONSOLE_OUT("ElementAddress (16-bit in HEX): 0x%04X\n", param.element_address); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKeyIndex (16-bit in HEX): 0x%04X\n", param.appkey_index); + + if (4 < CLI_strlen(argv[2])) + { + CONSOLE_OUT("Model ID Type: Vendor\n"); + param.model.type = 0x01; + } + else + { + CONSOLE_OUT("Model ID Type: SIG\n"); + param.model.type = 0x00; + } + + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.model.id = (UINT32)choice; + CONSOLE_OUT("ModelIdentifier: 0x%08X\n", param.model.id); + + /* Corresponding Local Model ID */ + if (4 < CLI_strlen(argv[3])) + { + param.client_model.type = 0x01; + CONSOLE_OUT("Model ID Type: Vendor\n"); + } + else + { + param.client_model.type = 0x00; + CONSOLE_OUT("Model ID Type: SIG\n"); + } + + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.client_model.id = (UINT32)choice; + CONSOLE_OUT("Local ModelIdentifier: 0x%08X\n", param.client_model.id); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + CONSOLE_OUT("Usage: unbind \n"); + return API_FAILURE; + } + + retval = MS_config_client_model_app_unbind(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Friend Get */ +API_RESULT cli_modelc_config_friend_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Config Friend Get\n"); + retval = MS_config_client_friend_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Gatt Proxy Get */ +API_RESULT cli_modelc_config_gatt_proxy_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Config Gatt Proxy Get\n"); + retval = MS_config_client_gatt_proxy_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Model Subscription Virtual Address Overwrite */ +API_RESULT cli_modelc_config_model_subscription_virtual_address_overwrite(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODELSUB_VADDR_OVERWRITE_PARAM param; + CONSOLE_OUT + (">> Send Config Model Subscription Virtual Address Overwrite\n"); + + if (3 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.element_address = (UINT16)choice; + CONSOLE_OUT("ElementAddress (16-bit in HEX): 0x%04X\n", param.element_address); + CLI_strtoarray + ( + argv[1], + CLI_strlen(argv[1]), + ¶m.label[0], + 16 + ); + + if (4 < CLI_strlen(argv[2])) + { + param.model.type = 0x01; + CONSOLE_OUT("Model ID Type: Vendor\n"); + } + else + { + param.model.type = 0x00; + CONSOLE_OUT("Model ID Type: SIG\n"); + } + + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.model.id = (UINT32)choice; + CONSOLE_OUT("ModelIdentifier: 0x%08X\n", param.model.id); + } + + retval = MS_config_client_model_subscription_vaddr_overwrite(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Sig Model App Get */ +API_RESULT cli_modelc_config_sig_model_app_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_SIG_MODEL_APP_GET_PARAM param; + CONSOLE_OUT + (">> Send Config Sig Model App Get\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[1], CLI_strlen(argv[0]), 16); + param.element_address = (UINT16)choice; + CONSOLE_OUT("ElementAddress (16-bit in HEX): 0x%04X\n", param.element_address); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.model_id = (UINT16)choice; + CONSOLE_OUT("ModelIdentifier (16-bit in HEX): 0x%04X\n", param.model_id); + } + + retval = MS_config_client_sig_model_app_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Model Subscription Add */ +API_RESULT cli_modelc_config_model_subscription_add(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODELSUB_ADD_PARAM param; + CONSOLE_OUT + (">> Send Config Model Subscription Add\n"); + + if (3 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.element_address = (UINT16)choice; + CONSOLE_OUT("ElementAddress (16-bit in HEX): 0x%04X\n", param.element_address); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.address = (UINT16)choice; + CONSOLE_OUT("Address (16-bit in HEX): 0x%04X\n", param.address); + + if (4 < CLI_strlen(argv[2])) + { + param.model.type = 0x01; + CONSOLE_OUT("Model ID Type: Vendor\n"); + } + else + { + param.model.type = 0x00; + CONSOLE_OUT("Model ID Type: SIG\n"); + } + + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.model.id = (UINT32)choice; + CONSOLE_OUT("ModelIdentifier: 0x%08X\n", param.model.id); + } + + retval = MS_config_client_model_subscription_add(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Network Transmit Set */ +API_RESULT cli_modelc_config_network_transmit_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_NETWORK_TRANSMIT_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Network Transmit Set\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.net_tx_count = (UCHAR)choice; + CONSOLE_OUT("NetWork Transmit Count (5-bit in HEX): 0x%02X\n", param.net_tx_count); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.net_tx_interval_steps = (UCHAR)choice; + CONSOLE_OUT("NetWork Transmit Interval Steps (3-bit in HEX): 0x%02X\n", param.net_tx_interval_steps); + } + + retval = MS_config_client_network_transmit_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Model Subscription Delete */ +API_RESULT cli_modelc_config_model_subscription_delete(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODELSUB_DEL_PARAM param; + CONSOLE_OUT + (">> Send Config Model Subscription Delete\n"); + + if (3 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.element_address = (UINT16)choice; + CONSOLE_OUT("ElementAddress (16-bit in HEX): 0x%04X\n", param.element_address); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.address = (UINT16)choice; + CONSOLE_OUT("Address (16-bit in HEX): 0x%04X\n", param.address); + + if (4 < CLI_strlen(argv[2])) + { + param.model.type = 0x01; + CONSOLE_OUT("Model ID Type: Vendor\n"); + } + else + { + param.model.type = 0x00; + CONSOLE_OUT("Model ID Type: SIG\n"); + } + + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.model.id = (UINT32)choice; + CONSOLE_OUT("ModelIdentifier: 0x%08X\n", param.model.id); + } + + retval = MS_config_client_model_subscription_delete(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Relay Get */ +API_RESULT cli_modelc_config_relay_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Config Relay Get\n"); + retval = MS_config_client_relay_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Heartbeat Subscription Set */ +API_RESULT cli_modelc_config_heartbeat_subscription_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_HEARTBEATSUB_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Heartbeat Subscription Set\n"); + + if (3 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.source = (UINT16)choice; + CONSOLE_OUT("Source (16-bit in HEX): 0x%04X\n", param.source); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.destination = (UINT16)choice; + CONSOLE_OUT("Destination (16-bit in HEX): 0x%04X\n", param.destination); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.periodlog = (UCHAR)choice; + CONSOLE_OUT("PeriodLog (8-bit in HEX): 0x%02X\n", param.periodlog); + } + + retval = MS_config_client_heartbeat_subscription_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Beacon Set */ +API_RESULT cli_modelc_config_beacon_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_BEACON_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Beacon Set\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.beacon = (UCHAR)choice; + CONSOLE_OUT("Beacon (8-bit in HEX): 0x%02X\n", param.beacon); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_beacon_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Node Reset */ +API_RESULT cli_modelc_config_node_reset(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Config Node Reset\n"); + retval = MS_config_client_node_reset(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Relay Set */ +API_RESULT cli_modelc_config_relay_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_RELAY_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Relay Set\n"); + + if (3 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.relay = (UCHAR)choice; + CONSOLE_OUT("Relay (8-bit in HEX): 0x%02X\n", param.relay); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.relay_rtx_count = (UCHAR)choice; + CONSOLE_OUT("RelayRetransmitCount (3-bit in HEX): 0x%02X\n", param.relay_rtx_count); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.relay_rtx_interval_steps = (UCHAR)choice; + CONSOLE_OUT("RelayRetransmitIntervalSteps (5-bit in HEX): 0x%02X\n", param.relay_rtx_interval_steps); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_relay_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Key Refresh Phase Get */ +API_RESULT cli_modelc_config_key_refresh_phase_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_KEYREFRESH_PHASE_GET_PARAM param; + CONSOLE_OUT + (">> Send Config Key Refresh Phase Get\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.netkey_index = (UINT16)choice; + CONSOLE_OUT("NetKeyIndex (16-bit in HEX): 0x%04X\n", param.netkey_index); + } + + retval = MS_config_client_keyrefresh_phase_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Model Subscription Virtual Address Delete */ +API_RESULT cli_modelc_config_model_subscription_virtual_address_delete(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODELSUB_VADDR_DEL_PARAM param; + CONSOLE_OUT + (">> Send Config Model Subscription Virtual Address Delete\n"); + + if (3 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.element_address = (UINT16)choice; + CONSOLE_OUT("ElementAddress (16-bit in HEX): 0x%04X\n", param.element_address); + CLI_strtoarray + ( + argv[1], + CLI_strlen(argv[1]), + ¶m.label[0], + 16 + ); + + if (4 < CLI_strlen(argv[2])) + { + param.model.type = 0x01; + CONSOLE_OUT("Model ID Type: Vendor\n"); + } + else + { + param.model.type = 0x00; + CONSOLE_OUT("Model ID Type: SIG\n"); + } + + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.model.id = (UINT32)choice; + CONSOLE_OUT("ModelIdentifier: 0x%08X\n", param.model.id); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_model_subscription_vaddr_delete(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Model Publication Virtual Address Set */ +API_RESULT cli_modelc_config_model_publication_virtual_address_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODELPUB_VADDR_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Model Publication Virtual Address Set\n"); + + if (9 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.element_address = (UINT16)choice; + CONSOLE_OUT("ElementAddress (16-bit in HEX): 0x%04X\n", param.element_address); + CLI_strtoarray + ( + argv[1], + CLI_strlen(argv[1]), + ¶m.publish_address[0], + 16 + ); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKeyIndex (12-bit in HEX): 0x%04X\n", param.appkey_index); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.credential_flag = (UCHAR)choice; + CONSOLE_OUT("CredentialFlag (1-bit in HEX): 0x%02X\n", param.credential_flag); + choice = CLI_strtoi(argv[4], CLI_strlen(argv[4]), 16); + param.publish_ttl = (UCHAR)choice; + CONSOLE_OUT("PublishTTL (8-bit in HEX): 0x%02X\n", param.publish_ttl); + choice = CLI_strtoi(argv[5], CLI_strlen(argv[5]), 16); + param.publish_period = (UCHAR)choice; + CONSOLE_OUT("PublishPeriod (8-bit in HEX): 0x%02X\n", param.publish_period); + choice = CLI_strtoi(argv[6], CLI_strlen(argv[6]), 16); + param.publish_rtx_count = (UCHAR)choice; + CONSOLE_OUT("PublishRetransmitCount (3-bit in HEX): 0x%02X\n", param.publish_rtx_count); + choice = CLI_strtoi(argv[7], CLI_strlen(argv[7]), 16); + param.publish_rtx_interval_steps = (UCHAR)choice; + CONSOLE_OUT("PublishRetransmitIntervalSteps (5-bit in HEX): 0x%02X\n", param.publish_rtx_interval_steps); + + if (4 < CLI_strlen(argv[8])) + { + param.model.type = 0x01; + CONSOLE_OUT("Model ID Type: Vendor\n"); + } + else + { + param.model.type = 0x00; + CONSOLE_OUT("Model ID Type: SIG\n"); + } + + choice = CLI_strtoi(argv[8], CLI_strlen(argv[8]), 16); + param.model.id = (UINT32)choice; + CONSOLE_OUT("ModelIdentifier: 0x%08X\n", param.model.id); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_model_publication_vaddr_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Gatt Proxy Set */ +API_RESULT cli_modelc_config_gatt_proxy_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_GATT_PROXY_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Gatt Proxy Set\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.proxy = (UCHAR)choice; + CONSOLE_OUT("GATTProxy (8-bit in HEX): 0x%02X\n", param.proxy); + } + + retval = MS_config_client_gatt_proxy_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Model Subscription Virtual Address Add */ +API_RESULT cli_modelc_config_model_subscription_virtual_address_add(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODELSUB_VADDR_ADD_PARAM param; + CONSOLE_OUT + (">> Send Config Model Subscription Virtual Address Add\n"); + + if (3 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.element_address = (UINT16)choice; + CONSOLE_OUT("ElementAddress (16-bit in HEX): 0x%04X\n", param.element_address); + CLI_strtoarray + ( + argv[1], + CLI_strlen(argv[1]), + ¶m.label[0], + 16 + ); + + if (4 < CLI_strlen(argv[2])) + { + param.model.type = 0x01; + CONSOLE_OUT("Model ID Type: Vendor\n"); + } + else + { + param.model.type = 0x00; + CONSOLE_OUT("Model ID Type: SIG\n"); + } + + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.model.id = (UINT32)choice; + CONSOLE_OUT("ModelIdentifier: 0x%08X\n", param.model.id); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_model_subscription_vaddr_add(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Default Ttl Get */ +API_RESULT cli_modelc_config_default_ttl_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Config Default Ttl Get\n"); + retval = MS_config_client_default_ttl_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Model App Bind */ +API_RESULT cli_modelc_config_model_app_bind(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODEL_APP_BIND_PARAM param; + CONSOLE_OUT + (">> Send Config Model App Bind\n"); + + if (4 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.element_address = (UINT16)choice; + CONSOLE_OUT("ElementAddress (16-bit in HEX): 0x%04X\n", param.element_address); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKeyIndex (16-bit in HEX): 0x%04X\n", param.appkey_index); + + if (4 < CLI_strlen(argv[2])) + { + param.model.type = 0x01; + CONSOLE_OUT("Model ID Type: Vendor\n"); + } + else + { + param.model.type = 0x00; + CONSOLE_OUT("Model ID Type: SIG\n"); + } + + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.model.id = (UINT32)choice; + + /* Corresponding Local Model ID */ + if (4 < CLI_strlen(argv[3])) + { + param.client_model.type = 0x01; + CONSOLE_OUT("Model ID Type: Vendor\n"); + } + else + { + param.client_model.type = 0x00; + CONSOLE_OUT("Model ID Type: SIG\n"); + } + + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.client_model.id = (UINT32)choice; + CONSOLE_OUT("Local ModelIdentifier: 0x%08X\n", param.client_model.id); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + CONSOLE_OUT("Usage: bind \n"); + return API_FAILURE; + } + + retval = MS_config_client_model_app_bind(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Node Identity Set */ +API_RESULT cli_modelc_config_node_identity_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_NODEID_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Node Identity Set\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.netkey_index = (UINT16)choice; + CONSOLE_OUT("NetKeyIndex (16-bit in HEX): 0x%04X\n", param.netkey_index); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.identity = (UCHAR)choice; + CONSOLE_OUT("Identity (8-bit in HEX): 0x%02X\n", param.identity); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_node_identity_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Sig Model Subscription Get */ +API_RESULT cli_modelc_config_sig_model_subscription_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_SIGMODELSUB_GET_PARAM param; + CONSOLE_OUT + (">> Send Config Sig Model Subscription Get\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.element_address = (UINT16)choice; + CONSOLE_OUT("ElementAddress (16-bit in HEX): 0x%04X\n", param.element_address); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.model_id = (UINT16)choice; + CONSOLE_OUT("ModelIdentifier (16-bit in HEX): 0x%04X\n", param.model_id); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_sig_model_subscription_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Netkey Add */ +API_RESULT cli_modelc_config_netkey_add(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_NETKEY_ADD_PARAM param; + CONSOLE_OUT + (">> Send Config Netkey Add\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.netkey_index = (UINT16)choice; + CONSOLE_OUT("NetKeyIndex (16-bit in HEX): 0x%04X\n", param.netkey_index); + CLI_strtoarray + ( + argv[1], + CLI_strlen(argv[1]), + ¶m.netkey[0], + 16 + ); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_netkey_add(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Appkey Update */ +API_RESULT cli_modelc_config_appkey_update(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_APPKEY_UPDATE_PARAM param; + CONSOLE_OUT + (">> Send Config Appkey Update\n"); + + if (3 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.netkey_index = (UINT16)choice; + CONSOLE_OUT("NetKeyIndex (12-bit in HEX): 0x%04X\n", param.netkey_index); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKeyIndex (12-bit in HEX): 0x%48X\n", param.appkey_index); + CLI_strtoarray + ( + argv[2], + CLI_strlen(argv[2]), + ¶m.appkey[0], + 16 + ); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_appkey_update(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Heartbeat Subscription Get */ +API_RESULT cli_modelc_config_heartbeat_subscription_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Config Heartbeat Subscription Get\n"); + retval = MS_config_client_heartbeat_subscription_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Vendor Model Subscription Get */ +API_RESULT cli_modelc_config_vendor_model_subscription_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_VENDORMODELSUB_GET_PARAM param; + CONSOLE_OUT + (">> Send Config Vendor Model Subscription Get\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.element_address = (UINT16)choice; + CONSOLE_OUT("ElementAddress (16-bit in HEX): 0x%04X\n", param.element_address); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.model_id = (UINT32)choice; + CONSOLE_OUT("ModelIdentifier (32-bit in HEX): 0x%08X\n", param.model_id); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_vendor_model_subscription_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Vendor Model App Get */ +API_RESULT cli_modelc_config_vendor_model_app_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_VENDOR_MODEL_APP_GET_PARAM param; + CONSOLE_OUT + (">> Send Config Vendor Model App Get\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.element_address = (UINT16)choice; + CONSOLE_OUT("ElementAddress (16-bit in HEX): 0x%04X\n", param.element_address); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.model_id = (UINT32)choice; + CONSOLE_OUT("ModelIdentifier (32-bit in HEX): 0x%08X\n", param.model_id); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_vendor_model_app_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Model Subscription Overwrite */ +API_RESULT cli_modelc_config_model_subscription_overwrite(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODELSUB_OVERWRITE_PARAM param; + CONSOLE_OUT + (">> Send Config Model Subscription Overwrite\n"); + + if (3 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.element_address = (UINT16)choice; + CONSOLE_OUT("ElementAddress (16-bit in HEX): 0x%04X\n", param.element_address); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.address = (UINT16)choice; + CONSOLE_OUT("Address (16-bit in HEX): 0x%04X\n", param.address); + + if (4 < CLI_strlen(argv[2])) + { + param.model.type = 0x01; + CONSOLE_OUT("Model ID Type: Vendor\n"); + } + else + { + param.model.type = 0x00; + CONSOLE_OUT("Model ID Type: SIG\n"); + } + + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.model.id = (UINT32)choice; + CONSOLE_OUT("ModelIdentifier: 0x%08X\n", param.model.id); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_model_subscription_overwrite(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Beacon Get */ +API_RESULT cli_modelc_config_beacon_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Config Beacon Get\n"); + retval = MS_config_client_beacon_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Model Subscription Delete All */ +API_RESULT cli_modelc_config_model_subscription_delete_all(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODELSUB_DELETEALL_PARAM param; + CONSOLE_OUT + (">> Send Config Model Subscription Delete All\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.element_address = (UINT16)choice; + CONSOLE_OUT("ElementAddress (16-bit in HEX): 0x%04X\n", param.element_address); + + if (4 < CLI_strlen(argv[1])) + { + param.model.type = 0x01; + CONSOLE_OUT("Model ID Type: Vendor\n"); + } + else + { + param.model.type = 0x00; + CONSOLE_OUT("Model ID Type: SIG\n"); + } + + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.model.id = (UINT32)choice; + CONSOLE_OUT("ModelIdentifier: 0x%08X\n", param.model.id); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_model_subscription_delete_all(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Netkey Delete */ +API_RESULT cli_modelc_config_netkey_delete(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_NETKEY_DELETE_PARAM param; + CONSOLE_OUT + (">> Send Config Netkey Delete\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.netkey_index = (UINT16)choice; + CONSOLE_OUT("NetKey (12-bit in HEX): 0x%04X\n", param.netkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_netkey_delete(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Friend Set */ +API_RESULT cli_modelc_config_friend_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_FRIEND_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Friend Set\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.friend = (UCHAR)choice; + CONSOLE_OUT("Friend (8-bit in HEX): 0x%02X\n", param.friend); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_friend_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Heartbeat Publication Set */ +API_RESULT cli_modelc_config_heartbeat_publication_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_HEARTBEATPUB_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Heartbeat Publication Set\n"); + + if (6 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.destination = (UINT16)choice; + CONSOLE_OUT("Destination (16-bit in HEX): 0x%04X\n", param.destination); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.countlog = (UCHAR)choice; + CONSOLE_OUT("CountLog (8-bit in HEX): 0x%02X\n", param.countlog); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.periodlog = (UCHAR)choice; + CONSOLE_OUT("PeriodLog (8-bit in HEX): 0x%02X\n", param.periodlog); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.ttl = (UCHAR)choice; + CONSOLE_OUT("TTL (8-bit in HEX): 0x%02X\n", param.ttl); + choice = CLI_strtoi(argv[4], CLI_strlen(argv[4]), 16); + param.features = (UINT16)choice; + CONSOLE_OUT("Features (16-bit in HEX): 0x%04X\n", param.features); + choice = CLI_strtoi(argv[5], CLI_strlen(argv[5]), 16); + param.netkey_index = (UINT16)choice; + CONSOLE_OUT("NetKeyIndex (16-bit in HEX): 0x%04X\n", param.netkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_heartbeat_publication_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Node Identity Get */ +API_RESULT cli_modelc_config_node_identity_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_NODEID_GET_PARAM param; + CONSOLE_OUT + (">> Send Config Node Identity Get\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.netkey_index = (UINT16)choice; + CONSOLE_OUT("NetKeyIndex (16-bit in HEX): 0x%04X\n", param.netkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_node_identity_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Default Ttl Set */ +API_RESULT cli_modelc_config_default_ttl_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_DEFAULT_TTL_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Default Ttl Set\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.ttl = (UCHAR)choice; + CONSOLE_OUT("TTL (8-bit in HEX): 0x%02X\n", param.ttl); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_default_ttl_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Netkey Update */ +API_RESULT cli_modelc_config_netkey_update(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_NETKEY_UPDATE_PARAM param; + CONSOLE_OUT + (">> Send Config Netkey Update\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.netkey_index = (UINT16)choice; + CONSOLE_OUT("NetKeyIndex (16-bit in HEX): 0x%04X\n", param.netkey_index); + CLI_strtoarray + ( + argv[1], + CLI_strlen(argv[1]), + ¶m.netkey[0], + 16 + ); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + /* Set Local NetKey */ + MS_access_cm_add_update_netkey + ( + 0, /* netkey_index */ + MS_ACCESS_CONFIG_NETKEY_UPDATE_OPCODE, /* opcode */ + ¶m.netkey[0] /* net_key */ + ); + retval = MS_config_client_netkey_update(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Heartbeat Publication Get */ +API_RESULT cli_modelc_config_heartbeat_publication_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Config Heartbeat Publication Get\n"); + retval = MS_config_client_heartbeat_publication_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Model Publication Set */ +API_RESULT cli_modelc_config_model_publication_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODELPUB_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Model Publication Set\n"); + + if (9 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.element_address = (UINT16)choice; + CONSOLE_OUT("ElementAddress (16-bit in HEX): 0x%04X\n", param.element_address); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.publish_address = (UINT16)choice; + CONSOLE_OUT("PublishAddress (16-bit in HEX): 0x%04X\n", param.publish_address); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKeyIndex (12-bit in HEX): 0x%04X\n", param.appkey_index); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.credential_flag = (UCHAR)choice; + CONSOLE_OUT("CredentialFlag (1-bit in HEX): 0x%02X\n", param.credential_flag); + choice = CLI_strtoi(argv[4], CLI_strlen(argv[4]), 16); + param.publish_ttl = (UCHAR)choice; + CONSOLE_OUT("PublishTTL (8-bit in HEX): 0x%02X\n", param.publish_ttl); + choice = CLI_strtoi(argv[5], CLI_strlen(argv[5]), 16); + param.publish_period = (UCHAR)choice; + CONSOLE_OUT("PublishPeriod (8-bit in HEX): 0x%02X\n", param.publish_period); + choice = CLI_strtoi(argv[6], CLI_strlen(argv[6]), 16); + param.publish_rtx_count = (UCHAR)choice; + CONSOLE_OUT("PublishRetransmitCount (3-bit in HEX): 0x%02X\n", param.publish_rtx_count); + choice = CLI_strtoi(argv[7], CLI_strlen(argv[7]), 16); + param.publish_rtx_interval_steps = (UCHAR)choice; + CONSOLE_OUT("PublishRetransmitIntervalSteps (5-bit in HEX): 0x%02X\n", param.publish_rtx_interval_steps); + + if (4 < CLI_strlen(argv[8])) + { + param.model.type = 0x01; + CONSOLE_OUT("Model ID Type: Vendor\n"); + } + else + { + param.model.type = 0x00; + CONSOLE_OUT("Model ID Type: SIG\n"); + } + + choice = CLI_strtoi(argv[8], CLI_strlen(argv[8]), 16); + param.model.id = (UINT32)choice; + CONSOLE_OUT("ModelIdentifier: 0x%08X\n", param.model.id); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_model_publication_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Netkey Get */ +API_RESULT cli_modelc_config_netkey_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Config Netkey Get\n"); + retval = MS_config_client_netkey_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Model Publication Get */ +API_RESULT cli_modelc_config_model_publication_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_MODELPUB_GET_PARAM param; + CONSOLE_OUT + (">> Send Config Model Publication Get\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.element_address = (UINT16)choice; + CONSOLE_OUT("ElementAddress (16-bit in HEX): 0x%04X\n", param.element_address); + + if (4 < CLI_strlen(argv[1])) + { + param.model.type = 0x01; + CONSOLE_OUT("Model ID Type: Vendor\n"); + } + else + { + param.model.type = 0x00; + CONSOLE_OUT("Model ID Type: SIG\n"); + } + + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.model.id = (UINT32)choice; + CONSOLE_OUT("ModelIdentifier: 0x%08X\n", param.model.id); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_model_publication_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Network Transmit Get */ +API_RESULT cli_modelc_config_network_transmit_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Config Network Transmit Get\n"); + retval = MS_config_client_network_transmit_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Composition Data Get */ +API_RESULT cli_modelc_config_composition_data_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_COMPDATA_GET_PARAM param; + CONSOLE_OUT + (">> Send Config Composition Data Get (Page No )\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.page = (UCHAR)choice; + CONSOLE_OUT("Page (8-bit in HEX): 0x%02X\n", param.page); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_composition_data_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Appkey Add */ +API_RESULT cli_modelc_config_appkey_add(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_APPKEY_ADD_PARAM param; + CONSOLE_OUT + (">> Send Config Appkey Add\n"); + + if (3 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.netkey_index = (UINT16)choice; + CONSOLE_OUT("NetKeyIndex (12-bit in HEX): 0x%04X\n", param.netkey_index); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKeyIndex (12-bit in HEX): 0x%04X\n", param.appkey_index); + CLI_strtoarray + ( + argv[2], + CLI_strlen(argv[2]), + ¶m.appkey[0], + 16 + ); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_appkey_add(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Key Refresh Phase Set */ +API_RESULT cli_modelc_config_key_refresh_phase_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_KEYREFRESH_PHASE_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Key Refresh Phase Set\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.netkey_index = (UINT16)choice; + CONSOLE_OUT("NetKeyIndex (16-bit in HEX): 0x%04X\n", param.netkey_index); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.transition = (UCHAR)choice; + CONSOLE_OUT("Transition (8-bit in HEX): 0x%02X\n", param.transition); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + /* Change Local State as well */ + MS_access_cm_set_key_refresh_phase + ( + 0, /* subnet_handle */ + ¶m.transition /* key_refresh_state */ + ); + param.transition = (UCHAR)choice; + retval = MS_config_client_keyrefresh_phase_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Appkey Get */ +API_RESULT cli_modelc_config_appkey_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_APPKEY_GET_PARAM param; + CONSOLE_OUT + (">> Send Config Appkey Get\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.netkey_index = (UINT16)choice; + CONSOLE_OUT("NetKeyIndex (12-bit in HEX): 0x%04X\n", param.netkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_appkey_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Appkey Delete */ +API_RESULT cli_modelc_config_appkey_delete(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_APPKEY_DELETE_PARAM param; + CONSOLE_OUT + (">> Send Config Appkey Delete\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.netkey_index = (UINT16)choice; + CONSOLE_OUT("NetKeyIndex (12-bit in HEX): 0x%04X\n", param.netkey_index); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKeyIndex (12-bit in HEX): 0x%04X\n", param.appkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_appkey_delete(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Low Power Node Polltimeout Get */ +API_RESULT cli_modelc_config_low_power_node_polltimeout_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_LPNPOLLTIMEOUT_GET_PARAM param; + CONSOLE_OUT + (">> Send Config Low Power Node Polltimeout Get\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.lpn_address = (UINT16)choice; + CONSOLE_OUT("LPNAddress (16-bit in HEX): 0x%04X\n", param.lpn_address); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_lpn_polltimeout_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Get Model Handle */ +API_RESULT cli_modelc_configuration_get_model_handle(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + #if 0 + retval = MS_configuration_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + #else + retval = API_FAILURE; + CONSOLE_OUT("To be implemented\n"); + #endif /* 0 */ + return retval; +} + +/* Set Publish Address */ +API_RESULT cli_modelc_configuration_set_publish_address(UINT32 argc, UCHAR* argv[]) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + MS_ACCESS_DEV_KEY_HANDLE dev_key_handle; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + model_handle = appl_configuration_client_model_handle; + CONSOLE_OUT("Model Handle (16-bit in HEX): 0x%04X\n", model_handle); + + /* Check Number of Arguments */ + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT("Config Server Address (16-bit in HEX): 0x%04X\n", publish_info.addr.addr); + retval = MS_access_cm_get_device_key_handle + ( + publish_info.addr.addr, + &dev_key_handle + ); + + if (API_SUCCESS == retval) + { + publish_info.appkey_index = MS_CONFIG_LIMITS(MS_MAX_APPS) + dev_key_handle; + CONSOLE_OUT("DevKey -> AppKey Index: 0x%04X\n", publish_info.appkey_index); + } + else + { + CONSOLE_OUT( + "\nDevice Key Entry not found for 0x%04X Address, retval 0x%04X\n", + publish_info.addr.addr, retval); + /** + NOTE: + Currently assigning default Device Key Index/Handle if there is no device key + mapped with the provided "Config Server Address". + This possible in scenarios where DUT is the provisioned device but also a Config + client. Then, the stack is not aware of the Provisioner's unicast address and the + default device key handle which holds the device key of the local device with respect + to the provisioner shall be used. + */ + CONSOLE_OUT( + "\nUsing Default Index 0x%04X for Device Key\n", MS_CONFIG_LIMITS(MS_MAX_APPS)); + publish_info.appkey_index = MS_CONFIG_LIMITS(MS_MAX_APPS); + } + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return retval; +} + +static void appl_config_client_print_composition_data +( + /* IN */ UCHAR* comp_data, + /* IN */ UINT16 data_len +) +{ + UINT32 marker, u32_val; + UINT16 u16_val; + UINT8 nums, numv, index; + UINT8 elem_index; + + if ((NULL == comp_data) || (15 > data_len)) + { + CONSOLE_OUT("Invalid Composition Data of Length:0x%02X\n", data_len); + return; + } + + /* Page Number */ + marker = 0; + CONSOLE_OUT("Page: 0x%02X\n", comp_data[marker]); + marker += 1; + /* CID */ + MS_UNPACK_LE_2_BYTE(&u16_val, &comp_data[marker]); + CONSOLE_OUT("CID: 0x%04X\n", u16_val); + marker += 2; + /* PID */ + MS_UNPACK_LE_2_BYTE(&u16_val, &comp_data[marker]); + CONSOLE_OUT("PID: 0x%04X\n", u16_val); + marker += 2; + /* VID */ + MS_UNPACK_LE_2_BYTE(&u16_val, &comp_data[marker]); + CONSOLE_OUT("VID: 0x%04X\n", u16_val); + marker += 2; + /* CRPL */ + MS_UNPACK_LE_2_BYTE(&u16_val, &comp_data[marker]); + CONSOLE_OUT("CRPL: 0x%04X\n", u16_val); + marker += 2; + /* Features */ + MS_UNPACK_LE_2_BYTE(&u16_val, &comp_data[marker]); + CONSOLE_OUT("Features: 0x%04X\n", u16_val); + marker += 2; + /* Parse Elements */ + elem_index = 0; + + while (4 < (data_len - marker)) + { + CONSOLE_OUT("Element #0x%02X\n", elem_index); + /* LOC */ + MS_UNPACK_LE_2_BYTE(&u16_val, &comp_data[marker]); + CONSOLE_OUT("LOC: 0x%04X\n", u16_val); + marker += 2; + /* NumS */ + nums = comp_data[marker]; + CONSOLE_OUT("NumS: 0x%02X\n", nums); + marker += 1; + /* NumV */ + numv = comp_data[marker]; + CONSOLE_OUT("NumV: 0x%02X\n", numv); + marker += 1; + + /* Check Length based on Model ID */ + if ((2 * nums + 4 * numv) > (data_len - marker)) + { + break; + } + + /* Print SIG Model IDs */ + CONSOLE_OUT("SIG MODEL ID(s):\n"); + + for (index = 0; index < nums; index ++) + { + MS_UNPACK_LE_2_BYTE(&u16_val, &comp_data[marker]); + CONSOLE_OUT("#0x%02X: 0x%04X\n", index, u16_val); + marker += 2; + } + + /* Print Vendor Model IDs */ + CONSOLE_OUT("Vendor MODEL ID(s):\n"); + + for (index = 0; index < numv; index ++) + { + MS_UNPACK_LE_4_BYTE(&u32_val, &comp_data[marker]); + CONSOLE_OUT("#0x%02X: 0x%08X\n", index, u32_val); + marker += 4; + } + + elem_index++; + } + + /* Check if all the data is parsed */ + if (marker != data_len) + { + CONSOLE_OUT("Invalid Composition Data. Parsing is not complete\n"); + } +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Configuration client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_configuration_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[CONFIGURATION_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_CONFIG_GATT_PROXY_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_GATT_PROXY_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_HEARTBEAT_PUBLICATION_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_HEARTBEAT_PUBLICATION_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_SIG_MODEL_APP_LIST_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_SIG_MODEL_APP_LIST_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_COMPOSITION_DATA_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_COMPOSITION_DATA_STATUS_OPCODE\n"); + appl_config_client_print_composition_data(data_param, data_len); + } + break; + + case MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_NETKEY_LIST_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_NETKEY_LIST_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_LOW_POWER_NODE_POLLTIMEOUT_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_LOW_POWER_NODE_POLLTIMEOUT_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_SIG_MODEL_SUBSCRIPTION_LIST_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_SIG_MODEL_SUBSCRIPTION_LIST_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_VENDOR_MODEL_SUBSCRIPTION_LIST_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_VENDOR_MODEL_SUBSCRIPTION_LIST_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_APPKEY_LIST_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_APPKEY_LIST_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_APPKEY_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_APPKEY_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_RELAY_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_RELAY_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_FRIEND_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_FRIEND_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_MODEL_APP_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_MODEL_APP_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_NODE_RESET_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_NODE_RESET_STATUS_OPCODE\n"); + } + break; + #if 0 + + case MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_STATUS_OPCODE\n"); + } + break; + #endif /* 0 */ + + case MS_ACCESS_CONFIG_DEFAULT_TTL_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_DEFAULT_TTL_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_NODE_IDENTITY_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_NODE_IDENTITY_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_HEARTBEAT_SUBSCRIPTION_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_HEARTBEAT_SUBSCRIPTION_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_KEY_REFRESH_PHASE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_KEY_REFRESH_PHASE_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_NETWORK_TRANSMIT_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_NETWORK_TRANSMIT_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_BEACON_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_BEACON_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_MODEL_PUBLICATION_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_MODEL_PUBLICATION_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_NETKEY_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_NETKEY_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_CONFIG_VENDOR_MODEL_APP_LIST_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_CONFIG_VENDOR_MODEL_APP_LIST_OPCODE\n"); + } + break; + } + + return retval; +} + +#endif /* CLI_CONFIG_CLIENT_MODEL */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_config_client.h b/src/components/ethermind/mesh/export/cli/model/client/cli_config_client.h new file mode 100644 index 0000000..6ed4f2b --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_config_client.h @@ -0,0 +1,201 @@ +/** + \file cli_configuration_client.h + + \brief This file defines the Mesh Configuration Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_CLI_CONFIG_CLIENT_ +#define _H_CLI_CONFIG_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_config_api.h" +#include "cli_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* configuration client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_configuration); + +/* configuration client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_configuration_setup); + +/* Send Config Model App Unbind */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_model_app_unbind); + +/* Send Config Friend Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_friend_get); + +/* Send Config Gatt Proxy Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_gatt_proxy_get); + +/* Send Config Model Subscription Virtual Address Overwrite */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_model_subscription_virtual_address_overwrite); + +/* Send Config Sig Model App Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_sig_model_app_get); + +/* Send Config Model Subscription Add */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_model_subscription_add); + +/* Send Config Network Transmit Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_network_transmit_set); + +/* Send Config Model Subscription Delete */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_model_subscription_delete); + +/* Send Config Relay Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_relay_get); + +/* Send Config Heartbeat Subscription Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_heartbeat_subscription_set); + +/* Send Config Beacon Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_beacon_set); + +/* Send Config Node Reset */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_node_reset); + +/* Send Config Relay Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_relay_set); + +/* Send Config Key Refresh Phase Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_key_refresh_phase_get); + +/* Send Config Model Subscription Virtual Address Delete */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_model_subscription_virtual_address_delete); + +/* Send Config Model Publication Virtual Address Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_model_publication_virtual_address_set); + +/* Send Config Gatt Proxy Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_gatt_proxy_set); + +/* Send Config Model Subscription Virtual Address Add */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_model_subscription_virtual_address_add); + +/* Send Config Default Ttl Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_default_ttl_get); + +/* Send Config Model App Bind */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_model_app_bind); + +/* Send Config Node Identity Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_node_identity_set); + +/* Send Config Sig Model Subscription Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_sig_model_subscription_get); + +/* Send Config Netkey Add */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_netkey_add); + +/* Send Config Appkey Update */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_appkey_update); + +/* Send Config Heartbeat Subscription Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_heartbeat_subscription_get); + +/* Send Config Vendor Model Subscription Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_vendor_model_subscription_get); + +/* Send Config Vendor Model App Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_vendor_model_app_get); + +/* Send Config Model Subscription Overwrite */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_model_subscription_overwrite); + +/* Send Config Beacon Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_beacon_get); + +/* Send Config Model Subscription Delete All */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_model_subscription_delete_all); + +/* Send Config Netkey Delete */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_netkey_delete); + +/* Send Config Friend Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_friend_set); + +/* Send Config Heartbeat Publication Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_heartbeat_publication_set); + +/* Send Config Node Identity Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_node_identity_get); + +/* Send Config Default Ttl Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_default_ttl_set); + +/* Send Config Netkey Update */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_netkey_update); + +/* Send Config Heartbeat Publication Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_heartbeat_publication_get); + +/* Send Config Model Publication Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_model_publication_set); + +/* Send Config Netkey Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_netkey_get); + +/* Send Config Model Publication Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_model_publication_get); + +/* Send Config Network Transmit Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_network_transmit_get); + +/* Send Config Composition Data Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_composition_data_get); + +/* Send Config Appkey Add */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_appkey_add); + +/* Send Config Key Refresh Phase Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_key_refresh_phase_set); + +/* Send Config Appkey Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_appkey_get); + +/* Send Config Appkey Delete */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_appkey_delete); + +/* Send Config Low Power Node Polltimeout Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_config_low_power_node_polltimeout_get); + +/* Get Model Handle */ +CLI_CMD_HANDLER_DECL(cli_modelc_configuration_get_model_handle); + +/* Set Publish Address */ +CLI_CMD_HANDLER_DECL(cli_modelc_configuration_set_publish_address); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Configuration client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT appl_configuration_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_CLI_CONFIG_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_generic_battery_client.c b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_battery_client.c new file mode 100644 index 0000000..7162455 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_battery_client.c @@ -0,0 +1,236 @@ +/** + \file cli_generic_battery_client.c + + \brief This file defines the Mesh Generic Battery Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "cli_generic_battery_client.h" + +#ifdef CLI_GENERICS_BATTERY_CLIENT_MODEL + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +DECL_CONST CLI_COMMAND cli_modelc_generic_battery_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + /* Setup */ + { "setup", "Model Generic_Battery Setup", cli_modelc_generic_battery_setup }, + + /* Get Model Handle */ + { "gethandle", "Get Model Handle", cli_modelc_generic_battery_get_model_handle }, + + /* Set Publish Address */ + { "publishaddr", "Set Publish Address ", cli_modelc_generic_battery_set_publish_address }, + + /* Send Generic Battery Get */ + { "get", "Send Generic Battery Get", cli_modelc_generic_battery_get} + +}; + + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_battery_client_model_handle; + + +/* --------------------------------------------- Function */ +API_RESULT cli_modelc_generic_battery(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT("In Model Client - Generic_Battery\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_modelc_generic_battery_cmd_list, sizeof(cli_modelc_generic_battery_cmd_list) / sizeof(CLI_COMMAND)); + retval = cli_help(argc, argv); + return retval; +} + +/* generic_battery client CLI entry point */ +API_RESULT cli_modelc_generic_battery_setup(UINT32 argc, UCHAR* argv[]) +{ + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + static UCHAR model_initialized = 0x00; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + /** + Register with Access Layer. + */ + retval = API_FAILURE; + + if (0x00 == model_initialized) + { + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_battery_client_init + ( + element_handle, + &appl_generic_battery_client_model_handle, + cli_generic_battery_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Battery Client Initialized. Model Handle: 0x%04X\n", + appl_generic_battery_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Battery Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + return retval; +} + +/* Send Generic Battery Get */ +API_RESULT cli_modelc_generic_battery_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Battery Get\n"); + retval = MS_generic_battery_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + + +/* Get Model Handle */ +API_RESULT cli_modelc_generic_battery_get_model_handle(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + #if 0 + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_generic_battery_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + #else + retval = API_FAILURE; + CONSOLE_OUT("To be implemented\n"); + #endif /* 0 */ + return retval; +} + + +/* Set Publish Address */ +API_RESULT cli_modelc_generic_battery_set_publish_address(UINT32 argc, UCHAR* argv[]) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + model_handle = appl_generic_battery_client_model_handle; + CONSOLE_OUT("Model Handle (16-bit in HEX): 0x%04X\n", model_handle); + + /* Check Number of Arguments */ + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT("Generic_Battery Server Address (16-bit in HEX): 0x%04X\n", publish_info.addr.addr); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + publish_info.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKey Index: 0x%04X\n", publish_info.appkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return retval; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Battery client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_generic_battery_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[GENERIC_BATTERY_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_GENERIC_BATTERY_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_BATTERY_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + +#endif /* CLI_GENERICS_BATTERY_CLIENT_MODEL */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_generic_battery_client.h b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_battery_client.h new file mode 100644 index 0000000..978567a --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_battery_client.h @@ -0,0 +1,63 @@ +/** + \file cli_generic_battery_client.h + + \brief This file defines the Mesh Generic Battery Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_CLI_GENERIC_BATTERY_CLIENT_ +#define _H_CLI_GENERIC_BATTERY_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_battery_api.h" +#include "cli_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_battery client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_battery); + +/* generic_battery client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_battery_setup); + +/* Send Generic Battery Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_battery_get); + +/* Get Model Handle */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_battery_get_model_handle); + +/* Set Publish Address */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_battery_set_publish_address); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Battery client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_generic_battery_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_CLI_GENERIC_BATTERY_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_generic_default_transition_time_client.c b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_default_transition_time_client.c new file mode 100644 index 0000000..e38ce0b --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_default_transition_time_client.c @@ -0,0 +1,290 @@ +/** + \file cli_generic_default_transition_time_client.c + + \brief This file defines the Mesh Generic Default Transition Time Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "cli_generic_default_transition_time_client.h" + +#ifdef CLI_GENERICS_TRANSITIONTIME_CLIENT_MODEL + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +DECL_CONST CLI_COMMAND cli_modelc_generic_default_transition_time_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + /* Setup */ + { "setup", "Model Generic_Default_Transition_Time Setup", cli_modelc_generic_default_transition_time_setup }, + + /* Get Model Handle */ + { "gethandle", "Get Model Handle", cli_modelc_generic_default_transition_time_get_model_handle }, + + /* Set Publish Address */ + { "publishaddr", "Set Publish Address ", cli_modelc_generic_default_transition_time_set_publish_address }, + + /* Send Generic Default Transition Time Get */ + { "get", "Send Generic Default Transition Time Get", cli_modelc_generic_default_transition_time_get}, + + /* Send Generic Default Transition Time Set */ + { "set", "Send Generic Default Transition Time Set", cli_modelc_generic_default_transition_time_set}, + + /* Send Generic Default Transition Time Set Unacknowledged */ + { "setun", "Send Generic Default Transition Time Set Unacknowledged", cli_modelc_generic_default_transition_time_set_unacknowledged}, + +}; + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_default_transition_time_client_model_handle; + + +/* --------------------------------------------- Function */ +API_RESULT cli_modelc_generic_default_transition_time(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT("In Model Client - Generic_Default_Transition_Time\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_modelc_generic_default_transition_time_cmd_list, sizeof(cli_modelc_generic_default_transition_time_cmd_list) / sizeof(CLI_COMMAND)); + retval = cli_help(argc, argv); + return retval; +} + +/* generic_default_transition_time client CLI entry point */ +API_RESULT cli_modelc_generic_default_transition_time_setup(UINT32 argc, UCHAR* argv[]) +{ + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + static UCHAR model_initialized = 0x00; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + /** + Register with Access Layer. + */ + retval = API_FAILURE; + + if (0x00 == model_initialized) + { + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_default_transition_time_client_init + ( + element_handle, + &appl_generic_default_transition_time_client_model_handle, + cli_generic_default_transition_time_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Default Transition Time Client Initialized. Model Handle: 0x%04X\n", + appl_generic_default_transition_time_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Default Transition Time Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + return retval; +} + +/* Send Generic Default Transition Time Get */ +API_RESULT cli_modelc_generic_default_transition_time_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Default Transition Time Get\n"); + retval = MS_generic_default_transition_time_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Default Transition Time Set */ +API_RESULT cli_modelc_generic_default_transition_time_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_DEFAULT_TRANSITION_TIME_STRUCT param; + CONSOLE_OUT + (">> Send Generic Default Transition Time Set\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.transition_number_of_steps = (UCHAR)choice; + CONSOLE_OUT("Transition Number of Steps (6-bit in HEX): 0x%02X\n", param.transition_number_of_steps); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.transition_step_resolution = (UCHAR)choice; + CONSOLE_OUT("Transition Step Resolution (2-bit in HEX): 0x%02X\n", param.transition_step_resolution); + } + + retval = MS_generic_default_transition_time_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Default Transition Time Set Unacknowledged */ +API_RESULT cli_modelc_generic_default_transition_time_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_DEFAULT_TRANSITION_TIME_STRUCT param; + CONSOLE_OUT + (">> Send Generic Default Transition Time Set Unacknowledged\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.transition_number_of_steps = (UCHAR)choice; + CONSOLE_OUT("Transition Number of Steps (6-bit in HEX): 0x%02X\n", param.transition_number_of_steps); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.transition_step_resolution = (UCHAR)choice; + CONSOLE_OUT("Transition Step Resolution (2-bit in HEX): 0x%02X\n", param.transition_step_resolution); + } + + retval = MS_generic_default_transition_time_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Get Model Handle */ +API_RESULT cli_modelc_generic_default_transition_time_get_model_handle(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + #if 0 + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_generic_default_transition_time_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + #else + retval = API_FAILURE; + CONSOLE_OUT("To be implemented\n"); + #endif /* 0 */ + return retval; +} + + +/* Set Publish Address */ +API_RESULT cli_modelc_generic_default_transition_time_set_publish_address(UINT32 argc, UCHAR* argv[]) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + model_handle = appl_generic_default_transition_time_client_model_handle; + CONSOLE_OUT("Model Handle (16-bit in HEX): 0x%04X\n", model_handle); + + /* Check Number of Arguments */ + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT("Generic_Default_Transition_Time Server Address (16-bit in HEX): 0x%04X\n", publish_info.addr.addr); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + publish_info.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKey Index: 0x%04X\n", publish_info.appkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return retval; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Default_Transition_Time client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_generic_default_transition_time_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[GENERIC_DEFAULT_TRANSITION_TIME_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_GENERIC_DEFAULT_TRANSITION_TIME_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_DEFAULT_TRANSITION_TIME_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + +#endif /* CLI_GENERICS_TRANSITIONTIME_CLIENT_MODEL */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_generic_default_transition_time_client.h b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_default_transition_time_client.h new file mode 100644 index 0000000..5ae7966 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_default_transition_time_client.h @@ -0,0 +1,69 @@ +/** + \file cli_generic_default_transition_time_client.h + + \brief This file defines the Mesh Generic Default Transition Time Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_CLI_GENERIC_DEFAULT_TRANSITION_TIME_CLIENT_ +#define _H_CLI_GENERIC_DEFAULT_TRANSITION_TIME_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_default_transition_time_api.h" +#include "cli_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_default_transition_time client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_default_transition_time); + +/* generic_default_transition_time client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_default_transition_time_setup); + +/* Send Generic Default Transition Time Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_default_transition_time_get); + +/* Send Generic Default Transition Time Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_default_transition_time_set); + +/* Send Generic Default Transition Time Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_default_transition_time_set_unacknowledged); + +/* Get Model Handle */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_default_transition_time_get_model_handle); + +/* Set Publish Address */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_default_transition_time_set_publish_address); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Default_Transition_Time client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_generic_default_transition_time_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_CLI_GENERIC_DEFAULT_TRANSITION_TIME_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_generic_level_client.c b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_level_client.c new file mode 100644 index 0000000..02594cf --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_level_client.c @@ -0,0 +1,492 @@ +/** + \file cli_generic_level_client.c + + \brief This file defines the Mesh Generic Level Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "cli_generic_level_client.h" + +#ifdef CLI_GENERICS_LEVEL_CLIENT_MODEL +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +DECL_CONST CLI_COMMAND cli_modelc_generic_level_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + /* Setup */ + { "setup", "Model Generic_Level Setup", cli_modelc_generic_level_setup }, + + /* Get Model Handle */ + { "gethandle", "Get Model Handle", cli_modelc_generic_level_get_model_handle }, + + /* Set Publish Address */ + { "publishaddr", "Set Publish Address ", cli_modelc_generic_level_set_publish_address }, + + /* Send Generic Delta Set */ + { "deltaset", "Send Generic Delta Set", cli_modelc_generic_delta_set}, + + /* Send Generic Delta Set Unacknowledged */ + { "deltasetun", "Send Generic Delta Set Unacknowledged", cli_modelc_generic_delta_set_unacknowledged}, + + /* Send Generic Level Get */ + { "levelget", "Send Generic Level Get", cli_modelc_generic_level_get}, + + /* Send Generic Level Set */ + { "levelset", "Send Generic Level Set", cli_modelc_generic_level_set}, + + /* Send Generic Level Set Unacknowledged */ + { "levelsetun", "Send Generic Level Set Unacknowledged", cli_modelc_generic_level_set_unacknowledged}, + + /* Send Generic Move Set */ + { "moveset", "Send Generic Move Set", cli_modelc_generic_move_set}, + + /* Send Generic Move Set Unacknowledged */ + { "movesetun", "Send Generic Move Set Unacknowledged", cli_modelc_generic_move_set_unacknowledged} +}; + + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_level_client_model_handle; + + +/* --------------------------------------------- Function */ +API_RESULT cli_modelc_generic_level(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT("In Model Client - Generic_Level\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_modelc_generic_level_cmd_list, sizeof(cli_modelc_generic_level_cmd_list) / sizeof(CLI_COMMAND)); + retval = cli_help(argc, argv); + return retval; +} + +/* generic_level client CLI entry point */ +API_RESULT cli_modelc_generic_level_setup(UINT32 argc, UCHAR* argv[]) +{ + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + static UCHAR model_initialized = 0x00; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + /** + Register with Access Layer. + */ + retval = API_FAILURE; + + if (0x00 == model_initialized) + { + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_level_client_init + ( + element_handle, + &appl_generic_level_client_model_handle, + cli_generic_level_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Level Client Initialized. Model Handle: 0x%04X\n", + appl_generic_level_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Level Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + return retval; +} + +/* Send Generic Delta Set */ +API_RESULT cli_modelc_generic_delta_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_DELTA_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Delta Set\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.delta_level = (UINT32)choice; + CONSOLE_OUT("Delta Level (32-bit in HEX): 0x%08X\n", param.delta_level); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_generic_delta_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Delta Set Unacknowledged */ +API_RESULT cli_modelc_generic_delta_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_DELTA_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Delta Set Unacknowledged\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.delta_level = (UINT32)choice; + CONSOLE_OUT("Delta Level (32-bit in HEX): 0x%08X\n", param.delta_level); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_generic_delta_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Level Get */ +API_RESULT cli_modelc_generic_level_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Level Get\n"); + retval = MS_generic_level_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Level Set */ +API_RESULT cli_modelc_generic_level_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_LEVEL_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Level Set\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.level = (UINT16)choice; + CONSOLE_OUT("Level (16-bit in HEX): 0x%04X\n", param.level); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_generic_level_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Level Set Unacknowledged */ +API_RESULT cli_modelc_generic_level_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_LEVEL_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Level Set Unacknowledged\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.level = (UINT16)choice; + CONSOLE_OUT("Level (16-bit in HEX): 0x%04X\n", param.level); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_generic_level_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Move Set */ +API_RESULT cli_modelc_generic_move_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_MOVE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Move Set\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.delta_level = (UINT16)choice; + CONSOLE_OUT("Delta Level (16-bit in HEX): 0x%04X\n", param.delta_level); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_generic_move_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Move Set Unacknowledged */ +API_RESULT cli_modelc_generic_move_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_MOVE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Move Set Unacknowledged\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.delta_level = (UINT16)choice; + CONSOLE_OUT("Delta Level (16-bit in HEX): 0x%04X\n", param.delta_level); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_generic_move_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + + +/* Get Model Handle */ +API_RESULT cli_modelc_generic_level_get_model_handle(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + #if 0 + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_generic_level_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + #else + retval = API_FAILURE; + CONSOLE_OUT("To be implemented\n"); + #endif /* 0 */ + return retval; +} + + +/* Set Publish Address */ +API_RESULT cli_modelc_generic_level_set_publish_address(UINT32 argc, UCHAR* argv[]) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + model_handle = appl_generic_level_client_model_handle; + CONSOLE_OUT("Model Handle (16-bit in HEX): 0x%04X\n", model_handle); + + /* Check Number of Arguments */ + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT("Generic_Level Server Address (16-bit in HEX): 0x%04X\n", publish_info.addr.addr); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + publish_info.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKey Index: 0x%04X\n", publish_info.appkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return retval; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Level client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_generic_level_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[GENERIC_LEVEL_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_GENERIC_LEVEL_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_LEVEL_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + +#endif /* CLI_GENERICS_LEVEL_CLIENT_MODEL */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_generic_level_client.h b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_level_client.h new file mode 100644 index 0000000..d62af1e --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_level_client.h @@ -0,0 +1,81 @@ +/** + \file cli_generic_level_client.h + + \brief This file defines the Mesh Generic Level Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_CLI_GENERIC_LEVEL_CLIENT_ +#define _H_CLI_GENERIC_LEVEL_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_level_api.h" +#include "cli_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_level client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_level); + +/* generic_level client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_level_setup); + +/* Send Generic Delta Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_delta_set); + +/* Send Generic Delta Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_delta_set_unacknowledged); + +/* Send Generic Level Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_level_get); + +/* Send Generic Level Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_level_set); + +/* Send Generic Level Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_level_set_unacknowledged); + +/* Send Generic Move Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_move_set); + +/* Send Generic Move Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_move_set_unacknowledged); + +/* Get Model Handle */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_level_get_model_handle); + +/* Set Publish Address */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_level_set_publish_address); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Level client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_generic_level_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_CLI_GENERIC_LEVEL_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_generic_location_client.c b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_location_client.c new file mode 100644 index 0000000..e22ac25 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_location_client.c @@ -0,0 +1,393 @@ +/** + \file cli_generic_location_client.c + + \brief This file defines the Mesh Generic Location Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "cli_generic_location_client.h" + +#ifdef CLI_GENERICS_LOCATION_CLIENT_MODEL + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +DECL_CONST CLI_COMMAND cli_modelc_generic_location_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + /* Setup */ + { "setup", "Model Generic_Location Setup", cli_modelc_generic_location_setup }, + + /* Get Model Handle */ + { "gethandle", "Get Model Handle", cli_modelc_generic_location_get_model_handle }, + + /* Set Publish Address */ + { "publishaddr", "Set Publish Address ", cli_modelc_generic_location_set_publish_address }, + + /* Send Generic Location Global Get */ + { "globalget", "Send Generic Location Global Get", cli_modelc_generic_location_global_get}, + + /* Send Generic Location Global Set */ + { "globalset", "Send Generic Location Global Set", cli_modelc_generic_location_global_set}, + + /* Send Generic Location Global Set Unacknowledged */ + { "globalsetun", "Send Generic Location Global Set Unacknowledged", cli_modelc_generic_location_global_set_unacknowledged}, + + /* Send Generic Location Local Get */ + { "localget", "Send Generic Location Local Get", cli_modelc_generic_location_local_get}, + + /* Send Generic Location Local Set */ + { "localset", "Send Generic Location Local Set", cli_modelc_generic_location_local_set}, + + /* Send Generic Location Local Set Unacknowledged */ + { "localsetun", "Send Generic Location Local Set Unacknowledged", cli_modelc_generic_location_local_set_unacknowledged} +}; + + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_location_client_model_handle; + + +/* --------------------------------------------- Function */ +API_RESULT cli_modelc_generic_location(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT("In Model Client - Generic_Location\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_modelc_generic_location_cmd_list, sizeof(cli_modelc_generic_location_cmd_list) / sizeof(CLI_COMMAND)); + retval = cli_help(argc, argv); + return retval; +} + +/* generic_location client CLI entry point */ +API_RESULT cli_modelc_generic_location_setup(UINT32 argc, UCHAR* argv[]) +{ + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + static UCHAR model_initialized = 0x00; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + /** + Register with Access Layer. + */ + retval = API_FAILURE; + + if (0x00 == model_initialized) + { + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_location_client_init + ( + element_handle, + &appl_generic_location_client_model_handle, + cli_generic_location_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Location Client Initialized. Model Handle: 0x%04X\n", + appl_generic_location_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Location Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + return retval; +} + +/* Send Generic Location Global Get */ +API_RESULT cli_modelc_generic_location_global_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Location Global Get\n"); + retval = MS_generic_location_global_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Location Global Set */ +API_RESULT cli_modelc_generic_location_global_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_LOCATION_GLOBAL_STRUCT param; + CONSOLE_OUT + (">> Send Generic Location Global Set\n"); + + if (3 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.global_latitude = (UINT32)choice; + CONSOLE_OUT("Global Latitude (32-bit in HEX): 0x%08X\n", param.global_latitude); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.global_longitude = (UINT32)choice; + CONSOLE_OUT("Global Longitude (32-bit in HEX): 0x%08X\n", param.global_longitude); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.global_altitude = (UINT16)choice; + CONSOLE_OUT("Global Altitude (16-bit in HEX): 0x%04X\n", param.global_altitude); + } + + retval = MS_generic_location_global_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Location Global Set Unacknowledged */ +API_RESULT cli_modelc_generic_location_global_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_LOCATION_GLOBAL_STRUCT param; + CONSOLE_OUT + (">> Send Generic Location Global Set Unacknowledged\n"); + + if (3 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.global_latitude = (UINT32)choice; + CONSOLE_OUT("Global Latitude (32-bit in HEX): 0x%08X\n", param.global_latitude); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.global_longitude = (UINT32)choice; + CONSOLE_OUT("Global Longitude (32-bit in HEX): 0x%08X\n", param.global_longitude); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.global_altitude = (UINT16)choice; + CONSOLE_OUT("Global Altitude (16-bit in HEX): 0x%04X\n", param.global_altitude); + } + + retval = MS_generic_location_global_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Location Local Get */ +API_RESULT cli_modelc_generic_location_local_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Location Local Get\n"); + retval = MS_generic_location_local_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Location Local Set */ +API_RESULT cli_modelc_generic_location_local_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_LOCATION_LOCAL_STRUCT param; + CONSOLE_OUT + (">> Send Generic Location Local Set\n"); + + if (5 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.local_north = (UINT16)choice; + CONSOLE_OUT("Local North (16-bit in HEX): 0x%04X\n", param.local_north); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.local_east = (UINT16)choice; + CONSOLE_OUT("Local East (16-bit in HEX): 0x%04X\n", param.local_east); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.local_altitude = (UINT16)choice; + CONSOLE_OUT("Local Altitude (16-bit in HEX): 0x%04X\n", param.local_altitude); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.floor_number = (UCHAR)choice; + CONSOLE_OUT("Floor Number (8-bit in HEX): 0x%02X\n", param.floor_number); + choice = CLI_strtoi(argv[4], CLI_strlen(argv[4]), 16); + param.uncertainty = (UINT16)choice; + CONSOLE_OUT("Uncertainty (16-bit in HEX): 0x%04X\n", param.uncertainty); + } + + retval = MS_generic_location_local_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Location Local Set Unacknowledged */ +API_RESULT cli_modelc_generic_location_local_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_LOCATION_LOCAL_STRUCT param; + CONSOLE_OUT + (">> Send Generic Location Local Set Unacknowledged\n"); + + if (5 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.local_north = (UINT16)choice; + CONSOLE_OUT("Local North (16-bit in HEX): 0x%04X\n", param.local_north); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.local_east = (UINT16)choice; + CONSOLE_OUT("Local East (16-bit in HEX): 0x%04X\n", param.local_east); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.local_altitude = (UINT16)choice; + CONSOLE_OUT("Local Altitude (16-bit in HEX): 0x%04X\n", param.local_altitude); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.floor_number = (UCHAR)choice; + CONSOLE_OUT("Floor Number (8-bit in HEX): 0x%02X\n", param.floor_number); + choice = CLI_strtoi(argv[4], CLI_strlen(argv[4]), 16); + param.uncertainty = (UINT16)choice; + CONSOLE_OUT("Uncertainty (16-bit in HEX): 0x%04X\n", param.uncertainty); + } + + retval = MS_generic_location_local_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + + +/* Get Model Handle */ +API_RESULT cli_modelc_generic_location_get_model_handle(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + #if 0 + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_generic_location_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + #else + retval = API_FAILURE; + CONSOLE_OUT("To be implemented\n"); + #endif /* 0 */ + return retval; +} + + +/* Set Publish Address */ +API_RESULT cli_modelc_generic_location_set_publish_address(UINT32 argc, UCHAR* argv[]) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + model_handle = appl_generic_location_client_model_handle; + CONSOLE_OUT("Model Handle (16-bit in HEX): 0x%04X\n", model_handle); + + /* Check Number of Arguments */ + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT("Generic_Location Server Address (16-bit in HEX): 0x%04X\n", publish_info.addr.addr); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + publish_info.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKey Index: 0x%04X\n", publish_info.appkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return retval; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Location client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_generic_location_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[GENERIC_LOCATION_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_GENERIC_LOCATION_GLOBAL_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_LOCATION_GLOBAL_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_GENERIC_LOCATION_LOCAL_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_LOCATION_LOCAL_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + +#endif /* CLI_GENERICS_LOCATION_CLIENT_MODEL */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_generic_location_client.h b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_location_client.h new file mode 100644 index 0000000..498da5c --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_location_client.h @@ -0,0 +1,78 @@ +/** + \file cli_generic_location_client.h + + \brief This file defines the Mesh Generic Location Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_CLI_GENERIC_LOCATION_CLIENT_ +#define _H_CLI_GENERIC_LOCATION_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_location_api.h" +#include "cli_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_location client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_location); + +/* generic_location client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_location_setup); + +/* Send Generic Location Global Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_location_global_get); + +/* Send Generic Location Global Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_location_global_set); + +/* Send Generic Location Global Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_location_global_set_unacknowledged); + +/* Send Generic Location Local Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_location_local_get); + +/* Send Generic Location Local Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_location_local_set); + +/* Send Generic Location Local Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_location_local_set_unacknowledged); + +/* Get Model Handle */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_location_get_model_handle); + +/* Set Publish Address */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_location_set_publish_address); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Location client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_generic_location_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_CLI_GENERIC_LOCATION_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_generic_onoff_client.c b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_onoff_client.c new file mode 100644 index 0000000..f8270b2 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_onoff_client.c @@ -0,0 +1,322 @@ +/** + \file cli_generic_onoff_client.c + + \brief This file defines the Mesh Generic Onoff Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "cli_generic_onoff_client.h" + +#ifdef CLI_GENERICS_ONOFF_CLIENT_MODEL + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +DECL_CONST CLI_COMMAND cli_modelc_generic_onoff_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + /* Setup */ + { "setup", "Model Generic_Onoff Setup", cli_modelc_generic_onoff_setup }, + + /* Get Model Handle */ + { "gethandle", "Get Model Handle", cli_modelc_generic_onoff_get_model_handle }, + + /* Set Publish Address */ + { "publishaddr", "Set Publish Address ", cli_modelc_generic_onoff_set_publish_address }, + + /* Send Generic Onoff Get */ + { "get", "Send Generic Onoff Get", cli_modelc_generic_onoff_get}, + + /* Send Generic Onoff Set */ + { "set", "Send Generic Onoff Set", cli_modelc_generic_onoff_set}, + + /* Send Generic Onoff Set Unacknowledged */ + { "setun", "Send Generic Onoff Set Unacknowledged", cli_modelc_generic_onoff_set_unacknowledged}, + +}; + + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_onoff_client_model_handle; + + +/* --------------------------------------------- Function */ +API_RESULT cli_modelc_generic_onoff(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT("In Model Client - Generic_Onoff\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_modelc_generic_onoff_cmd_list, sizeof(cli_modelc_generic_onoff_cmd_list) / sizeof(CLI_COMMAND)); + retval = cli_help(argc, argv); + return retval; +} + +/* generic_onoff client CLI entry point */ +API_RESULT cli_modelc_generic_onoff_setup(UINT32 argc, UCHAR* argv[]) +{ + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + static UCHAR model_initialized = 0x00; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + /** + Register with Access Layer. + */ + retval = API_FAILURE; + + if (0x00 == model_initialized) + { + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_onoff_client_init + ( + element_handle, + &appl_generic_onoff_client_model_handle, + cli_generic_onoff_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Onoff Client Initialized. Model Handle: 0x%04X\n", + appl_generic_onoff_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Onoff Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + return retval; +} + +/* Send Generic Onoff Get */ +API_RESULT cli_modelc_generic_onoff_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Onoff Get\n"); + retval = MS_generic_onoff_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + + +/* Send Generic Onoff Set */ +API_RESULT cli_modelc_generic_onoff_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_ONOFF_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Onoff Set\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.onoff = (UCHAR)choice; + CONSOLE_OUT("OnOff (8-bit in HEX): 0x%02X\n", param.onoff); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_generic_onoff_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Onoff Set Unacknowledged */ +API_RESULT cli_modelc_generic_onoff_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_ONOFF_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Onoff Set Unacknowledged\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.onoff = (UCHAR)choice; + CONSOLE_OUT("OnOff (8-bit in HEX): 0x%02X\n", param.onoff); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_generic_onoff_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Get Model Handle */ +API_RESULT cli_modelc_generic_onoff_get_model_handle(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + #if 0 + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_generic_onoff_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + #else + retval = API_FAILURE; + CONSOLE_OUT("To be implemented\n"); + #endif /* 0 */ + return retval; +} + + +/* Set Publish Address */ +API_RESULT cli_modelc_generic_onoff_set_publish_address(UINT32 argc, UCHAR* argv[]) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + model_handle = appl_generic_onoff_client_model_handle; + CONSOLE_OUT("Model Handle (16-bit in HEX): 0x%04X\n", model_handle); + + /* Check Number of Arguments */ + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT("Generic_Onoff Server Address (16-bit in HEX): 0x%04X\n", publish_info.addr.addr); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + publish_info.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKey Index: 0x%04X\n", publish_info.appkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return retval; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_generic_onoff_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[GENERIC_ONOFF_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_GENERIC_ONOFF_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_ONOFF_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + +#endif /* CLI_GENERICS_ONOFF_CLIENT_MODEL */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_generic_onoff_client.h b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_onoff_client.h new file mode 100644 index 0000000..68e4595 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_onoff_client.h @@ -0,0 +1,69 @@ +/** + \file cli_generic_onoff_client.h + + \brief This file defines the Mesh Generic Onoff Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_CLI_GENERIC_ONOFF_CLIENT_ +#define _H_CLI_GENERIC_ONOFF_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_onoff_api.h" +#include "cli_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_onoff client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_onoff); + +/* generic_onoff client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_onoff_setup); + +/* Send Generic Onoff Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_onoff_get); + +/* Send Generic Onoff Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_onoff_set); + +/* Send Generic Onoff Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_onoff_set_unacknowledged); + +/* Get Model Handle */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_onoff_get_model_handle); + +/* Set Publish Address */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_onoff_set_publish_address); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_generic_onoff_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_CLI_GENERIC_ONOFF_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_generic_power_level_client.c b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_power_level_client.c new file mode 100644 index 0000000..184946d --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_power_level_client.c @@ -0,0 +1,493 @@ +/** + \file cli_generic_power_level_client.c + + \brief This file defines the Mesh Generic Power Level Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "cli_generic_power_level_client.h" + +#ifdef CLI_GENERICS_PWRLEVEL_CLIENT_MODEL + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +DECL_CONST CLI_COMMAND cli_modelc_generic_power_level_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + /* Setup */ + { "setup", "Model Generic_Power_Level Setup", cli_modelc_generic_power_level_setup }, + + /* Get Model Handle */ + { "gethandle", "Get Model Handle", cli_modelc_generic_power_level_get_model_handle }, + + /* Set Publish Address */ + { "publishaddr", "Set Publish Address ", cli_modelc_generic_power_level_set_publish_address }, + + /* Send Generic Power Default Get */ + { "defaultget", "Send Generic Power Default Get", cli_modelc_generic_power_default_get}, + + /* Send Generic Power Default Set */ + { "defaultset", "Send Generic Power Default Set", cli_modelc_generic_power_default_set}, + + /* Send Generic Power Default Set Unacknowledged */ + { "defaultsetun", "Send Generic Power Default Set Unacknowledged", cli_modelc_generic_power_default_set_unacknowledged}, + + /* Send Generic Power Last Get */ + { "lastget", "Send Generic Power Last Get", cli_modelc_generic_power_last_get}, + + /* Send Generic Power Level Get */ + { "levelget", "Send Generic Power Level Get", cli_modelc_generic_power_level_get}, + + /* Send Generic Power Level Set */ + { "levelset", "Send Generic Power Level Set", cli_modelc_generic_power_level_set}, + + /* Send Generic Power Level Set Unacknowledged */ + { "levelsetun", "Send Generic Power Level Set Unacknowledged", cli_modelc_generic_power_level_set_unacknowledged}, + + /* Send Generic Power Range Get */ + { "rangeget", "Send Generic Power Range Get", cli_modelc_generic_power_range_get}, + + /* Send Generic Power Range Set */ + { "rangeset", "Send Generic Power Range Set", cli_modelc_generic_power_range_set}, + + /* Send Generic Power Range Set Unacknowledged */ + { "rangesetun", "Send Generic Power Range Set Unacknowledged", cli_modelc_generic_power_range_set_unacknowledged} +}; + + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_power_level_client_model_handle; + + +/* --------------------------------------------- Function */ +API_RESULT cli_modelc_generic_power_level(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT("In Model Client - Generic_Power_Level\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_modelc_generic_power_level_cmd_list, sizeof(cli_modelc_generic_power_level_cmd_list) / sizeof(CLI_COMMAND)); + retval = cli_help(argc, argv); + return retval; +} + +/* generic_power_level client CLI entry point */ +API_RESULT cli_modelc_generic_power_level_setup(UINT32 argc, UCHAR* argv[]) +{ + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + static UCHAR model_initialized = 0x00; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + /** + Register with Access Layer. + */ + retval = API_FAILURE; + + if (0x00 == model_initialized) + { + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_power_level_client_init + ( + element_handle, + &appl_generic_power_level_client_model_handle, + cli_generic_power_level_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Power Level Client Initialized. Model Handle: 0x%04X\n", + appl_generic_power_level_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Power Level Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + return retval; +} + +/* Send Generic Power Default Get */ +API_RESULT cli_modelc_generic_power_default_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Power Default Get\n"); + retval = MS_generic_power_default_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Power Default Set */ +API_RESULT cli_modelc_generic_power_default_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_POWER_DEFAULT_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Power Default Set\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.power = (UINT16)choice; + CONSOLE_OUT("Power (16-bit in HEX): 0x%04X\n", param.power); + } + + retval = MS_generic_power_default_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Power Default Set Unacknowledged */ +API_RESULT cli_modelc_generic_power_default_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_POWER_DEFAULT_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Power Default Set Unacknowledged\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.power = (UINT16)choice; + CONSOLE_OUT("Power (16-bit in HEX): 0x%04X\n", param.power); + } + + retval = MS_generic_power_default_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + + +/* Send Generic Power Last Get */ +API_RESULT cli_modelc_generic_power_last_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Power Last Get\n"); + retval = MS_generic_power_last_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Power Level Get */ +API_RESULT cli_modelc_generic_power_level_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Power Level Get\n"); + retval = MS_generic_power_level_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Power Level Set */ +API_RESULT cli_modelc_generic_power_level_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_POWER_LEVEL_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Power Level Set\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.power = (UINT16)choice; + CONSOLE_OUT("Power (16-bit in HEX): 0x%04X\n", param.power); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_generic_power_level_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Power Level Set Unacknowledged */ +API_RESULT cli_modelc_generic_power_level_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_POWER_LEVEL_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Power Level Set Unacknowledged\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.power = (UINT16)choice; + CONSOLE_OUT("Power (16-bit in HEX): 0x%04X\n", param.power); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_generic_power_level_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Power Range Get */ +API_RESULT cli_modelc_generic_power_range_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Power Range Get\n"); + retval = MS_generic_power_range_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Power Range Set */ +API_RESULT cli_modelc_generic_power_range_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_POWER_RANGE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Power Range Set\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.range_min = (UINT16)choice; + CONSOLE_OUT("Range Min (16-bit in HEX): 0x%04X\n", param.range_min); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.range_max = (UINT16)choice; + CONSOLE_OUT("Range Max (16-bit in HEX): 0x%04X\n", param.range_max); + } + + retval = MS_generic_power_range_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Power Range Set Unacknowledged */ +API_RESULT cli_modelc_generic_power_range_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_POWER_RANGE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Power Range Set Unacknowledged\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.range_min = (UINT16)choice; + CONSOLE_OUT("Range Min (16-bit in HEX): 0x%04X\n", param.range_min); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.range_max = (UINT16)choice; + CONSOLE_OUT("Range Max (16-bit in HEX): 0x%04X\n", param.range_max); + } + + retval = MS_generic_power_range_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Get Model Handle */ +API_RESULT cli_modelc_generic_power_level_get_model_handle(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + #if 0 + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_generic_power_level_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + #else + retval = API_FAILURE; + CONSOLE_OUT("To be implemented\n"); + #endif /* 0 */ + return retval; +} + + +/* Set Publish Address */ +API_RESULT cli_modelc_generic_power_level_set_publish_address(UINT32 argc, UCHAR* argv[]) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + model_handle = appl_generic_power_level_client_model_handle; + CONSOLE_OUT("Model Handle (16-bit in HEX): 0x%04X\n", model_handle); + + /* Check Number of Arguments */ + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT("Generic_Power_Level Server Address (16-bit in HEX): 0x%04X\n", publish_info.addr.addr); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + publish_info.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKey Index: 0x%04X\n", publish_info.appkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return retval; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Level client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_generic_power_level_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[GENERIC_POWER_LEVEL_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_GENERIC_POWER_DEFAULT_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_POWER_DEFAULT_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_GENERIC_POWER_LAST_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_POWER_LAST_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_GENERIC_POWER_LEVEL_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_POWER_LEVEL_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_GENERIC_POWER_RANGE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_POWER_RANGE_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + +#endif /* CLI_GENERICS_PWRLEVEL_CLIENT_MODEL */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_generic_power_level_client.h b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_power_level_client.h new file mode 100644 index 0000000..1f0766a --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_power_level_client.h @@ -0,0 +1,90 @@ +/** + \file cli_generic_power_level_client.h + + \brief This file defines the Mesh Generic Power Level Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_CLI_GENERIC_POWER_LEVEL_CLIENT_ +#define _H_CLI_GENERIC_POWER_LEVEL_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_power_level_api.h" +#include "cli_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_power_level client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_power_level); + +/* generic_power_level client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_power_level_setup); + +/* Send Generic Power Default Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_power_default_get); + +/* Send Generic Power Default Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_power_default_set); + +/* Send Generic Power Default Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_power_default_set_unacknowledged); + +/* Send Generic Power Last Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_power_last_get); + +/* Send Generic Power Level Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_power_level_get); + +/* Send Generic Power Level Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_power_level_set); + +/* Send Generic Power Level Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_power_level_set_unacknowledged); + +/* Send Generic Power Range Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_power_range_get); + +/* Send Generic Power Range Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_power_range_set); + +/* Send Generic Power Range Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_power_range_set_unacknowledged); + +/* Get Model Handle */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_power_level_get_model_handle); + +/* Set Publish Address */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_power_level_set_publish_address); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Level client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_generic_power_level_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_CLI_GENERIC_POWER_LEVEL_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_generic_power_onoff_client.c b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_power_onoff_client.c new file mode 100644 index 0000000..1584b8c --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_power_onoff_client.c @@ -0,0 +1,286 @@ +/** + \file cli_generic_power_onoff_client.c + + \brief This file defines the Mesh Generic Power Onoff Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "cli_generic_power_onoff_client.h" + +#ifdef CLI_GENERICS_PWRONOFF_CLIENT_MODEL + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +DECL_CONST CLI_COMMAND cli_modelc_generic_power_onoff_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + /* Setup */ + { "setup", "Model Generic_Power_Onoff Setup", cli_modelc_generic_power_onoff_setup }, + + /* Get Model Handle */ + { "gethandle", "Get Model Handle", cli_modelc_generic_power_onoff_get_model_handle }, + + /* Set Publish Address */ + { "publishaddr", "Set Publish Address ", cli_modelc_generic_power_onoff_set_publish_address }, + + /* Send Generic Onpowerup Get */ + { "get", "Send Generic Onpowerup Get", cli_modelc_generic_onpowerup_get}, + + /* Send Generic Onpowerup Set */ + { "set", "Send Generic Onpowerup Set", cli_modelc_generic_onpowerup_set}, + + /* Send Generic Onpowerup Set Unacknowledged */ + { "setun", "Send Generic Onpowerup Set Unacknowledged", cli_modelc_generic_onpowerup_set_unacknowledged} + +}; + + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_power_onoff_client_model_handle; + + +/* --------------------------------------------- Function */ +API_RESULT cli_modelc_generic_power_onoff(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT("In Model Client - Generic_Power_Onoff\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_modelc_generic_power_onoff_cmd_list, sizeof(cli_modelc_generic_power_onoff_cmd_list) / sizeof(CLI_COMMAND)); + retval = cli_help(argc, argv); + return retval; +} + +/* generic_power_onoff client CLI entry point */ +API_RESULT cli_modelc_generic_power_onoff_setup(UINT32 argc, UCHAR* argv[]) +{ + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + static UCHAR model_initialized = 0x00; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + /** + Register with Access Layer. + */ + retval = API_FAILURE; + + if (0x00 == model_initialized) + { + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_power_onoff_client_init + ( + element_handle, + &appl_generic_power_onoff_client_model_handle, + cli_generic_power_onoff_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Power Onoff Client Initialized. Model Handle: 0x%04X\n", + appl_generic_power_onoff_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Power Onoff Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + return retval; +} + +/* Send Generic Onpowerup Get */ +API_RESULT cli_modelc_generic_onpowerup_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Onpowerup Get\n"); + retval = MS_generic_onpowerup_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + + +/* Send Generic Onpowerup Set */ +API_RESULT cli_modelc_generic_onpowerup_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_ONPOWERUP_STRUCT param; + CONSOLE_OUT + (">> Send Generic Onpowerup Set\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.onpowerup = (UCHAR)choice; + CONSOLE_OUT("OnPowerUp (8-bit in HEX): 0x%02X\n", param.onpowerup); + } + + retval = MS_generic_onpowerup_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Onpowerup Set Unacknowledged */ +API_RESULT cli_modelc_generic_onpowerup_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_ONPOWERUP_STRUCT param; + CONSOLE_OUT + (">> Send Generic Onpowerup Set Unacknowledged\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.onpowerup = (UCHAR)choice; + CONSOLE_OUT("OnPowerUp (8-bit in HEX): 0x%02X\n", param.onpowerup); + } + + retval = MS_generic_onpowerup_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Get Model Handle */ +API_RESULT cli_modelc_generic_power_onoff_get_model_handle(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + #if 0 + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_generic_power_onoff_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + #else + retval = API_FAILURE; + CONSOLE_OUT("To be implemented\n"); + #endif /* 0 */ + return retval; +} + + +/* Set Publish Address */ +API_RESULT cli_modelc_generic_power_onoff_set_publish_address(UINT32 argc, UCHAR* argv[]) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + model_handle = appl_generic_power_onoff_client_model_handle; + CONSOLE_OUT("Model Handle (16-bit in HEX): 0x%04X\n", model_handle); + + /* Check Number of Arguments */ + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT("Generic_Power_Onoff Server Address (16-bit in HEX): 0x%04X\n", publish_info.addr.addr); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + publish_info.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKey Index: 0x%04X\n", publish_info.appkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return retval; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Onoff client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_generic_power_onoff_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[GENERIC_POWER_ONOFF_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_GENERIC_ONPOWERUP_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_ONPOWERUP_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + +#endif /* CLI_GENERICS_PWRONOFF_CLIENT_MODEL */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_generic_power_onoff_client.h b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_power_onoff_client.h new file mode 100644 index 0000000..aa80318 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_power_onoff_client.h @@ -0,0 +1,69 @@ +/** + \file cli_generic_power_onoff_client.h + + \brief This file defines the Mesh Generic Power Onoff Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_CLI_GENERIC_POWER_ONOFF_CLIENT_ +#define _H_CLI_GENERIC_POWER_ONOFF_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_power_onoff_api.h" +#include "cli_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_power_onoff client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_power_onoff); + +/* generic_power_onoff client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_power_onoff_setup); + +/* Send Generic Onpowerup Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_onpowerup_get); + +/* Send Generic Onpowerup Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_onpowerup_set); + +/* Send Generic Onpowerup Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_onpowerup_set_unacknowledged); + +/* Get Model Handle */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_power_onoff_get_model_handle); + +/* Set Publish Address */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_power_onoff_set_publish_address); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Power_Onoff client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_generic_power_onoff_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_CLI_GENERIC_POWER_ONOFF_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_generic_property_client.c b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_property_client.c new file mode 100644 index 0000000..6485331 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_property_client.c @@ -0,0 +1,685 @@ +/** + \file cli_generic_property_client.c + + \brief This file defines the Mesh Generic Property Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "cli_generic_property_client.h" + +#ifdef CLI_GENERICS_PROPERTY_CLIENT_MODEL + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +DECL_CONST CLI_COMMAND cli_modelc_generic_property_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + /* Setup */ + { "setup", "Model Generic_Property Setup", cli_modelc_generic_property_setup }, + + /* Get Model Handle */ + { "gethandle", "Get Model Handle", cli_modelc_generic_property_get_model_handle }, + + /* Set Publish Address */ + { "publishaddr", "Set Publish Address ", cli_modelc_generic_property_set_publish_address }, + + /* Send Generic Admin Properties Get */ + { "adminpropertiesget", "Send Generic Admin Properties Get", cli_modelc_generic_admin_properties_get}, + + /* Send Generic Admin Property Get */ + { "adminpropertyget", "Send Generic Admin Property Get", cli_modelc_generic_admin_property_get}, + + /* Send Generic Admin Property Set */ + { "adminpropertyset", "Send Generic Admin Property Set", cli_modelc_generic_admin_property_set}, + + /* Send Generic Admin Property Set Unacknowledged */ + { "adminpropertysetun", "Send Generic Admin Property Set Unacknowledged", cli_modelc_generic_admin_property_set_unacknowledged}, + + /* Send Generic Client Properties Get */ + { "clientpropertiesget", "Send Generic Client Properties Get", cli_modelc_generic_client_properties_get}, + + /* Send Generic Manufacturer Properties Get */ + { "manufacturerpropertiesget", "Send Generic Manufacturer Properties Get", cli_modelc_generic_manufacturer_properties_get}, + + /* Send Generic Manufacturer Property Get */ + { "manufacturerpropertyget", "Send Generic Manufacturer Property Get", cli_modelc_generic_manufacturer_property_get}, + + /* Send Generic Manufacturer Property Set */ + { "manufacturerpropertyset", "Send Generic Manufacturer Property Set", cli_modelc_generic_manufacturer_property_set}, + + /* Send Generic Manufacturer Property Set Unacknowledged */ + { "manufacturerpropertysetun", "Send Generic Manufacturer Property Set Unacknowledged", cli_modelc_generic_manufacturer_property_set_unacknowledged}, + + /* Send Generic User Properties Get */ + { "userpropertiesget", "Send Generic User Properties Get", cli_modelc_generic_user_properties_get}, + + /* Send Generic User Property Get */ + { "userpropertyget", "Send Generic User Property Get", cli_modelc_generic_user_property_get}, + + /* Send Generic User Property Set */ + { "userpropertyset", "Send Generic User Property Set", cli_modelc_generic_user_property_set}, + + /* Send Generic User Property Set Unacknowledged */ + { "userpropertysetun", "Send Generic User Property Set Unacknowledged", cli_modelc_generic_user_property_set_unacknowledged} +}; + + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_generic_property_client_model_handle; + + +/* --------------------------------------------- Function */ +API_RESULT cli_modelc_generic_property(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT("In Model Client - Generic_Property\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_modelc_generic_property_cmd_list, sizeof(cli_modelc_generic_property_cmd_list) / sizeof(CLI_COMMAND)); + retval = cli_help(argc, argv); + return retval; +} + +/* generic_property client CLI entry point */ +API_RESULT cli_modelc_generic_property_setup(UINT32 argc, UCHAR* argv[]) +{ + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + static UCHAR model_initialized = 0x00; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + /** + Register with Access Layer. + */ + retval = API_FAILURE; + + if (0x00 == model_initialized) + { + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_generic_property_client_init + ( + element_handle, + &appl_generic_property_client_model_handle, + cli_generic_property_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Property Client Initialized. Model Handle: 0x%04X\n", + appl_generic_property_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Property Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + return retval; +} + +/* Send Generic Admin Properties Get */ +API_RESULT cli_modelc_generic_admin_properties_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Admin Properties Get\n"); + retval = MS_generic_admin_properties_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Admin Property Get */ +API_RESULT cli_modelc_generic_admin_property_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_ADMIN_PROPERTY_GET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Admin Property Get\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.admin_property_id = (UINT16)choice; + CONSOLE_OUT("Admin Property ID (16-bit in HEX): 0x%04X\n", param.admin_property_id); + } + + retval = MS_generic_admin_property_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Admin Property Set */ +API_RESULT cli_modelc_generic_admin_property_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_ADMIN_PROPERTY_SET_STRUCT param; + retval = API_FAILURE; + CONSOLE_OUT + (">> Send Generic Admin Property Set\n"); + + if (3 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.admin_property_id = (UINT16)choice; + CONSOLE_OUT("Admin Property ID (16-bit in HEX): 0x%04X\n", param.admin_property_id); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.admin_user_access = (UCHAR)choice; + CONSOLE_OUT("Admin User Access (8-bit in HEX): 0x%02X\n", param.admin_user_access); + choice = CLI_strlen(argv[2]); + { + UINT16 input_len; + input_len = (UINT16)(choice + 1)/2; + param.admin_property_value = EM_alloc_mem(input_len); + + if(NULL == param.admin_property_value) + { + CONSOLE_OUT + ("Memory allocation failed for Admin Property Value. Returning\n"); + return retval; + } + + param.admin_property_value_len = (UINT16) input_len; + CLI_strtoarray + ( + argv[2], + CLI_strlen(argv[2]), + ¶m.admin_property_value[0], + input_len + ); + } + } + + retval = MS_generic_admin_property_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.admin_property_value) + { + EM_free_mem(param.admin_property_value); + } + + return retval; +} + +/* Send Generic Admin Property Set Unacknowledged */ +API_RESULT cli_modelc_generic_admin_property_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_ADMIN_PROPERTY_SET_STRUCT param; + retval = API_FAILURE; + CONSOLE_OUT + (">> Send Generic Admin Property Set Unacknowledged\n"); + + if (3 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.admin_property_id = (UINT16)choice; + CONSOLE_OUT("Admin Property ID (16-bit in HEX): 0x%04X\n", param.admin_property_id); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.admin_user_access = (UCHAR)choice; + CONSOLE_OUT("Admin User Access (8-bit in HEX): 0x%02X\n", param.admin_user_access); + choice = CLI_strlen(argv[2]); + { + UINT16 input_len; + input_len = (UINT16)(choice + 1)/2; + param.admin_property_value = EM_alloc_mem(input_len); + + if(NULL == param.admin_property_value) + { + CONSOLE_OUT + ("Memory allocation failed for Admin Property Value. Returning\n"); + return retval; + } + + param.admin_property_value_len = (UINT16) input_len; + CLI_strtoarray + ( + argv[2], + CLI_strlen(argv[2]), + ¶m.admin_property_value[0], + input_len + ); + } + } + + retval = MS_generic_admin_property_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.admin_property_value) + { + EM_free_mem(param.admin_property_value); + } + + return retval; +} + +/* Send Generic Client Properties Get */ +API_RESULT cli_modelc_generic_client_properties_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_CLIENT_PROPERTIES_GET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Client Properties Get\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.client_property_id = (UINT16)choice; + CONSOLE_OUT("Client Property ID (16-bit in HEX): 0x%04X\n", param.client_property_id); + } + + retval = MS_generic_client_properties_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Manufacturer Properties Get */ +API_RESULT cli_modelc_generic_manufacturer_properties_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic Manufacturer Properties Get\n"); + retval = MS_generic_manufacturer_properties_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Manufacturer Property Get */ +API_RESULT cli_modelc_generic_manufacturer_property_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_MANUFACTURER_PROPERTY_GET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Manufacturer Property Get\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.manufacturer_property_id = (UINT16)choice; + CONSOLE_OUT("Manufacturer Property ID (16-bit in HEX): 0x%04X\n", param.manufacturer_property_id); + } + + retval = MS_generic_manufacturer_property_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Manufacturer Property Set */ +API_RESULT cli_modelc_generic_manufacturer_property_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_MANUFACTURER_PROPERTY_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Manufacturer Property Set\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.manufacturer_property_id = (UINT16)choice; + CONSOLE_OUT("Manufacturer Property ID (16-bit in HEX): 0x%04X\n", param.manufacturer_property_id); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.manufacturer_user_access = (UCHAR)choice; + CONSOLE_OUT("Manufacturer User Access (8-bit in HEX): 0x%02X\n", param.manufacturer_user_access); + } + + retval = MS_generic_manufacturer_property_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic Manufacturer Property Set Unacknowledged */ +API_RESULT cli_modelc_generic_manufacturer_property_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_MANUFACTURER_PROPERTY_SET_STRUCT param; + CONSOLE_OUT + (">> Send Generic Manufacturer Property Set Unacknowledged\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.manufacturer_property_id = (UINT16)choice; + CONSOLE_OUT("Manufacturer Property ID (16-bit in HEX): 0x%04X\n", param.manufacturer_property_id); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.manufacturer_user_access = (UCHAR)choice; + CONSOLE_OUT("Manufacturer User Access (8-bit in HEX): 0x%02X\n", param.manufacturer_user_access); + } + + retval = MS_generic_manufacturer_property_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic User Properties Get */ +API_RESULT cli_modelc_generic_user_properties_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Generic User Properties Get\n"); + retval = MS_generic_user_properties_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic User Property Get */ +API_RESULT cli_modelc_generic_user_property_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_USER_PROPERTY_GET_STRUCT param; + CONSOLE_OUT + (">> Send Generic User Property Get\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.user_property_id = (UINT16)choice; + CONSOLE_OUT("User Property ID (16-bit in HEX): 0x%04X\n", param.user_property_id); + } + + retval = MS_generic_user_property_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Generic User Property Set */ +API_RESULT cli_modelc_generic_user_property_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_USER_PROPERTY_SET_STRUCT param; + retval = API_FAILURE; + CONSOLE_OUT + (">> Send Generic User Property Set\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.user_property_id = (UINT16)choice; + CONSOLE_OUT("User Property ID (16-bit in HEX): 0x%04X\n", param.user_property_id); + choice = CLI_strlen(argv[1]); + { + UINT16 input_len; + input_len = (UINT16)(choice + 1)/2; + param.user_property_value = EM_alloc_mem(input_len); + + if(NULL == param.user_property_value) + { + CONSOLE_OUT + ("Memory allocation failed for User Property Value. Returning\n"); + return retval; + } + + param.user_property_value_len = (UINT16) input_len; + CLI_strtoarray + ( + argv[1], + CLI_strlen(argv[1]), + ¶m.user_property_value[0], + input_len + ); + } + } + + retval = MS_generic_user_property_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.user_property_value) + { + EM_free_mem(param.user_property_value); + } + + return retval; +} + + +/* Send Generic User Property Set Unacknowledged */ +API_RESULT cli_modelc_generic_user_property_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_GENERIC_USER_PROPERTY_SET_STRUCT param; + retval = API_FAILURE; + CONSOLE_OUT + (">> Send Generic User Property Set Unacknowledged\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.user_property_id = (UINT16)choice; + CONSOLE_OUT("User Property ID (16-bit in HEX): 0x%04X\n", param.user_property_id); + choice = CLI_strlen(argv[1]); + { + UINT16 input_len; + input_len = (UINT16)(choice + 1)/2; + param.user_property_value = EM_alloc_mem(input_len); + + if(NULL == param.user_property_value) + { + CONSOLE_OUT + ("Memory allocation failed for User Property Value. Returning\n"); + return retval; + } + + param.user_property_value_len = (UINT16) input_len; + CLI_strtoarray + ( + argv[1], + CLI_strlen(argv[1]), + ¶m.user_property_value[0], + input_len + ); + } + } + + retval = MS_generic_user_property_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.user_property_value) + { + EM_free_mem(param.user_property_value); + } + + return retval; +} + +/* Get Model Handle */ +API_RESULT cli_modelc_generic_property_get_model_handle(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + #if 0 + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_generic_property_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + #else + retval = API_FAILURE; + CONSOLE_OUT("To be implemented\n"); + #endif /* 0 */ + return retval; +} + + +/* Set Publish Address */ +API_RESULT cli_modelc_generic_property_set_publish_address(UINT32 argc, UCHAR* argv[]) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + model_handle = appl_generic_property_client_model_handle; + CONSOLE_OUT("Model Handle (16-bit in HEX): 0x%04X\n", model_handle); + + /* Check Number of Arguments */ + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT("Generic_Property Server Address (16-bit in HEX): 0x%04X\n", publish_info.addr.addr); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + publish_info.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKey Index: 0x%04X\n", publish_info.appkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return retval; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Property client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_generic_property_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[GENERIC_PROPERTY_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_GENERIC_ADMIN_PROPERTIES_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_ADMIN_PROPERTIES_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_GENERIC_ADMIN_PROPERTY_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_ADMIN_PROPERTY_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_GENERIC_CLIENT_PROPERTIES_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_CLIENT_PROPERTIES_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_GENERIC_MANUFACTURER_PROPERTIES_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_MANUFACTURER_PROPERTIES_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_GENERIC_MANUFACTURER_PROPERTY_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_MANUFACTURER_PROPERTY_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_GENERIC_USER_PROPERTIES_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_USER_PROPERTIES_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_GENERIC_USER_PROPERTY_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_GENERIC_USER_PROPERTY_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + +#endif /* CLI_GENERICS_PROPERTY_CLIENT_MODEL */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_generic_property_client.h b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_property_client.h new file mode 100644 index 0000000..78e493d --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_generic_property_client.h @@ -0,0 +1,99 @@ +/** + \file cli_generic_property_client.h + + \brief This file defines the Mesh Generic Property Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_CLI_GENERIC_PROPERTY_CLIENT_ +#define _H_CLI_GENERIC_PROPERTY_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_generic_property_api.h" +#include "cli_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* generic_property client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_property); + +/* generic_property client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_property_setup); + +/* Send Generic Admin Properties Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_admin_properties_get); + +/* Send Generic Admin Property Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_admin_property_get); + +/* Send Generic Admin Property Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_admin_property_set); + +/* Send Generic Admin Property Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_admin_property_set_unacknowledged); + +/* Send Generic Client Properties Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_client_properties_get); + +/* Send Generic Manufacturer Properties Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_manufacturer_properties_get); + +/* Send Generic Manufacturer Property Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_manufacturer_property_get); + +/* Send Generic Manufacturer Property Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_manufacturer_property_set); + +/* Send Generic Manufacturer Property Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_manufacturer_property_set_unacknowledged); + +/* Send Generic User Properties Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_user_properties_get); + +/* Send Generic User Property Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_user_property_get); + +/* Send Generic User Property Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_user_property_set); + +/* Send Generic User Property Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_user_property_set_unacknowledged); + +/* Get Model Handle */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_property_get_model_handle); + +/* Set Publish Address */ +CLI_CMD_HANDLER_DECL(cli_modelc_generic_property_set_publish_address); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Generic_Property client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_generic_property_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_CLI_GENERIC_PROPERTY_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_health_client.c b/src/components/ethermind/mesh/export/cli/model/client/cli_health_client.c new file mode 100644 index 0000000..8180b8d --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_health_client.c @@ -0,0 +1,501 @@ +/** + \file cli_health_client.c + + \brief This file defines the Mesh Health Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "cli_health_client.h" + +#ifdef CLI_HEALTH_CLIENT_MODEL + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +DECL_CONST CLI_COMMAND cli_modelc_health_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + /* Setup */ + { "setup", "Model Health Setup", cli_modelc_health_setup }, + + /* Get Model Handle */ + { "gethandle", "Get Model Handle", cli_modelc_health_get_model_handle }, + + /* Set Publish Address */ + { "publishaddr", "Set Publish Address ", cli_modelc_health_set_publish_address }, + + /* Send Health Attention Get */ + { "attentionget", "Send Health Attention Get", cli_modelc_health_attention_get}, + + /* Send Health Attention Set */ + { "attentionset", "Send Health Attention Set", cli_modelc_health_attention_set}, + + /* Send Health Attention Set Unacknowledged */ + { "attentionsetun", "Send Health Attention Set Unacknowledged", cli_modelc_health_attention_set_unacknowledged}, + + /* Send Health Fault Clear */ + { "faultclear", "Send Health Fault Clear", cli_modelc_health_fault_clear}, + + /* Send Health Fault Clear Unacknowledged */ + { "faultclearun", "Send Health Fault Clear Unacknowledged", cli_modelc_health_fault_clear_unacknowledged}, + + /* Send Health Fault Get */ + { "faultget", "Send Health Fault Get", cli_modelc_health_fault_get}, + + /* Send Health Fault Test */ + { "faulttest", "Send Health Fault Test", cli_modelc_health_fault_test}, + + /* Send Health Fault Test Unacknowledged */ + { "faulttestun", "Send Health Fault Test Unacknowledged", cli_modelc_health_fault_test_unacknowledged}, + + /* Send Health Period Get */ + { "periodget", "Send Health Period Get", cli_modelc_health_period_get}, + + /* Send Health Period Set */ + { "periodset", "Send Health Period Set", cli_modelc_health_period_set}, + + /* Send Health Period Set Unacknowledged */ + { "periodsetun", "Send Health Period Set Unacknowledged", cli_modelc_health_period_set_unacknowledged} +}; + + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_health_client_model_handle; + + +/* --------------------------------------------- Function */ +API_RESULT cli_modelc_health(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT("In Model Client - Health\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_modelc_health_cmd_list, sizeof(cli_modelc_health_cmd_list) / sizeof(CLI_COMMAND)); + retval = cli_help(argc, argv); + return retval; +} + +/* health client CLI entry point */ +API_RESULT cli_modelc_health_setup(UINT32 argc, UCHAR* argv[]) +{ + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + static UCHAR model_initialized = 0x00; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + /** + Register with Access Layer. + */ + retval = API_FAILURE; + + if (0x00 == model_initialized) + { + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_health_client_init + ( + element_handle, + &appl_health_client_model_handle, + cli_health_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Health Client Initialized. Model Handle: 0x%04X\n", + appl_health_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Health Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + return retval; +} + +/* Send Health Attention Get */ +API_RESULT cli_modelc_health_attention_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Health Attention Get\n"); + retval = MS_health_attention_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Health Attention Set */ +API_RESULT cli_modelc_health_attention_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_HEALTH_ATTENTION_STRUCT param; + CONSOLE_OUT + (">> Send Health Attention Set\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.attention = (UCHAR)choice; + CONSOLE_OUT("Attention (8-bit in HEX): 0x%02X\n", param.attention); + } + + retval = MS_health_attention_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Health Attention Set Unacknowledged */ +API_RESULT cli_modelc_health_attention_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_HEALTH_ATTENTION_STRUCT param; + CONSOLE_OUT + (">> Send Health Attention Set Unacknowledged\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.attention = (UCHAR)choice; + CONSOLE_OUT("Attention (8-bit in HEX): 0x%02X\n", param.attention); + } + + retval = MS_health_attention_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Health Fault Clear */ +API_RESULT cli_modelc_health_fault_clear(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_HEALTH_FAULT_GET_CLEAR_STRUCT param; + CONSOLE_OUT + (">> Send Health Fault Clear\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.company_id = (UINT16)choice; + CONSOLE_OUT("Company ID (16-bit in HEX): 0x%04X\n", param.company_id); + } + + retval = MS_health_fault_clear(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Health Fault Clear Unacknowledged */ +API_RESULT cli_modelc_health_fault_clear_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_HEALTH_FAULT_GET_CLEAR_STRUCT param; + CONSOLE_OUT + (">> Send Health Fault Clear Unacknowledged\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.company_id = (UINT16)choice; + CONSOLE_OUT("Company ID (16-bit in HEX): 0x%04X\n", param.company_id); + } + + retval = MS_health_fault_clear_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Health Fault Get */ +API_RESULT cli_modelc_health_fault_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_HEALTH_FAULT_GET_CLEAR_STRUCT param; + CONSOLE_OUT + (">> Send Health Fault Get\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.company_id = (UINT16)choice; + CONSOLE_OUT("Company ID (16-bit in HEX): 0x%04X\n", param.company_id); + } + + retval = MS_health_fault_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Health Fault Test */ +API_RESULT cli_modelc_health_fault_test(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_HEALTH_FAULT_TEST_STRUCT param; + CONSOLE_OUT + (">> Send Health Fault Test\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.test_id = (UCHAR)choice; + CONSOLE_OUT("Test ID (8-bit in HEX): 0x%02X\n", param.test_id); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.company_id = (UINT16)choice; + CONSOLE_OUT("Company ID (16-bit in HEX): 0x%04X\n", param.company_id); + } + + retval = MS_health_fault_test(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Health Fault Test Unacknowledged */ +API_RESULT cli_modelc_health_fault_test_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_HEALTH_FAULT_TEST_STRUCT param; + CONSOLE_OUT + (">> Send Health Fault Test Unacknowledged\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.test_id = (UCHAR)choice; + CONSOLE_OUT("Test ID (8-bit in HEX): 0x%02X\n", param.test_id); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.company_id = (UINT16)choice; + CONSOLE_OUT("Company ID (16-bit in HEX): 0x%04X\n", param.company_id); + } + + retval = MS_health_fault_test_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Health Period Get */ +API_RESULT cli_modelc_health_period_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Health Period Get\n"); + retval = MS_health_period_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Health Period Set */ +API_RESULT cli_modelc_health_period_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_HEALTH_PERIOD_STRUCT param; + CONSOLE_OUT + (">> Send Health Period Set\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.fastperioddivisor = (UCHAR)choice; + CONSOLE_OUT("FastPeriodDivisor (8-bit in HEX): 0x%02X\n", param.fastperioddivisor); + } + + retval = MS_health_period_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Health Period Set Unacknowledged */ +API_RESULT cli_modelc_health_period_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_HEALTH_PERIOD_STRUCT param; + CONSOLE_OUT + (">> Send Health Period Set Unacknowledged\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.fastperioddivisor = (UCHAR)choice; + CONSOLE_OUT("FastPeriodDivisor (8-bit in HEX): 0x%02X\n", param.fastperioddivisor); + } + + retval = MS_health_period_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Get Model Handle */ +API_RESULT cli_modelc_health_get_model_handle(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + #if 0 + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_health_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + #else + retval = API_FAILURE; + CONSOLE_OUT("To be implemented\n"); + #endif /* 0 */ + return retval; +} + + +/* Set Publish Address */ +API_RESULT cli_modelc_health_set_publish_address(UINT32 argc, UCHAR* argv[]) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + model_handle = appl_health_client_model_handle; + CONSOLE_OUT("Model Handle (16-bit in HEX): 0x%04X\n", model_handle); + + /* Check Number of Arguments */ + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT("Health Server Address (16-bit in HEX): 0x%04X\n", publish_info.addr.addr); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + publish_info.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKey Index: 0x%04X\n", publish_info.appkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return retval; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Health client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_health_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[HEALTH_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_HEALTH_ATTENTION_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_HEALTH_ATTENTION_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_HEALTH_CURRENT_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_HEALTH_CURRENT_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_HEALTH_FAULT_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_HEALTH_FAULT_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_HEALTH_PERIOD_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_HEALTH_PERIOD_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + +#endif /* CLI_HEALTH_CLIENT_MODEL */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_health_client.h b/src/components/ethermind/mesh/export/cli/model/client/cli_health_client.h new file mode 100644 index 0000000..e261b26 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_health_client.h @@ -0,0 +1,93 @@ +/** + \file cli_health_client.h + + \brief This file defines the Mesh Health Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_CLI_HEALTH_CLIENT_ +#define _H_CLI_HEALTH_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_health_client_api.h" +#include "cli_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* health client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_health); + +/* health client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_health_setup); + +/* Send Health Attention Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_health_attention_get); + +/* Send Health Attention Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_health_attention_set); + +/* Send Health Attention Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_health_attention_set_unacknowledged); + +/* Send Health Fault Clear */ +CLI_CMD_HANDLER_DECL(cli_modelc_health_fault_clear); + +/* Send Health Fault Clear Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_health_fault_clear_unacknowledged); + +/* Send Health Fault Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_health_fault_get); + +/* Send Health Fault Test */ +CLI_CMD_HANDLER_DECL(cli_modelc_health_fault_test); + +/* Send Health Fault Test Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_health_fault_test_unacknowledged); + +/* Send Health Period Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_health_period_get); + +/* Send Health Period Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_health_period_set); + +/* Send Health Period Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_health_period_set_unacknowledged); + +/* Get Model Handle */ +CLI_CMD_HANDLER_DECL(cli_modelc_health_get_model_handle); + +/* Set Publish Address */ +CLI_CMD_HANDLER_DECL(cli_modelc_health_set_publish_address); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Health client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_health_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_CLI_HEALTH_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_light_ctl_client.c b/src/components/ethermind/mesh/export/cli/model/client/cli_light_ctl_client.c new file mode 100644 index 0000000..e91bba0 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_light_ctl_client.c @@ -0,0 +1,610 @@ +/** + \file cli_light_ctl_client.c + + \brief This file defines the Mesh Light Ctl Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "cli_light_ctl_client.h" + +#ifdef CLI_LIGHTINGS_CTL_CLIENT_MODEL + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +DECL_CONST CLI_COMMAND cli_modelc_light_ctl_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + /* Setup */ + { "setup", "Model Light_Ctl Setup", cli_modelc_light_ctl_setup }, + + /* Get Model Handle */ + { "gethandle", "Get Model Handle", cli_modelc_light_ctl_get_model_handle }, + + /* Set Publish Address */ + { "publishaddr", "Set Publish Address ", cli_modelc_light_ctl_set_publish_address }, + + /* Send Light Ctl Default Get */ + { "defaultget", "Send Light Ctl Default Get", cli_modelc_light_ctl_default_get}, + + /* Send Light Ctl Default Set */ + { "defaultset", "Send Light Ctl Default Set", cli_modelc_light_ctl_default_set}, + + /* Send Light Ctl Default Set Unacknowledged */ + { "defaultsetun", "Send Light Ctl Default Set Unacknowledged", cli_modelc_light_ctl_default_set_unacknowledged}, + + /* Send Light Ctl Get */ + { "ctlget", "Send Light Ctl Get", cli_modelc_light_ctl_get}, + + /* Send Light Ctl Set */ + { "ctlset", "Send Light Ctl Set", cli_modelc_light_ctl_set}, + + /* Send Light Ctl Set Unacknowledged */ + { "ctlsetun", "Send Light Ctl Set Unacknowledged", cli_modelc_light_ctl_set_unacknowledged}, + + /* Send Light Ctl Temperature Get */ + { "tempget", "Send Light Ctl Temperature Get", cli_modelc_light_ctl_temperature_get}, + + /* Send Light Ctl Temperature Range Get */ + { "temprangeget", "Send Light Ctl Temperature Range Get", cli_modelc_light_ctl_temperature_range_get}, + + /* Send Light Ctl Temperature Range Set */ + { "temprangeset", "Send Light Ctl Temperature Range Set", cli_modelc_light_ctl_temperature_range_set}, + + /* Send Light Ctl Temperature Range Set Unacknowledged */ + { "temprangesetun", "Send Light Ctl Temperature Range Set Unacknowledged", cli_modelc_light_ctl_temperature_range_set_unacknowledged}, + + /* Send Light Ctl Temperature Set */ + { "tempset", "Send Light Ctl Temperature Set", cli_modelc_light_ctl_temperature_set}, + + /* Send Light Ctl Temperature Set Unacknowledged */ + { "tempsetun", "Send Light Ctl Temperature Set Unacknowledged", cli_modelc_light_ctl_temperature_set_unacknowledged} +}; + + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_light_ctl_client_model_handle; + + +/* --------------------------------------------- Function */ +API_RESULT cli_modelc_light_ctl(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT("In Model Client - Light_Ctl\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_modelc_light_ctl_cmd_list, sizeof(cli_modelc_light_ctl_cmd_list) / sizeof(CLI_COMMAND)); + retval = cli_help(argc, argv); + return retval; +} + +/* light_ctl client CLI entry point */ +API_RESULT cli_modelc_light_ctl_setup(UINT32 argc, UCHAR* argv[]) +{ + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + static UCHAR model_initialized = 0x00; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + /** + Register with Access Layer. + */ + retval = API_FAILURE; + + if (0x00 == model_initialized) + { + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_light_ctl_client_init + ( + element_handle, + &appl_light_ctl_client_model_handle, + cli_light_ctl_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Ctl Client Initialized. Model Handle: 0x%04X\n", + appl_light_ctl_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Ctl Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + return retval; +} + +/* Send Light Ctl Default Get */ +API_RESULT cli_modelc_light_ctl_default_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Ctl Default Get\n"); + retval = MS_light_ctl_default_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Ctl Default Set */ +API_RESULT cli_modelc_light_ctl_default_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_CTL_DEFAULT_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Ctl Default Set\n"); + + if (3 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.lightness = (UINT16)choice; + CONSOLE_OUT("Lightness (16-bit in HEX): 0x%04X\n", param.lightness); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.temperature = (UINT16)choice; + CONSOLE_OUT("Temperature (16-bit in HEX): 0x%04X\n", param.temperature); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.delta_uv = (UINT16)choice; + CONSOLE_OUT("Delta UV (16-bit in HEX): 0x%04X\n", param.delta_uv); + } + + retval = MS_light_ctl_default_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Ctl Default Set Unacknowledged */ +API_RESULT cli_modelc_light_ctl_default_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_CTL_DEFAULT_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Ctl Default Set Unacknowledged\n"); + + if (3 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.lightness = (UINT16)choice; + CONSOLE_OUT("Lightness (16-bit in HEX): 0x%04X\n", param.lightness); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.temperature = (UINT16)choice; + CONSOLE_OUT("Temperature (16-bit in HEX): 0x%04X\n", param.temperature); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.delta_uv = (UINT16)choice; + CONSOLE_OUT("Delta UV (16-bit in HEX): 0x%04X\n", param.delta_uv); + } + + retval = MS_light_ctl_default_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Ctl Get */ +API_RESULT cli_modelc_light_ctl_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Ctl Get\n"); + retval = MS_light_ctl_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Ctl Set */ +API_RESULT cli_modelc_light_ctl_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_CTL_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Ctl Set\n"); + + if (4 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.ctl_lightness = (UINT16)choice; + CONSOLE_OUT("CTL Lightness (16-bit in HEX): 0x%04X\n", param.ctl_lightness); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.ctl_temperature = (UINT16)choice; + CONSOLE_OUT("CTL Temperature (16-bit in HEX): 0x%04X\n", param.ctl_temperature); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.ctl_delta_uv = (UINT16)choice; + CONSOLE_OUT("CTL Delta UV (16-bit in HEX): 0x%04X\n", param.ctl_delta_uv); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (6 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[4], CLI_strlen(argv[4]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[5], CLI_strlen(argv[5]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_light_ctl_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Ctl Set Unacknowledged */ +API_RESULT cli_modelc_light_ctl_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_CTL_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Ctl Set Unacknowledged\n"); + + if (4 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.ctl_lightness = (UINT16)choice; + CONSOLE_OUT("CTL Lightness (16-bit in HEX): 0x%04X\n", param.ctl_lightness); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.ctl_temperature = (UINT16)choice; + CONSOLE_OUT("CTL Temperature (16-bit in HEX): 0x%04X\n", param.ctl_temperature); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.ctl_delta_uv = (UINT16)choice; + CONSOLE_OUT("CTL Delta UV (16-bit in HEX): 0x%04X\n", param.ctl_delta_uv); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (6 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[4], CLI_strlen(argv[4]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[5], CLI_strlen(argv[5]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_light_ctl_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Ctl Temperature Get */ +API_RESULT cli_modelc_light_ctl_temperature_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Ctl Temperature Get\n"); + retval = MS_light_ctl_temperature_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Ctl Temperature Range Get */ +API_RESULT cli_modelc_light_ctl_temperature_range_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Ctl Temperature Range Get\n"); + retval = MS_light_ctl_temperature_range_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + + +/* Send Light Ctl Temperature Range Set */ +API_RESULT cli_modelc_light_ctl_temperature_range_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_CTL_TEMPERATURE_RANGE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Ctl Temperature Range Set\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.range_min = (UINT16)choice; + CONSOLE_OUT("Range Min (16-bit in HEX): 0x%04X\n", param.range_min); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.range_max = (UINT16)choice; + CONSOLE_OUT("Range Max (16-bit in HEX): 0x%04X\n", param.range_max); + } + + retval = MS_light_ctl_temperature_range_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Ctl Temperature Range Set Unacknowledged */ +API_RESULT cli_modelc_light_ctl_temperature_range_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_CTL_TEMPERATURE_RANGE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Ctl Temperature Range Set Unacknowledged\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.range_min = (UINT16)choice; + CONSOLE_OUT("Range Min (16-bit in HEX): 0x%04X\n", param.range_min); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.range_max = (UINT16)choice; + CONSOLE_OUT("Range Max (16-bit in HEX): 0x%04X\n", param.range_max); + } + + retval = MS_light_ctl_temperature_range_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + + +/* Send Light Ctl Temperature Set */ +API_RESULT cli_modelc_light_ctl_temperature_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_CTL_TEMPERATURE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Ctl Temperature Set\n"); + + if (3 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.ctl_temperature = (UINT16)choice; + CONSOLE_OUT("CTL Temperature (16-bit in HEX): 0x%04X\n", param.ctl_temperature); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.ctl_delta_uv = (UINT16)choice; + CONSOLE_OUT("CTL Delta UV (16-bit in HEX): 0x%04X\n", param.ctl_delta_uv); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (5 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[4], CLI_strlen(argv[4]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_light_ctl_temperature_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Ctl Temperature Set Unacknowledged */ +API_RESULT cli_modelc_light_ctl_temperature_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_CTL_TEMPERATURE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Ctl Temperature Set Unacknowledged\n"); + + if (3 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.ctl_temperature = (UINT16)choice; + CONSOLE_OUT("CTL Temperature (16-bit in HEX): 0x%04X\n", param.ctl_temperature); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.ctl_delta_uv = (UINT16)choice; + CONSOLE_OUT("CTL Delta UV (16-bit in HEX): 0x%04X\n", param.ctl_delta_uv); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (5 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[4], CLI_strlen(argv[4]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_light_ctl_temperature_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Get Model Handle */ +API_RESULT cli_modelc_light_ctl_get_model_handle(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + #if 0 + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_light_ctl_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + #else + retval = API_FAILURE; + CONSOLE_OUT("To be implemented\n"); + #endif /* 0 */ + return retval; +} + + +/* Set Publish Address */ +API_RESULT cli_modelc_light_ctl_set_publish_address(UINT32 argc, UCHAR* argv[]) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + model_handle = appl_light_ctl_client_model_handle; + CONSOLE_OUT("Model Handle (16-bit in HEX): 0x%04X\n", model_handle); + + /* Check Number of Arguments */ + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT("Light_Ctl Server Address (16-bit in HEX): 0x%04X\n", publish_info.addr.addr); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + publish_info.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKey Index: 0x%04X\n", publish_info.appkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return retval; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Light_Ctl client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_light_ctl_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[LIGHT_CTL_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_LIGHT_CTL_DEFAULT_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_CTL_DEFAULT_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_CTL_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_CTL_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_CTL_TEMPERATURE_RANGE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_CTL_TEMPERATURE_RANGE_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_CTL_TEMPERATURE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_CTL_TEMPERATURE_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + +#endif /* CLI_LIGHTINGS_CTL_CLIENT_MODEL */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_light_ctl_client.h b/src/components/ethermind/mesh/export/cli/model/client/cli_light_ctl_client.h new file mode 100644 index 0000000..3d8f0ba --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_light_ctl_client.h @@ -0,0 +1,96 @@ +/** + \file cli_light_ctl_client.h + + \brief This file defines the Mesh Light Ctl Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_CLI_LIGHT_CTL_CLIENT_ +#define _H_CLI_LIGHT_CTL_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_light_ctl_api.h" +#include "cli_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* light_ctl client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_ctl); + +/* light_ctl client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_ctl_setup); + +/* Send Light Ctl Default Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_ctl_default_get); + +/* Send Light Ctl Default Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_ctl_default_set); + +/* Send Light Ctl Default Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_ctl_default_set_unacknowledged); + +/* Send Light Ctl Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_ctl_get); + +/* Send Light Ctl Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_ctl_set); + +/* Send Light Ctl Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_ctl_set_unacknowledged); + +/* Send Light Ctl Temperature Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_ctl_temperature_get); + +/* Send Light Ctl Temperature Range Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_ctl_temperature_range_get); + +/* Send Light Ctl Temperature Range Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_ctl_temperature_range_set); + +/* Send Light Ctl Temperature Range Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_ctl_temperature_range_set_unacknowledged); + +/* Send Light Ctl Temperature Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_ctl_temperature_set); + +/* Send Light Ctl Temperature Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_ctl_temperature_set_unacknowledged); + +/* Get Model Handle */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_ctl_get_model_handle); + +/* Set Publish Address */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_ctl_set_publish_address); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Light_Ctl client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_light_ctl_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_CLI_LIGHT_CTL_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_light_hsl_client.c b/src/components/ethermind/mesh/export/cli/model/client/cli_light_hsl_client.c new file mode 100644 index 0000000..aef0121 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_light_hsl_client.c @@ -0,0 +1,745 @@ +/** + \file cli_light_hsl_client.c + + \brief This file defines the Mesh Light Hsl Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "cli_light_hsl_client.h" + +#ifdef CLI_LIGHTINGS_HSL_CLIENT_MODEL + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +DECL_CONST CLI_COMMAND cli_modelc_light_hsl_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + /* Setup */ + { "setup", "Model Light_Hsl Setup", cli_modelc_light_hsl_setup }, + + /* Get Model Handle */ + { "gethandle", "Get Model Handle", cli_modelc_light_hsl_get_model_handle }, + + /* Set Publish Address */ + { "publishaddr", "Set Publish Address ", cli_modelc_light_hsl_set_publish_address }, + + /* Send Light Hsl Default Get */ + { "defaultget", "Send Light Hsl Default Get", cli_modelc_light_hsl_default_get}, + + /* Send Light Hsl Default Set */ + { "defaultset", "Send Light Hsl Default Set", cli_modelc_light_hsl_default_set}, + + /* Send Light Hsl Default Set Unacknowledged */ + { "defaultsetun", "Send Light Hsl Default Set Unacknowledged", cli_modelc_light_hsl_default_set_unacknowledged}, + + /* Send Light Hsl Get */ + { "hslget", "Send Light Hsl Get", cli_modelc_light_hsl_get}, + + /* Send Light Hsl Hue Get */ + { "hueget", "Send Light Hsl Hue Get", cli_modelc_light_hsl_hue_get}, + + /* Send Light Hsl Hue Set */ + { "hueset", "Send Light Hsl Hue Set", cli_modelc_light_hsl_hue_set}, + + /* Send Light Hsl Hue Set Unacknowledged */ + { "huesetun", "Send Light Hsl Hue Set Unacknowledged", cli_modelc_light_hsl_hue_set_unacknowledged}, + + /* Send Light Hsl Range Get */ + { "rangeget", "Send Light Hsl Range Get", cli_modelc_light_hsl_range_get}, + + /* Send Light Hsl Range Set */ + { "rangeset", "Send Light Hsl Range Set", cli_modelc_light_hsl_range_set}, + + /* Send Light Hsl Range Set Unacknowledged */ + { "rangesetun", "Send Light Hsl Range Set Unacknowledged", cli_modelc_light_hsl_range_set_unacknowledged}, + + /* Send Light Hsl Saturation Get */ + { "saturget", "Send Light Hsl Saturation Get", cli_modelc_light_hsl_saturation_get}, + + /* Send Light Hsl Saturation Set */ + { "saturset", "Send Light Hsl Saturation Set", cli_modelc_light_hsl_saturation_set}, + + /* Send Light Hsl Saturation Set Unacknowledged */ + { "satursetun", "Send Light Hsl Saturation Set Unacknowledged", cli_modelc_light_hsl_saturation_set_unacknowledged}, + + /* Send Light Hsl Set */ + { "hslset", "Send Light Hsl Set", cli_modelc_light_hsl_set}, + + /* Send Light Hsl Set Unacknowledged */ + { "hslsetun", "Send Light Hsl Set Unacknowledged", cli_modelc_light_hsl_set_unacknowledged}, + + /* Send Light Hsl Target Get */ + { "targetget", "Send Light Hsl Target Get", cli_modelc_light_hsl_target_get} +}; + + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_light_hsl_client_model_handle; + + +/* --------------------------------------------- Function */ +API_RESULT cli_modelc_light_hsl(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT("In Model Client - Light_Hsl\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_modelc_light_hsl_cmd_list, sizeof(cli_modelc_light_hsl_cmd_list) / sizeof(CLI_COMMAND)); + retval = cli_help(argc, argv); + return retval; +} + +/* light_hsl client CLI entry point */ +API_RESULT cli_modelc_light_hsl_setup(UINT32 argc, UCHAR* argv[]) +{ + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + static UCHAR model_initialized = 0x00; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + /** + Register with Access Layer. + */ + retval = API_FAILURE; + + if (0x00 == model_initialized) + { + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_light_hsl_client_init + ( + element_handle, + &appl_light_hsl_client_model_handle, + cli_light_hsl_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Hsl Client Initialized. Model Handle: 0x%04X\n", + appl_light_hsl_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Hsl Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + return retval; +} + +/* Send Light Hsl Default Get */ +API_RESULT cli_modelc_light_hsl_default_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Hsl Default Get\n"); + retval = MS_light_hsl_default_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Hsl Default Set */ +API_RESULT cli_modelc_light_hsl_default_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_HSL_DEFAULT_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Hsl Default Set\n"); + + if (3 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.lightness = (UINT16)choice; + CONSOLE_OUT("Lightness (16-bit in HEX): 0x%04X\n", param.lightness); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.hue = (UINT16)choice; + CONSOLE_OUT("Hue (16-bit in HEX): 0x%04X\n", param.hue); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.saturation = (UINT16)choice; + CONSOLE_OUT("Saturation (16-bit in HEX): 0x%04X\n", param.saturation); + } + + retval = MS_light_hsl_default_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Hsl Default Set Unacknowledged */ +API_RESULT cli_modelc_light_hsl_default_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_HSL_DEFAULT_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Hsl Default Set Unacknowledged\n"); + + if (3 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.lightness = (UINT16)choice; + CONSOLE_OUT("Lightness (16-bit in HEX): 0x%04X\n", param.lightness); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.hue = (UINT16)choice; + CONSOLE_OUT("Hue (16-bit in HEX): 0x%04X\n", param.hue); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.saturation = (UINT16)choice; + CONSOLE_OUT("Saturation (16-bit in HEX): 0x%04X\n", param.saturation); + } + + retval = MS_light_hsl_default_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Hsl Get */ +API_RESULT cli_modelc_light_hsl_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Hsl Get\n"); + retval = MS_light_hsl_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Hsl Hue Get */ +API_RESULT cli_modelc_light_hsl_hue_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Hsl Hue Get\n"); + retval = MS_light_hsl_hue_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Hsl Hue Set */ +API_RESULT cli_modelc_light_hsl_hue_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_HSL_HUE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Hsl Hue Set\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.hue = (UINT16)choice; + CONSOLE_OUT("Hue (16-bit in HEX): 0x%04X\n", param.hue); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_light_hsl_hue_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Hsl Hue Set Unacknowledged */ +API_RESULT cli_modelc_light_hsl_hue_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_HSL_HUE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Hsl Hue Set Unacknowledged\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.hue = (UINT16)choice; + CONSOLE_OUT("Hue (16-bit in HEX): 0x%04X\n", param.hue); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_light_hsl_hue_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Hsl Range Get */ +API_RESULT cli_modelc_light_hsl_range_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Hsl Range Get\n"); + retval = MS_light_hsl_range_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Hsl Range Set */ +API_RESULT cli_modelc_light_hsl_range_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_HSL_RANGE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Hsl Range Set\n"); + + if (4 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.hue_range_min = (UINT16)choice; + CONSOLE_OUT("Hue Range Min (16-bit in HEX): 0x%04X\n", param.hue_range_min); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.hue_range_max = (UINT16)choice; + CONSOLE_OUT("Hue Range Max (16-bit in HEX): 0x%04X\n", param.hue_range_max); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.saturation_range_min = (UINT16)choice; + CONSOLE_OUT("Saturation Range Min (16-bit in HEX): 0x%04X\n", param.saturation_range_min); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.saturation_range_max = (UINT16)choice; + CONSOLE_OUT("Saturation Range Max (16-bit in HEX): 0x%04X\n", param.saturation_range_max); + } + + retval = MS_light_hsl_range_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Hsl Range Set Unacknowledged */ +API_RESULT cli_modelc_light_hsl_range_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_HSL_RANGE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Hsl Range Set Unacknowledged\n"); + + if (4 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.hue_range_min = (UINT16)choice; + CONSOLE_OUT("Hue Range Min (16-bit in HEX): 0x%04X\n", param.hue_range_min); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.hue_range_max = (UINT16)choice; + CONSOLE_OUT("Hue Range Max (16-bit in HEX): 0x%04X\n", param.hue_range_max); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.saturation_range_min = (UINT16)choice; + CONSOLE_OUT("Saturation Range Min (16-bit in HEX): 0x%04X\n", param.saturation_range_min); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.saturation_range_max = (UINT16)choice; + CONSOLE_OUT("Saturation Range Max (16-bit in HEX): 0x%04X\n", param.saturation_range_max); + } + + retval = MS_light_hsl_range_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Hsl Saturation Get */ +API_RESULT cli_modelc_light_hsl_saturation_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Hsl Saturation Get\n"); + retval = MS_light_hsl_saturation_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Hsl Saturation Set */ +API_RESULT cli_modelc_light_hsl_saturation_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_HSL_SATURATION_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Hsl Saturation Set\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.saturation = (UINT16)choice; + CONSOLE_OUT("Saturation (16-bit in HEX): 0x%04X\n", param.saturation); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_light_hsl_saturation_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Hsl Saturation Set Unacknowledged */ +API_RESULT cli_modelc_light_hsl_saturation_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_HSL_SATURATION_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Hsl Saturation Set Unacknowledged\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.saturation = (UINT16)choice; + CONSOLE_OUT("Saturation (16-bit in HEX): 0x%04X\n", param.saturation); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_light_hsl_saturation_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + + +/* Send Light Hsl Set */ +API_RESULT cli_modelc_light_hsl_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_HSL_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Hsl Set\n"); + + if (4 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.hsl_lightness = (UINT16)choice; + CONSOLE_OUT("HSL Lightness (16-bit in HEX): 0x%04X\n", param.hsl_lightness); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.hsl_hue = (UINT16)choice; + CONSOLE_OUT("HSL Hue (16-bit in HEX): 0x%04X\n", param.hsl_hue); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.hsl_saturation = (UINT16)choice; + CONSOLE_OUT("HSL Saturation (16-bit in HEX): 0x%04X\n", param.hsl_saturation); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (6 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[4], CLI_strlen(argv[4]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[5], CLI_strlen(argv[5]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_light_hsl_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Hsl Set Unacknowledged */ +API_RESULT cli_modelc_light_hsl_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_HSL_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Hsl Set Unacknowledged\n"); + + if (4 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.hsl_lightness = (UINT16)choice; + CONSOLE_OUT("HSL Lightness (16-bit in HEX): 0x%04X\n", param.hsl_lightness); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.hsl_hue = (UINT16)choice; + CONSOLE_OUT("HSL Hue (16-bit in HEX): 0x%04X\n", param.hsl_hue); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.hsl_saturation = (UINT16)choice; + CONSOLE_OUT("HSL Saturation (16-bit in HEX): 0x%04X\n", param.hsl_saturation); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (6 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[4], CLI_strlen(argv[4]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[5], CLI_strlen(argv[5]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_light_hsl_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Hsl Target Get */ +API_RESULT cli_modelc_light_hsl_target_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Hsl Target Get\n"); + retval = MS_light_hsl_target_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Get Model Handle */ +API_RESULT cli_modelc_light_hsl_get_model_handle(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + #if 0 + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_light_hsl_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + #else + retval = API_FAILURE; + CONSOLE_OUT("To be implemented\n"); + #endif /* 0 */ + return retval; +} + + +/* Set Publish Address */ +API_RESULT cli_modelc_light_hsl_set_publish_address(UINT32 argc, UCHAR* argv[]) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + model_handle = appl_light_hsl_client_model_handle; + CONSOLE_OUT("Model Handle (16-bit in HEX): 0x%04X\n", model_handle); + + /* Check Number of Arguments */ + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT("Light_Hsl Server Address (16-bit in HEX): 0x%04X\n", publish_info.addr.addr); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + publish_info.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKey Index: 0x%04X\n", publish_info.appkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return retval; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Light_Hsl client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_light_hsl_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[LIGHT_HSL_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_LIGHT_HSL_DEFAULT_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_HSL_DEFAULT_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_HSL_HUE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_HSL_HUE_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_HSL_RANGE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_HSL_RANGE_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_HSL_SATURATION_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_HSL_SATURATION_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_HSL_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_HSL_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_HSL_TARGET_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_HSL_TARGET_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + +#endif /* CLI_LIGHTINGS_HSL_CLIENT_MODEL */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_light_hsl_client.h b/src/components/ethermind/mesh/export/cli/model/client/cli_light_hsl_client.h new file mode 100644 index 0000000..e123111 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_light_hsl_client.h @@ -0,0 +1,108 @@ +/** + \file cli_light_hsl_client.h + + \brief This file defines the Mesh Light Hsl Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_CLI_LIGHT_HSL_CLIENT_ +#define _H_CLI_LIGHT_HSL_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_light_hsl_api.h" +#include "cli_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* light_hsl client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_hsl); + +/* light_hsl client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_hsl_setup); + +/* Send Light Hsl Default Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_hsl_default_get); + +/* Send Light Hsl Default Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_hsl_default_set); + +/* Send Light Hsl Default Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_hsl_default_set_unacknowledged); + +/* Send Light Hsl Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_hsl_get); + +/* Send Light Hsl Hue Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_hsl_hue_get); + +/* Send Light Hsl Hue Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_hsl_hue_set); + +/* Send Light Hsl Hue Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_hsl_hue_set_unacknowledged); + +/* Send Light Hsl Range Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_hsl_range_get); + +/* Send Light Hsl Range Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_hsl_range_set); + +/* Send Light Hsl Range Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_hsl_range_set_unacknowledged); + +/* Send Light Hsl Saturation Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_hsl_saturation_get); + +/* Send Light Hsl Saturation Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_hsl_saturation_set); + +/* Send Light Hsl Saturation Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_hsl_saturation_set_unacknowledged); + +/* Send Light Hsl Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_hsl_set); + +/* Send Light Hsl Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_hsl_set_unacknowledged); + +/* Send Light Hsl Target Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_hsl_target_get); + +/* Get Model Handle */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_hsl_get_model_handle); + +/* Set Publish Address */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_hsl_set_publish_address); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Light_Hsl client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_light_hsl_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_CLI_LIGHT_HSL_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_light_lc_client.c b/src/components/ethermind/mesh/export/cli/model/client/cli_light_lc_client.c new file mode 100644 index 0000000..2dcb7ef --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_light_lc_client.c @@ -0,0 +1,604 @@ +/** + \file cli_light_lc_client.c + + \brief This file defines the Mesh Light Lc Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "cli_light_lc_client.h" + +#ifdef CLI_LIGHTINGS_LC_CLIENT_MODEL + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +DECL_CONST CLI_COMMAND cli_modelc_light_lc_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + /* Setup */ + { "setup", "Model Light_Lc Setup", cli_modelc_light_lc_setup }, + + /* Get Model Handle */ + { "gethandle", "Get Model Handle", cli_modelc_light_lc_get_model_handle }, + + /* Set Publish Address */ + { "publishaddr", "Set Publish Address ", cli_modelc_light_lc_set_publish_address }, + + /* Send Light Lc Light Onoff Get */ + { "lightonoffget", "Send Light Lc Light Onoff Get", cli_modelc_light_lc_light_onoff_get}, + + /* Send Light Lc Light Onoff Set */ + { "lightonoffset", "Send Light Lc Light Onoff Set", cli_modelc_light_lc_light_onoff_set}, + + /* Send Light Lc Light Onoff Set Unacknowledged */ + { "lightonoffsetun", "Send Light Lc Light Onoff Set Unacknowledged", cli_modelc_light_lc_light_onoff_set_unacknowledged}, + + /* Send Light Lc Mode Get */ + { "modeget", "Send Light Lc Mode Get", cli_modelc_light_lc_mode_get}, + + /* Send Light Lc Mode Set */ + { "modeset", "Send Light Lc Mode Set", cli_modelc_light_lc_mode_set}, + + /* Send Light Lc Mode Set Unacknowledged */ + { "modesetun", "Send Light Lc Mode Set Unacknowledged", cli_modelc_light_lc_mode_set_unacknowledged}, + + /* Send Light Lc Om Get */ + { "omget", "Send Light Lc Om Get", cli_modelc_light_lc_om_get}, + + /* Send Light Lc Om Set */ + { "omset", "Send Light Lc Om Set", cli_modelc_light_lc_om_set}, + + /* Send Light Lc Om Set Unacknowledged */ + { "omsetun", "Send Light Lc Om Set Unacknowledged", cli_modelc_light_lc_om_set_unacknowledged}, + + /* Send Light Lc Property Get */ + { "propertyget", "Send Light Lc Property Get", cli_modelc_light_lc_property_get}, + + /* Send Light Lc Property Set */ + { "propertyset", "Send Light Lc Property Set", cli_modelc_light_lc_property_set}, + + /* Send Light Lc Property Set Unacknowledged */ + { "propertysetun", "Send Light Lc Property Set Unacknowledged", cli_modelc_light_lc_property_set_unacknowledged} +}; + + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_light_lc_client_model_handle; + + +/* --------------------------------------------- Function */ +API_RESULT cli_modelc_light_lc(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT("In Model Client - Light_Lc\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_modelc_light_lc_cmd_list, sizeof(cli_modelc_light_lc_cmd_list) / sizeof(CLI_COMMAND)); + retval = cli_help(argc, argv); + return retval; +} + +/* light_lc client CLI entry point */ +API_RESULT cli_modelc_light_lc_setup(UINT32 argc, UCHAR* argv[]) +{ + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + static UCHAR model_initialized = 0x00; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + /** + Register with Access Layer. + */ + retval = API_FAILURE; + + if (0x00 == model_initialized) + { + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_light_lc_client_init + ( + element_handle, + &appl_light_lc_client_model_handle, + cli_light_lc_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Lc Client Initialized. Model Handle: 0x%04X\n", + appl_light_lc_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Lc Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + return retval; +} + +/* Send Light Lc Light Onoff Get */ +API_RESULT cli_modelc_light_lc_light_onoff_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Lc Light Onoff Get\n"); + retval = MS_light_lc_light_onoff_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Lc Light Onoff Set */ +API_RESULT cli_modelc_light_lc_light_onoff_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LC_LIGHT_ONOFF_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lc Light Onoff Set\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.light_onoff = (UCHAR)choice; + CONSOLE_OUT("Light OnOff (8-bit in HEX): 0x%02X\n", param.light_onoff); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_light_lc_light_onoff_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Lc Light Onoff Set Unacknowledged */ +API_RESULT cli_modelc_light_lc_light_onoff_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LC_LIGHT_ONOFF_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lc Light Onoff Set Unacknowledged\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.light_onoff = (UCHAR)choice; + CONSOLE_OUT("Light OnOff (8-bit in HEX): 0x%02X\n", param.light_onoff); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_light_lc_light_onoff_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Lc Mode Get */ +API_RESULT cli_modelc_light_lc_mode_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Lc Mode Get\n"); + retval = MS_light_lc_mode_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Lc Mode Set */ +API_RESULT cli_modelc_light_lc_mode_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LC_MODE_STRUCT param; + CONSOLE_OUT + (">> Send Light Lc Mode Set\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.mode = (UCHAR)choice; + CONSOLE_OUT("Mode (8-bit in HEX): 0x%02X\n", param.mode); + } + + retval = MS_light_lc_mode_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Lc Mode Set Unacknowledged */ +API_RESULT cli_modelc_light_lc_mode_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LC_MODE_STRUCT param; + CONSOLE_OUT + (">> Send Light Lc Mode Set Unacknowledged\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.mode = (UCHAR)choice; + CONSOLE_OUT("Mode (8-bit in HEX): 0x%02X\n", param.mode); + } + + retval = MS_light_lc_mode_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Lc Om Get */ +API_RESULT cli_modelc_light_lc_om_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Lc Om Get\n"); + retval = MS_light_lc_om_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Lc Om Set */ +API_RESULT cli_modelc_light_lc_om_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LC_OM_STRUCT param; + CONSOLE_OUT + (">> Send Light Lc Om Set\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.mode = (UCHAR)choice; + CONSOLE_OUT("Mode (8-bit in HEX): 0x%02X\n", param.mode); + } + + retval = MS_light_lc_om_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Lc Om Set Unacknowledged */ +API_RESULT cli_modelc_light_lc_om_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LC_OM_STRUCT param; + CONSOLE_OUT + (">> Send Light Lc Om Set Unacknowledged\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.mode = (UCHAR)choice; + CONSOLE_OUT("Mode (8-bit in HEX): 0x%02X\n", param.mode); + } + + retval = MS_light_lc_om_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Lc Property Get */ +API_RESULT cli_modelc_light_lc_property_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LC_PROPERTY_GET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lc Property Get\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.light_lc_property_id = (UINT16)choice; + CONSOLE_OUT("Light LC Property ID (16-bit in HEX): 0x%04X\n", param.light_lc_property_id); + } + + retval = MS_light_lc_property_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} +/* Send Light Lc Property Set */ +API_RESULT cli_modelc_light_lc_property_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LC_PROPERTY_SET_STRUCT param; + retval = API_FAILURE; + CONSOLE_OUT + (">> Send Light Lc Property Set\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.light_lc_property_id = (UINT16)choice; + CONSOLE_OUT("Light LC Property ID (16-bit in HEX): 0x%04X\n", param.light_lc_property_id); + choice = CLI_strlen(argv[1]); + { + UINT16 input_len; + input_len = (UINT16)choice; + param.light_lc_property_value = EM_alloc_mem(input_len); + + if(NULL == param.light_lc_property_value) + { + CONSOLE_OUT + ("Memory allocation failed for Light LC Property Value. Returning\n"); + return retval; + } + + param.light_lc_property_value_len = (UINT16) input_len; + CLI_strtoarray + ( + argv[1], + CLI_strlen(argv[1]), + ¶m.light_lc_property_value[0], + input_len + ); + } + } + + retval = MS_light_lc_property_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.light_lc_property_value) + { + EM_free_mem(param.light_lc_property_value); + } + + return retval; +} + + +/* Send Light Lc Property Set Unacknowledged */ +API_RESULT cli_modelc_light_lc_property_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LC_PROPERTY_SET_STRUCT param; + retval = API_FAILURE; + CONSOLE_OUT + (">> Send Light Lc Property Set Unacknowledged\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.light_lc_property_id = (UINT16)choice; + CONSOLE_OUT("Light LC Property ID (16-bit in HEX): 0x%04X\n", param.light_lc_property_id); + choice = CLI_strlen(argv[1]); + { + UINT16 input_len; + input_len = (UINT16)choice; + param.light_lc_property_value = EM_alloc_mem(input_len); + + if(NULL == param.light_lc_property_value) + { + CONSOLE_OUT + ("Memory allocation failed for Light LC Property Value. Returning\n"); + return retval; + } + + param.light_lc_property_value_len = (UINT16) input_len; + CLI_strtoarray + ( + argv[1], + CLI_strlen(argv[1]), + ¶m.light_lc_property_value[0], + input_len + ); + } + } + + retval = MS_light_lc_property_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.light_lc_property_value) + { + EM_free_mem(param.light_lc_property_value); + } + + return retval; +} + +/* Get Model Handle */ +API_RESULT cli_modelc_light_lc_get_model_handle(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + #if 0 + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_light_lc_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + #else + retval = API_FAILURE; + CONSOLE_OUT("To be implemented\n"); + #endif /* 0 */ + return retval; +} + + +/* Set Publish Address */ +API_RESULT cli_modelc_light_lc_set_publish_address(UINT32 argc, UCHAR* argv[]) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + model_handle = appl_light_lc_client_model_handle; + CONSOLE_OUT("Model Handle (16-bit in HEX): 0x%04X\n", model_handle); + + /* Check Number of Arguments */ + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT("Light_Lc Server Address (16-bit in HEX): 0x%04X\n", publish_info.addr.addr); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + publish_info.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKey Index: 0x%04X\n", publish_info.appkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return retval; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Light_Lc client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_light_lc_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[LIGHT_LC_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_LIGHT_LC_LIGHT_ONOFF_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_LC_LIGHT_ONOFF_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_LC_MODE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_LC_MODE_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_LC_OM_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_LC_OM_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_LC_PROPERTY_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_LC_PROPERTY_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + +#endif /* CLI_LIGHTINGS_LC_CLIENT_MODEL */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_light_lc_client.h b/src/components/ethermind/mesh/export/cli/model/client/cli_light_lc_client.h new file mode 100644 index 0000000..51b9c83 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_light_lc_client.h @@ -0,0 +1,96 @@ +/** + \file cli_light_lc_client.h + + \brief This file defines the Mesh Light Lc Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_CLI_LIGHT_LC_CLIENT_ +#define _H_CLI_LIGHT_LC_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_light_lc_api.h" +#include "cli_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* light_lc client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lc); + +/* light_lc client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lc_setup); + +/* Send Light Lc Light Onoff Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lc_light_onoff_get); + +/* Send Light Lc Light Onoff Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lc_light_onoff_set); + +/* Send Light Lc Light Onoff Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lc_light_onoff_set_unacknowledged); + +/* Send Light Lc Mode Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lc_mode_get); + +/* Send Light Lc Mode Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lc_mode_set); + +/* Send Light Lc Mode Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lc_mode_set_unacknowledged); + +/* Send Light Lc Om Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lc_om_get); + +/* Send Light Lc Om Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lc_om_set); + +/* Send Light Lc Om Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lc_om_set_unacknowledged); + +/* Send Light Lc Property Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lc_property_get); + +/* Send Light Lc Property Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lc_property_set); + +/* Send Light Lc Property Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lc_property_set_unacknowledged); + +/* Get Model Handle */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lc_get_model_handle); + +/* Set Publish Address */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lc_set_publish_address); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Light_Lc client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_light_lc_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_CLI_LIGHT_LC_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_light_lightness_client.c b/src/components/ethermind/mesh/export/cli/model/client/cli_light_lightness_client.c new file mode 100644 index 0000000..39ef474 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_light_lightness_client.c @@ -0,0 +1,601 @@ +/** + \file cli_light_lightness_client.c + + \brief This file defines the Mesh Light Lightness Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "cli_light_lightness_client.h" + +#ifdef CLI_LIGHTINGS_LIGHTNESS_CLIENT_MODEL + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +DECL_CONST CLI_COMMAND cli_modelc_light_lightness_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + /* Setup */ + { "setup", "Model Light_Lightness Setup", cli_modelc_light_lightness_setup }, + + /* Get Model Handle */ + { "gethandle", "Get Model Handle", cli_modelc_light_lightness_get_model_handle }, + + /* Set Publish Address */ + { "publishaddr", "Set Publish Address ", cli_modelc_light_lightness_set_publish_address }, + + /* Send Light Lightness Default Get */ + { "defaultget", "Send Light Lightness Default Get", cli_modelc_light_lightness_default_get}, + + /* Send Light Lightness Default Set */ + { "defaultset", "Send Light Lightness Default Set", cli_modelc_light_lightness_default_set}, + + /* Send Light Lightness Default Set Unacknowledged */ + { "defaultsetun", "Send Light Lightness Default Set Unacknowledged", cli_modelc_light_lightness_default_set_unacknowledged}, + + /* Send Light Lightness Get */ + { "lightnessget", "Send Light Lightness Get", cli_modelc_light_lightness_get}, + + /* Send Light Lightness Last Get */ + { "lastget", "Send Light Lightness Last Get", cli_modelc_light_lightness_last_get}, + + /* Send Light Lightness Linear Get */ + { "linearget", "Send Light Lightness Linear Get", cli_modelc_light_lightness_linear_get}, + + /* Send Light Lightness Linear Set */ + { "linearset", "Send Light Lightness Linear Set", cli_modelc_light_lightness_linear_set}, + + /* Send Light Lightness Linear Set Unacknowledged */ + { "linearsetun", "Send Light Lightness Linear Set Unacknowledged", cli_modelc_light_lightness_linear_set_unacknowledged}, + + /* Send Light Lightness Range Get */ + { "rangeget", "Send Light Lightness Range Get", cli_modelc_light_lightness_range_get}, + + /* Send Light Lightness Range Set */ + { "rangeset", "Send Light Lightness Range Set", cli_modelc_light_lightness_range_set}, + + /* Send Light Lightness Range Set Unacknowledged */ + { "rangesetun", "Send Light Lightness Range Set Unacknowledged", cli_modelc_light_lightness_range_set_unacknowledged}, + + /* Send Light Lightness Set */ + { "lightnessset", "Send Light Lightness Set", cli_modelc_light_lightness_set}, + + /* Send Light Lightness Set Unacknowledged */ + { "lightnesssetun", "Send Light Lightness Set Unacknowledged", cli_modelc_light_lightness_set_unacknowledged} +}; + + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_light_lightness_client_model_handle; + + +/* --------------------------------------------- Function */ +API_RESULT cli_modelc_light_lightness(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT("In Model Client - Light_Lightness\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_modelc_light_lightness_cmd_list, sizeof(cli_modelc_light_lightness_cmd_list) / sizeof(CLI_COMMAND)); + retval = cli_help(argc, argv); + return retval; +} + +/* light_lightness client CLI entry point */ +API_RESULT cli_modelc_light_lightness_setup(UINT32 argc, UCHAR* argv[]) +{ + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + static UCHAR model_initialized = 0x00; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + /** + Register with Access Layer. + */ + retval = API_FAILURE; + + if (0x00 == model_initialized) + { + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_light_lightness_client_init + ( + element_handle, + &appl_light_lightness_client_model_handle, + cli_light_lightness_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Lightness Client Initialized. Model Handle: 0x%04X\n", + appl_light_lightness_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Lightness Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + return retval; +} + +/* Send Light Lightness Default Get */ +API_RESULT cli_modelc_light_lightness_default_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Lightness Default Get\n"); + retval = MS_light_lightness_default_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Lightness Default Set */ +API_RESULT cli_modelc_light_lightness_default_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LIGHTNESS_DEFAULT_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lightness Default Set\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.lightness = (UINT16)choice; + CONSOLE_OUT("Lightness (16-bit in HEX): 0x%04X\n", param.lightness); + } + + retval = MS_light_lightness_default_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Lightness Default Set Unacknowledged */ +API_RESULT cli_modelc_light_lightness_default_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LIGHTNESS_DEFAULT_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lightness Default Set Unacknowledged\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.lightness = (UINT16)choice; + CONSOLE_OUT("Lightness (16-bit in HEX): 0x%04X\n", param.lightness); + } + + retval = MS_light_lightness_default_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Lightness Get */ +API_RESULT cli_modelc_light_lightness_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Lightness Get\n"); + retval = MS_light_lightness_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Lightness Last Get */ +API_RESULT cli_modelc_light_lightness_last_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Lightness Last Get\n"); + retval = MS_light_lightness_last_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Lightness Linear Get */ +API_RESULT cli_modelc_light_lightness_linear_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Lightness Linear Get\n"); + retval = MS_light_lightness_linear_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + + +/* Send Light Lightness Linear Set */ +API_RESULT cli_modelc_light_lightness_linear_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LIGHTNESS_LINEAR_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lightness Linear Set\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.lightness = (UINT16)choice; + CONSOLE_OUT("Lightness (16-bit in HEX): 0x%04X\n", param.lightness); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_light_lightness_linear_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Lightness Linear Set Unacknowledged */ +API_RESULT cli_modelc_light_lightness_linear_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LIGHTNESS_LINEAR_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lightness Linear Set Unacknowledged\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.lightness = (UINT16)choice; + CONSOLE_OUT("Lightness (16-bit in HEX): 0x%04X\n", param.lightness); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_light_lightness_linear_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Lightness Range Get */ +API_RESULT cli_modelc_light_lightness_range_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Lightness Range Get\n"); + retval = MS_light_lightness_range_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Lightness Range Set */ +API_RESULT cli_modelc_light_lightness_range_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LIGHTNESS_RANGE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lightness Range Set\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.range_min = (UINT16)choice; + CONSOLE_OUT("Range Min (16-bit in HEX): 0x%04X\n", param.range_min); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.range_max = (UINT16)choice; + CONSOLE_OUT("Range Max (16-bit in HEX): 0x%04X\n", param.range_max); + } + + retval = MS_light_lightness_range_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Lightness Range Set Unacknowledged */ +API_RESULT cli_modelc_light_lightness_range_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LIGHTNESS_RANGE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lightness Range Set Unacknowledged\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.range_min = (UINT16)choice; + CONSOLE_OUT("Range Min (16-bit in HEX): 0x%04X\n", param.range_min); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.range_max = (UINT16)choice; + CONSOLE_OUT("Range Max (16-bit in HEX): 0x%04X\n", param.range_max); + } + + retval = MS_light_lightness_range_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Lightness Set */ +API_RESULT cli_modelc_light_lightness_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LIGHTNESS_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lightness Set\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.lightness = (UINT16)choice; + CONSOLE_OUT("Lightness (16-bit in HEX): 0x%04X\n", param.lightness); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_light_lightness_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Lightness Set Unacknowledged */ +API_RESULT cli_modelc_light_lightness_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_LIGHTNESS_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Lightness Set Unacknowledged\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.lightness = (UINT16)choice; + CONSOLE_OUT("Lightness (16-bit in HEX): 0x%04X\n", param.lightness); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_light_lightness_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Get Model Handle */ +API_RESULT cli_modelc_light_lightness_get_model_handle(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + #if 0 + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_light_lightness_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + #else + retval = API_FAILURE; + CONSOLE_OUT("To be implemented\n"); + #endif /* 0 */ + return retval; +} + + +/* Set Publish Address */ +API_RESULT cli_modelc_light_lightness_set_publish_address(UINT32 argc, UCHAR* argv[]) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + model_handle = appl_light_lightness_client_model_handle; + CONSOLE_OUT("Model Handle (16-bit in HEX): 0x%04X\n", model_handle); + + /* Check Number of Arguments */ + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT("Light_Lightness Server Address (16-bit in HEX): 0x%04X\n", publish_info.addr.addr); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + publish_info.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKey Index: 0x%04X\n", publish_info.appkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return retval; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Light_Lightness client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_light_lightness_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[LIGHT_LIGHTNESS_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_LIGHT_LIGHTNESS_DEFAULT_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_LIGHTNESS_DEFAULT_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_LIGHTNESS_LAST_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_LIGHTNESS_LAST_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_LIGHTNESS_LINEAR_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_LIGHTNESS_LINEAR_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_LIGHTNESS_RANGE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_LIGHTNESS_RANGE_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_LIGHTNESS_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_LIGHTNESS_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + +#endif /* CLI_LIGHTINGS_LIGHTNESS_CLIENT_MODEL */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_light_lightness_client.h b/src/components/ethermind/mesh/export/cli/model/client/cli_light_lightness_client.h new file mode 100644 index 0000000..3910d9e --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_light_lightness_client.h @@ -0,0 +1,99 @@ +/** + \file cli_light_lightness_client.h + + \brief This file defines the Mesh Light Lightness Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_CLI_LIGHT_LIGHTNESS_CLIENT_ +#define _H_CLI_LIGHT_LIGHTNESS_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_light_lightness_api.h" +#include "cli_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* light_lightness client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lightness); + +/* light_lightness client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lightness_setup); + +/* Send Light Lightness Default Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lightness_default_get); + +/* Send Light Lightness Default Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lightness_default_set); + +/* Send Light Lightness Default Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lightness_default_set_unacknowledged); + +/* Send Light Lightness Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lightness_get); + +/* Send Light Lightness Last Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lightness_last_get); + +/* Send Light Lightness Linear Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lightness_linear_get); + +/* Send Light Lightness Linear Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lightness_linear_set); + +/* Send Light Lightness Linear Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lightness_linear_set_unacknowledged); + +/* Send Light Lightness Range Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lightness_range_get); + +/* Send Light Lightness Range Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lightness_range_set); + +/* Send Light Lightness Range Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lightness_range_set_unacknowledged); + +/* Send Light Lightness Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lightness_set); + +/* Send Light Lightness Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lightness_set_unacknowledged); + +/* Get Model Handle */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lightness_get_model_handle); + +/* Set Publish Address */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_lightness_set_publish_address); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Light_Lightness client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_light_lightness_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_CLI_LIGHT_LIGHTNESS_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_light_xyl_client.c b/src/components/ethermind/mesh/export/cli/model/client/cli_light_xyl_client.c new file mode 100644 index 0000000..9cbd000 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_light_xyl_client.c @@ -0,0 +1,527 @@ +/** + \file cli_light_xyl_client.c + + \brief This file defines the Mesh Light Xyl Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "cli_light_xyl_client.h" + +#ifdef CLI_LIGHTINGS_XYL_CLIENT_MODEL + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +DECL_CONST CLI_COMMAND cli_modelc_light_xyl_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + /* Setup */ + { "setup", "Model Light_Xyl Setup", cli_modelc_light_xyl_setup }, + + /* Get Model Handle */ + { "gethandle", "Get Model Handle", cli_modelc_light_xyl_get_model_handle }, + + /* Set Publish Address */ + { "publishaddr", "Set Publish Address ", cli_modelc_light_xyl_set_publish_address }, + + /* Send Light Xyl Default Get */ + { "defaultget", "Send Light Xyl Default Get", cli_modelc_light_xyl_default_get}, + + /* Send Light Xyl Default Set */ + { "defaultset", "Send Light Xyl Default Set", cli_modelc_light_xyl_default_set}, + + /* Send Light Xyl Default Set Unacknowledged */ + { "defaultsetun", "Send Light Xyl Default Set Unacknowledged", cli_modelc_light_xyl_default_set_unacknowledged}, + + /* Send Light Xyl Get */ + { "xylget", "Send Light Xyl Get", cli_modelc_light_xyl_get}, + + /* Send Light Xyl Range Get */ + { "rangeget", "Send Light Xyl Range Get", cli_modelc_light_xyl_range_get}, + + /* Send Light Xyl Range Set */ + { "rangeset", "Send Light Xyl Range Set", cli_modelc_light_xyl_range_set}, + + /* Send Light Xyl Range Set Unacknowledged */ + { "rangesetun", "Send Light Xyl Range Set Unacknowledged", cli_modelc_light_xyl_range_set_unacknowledged}, + + /* Send Light Xyl Set */ + { "xylset", "Send Light Xyl Set", cli_modelc_light_xyl_set}, + + /* Send Light Xyl Set Unacknowledged */ + { "xylsetun", "Send Light Xyl Set Unacknowledged", cli_modelc_light_xyl_set_unacknowledged}, + + /* Send Light Xyl Target Get */ + { "targetget", "Send Light Xyl Target Get", cli_modelc_light_xyl_target_get} +}; + + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_light_xyl_client_model_handle; + + +/* --------------------------------------------- Function */ +API_RESULT cli_modelc_light_xyl(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT("In Model Client - Light_Xyl\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_modelc_light_xyl_cmd_list, sizeof(cli_modelc_light_xyl_cmd_list) / sizeof(CLI_COMMAND)); + retval = cli_help(argc, argv); + return retval; +} + +/* light_xyl client CLI entry point */ +API_RESULT cli_modelc_light_xyl_setup(UINT32 argc, UCHAR* argv[]) +{ + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + static UCHAR model_initialized = 0x00; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + /** + Register with Access Layer. + */ + retval = API_FAILURE; + + if (0x00 == model_initialized) + { + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_light_xyl_client_init + ( + element_handle, + &appl_light_xyl_client_model_handle, + cli_light_xyl_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Xyl Client Initialized. Model Handle: 0x%04X\n", + appl_light_xyl_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Xyl Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + return retval; +} + +/* Send Light Xyl Default Get */ +API_RESULT cli_modelc_light_xyl_default_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Xyl Default Get\n"); + retval = MS_light_xyl_default_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Xyl Default Set */ +API_RESULT cli_modelc_light_xyl_default_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_XYL_DEFAULT_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Xyl Default Set\n"); + + if (3 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.lightness = (UINT16)choice; + CONSOLE_OUT("Lightness (16-bit in HEX): 0x%04X\n", param.lightness); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.xyl_x = (UINT16)choice; + CONSOLE_OUT("xyL x (16-bit in HEX): 0x%04X\n", param.xyl_x); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.xyl_y = (UINT16)choice; + CONSOLE_OUT("xyL y (16-bit in HEX): 0x%04X\n", param.xyl_y); + } + + retval = MS_light_xyl_default_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Xyl Default Set Unacknowledged */ +API_RESULT cli_modelc_light_xyl_default_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_XYL_DEFAULT_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Xyl Default Set Unacknowledged\n"); + + if (3 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.lightness = (UINT16)choice; + CONSOLE_OUT("Lightness (16-bit in HEX): 0x%04X\n", param.lightness); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.xyl_x = (UINT16)choice; + CONSOLE_OUT("xyL x (16-bit in HEX): 0x%04X\n", param.xyl_x); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.xyl_y = (UINT16)choice; + CONSOLE_OUT("xyL y (16-bit in HEX): 0x%04X\n", param.xyl_y); + } + + retval = MS_light_xyl_default_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Xyl Get */ +API_RESULT cli_modelc_light_xyl_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Xyl Get\n"); + retval = MS_light_xyl_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Xyl Range Get */ +API_RESULT cli_modelc_light_xyl_range_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Xyl Range Get\n"); + retval = MS_light_xyl_range_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Xyl Range Set */ +API_RESULT cli_modelc_light_xyl_range_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_XYL_RANGE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Xyl Range Set\n"); + + if (4 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.xyl_x_range_min = (UINT16)choice; + CONSOLE_OUT("xyL x Range Min (16-bit in HEX): 0x%04X\n", param.xyl_x_range_min); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.xyl_x_range_max = (UINT16)choice; + CONSOLE_OUT("xyL x Range Max (16-bit in HEX): 0x%04X\n", param.xyl_x_range_max); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.xyl_y_range_min = (UINT16)choice; + CONSOLE_OUT("xyL y Range Min (16-bit in HEX): 0x%04X\n", param.xyl_y_range_min); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.xyl_y_range_max = (UINT16)choice; + CONSOLE_OUT("xyL y Range Max (16-bit in HEX): 0x%04X\n", param.xyl_y_range_max); + } + + retval = MS_light_xyl_range_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Xyl Range Set Unacknowledged */ +API_RESULT cli_modelc_light_xyl_range_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_XYL_RANGE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Xyl Range Set Unacknowledged\n"); + + if (4 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.xyl_x_range_min = (UINT16)choice; + CONSOLE_OUT("xyL x Range Min (16-bit in HEX): 0x%04X\n", param.xyl_x_range_min); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.xyl_x_range_max = (UINT16)choice; + CONSOLE_OUT("xyL x Range Max (16-bit in HEX): 0x%04X\n", param.xyl_x_range_max); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.xyl_y_range_min = (UINT16)choice; + CONSOLE_OUT("xyL y Range Min (16-bit in HEX): 0x%04X\n", param.xyl_y_range_min); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.xyl_y_range_max = (UINT16)choice; + CONSOLE_OUT("xyL y Range Max (16-bit in HEX): 0x%04X\n", param.xyl_y_range_max); + } + + retval = MS_light_xyl_range_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Xyl Set */ +API_RESULT cli_modelc_light_xyl_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_XYL_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Xyl Set\n"); + + if (4 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.xyl_lightness = (UINT16)choice; + CONSOLE_OUT("xyL Lightness (16-bit in HEX): 0x%04X\n", param.xyl_lightness); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.xyl_x = (UINT16)choice; + CONSOLE_OUT("xyL x (16-bit in HEX): 0x%04X\n", param.xyl_x); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.xyl_y = (UINT16)choice; + CONSOLE_OUT("xyL y (16-bit in HEX): 0x%04X\n", param.xyl_y); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (6 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[4], CLI_strlen(argv[4]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[5], CLI_strlen(argv[5]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_light_xyl_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Xyl Set Unacknowledged */ +API_RESULT cli_modelc_light_xyl_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_LIGHT_XYL_SET_STRUCT param; + CONSOLE_OUT + (">> Send Light Xyl Set Unacknowledged\n"); + + if (4 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.xyl_lightness = (UINT16)choice; + CONSOLE_OUT("xyL Lightness (16-bit in HEX): 0x%04X\n", param.xyl_lightness); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.xyl_x = (UINT16)choice; + CONSOLE_OUT("xyL x (16-bit in HEX): 0x%04X\n", param.xyl_x); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.xyl_y = (UINT16)choice; + CONSOLE_OUT("xyL y (16-bit in HEX): 0x%04X\n", param.xyl_y); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (6 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[4], CLI_strlen(argv[4]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[5], CLI_strlen(argv[5]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_light_xyl_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Light Xyl Target Get */ +API_RESULT cli_modelc_light_xyl_target_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Light Xyl Target Get\n"); + retval = MS_light_xyl_target_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Get Model Handle */ +API_RESULT cli_modelc_light_xyl_get_model_handle(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + #if 0 + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_light_xyl_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + #else + retval = API_FAILURE; + CONSOLE_OUT("To be implemented\n"); + #endif /* 0 */ + return retval; +} + +/* Set Publish Address */ +API_RESULT cli_modelc_light_xyl_set_publish_address(UINT32 argc, UCHAR* argv[]) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + model_handle = appl_light_xyl_client_model_handle; + CONSOLE_OUT("Model Handle (16-bit in HEX): 0x%04X\n", model_handle); + + /* Check Number of Arguments */ + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT("Light_Xyl Server Address (16-bit in HEX): 0x%04X\n", publish_info.addr.addr); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + publish_info.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKey Index: 0x%04X\n", publish_info.appkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return retval; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Light_Xyl client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_light_xyl_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[LIGHT_XYL_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_LIGHT_XYL_DEFAULT_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_XYL_DEFAULT_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_XYL_RANGE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_XYL_RANGE_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_XYL_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_XYL_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_LIGHT_XYL_TARGET_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_LIGHT_XYL_TARGET_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + +#endif /* CLI_LIGHTINGS_XYL_CLIENT_MODEL */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_light_xyl_client.h b/src/components/ethermind/mesh/export/cli/model/client/cli_light_xyl_client.h new file mode 100644 index 0000000..743c674 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_light_xyl_client.h @@ -0,0 +1,90 @@ +/** + \file cli_light_xyl_client.h + + \brief This file defines the Mesh Light Xyl Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_CLI_LIGHT_XYL_CLIENT_ +#define _H_CLI_LIGHT_XYL_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_light_xyl_api.h" +#include "cli_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* light_xyl client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_xyl); + +/* light_xyl client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_xyl_setup); + +/* Send Light Xyl Default Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_xyl_default_get); + +/* Send Light Xyl Default Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_xyl_default_set); + +/* Send Light Xyl Default Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_xyl_default_set_unacknowledged); + +/* Send Light Xyl Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_xyl_get); + +/* Send Light Xyl Range Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_xyl_range_get); + +/* Send Light Xyl Range Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_xyl_range_set); + +/* Send Light Xyl Range Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_xyl_range_set_unacknowledged); + +/* Send Light Xyl Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_xyl_set); + +/* Send Light Xyl Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_xyl_set_unacknowledged); + +/* Send Light Xyl Target Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_xyl_target_get); + +/* Get Model Handle */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_xyl_get_model_handle); + +/* Set Publish Address */ +CLI_CMD_HANDLER_DECL(cli_modelc_light_xyl_set_publish_address); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Light_Xyl client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_light_xyl_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_CLI_LIGHT_XYL_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_scene_client.c b/src/components/ethermind/mesh/export/cli/model/client/cli_scene_client.c new file mode 100644 index 0000000..2a23b8c --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_scene_client.c @@ -0,0 +1,441 @@ +/** + \file cli_scene_client.c + + \brief This file defines the Mesh Scene Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "cli_scene_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +DECL_CONST CLI_COMMAND cli_modelc_scene_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + /* Setup */ + { "setup", "Model Scene Setup", cli_modelc_scene_setup }, + + /* Get Model Handle */ + { "gethandle", "Get Model Handle", cli_modelc_scene_get_model_handle }, + + /* Set Publish Address */ + { "publishaddr", "Set Publish Address ", cli_modelc_scene_set_publish_address }, + + /* Send Scene Delete */ + { "delete", "Send Scene Delete", cli_modelc_scene_delete}, + + /* Send Scene Delete Unacknowledged */ + { "deleteun", "Send Scene Delete Unacknowledged", cli_modelc_scene_delete_unacknowledged}, + + /* Send Scene Get */ + { "get", "Send Scene Get", cli_modelc_scene_get}, + + /* Send Scene Recall */ + { "recall", "Send Scene Recall", cli_modelc_scene_recall}, + + /* Send Scene Recall Unacknowledged */ + { "recallun", "Send Scene Recall Unacknowledged", cli_modelc_scene_recall_unacknowledged}, + + /* Send Scene Register Get */ + { "registerget", "Send Scene Register Get", cli_modelc_scene_register_get}, + + /* Send Scene Store */ + { "store", "Send Scene Store", cli_modelc_scene_store}, + + /* Send Scene Store Unacknowledged */ + { "storeun", "Send Scene Store Unacknowledged", cli_modelc_scene_store_unacknowledged} +}; + + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_scene_client_model_handle; + + +/* --------------------------------------------- Function */ +API_RESULT cli_modelc_scene(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT("In Model Client - Scene\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_modelc_scene_cmd_list, sizeof(cli_modelc_scene_cmd_list) / sizeof(CLI_COMMAND)); + retval = cli_help(argc, argv); + return retval; +} + +/* scene client CLI entry point */ +API_RESULT cli_modelc_scene_setup(UINT32 argc, UCHAR* argv[]) +{ + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + static UCHAR model_initialized = 0x00; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + /** + Register with Access Layer. + */ + retval = API_FAILURE; + + if (0x00 == model_initialized) + { + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_scene_client_init + ( + element_handle, + &appl_scene_client_model_handle, + cli_scene_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Scene Client Initialized. Model Handle: 0x%04X\n", + appl_scene_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Scene Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + return retval; +} + +/* Send Scene Delete */ +API_RESULT cli_modelc_scene_delete(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_SCENE_STRUCT param; + CONSOLE_OUT + (">> Send Scene Delete\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.scene_number = (UINT16)choice; + CONSOLE_OUT("Scene Number (16-bit in HEX): 0x%04X\n", param.scene_number); + } + + retval = MS_scene_delete(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Scene Delete Unacknowledged */ +API_RESULT cli_modelc_scene_delete_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_SCENE_STRUCT param; + CONSOLE_OUT + (">> Send Scene Delete Unacknowledged\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.scene_number = (UINT16)choice; + CONSOLE_OUT("Scene Number (16-bit in HEX): 0x%04X\n", param.scene_number); + } + + retval = MS_scene_delete_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Scene Get */ +API_RESULT cli_modelc_scene_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Scene Get\n"); + retval = MS_scene_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Scene Recall */ +API_RESULT cli_modelc_scene_recall(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_SCENE_RECALL_STRUCT param; + CONSOLE_OUT + (">> Send Scene Recall\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.scene_number = (UINT16)choice; + CONSOLE_OUT("Scene Number (16-bit in HEX): 0x%04X\n", param.scene_number); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_scene_recall(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Scene Recall Unacknowledged */ +API_RESULT cli_modelc_scene_recall_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_SCENE_RECALL_STRUCT param; + CONSOLE_OUT + (">> Send Scene Recall Unacknowledged\n"); + + if (2 <= argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.scene_number = (UINT16)choice; + CONSOLE_OUT("Scene Number (16-bit in HEX): 0x%04X\n", param.scene_number); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.tid = (UCHAR)choice; + CONSOLE_OUT("TID (8-bit in HEX): 0x%02X\n", param.tid); + } + + if (4 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.transition_time = (UCHAR)choice; + CONSOLE_OUT("Transition Time (8-bit in HEX): 0x%02X\n", param.transition_time); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.delay = (UCHAR)choice; + CONSOLE_OUT("Delay (8-bit in HEX): 0x%02X\n", param.delay); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_scene_recall_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Scene Register Get */ +API_RESULT cli_modelc_scene_register_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Scene Register Get\n"); + retval = MS_scene_register_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Scene Store */ +API_RESULT cli_modelc_scene_store(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_SCENE_STRUCT param; + CONSOLE_OUT + (">> Send Scene Store\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.scene_number = (UINT16)choice; + CONSOLE_OUT("Scene Number (16-bit in HEX): 0x%04X\n", param.scene_number); + } + + retval = MS_scene_store(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Scene Store Unacknowledged */ +API_RESULT cli_modelc_scene_store_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_SCENE_STRUCT param; + CONSOLE_OUT + (">> Send Scene Store Unacknowledged\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.scene_number = (UINT16)choice; + CONSOLE_OUT("Scene Number (16-bit in HEX): 0x%04X\n", param.scene_number); + } + + retval = MS_scene_store_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + + +/* Get Model Handle */ +API_RESULT cli_modelc_scene_get_model_handle(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + #if 0 + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_scene_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + #else + retval = API_FAILURE; + CONSOLE_OUT("To be implemented\n"); + #endif /* 0 */ + return retval; +} + + +/* Set Publish Address */ +API_RESULT cli_modelc_scene_set_publish_address(UINT32 argc, UCHAR* argv[]) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + model_handle = appl_scene_client_model_handle; + CONSOLE_OUT("Model Handle (16-bit in HEX): 0x%04X\n", model_handle); + + /* Check Number of Arguments */ + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT("Scene Server Address (16-bit in HEX): 0x%04X\n", publish_info.addr.addr); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + publish_info.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKey Index: 0x%04X\n", publish_info.appkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return retval; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Scene client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_scene_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[SCENE_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_SCENE_REGISTER_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SCENE_REGISTER_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_SCENE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SCENE_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_scene_client.h b/src/components/ethermind/mesh/export/cli/model/client/cli_scene_client.h new file mode 100644 index 0000000..299ede5 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_scene_client.h @@ -0,0 +1,84 @@ +/** + \file cli_scene_client.h + + \brief This file defines the Mesh Scene Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_CLI_SCENE_CLIENT_ +#define _H_CLI_SCENE_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_scene_api.h" +#include "cli_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* scene client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_scene); + +/* scene client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_scene_setup); + +/* Send Scene Delete */ +CLI_CMD_HANDLER_DECL(cli_modelc_scene_delete); + +/* Send Scene Delete Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_scene_delete_unacknowledged); + +/* Send Scene Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_scene_get); + +/* Send Scene Recall */ +CLI_CMD_HANDLER_DECL(cli_modelc_scene_recall); + +/* Send Scene Recall Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_scene_recall_unacknowledged); + +/* Send Scene Register Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_scene_register_get); + +/* Send Scene Store */ +CLI_CMD_HANDLER_DECL(cli_modelc_scene_store); + +/* Send Scene Store Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_scene_store_unacknowledged); + +/* Get Model Handle */ +CLI_CMD_HANDLER_DECL(cli_modelc_scene_get_model_handle); + +/* Set Publish Address */ +CLI_CMD_HANDLER_DECL(cli_modelc_scene_set_publish_address); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Scene client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_scene_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_CLI_SCENE_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_scheduler_client.c b/src/components/ethermind/mesh/export/cli/model/client/cli_scheduler_client.c new file mode 100644 index 0000000..4da356b --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_scheduler_client.c @@ -0,0 +1,398 @@ +/** + \file cli_scheduler_client.c + + \brief This file defines the Mesh Scheduler Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "cli_scheduler_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +DECL_CONST CLI_COMMAND cli_modelc_scheduler_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + /* Setup */ + { "setup", "Model Scheduler Setup", cli_modelc_scheduler_setup }, + + /* Get Model Handle */ + { "gethandle", "Get Model Handle", cli_modelc_scheduler_get_model_handle }, + + /* Set Publish Address */ + { "publishaddr", "Set Publish Address ", cli_modelc_scheduler_set_publish_address }, + + /* Send Scheduler Action Get */ + { "actionget", "Send Scheduler Action Get", cli_modelc_scheduler_action_get}, + + /* Send Scheduler Action Set */ + { "actionset", "Send Scheduler Action Set", cli_modelc_scheduler_action_set}, + + /* Send Scheduler Action Set Unacknowledged */ + { "actionsetun", "Send Scheduler Action Set Unacknowledged", cli_modelc_scheduler_action_set_unacknowledged}, + + /* Send Scheduler Get */ + { "get", "Send Scheduler Get", cli_modelc_scheduler_get} +}; + + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_scheduler_client_model_handle; + + +/* --------------------------------------------- Function */ +API_RESULT cli_modelc_scheduler(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT("In Model Client - Scheduler\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_modelc_scheduler_cmd_list, sizeof(cli_modelc_scheduler_cmd_list) / sizeof(CLI_COMMAND)); + retval = cli_help(argc, argv); + return retval; +} + +/* scheduler client CLI entry point */ +API_RESULT cli_modelc_scheduler_setup(UINT32 argc, UCHAR* argv[]) +{ + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + static UCHAR model_initialized = 0x00; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + /** + Register with Access Layer. + */ + retval = API_FAILURE; + + if (0x00 == model_initialized) + { + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_scheduler_client_init + ( + element_handle, + &appl_scheduler_client_model_handle, + cli_scheduler_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Scheduler Client Initialized. Model Handle: 0x%04X\n", + appl_scheduler_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Scheduler Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + return retval; +} + +/* Send Scheduler Action Get */ +API_RESULT cli_modelc_scheduler_action_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_SCHEDULER_ACTION_GET_STRUCT param; + CONSOLE_OUT + (">> Send Scheduler Action Get\n"); + + /* Check Number of Arguments */ + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.index = (UCHAR)choice; + CONSOLE_OUT("Index (8-bit in HEX): 0x%02X\n", param.index); + } + + retval = MS_scheduler_action_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Scheduler Action Set */ +API_RESULT cli_modelc_scheduler_action_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_SCHEDULER_ACTION_SET_STRUCT param; + CONSOLE_OUT + (">> Send Scheduler Action Set\n"); + + /* Check Number of Arguments */ + if (11 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.index = (UCHAR)choice; + CONSOLE_OUT("Index (4-bit in HEX): 0x%02X\n", param.index); + CONSOLE_OUT + ("Scheduled year for the action (7-bit in HEX)\n"); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.year = (UINT8)choice; + CONSOLE_OUT + ("Scheduled month for the action (12-bit in HEX)\n"); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.month = (UINT16)choice; + CONSOLE_OUT + ("Scheduled day of the month for the action (5-bit in HEX)\n"); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.day = (UINT8)choice; + CONSOLE_OUT + ("Scheduled hour for the action (5-bit in HEX)\n"); + choice = CLI_strtoi(argv[4], CLI_strlen(argv[4]), 16); + param.hour = (UINT8)choice; + CONSOLE_OUT + ("Scheduled minute for the action (6-bit in HEX)\n"); + choice = CLI_strtoi(argv[5], CLI_strlen(argv[5]), 16); + param.minute = (UINT8)choice; + CONSOLE_OUT + ("Scheduled second for the action (6-bit in HEX)\n"); + choice = CLI_strtoi(argv[6], CLI_strlen(argv[6]), 16); + param.second = (UINT8)choice; + CONSOLE_OUT + ("Scheduled days of the week for the action (7-bit in HEX)\n"); + choice = CLI_strtoi(argv[7], CLI_strlen(argv[7]), 16); + param.day_of_week = (UINT8)choice; + CONSOLE_OUT + ("Action to be performed at the scheduled time (4-bit in HEX)\n"); + choice = CLI_strtoi(argv[8], CLI_strlen(argv[8]), 16); + param.action = (UINT8)choice; + CONSOLE_OUT + ("Scene number to be used for some actions (16-bit in HEX)\n"); + choice = CLI_strtoi(argv[9], CLI_strlen(argv[9]), 16); + param.scene_number = (UINT16)choice; + CONSOLE_OUT + ("Transition time for this action (8-bit in HEX)\n"); + choice = CLI_strtoi(argv[10], CLI_strlen(argv[10]), 16); + param.transition_time = (UINT8)choice; + } + + retval = MS_scheduler_action_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Scheduler Action Set Unacknowledged */ +API_RESULT cli_modelc_scheduler_action_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_SCHEDULER_ACTION_SET_STRUCT param; + CONSOLE_OUT + (">> Send Scheduler Action Set Unacknowledged\n"); + + /* Check Number of Arguments */ + if (11 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.index = (UCHAR)choice; + CONSOLE_OUT("Index (4-bit in HEX): 0x%02X\n", param.index); + CONSOLE_OUT + ("Scheduled year for the action (7-bit in HEX)\n"); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.year = (UINT8)choice; + CONSOLE_OUT + ("Scheduled month for the action (12-bit in HEX)\n"); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.month = (UINT16)choice; + CONSOLE_OUT + ("Scheduled day of the month for the action (5-bit in HEX)\n"); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.day = (UINT8)choice; + CONSOLE_OUT + ("Scheduled hour for the action (5-bit in HEX)\n"); + choice = CLI_strtoi(argv[4], CLI_strlen(argv[4]), 16); + param.hour = (UINT8)choice; + CONSOLE_OUT + ("Scheduled minute for the action (6-bit in HEX)\n"); + choice = CLI_strtoi(argv[5], CLI_strlen(argv[5]), 16); + param.minute = (UINT8)choice; + CONSOLE_OUT + ("Scheduled second for the action (6-bit in HEX)\n"); + choice = CLI_strtoi(argv[6], CLI_strlen(argv[6]), 16); + param.second = (UINT8)choice; + CONSOLE_OUT + ("Scheduled days of the week for the action (7-bit in HEX)\n"); + choice = CLI_strtoi(argv[7], CLI_strlen(argv[7]), 16); + param.day_of_week = (UINT8)choice; + CONSOLE_OUT + ("Action to be performed at the scheduled time (4-bit in HEX)\n"); + choice = CLI_strtoi(argv[8], CLI_strlen(argv[8]), 16); + param.action = (UINT8)choice; + CONSOLE_OUT + ("Scene number to be used for some actions (16-bit in HEX)\n"); + choice = CLI_strtoi(argv[9], CLI_strlen(argv[9]), 16); + param.scene_number = (UINT16)choice; + CONSOLE_OUT + ("Transition time for this action (8-bit in HEX)\n"); + choice = CLI_strtoi(argv[10], CLI_strlen(argv[10]), 16); + param.transition_time = (UINT8)choice; + } + + retval = MS_scheduler_action_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Scheduler Get */ +API_RESULT cli_modelc_scheduler_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Scheduler Get\n"); + retval = MS_scheduler_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + + +/* Get Model Handle */ +API_RESULT cli_modelc_scheduler_get_model_handle(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + #if 0 + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_scheduler_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + #else + retval = API_FAILURE; + CONSOLE_OUT("To be implemented\n"); + #endif /* 0 */ + return retval; +} + + +/* Set Publish Address */ +API_RESULT cli_modelc_scheduler_set_publish_address(UINT32 argc, UCHAR* argv[]) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + model_handle = appl_scheduler_client_model_handle; + CONSOLE_OUT("Model Handle (16-bit in HEX): 0x%04X\n", model_handle); + + /* Check Number of Arguments */ + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT("Scheduler Server Address (16-bit in HEX): 0x%04X\n", publish_info.addr.addr); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + publish_info.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKey Index: 0x%04X\n", publish_info.appkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return retval; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Scheduler client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_scheduler_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[SCHEDULER_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_SCHEDULER_ACTION_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SCHEDULER_ACTION_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_SCHEDULER_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SCHEDULER_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_scheduler_client.h b/src/components/ethermind/mesh/export/cli/model/client/cli_scheduler_client.h new file mode 100644 index 0000000..1040919 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_scheduler_client.h @@ -0,0 +1,72 @@ +/** + \file cli_scheduler_client.h + + \brief This file defines the Mesh Scheduler Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_CLI_SCHEDULER_CLIENT_ +#define _H_CLI_SCHEDULER_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_scheduler_api.h" +#include "cli_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* scheduler client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_scheduler); + +/* scheduler client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_scheduler_setup); + +/* Send Scheduler Action Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_scheduler_action_get); + +/* Send Scheduler Action Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_scheduler_action_set); + +/* Send Scheduler Action Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_scheduler_action_set_unacknowledged); + +/* Send Scheduler Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_scheduler_get); + +/* Get Model Handle */ +CLI_CMD_HANDLER_DECL(cli_modelc_scheduler_get_model_handle); + +/* Set Publish Address */ +CLI_CMD_HANDLER_DECL(cli_modelc_scheduler_set_publish_address); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Scheduler client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_scheduler_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_CLI_SCHEDULER_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_sensor_client.c b/src/components/ethermind/mesh/export/cli/model/client/cli_sensor_client.c new file mode 100644 index 0000000..62f6c29 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_sensor_client.c @@ -0,0 +1,1000 @@ +/** + \file cli_sensor_client.c + + \brief This file defines the Mesh Sensor Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "cli_sensor_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +DECL_CONST CLI_COMMAND cli_modelc_sensor_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + /* Setup */ + { "setup", "Model Sensor Setup", cli_modelc_sensor_setup }, + + /* Get Model Handle */ + { "gethandle", "Get Model Handle", cli_modelc_sensor_get_model_handle }, + + /* Set Publish Address */ + { "publishaddr", "Set Publish Address ", cli_modelc_sensor_set_publish_address }, + + /* Send Sensor Cadence Get */ + { "cadenceget", "Send Sensor Cadence Get", cli_modelc_sensor_cadence_get}, + + /* Send Sensor Cadence Set */ + { "cadenceset", "Send Sensor Cadence Set", cli_modelc_sensor_cadence_set}, + + /* Send Sensor Cadence Set Unacknowledged */ + { "cadencesetun", "Send Sensor Cadence Set Unacknowledged", cli_modelc_sensor_cadence_set_unacknowledged}, + + /* Send Sensor Column Get */ + { "columnget", "Send Sensor Column Get", cli_modelc_sensor_column_get}, + + /* Send Sensor Descriptor Get */ + { "descriptorget", "Send Sensor Descriptor Get", cli_modelc_sensor_descriptor_get}, + + /* Send Sensor Get */ + { "get", "Send Sensor Get", cli_modelc_sensor_get}, + + /* Send Sensor Series Get */ + { "seriesget", "Send Sensor Series Get", cli_modelc_sensor_series_get}, + + /* Send Sensor Setting Get */ + { "settingget", "Send Sensor Setting Get", cli_modelc_sensor_setting_get}, + + /* Send Sensor Setting Set */ + { "settingset", "Send Sensor Setting Set", cli_modelc_sensor_setting_set}, + + /* Send Sensor Setting Set Unacknowledged */ + { "settingsetun", "Send Sensor Setting Set Unacknowledged", cli_modelc_sensor_setting_set_unacknowledged}, + + /* Send Sensor Settings Get */ + { "settingsget", "Send Sensor Settings Get", cli_modelc_sensor_settings_get} +}; + + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_sensor_client_model_handle; + + +/* --------------------------------------------- Function */ +API_RESULT cli_modelc_sensor(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT("In Model Client - Sensor\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_modelc_sensor_cmd_list, sizeof(cli_modelc_sensor_cmd_list) / sizeof(CLI_COMMAND)); + retval = cli_help(argc, argv); + return retval; +} + +/* sensor client CLI entry point */ +API_RESULT cli_modelc_sensor_setup(UINT32 argc, UCHAR* argv[]) +{ + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + static UCHAR model_initialized = 0x00; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + /** + Register with Access Layer. + */ + retval = API_FAILURE; + + if (0x00 == model_initialized) + { + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_sensor_client_init + ( + element_handle, + &appl_sensor_client_model_handle, + cli_sensor_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Sensor Client Initialized. Model Handle: 0x%04X\n", + appl_sensor_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Sensor Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + return retval; +} + +/* Send Sensor Cadence Get */ +API_RESULT cli_modelc_sensor_cadence_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_SENSOR_CADENCE_GET_STRUCT param; + CONSOLE_OUT + (">> Send Sensor Cadence Get\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], (UINT16)CLI_strlen(argv[0]), 16); + param.property_id = (UINT16)choice; + CONSOLE_OUT("Property ID (16-bit in HEX): 0x%04X\n", param.property_id); + } + + retval = MS_sensor_cadence_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Sensor Cadence Set */ +API_RESULT cli_modelc_sensor_cadence_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + INT32 choice; + UINT16 argv_index; + UINT16 input_len; + MS_SENSOR_CADENCE_SET_STRUCT param; + argv_index = 0; + CONSOLE_OUT + (">> Send Sensor Cadence Set\n"); + + if (8 == argc) + { + CONSOLE_OUT + ("Property ID (16-bit in HEX)\n"); + choice = CLI_strtoi(argv[argv_index], (UINT16)CLI_strlen(argv[argv_index]), 16); + argv_index++; + param.property_id = (UINT16)choice; + CONSOLE_OUT + ("Fast Cadence Period Divisor (7-bit in HEX)\n"); + choice = CLI_strtoi(argv[argv_index], (UINT16)CLI_strlen(argv[argv_index]), 16); + argv_index++; + param.fast_cadence_period_divisor = (UCHAR)choice; + CONSOLE_OUT + ("Status Trigger Type (1-bit in HEX)\n"); + choice = CLI_strtoi(argv[argv_index], (UINT16)CLI_strlen(argv[argv_index]), 16); + argv_index++; + param.status_trigger_type = (UCHAR)choice; + choice = CLI_strlen(argv[argv_index]); + choice = (choice + 1) / 2; + CONSOLE_OUT + ("Status Trigger Delta Down (%d-octets in HEX)\n", (UINT16)choice); + input_len = (UINT16)choice; + param.status_trigger_delta_down = EM_alloc_mem(input_len); + + if (NULL == param.status_trigger_delta_down) + { + CONSOLE_OUT + ("Memory allocation failed for Status Trigger Delta Down. Returning\n"); + return API_FAILURE; + } + + param.status_trigger_delta_down_len = (UINT16)input_len; + CLI_strtoarray + ( + argv[argv_index], + (UINT16)CLI_strlen(argv[argv_index]), + param.status_trigger_delta_down, + input_len + ); + argv_index++; + choice = CLI_strlen(argv[argv_index]); + choice = (choice + 1) / 2; + CONSOLE_OUT + ("Status Trigger Delta Up (%d-octets in HEX)\n", (UINT16)choice); + input_len = (UINT16)choice; + param.status_trigger_delta_up = EM_alloc_mem(input_len); + + if (NULL == param.status_trigger_delta_up) + { + CONSOLE_OUT + ("Memory allocation failed for Status Trigger Delta Up. Returning\n"); + return API_FAILURE; + } + + param.status_trigger_delta_up_len = (UINT16)input_len; + CLI_strtoarray + ( + argv[argv_index], + (UINT16)CLI_strlen(argv[argv_index]), + param.status_trigger_delta_up, + input_len + ); + argv_index++; + CONSOLE_OUT + ("Status Min Interval (8-bit in HEX)\n"); + choice = CLI_strtoi(argv[argv_index], (UINT16)CLI_strlen(argv[argv_index]), 16); + argv_index++; + param.status_min_interval = (UCHAR)choice; + choice = CLI_strlen(argv[argv_index]); + choice = (choice + 1) / 2; + CONSOLE_OUT + ("Fast Cadence Low (%d-octets in HEX)\n", (UINT16)choice); + input_len = (UINT16)choice; + param.fast_cadence_low = EM_alloc_mem(input_len); + + if (NULL == param.fast_cadence_low) + { + CONSOLE_OUT + ("Memory allocation failed for Fast Cadence Low. Returning\n"); + return API_FAILURE; + } + + param.fast_cadence_low_len = (UINT16)input_len; + CLI_strtoarray + ( + argv[argv_index], + (UINT16)CLI_strlen(argv[argv_index]), + param.fast_cadence_low, + input_len + ); + argv_index++; + choice = CLI_strlen(argv[argv_index]); + choice = (choice + 1) / 2; + CONSOLE_OUT + ("Fast Cadence High (%d-octets in HEX)\n", (UINT16)choice); + input_len = (UINT16)choice; + param.fast_cadence_high = EM_alloc_mem(input_len); + + if (NULL == param.fast_cadence_high) + { + CONSOLE_OUT + ("Memory allocation failed for Fast Cadence High. Returning\n"); + return API_FAILURE; + } + + param.fast_cadence_high_len = (UINT16)input_len; + CLI_strtoarray + ( + argv[argv_index], + (UINT16)CLI_strlen(argv[argv_index]), + param.fast_cadence_high, + input_len + ); + argv_index++; + } + + retval = MS_sensor_cadence_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.fast_cadence_high) + { + EM_free_mem(param.fast_cadence_high); + } + + if(NULL != param.fast_cadence_low) + { + EM_free_mem(param.fast_cadence_low); + } + + if(NULL != param.status_trigger_delta_up) + { + EM_free_mem(param.status_trigger_delta_up); + } + + if(NULL != param.status_trigger_delta_down) + { + EM_free_mem(param.status_trigger_delta_down); + } + + return retval; +} + +/* Send Sensor Cadence Set Unacknowledged */ +API_RESULT cli_modelc_sensor_cadence_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + UINT16 argv_index; + UINT16 input_len; + MS_SENSOR_CADENCE_SET_STRUCT param; + argv_index = 0; + CONSOLE_OUT + (">> Send Sensor Cadence Set Unacknowledged\n"); + + if (8 == argc) + { + CONSOLE_OUT + ("Property ID (16-bit in HEX)\n"); + choice = CLI_strtoi(argv[argv_index], (UINT16)CLI_strlen(argv[argv_index]), 16); + argv_index++; + param.property_id = (UINT16)choice; + CONSOLE_OUT + ("Fast Cadence Period Divisor (7-bit in HEX)\n"); + choice = CLI_strtoi(argv[argv_index], (UINT16)CLI_strlen(argv[argv_index]), 16); + argv_index++; + param.fast_cadence_period_divisor = (UCHAR)choice; + CONSOLE_OUT + ("Status Trigger Type (1-bit in HEX)\n"); + choice = CLI_strtoi(argv[argv_index], (UINT16)CLI_strlen(argv[argv_index]), 16); + argv_index++; + param.status_trigger_type = (UCHAR)choice; + choice = CLI_strlen(argv[argv_index]); + choice = (choice + 1) / 2; + CONSOLE_OUT + ("Status Trigger Delta Down (%d-octets in HEX)\n", (UINT16)choice); + input_len = (UINT16)choice; + param.status_trigger_delta_down = EM_alloc_mem(input_len); + + if (NULL == param.status_trigger_delta_down) + { + CONSOLE_OUT + ("Memory allocation failed for Status Trigger Delta Down. Returning\n"); + return API_FAILURE; + } + + param.status_trigger_delta_down_len = (UINT16)input_len; + CLI_strtoarray + ( + argv[argv_index], + (UINT16)CLI_strlen(argv[argv_index]), + param.status_trigger_delta_down, + input_len + ); + argv_index++; + choice = CLI_strlen(argv[argv_index]); + choice = (choice + 1) / 2; + CONSOLE_OUT + ("Status Trigger Delta Up (%d-octets in HEX)\n", (UINT16)choice); + input_len = (UINT16)choice; + param.status_trigger_delta_up = EM_alloc_mem(input_len); + + if (NULL == param.status_trigger_delta_up) + { + CONSOLE_OUT + ("Memory allocation failed for Status Trigger Delta Up. Returning\n"); + return API_FAILURE; + } + + param.status_trigger_delta_up_len = (UINT16)input_len; + CLI_strtoarray + ( + argv[argv_index], + (UINT16)CLI_strlen(argv[argv_index]), + param.status_trigger_delta_up, + input_len + ); + argv_index++; + CONSOLE_OUT + ("Status Min Interval (8-bit in HEX)\n"); + choice = CLI_strtoi(argv[argv_index], (UINT16)CLI_strlen(argv[argv_index]), 16); + argv_index++; + param.status_min_interval = (UCHAR)choice; + choice = CLI_strlen(argv[argv_index]); + choice = (choice + 1) / 2; + CONSOLE_OUT + ("Fast Cadence Low (%d-octets in HEX)\n", (UINT16)choice); + input_len = (UINT16)choice; + param.fast_cadence_low = EM_alloc_mem(input_len); + + if (NULL == param.fast_cadence_low) + { + CONSOLE_OUT + ("Memory allocation failed for Fast Cadence Low. Returning\n"); + return API_FAILURE; + } + + param.fast_cadence_low_len = (UINT16)input_len; + CLI_strtoarray + ( + argv[argv_index], + (UINT16)CLI_strlen(argv[argv_index]), + param.fast_cadence_low, + input_len + ); + argv_index++; + choice = CLI_strlen(argv[argv_index]); + choice = (choice + 1) / 2; + CONSOLE_OUT + ("Fast Cadence High (%d-octets in HEX)\n", (UINT16)choice); + input_len = (UINT16)choice; + param.fast_cadence_high = EM_alloc_mem(input_len); + + if (NULL == param.fast_cadence_high) + { + CONSOLE_OUT + ("Memory allocation failed for Fast Cadence High. Returning\n"); + return API_FAILURE; + } + + param.fast_cadence_high_len = (UINT16)input_len; + CLI_strtoarray + ( + argv[argv_index], + (UINT16)CLI_strlen(argv[argv_index]), + param.fast_cadence_high, + input_len + ); + argv_index++; + } + + retval = MS_sensor_cadence_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.fast_cadence_high) + { + EM_free_mem(param.fast_cadence_high); + } + + if(NULL != param.fast_cadence_low) + { + EM_free_mem(param.fast_cadence_low); + } + + if(NULL != param.status_trigger_delta_up) + { + EM_free_mem(param.status_trigger_delta_up); + } + + if(NULL != param.status_trigger_delta_down) + { + EM_free_mem(param.status_trigger_delta_down); + } + + return retval; +} + +/* Send Sensor Column Get */ +API_RESULT cli_modelc_sensor_column_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + UINT16 argv_index; + UINT16 input_len; + MS_SENSOR_COLUMN_GET_STRUCT param; + argv_index = 0; + CONSOLE_OUT + (">> Send Sensor Column Get\n"); + + if (2 == argc) + { + CONSOLE_OUT + ("Property ID (16-bit in HEX)\n"); + choice = CLI_strtoi(argv[argv_index], (UINT16)CLI_strlen(argv[argv_index]), 16); + argv_index++; + param.property_id = (UINT16)choice; + choice = CLI_strlen(argv[argv_index]); + choice = (choice + 1) / 2; + CONSOLE_OUT + ("Raw Value X (%d-octets in HEX)\n", (UINT16)choice); + input_len = (UINT16)choice; + param.raw_value_x = EM_alloc_mem(input_len); + + if (NULL == param.raw_value_x) + { + CONSOLE_OUT + ("Memory allocation failed for Raw Value X. Returning\n"); + return API_FAILURE; + } + + param.raw_value_x_len = (UINT16)input_len; + CLI_strtoarray + ( + argv[argv_index], + (UINT16)CLI_strlen(argv[argv_index]), + param.raw_value_x, + input_len + ); + argv_index++; + } + + retval = MS_sensor_column_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.raw_value_x) + { + EM_free_mem(param.raw_value_x); + } + + return retval; +} + +/* Send Sensor Descriptor Get */ +API_RESULT cli_modelc_sensor_descriptor_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_SENSOR_DESCRIPTOR_GET_STRUCT param; + CONSOLE_OUT + (">> Send Sensor Descriptor Get\n"); + + /* Check Number of Arguments */ + if (1 == argc) + { + param.optional_fields_present = 0x01; + choice = CLI_strtoi(argv[0], (UINT16) CLI_strlen(argv[0]), 16); + param.property_id = (UINT16)choice; + CONSOLE_OUT("Property ID (16-bit in HEX): 0x%04X\n", param.property_id); + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_sensor_descriptor_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Sensor Get */ +API_RESULT cli_modelc_sensor_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_SENSOR_GET_STRUCT param; + CONSOLE_OUT + (">> Send Sensor Get\n"); + + if (1 == argc) + { + param.optional_fields_present = 0x01; + CONSOLE_OUT + ("Property ID (16-bit in HEX)\n"); + choice = CLI_strtoi(argv[0], (UINT16)CLI_strlen(argv[0]), 16); + param.property_id = (UINT16)choice; + } + else + { + param.optional_fields_present = 0x00; + } + + retval = MS_sensor_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Sensor Series Get */ +API_RESULT cli_modelc_sensor_series_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + UINT16 argv_index; + UINT16 input_len; + MS_SENSOR_SERIES_GET_STRUCT param; + argv_index = 0; + CONSOLE_OUT + (">> Send Sensor Series Get\n"); + CONSOLE_OUT + ("Property ID (16-bit in HEX)\n"); + choice = CLI_strtoi(argv[argv_index], (UINT16)CLI_strlen(argv[argv_index]), 16); + argv_index++; + param.property_id = (UINT16)choice; + + if(1 == argc) + { + param.optional_fields_present = 0x00; + } + else + { + param.optional_fields_present = 0x01; + choice = CLI_strlen(argv[argv_index]); + choice = (choice + 1) / 2; + CONSOLE_OUT + ("Raw Value X1 (%d-octets in HEX)\n", (UINT16)choice); + input_len = (UINT16)choice; + param.raw_value_x1 = EM_alloc_mem(input_len); + + if(NULL == param.raw_value_x1) + { + CONSOLE_OUT + ("Memory allocation failed for Raw Value X1. Returning\n"); + return API_FAILURE; + } + + param.raw_value_x1_len = (UINT16) input_len; + CLI_strtoarray + ( + argv[argv_index], + (UINT16)CLI_strlen(argv[argv_index]), + param.raw_value_x1, + input_len + ); + argv_index++; + choice = CLI_strlen(argv[argv_index]); + choice = (choice + 1) / 2; + CONSOLE_OUT + ("Raw Value X2 (%d-octets in HEX)\n", (UINT16)choice); + input_len = (UINT16)choice; + param.raw_value_x2 = EM_alloc_mem(input_len); + + if(NULL == param.raw_value_x2) + { + CONSOLE_OUT + ("Memory allocation failed for Raw Value X2. Returning\n"); + return API_FAILURE; + } + + param.raw_value_x2_len = (UINT16) input_len; + CLI_strtoarray + ( + argv[argv_index], + (UINT16)CLI_strlen(argv[argv_index]), + param.raw_value_x2, + input_len + ); + argv_index++; + } + + retval = MS_sensor_series_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.raw_value_x1) + { + EM_free_mem(param.raw_value_x1); + } + + if(NULL != param.raw_value_x2) + { + EM_free_mem(param.raw_value_x2); + } + + return retval; +} + +/* Send Sensor Setting Get */ +API_RESULT cli_modelc_sensor_setting_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_SENSOR_SETTING_GET_STRUCT param; + CONSOLE_OUT + (">> Send Sensor Setting Get\n"); + + if (2 == argc) + { + CONSOLE_OUT + ("Sensor Property ID (16-bit in HEX)\n"); + choice = CLI_strtoi(argv[0], (UINT16)CLI_strlen(argv[0]), 16); + param.sensor_property_id = (UINT16)choice; + CONSOLE_OUT + ("Sensor Setting Property ID (16-bit in HEX)\n"); + choice = CLI_strtoi(argv[1], (UINT16)CLI_strlen(argv[1]), 16); + param.sensor_setting_property_id = (UINT16)choice; + } + + retval = MS_sensor_setting_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Sensor Setting Set */ +API_RESULT cli_modelc_sensor_setting_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + UINT16 argv_index; + UINT16 input_len; + MS_SENSOR_SETTING_SET_STRUCT param; + argv_index = 0; + CONSOLE_OUT + (">> Send Sensor Setting Set\n"); + + if (3 == argc) + { + CONSOLE_OUT + ("Sensor Property ID (16-bit in HEX)\n"); + choice = CLI_strtoi(argv[argv_index], (UINT16)CLI_strlen(argv[argv_index]), 16); + argv_index++; + param.sensor_property_id = (UINT16)choice; + CONSOLE_OUT + ("Sensor Setting Property ID (16-bit in HEX)\n"); + choice = CLI_strtoi(argv[argv_index], (UINT16)CLI_strlen(argv[argv_index]), 16); + argv_index++; + param.sensor_setting_property_id = (UINT16)choice; + choice = CLI_strlen(argv[argv_index]); + choice = (choice + 1) / 2; + CONSOLE_OUT + ("Sensor Setting Raw (%d-octets in HEX)\n", (UINT16)choice); + input_len = (UINT16)choice; + param.sensor_setting_raw = EM_alloc_mem(input_len); + + if (NULL == param.sensor_setting_raw) + { + CONSOLE_OUT + ("Memory allocation failed for Sensor Setting Raw. Returning\n"); + return API_FAILURE; + } + + param.sensor_setting_raw_len = (UINT16)input_len; + CLI_strtoarray + ( + argv[argv_index], + (UINT16)CLI_strlen(argv[argv_index]), + param.sensor_setting_raw, + input_len + ); + argv_index++; + } + + retval = MS_sensor_setting_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.sensor_setting_raw) + { + EM_free_mem(param.sensor_setting_raw); + } + + return retval; +} + +/* Send Sensor Setting Set Unacknowledged */ +API_RESULT cli_modelc_sensor_setting_set_unacknowledged(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + UINT16 argv_index; + UINT16 input_len; + MS_SENSOR_SETTING_SET_STRUCT param; + argv_index = 0; + CONSOLE_OUT + (">> Send Sensor Setting Set Unacknowledged\n"); + + if (3 == argc) + { + CONSOLE_OUT + ("Sensor Property ID (16-bit in HEX)\n"); + choice = CLI_strtoi(argv[argv_index], (UINT16)CLI_strlen(argv[argv_index]), 16); + argv_index++; + param.sensor_property_id = (UINT16)choice; + CONSOLE_OUT + ("Sensor Setting Property ID (16-bit in HEX)\n"); + choice = CLI_strtoi(argv[argv_index], (UINT16)CLI_strlen(argv[argv_index]), 16); + argv_index++; + param.sensor_setting_property_id = (UINT16)choice; + choice = CLI_strlen(argv[argv_index]); + choice = (choice + 1) / 2; + CONSOLE_OUT + ("Sensor Setting Raw (%d-octets in HEX)\n", (UINT16)choice); + input_len = (UINT16)choice; + param.sensor_setting_raw = EM_alloc_mem(input_len); + + if (NULL == param.sensor_setting_raw) + { + CONSOLE_OUT + ("Memory allocation failed for Sensor Setting Raw. Returning\n"); + return API_FAILURE; + } + + param.sensor_setting_raw_len = (UINT16)input_len; + CLI_strtoarray + ( + argv[argv_index], + (UINT16)CLI_strlen(argv[argv_index]), + param.sensor_setting_raw, + input_len + ); + argv_index++; + } + + retval = MS_sensor_setting_set_unacknowledged(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + + if(NULL != param.sensor_setting_raw) + { + EM_free_mem(param.sensor_setting_raw); + } + + return retval; +} + + +/* Send Sensor Settings Get */ +API_RESULT cli_modelc_sensor_settings_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_SENSOR_SETTINGS_GET_STRUCT param; + CONSOLE_OUT + (">> Send Sensor Settings Get\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], (UINT16)CLI_strlen(argv[0]), 16); + param.sensor_property_id = (UINT16)choice; + CONSOLE_OUT("Sensor Property ID (16-bit in HEX): 0x%04X\n", param.sensor_property_id); + } + + retval = MS_sensor_settings_get(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Get Model Handle */ +API_RESULT cli_modelc_sensor_get_model_handle(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + #if 0 + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_sensor_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + #else + retval = API_FAILURE; + CONSOLE_OUT("To be implemented\n"); + #endif /* 0 */ + return retval; +} + + +/* Set Publish Address */ +API_RESULT cli_modelc_sensor_set_publish_address(UINT32 argc, UCHAR* argv[]) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + model_handle = appl_sensor_client_model_handle; + CONSOLE_OUT("Model Handle (16-bit in HEX): 0x%04X\n", model_handle); + + /* Check Number of Arguments */ + if (2 == argc) + { + choice = CLI_strtoi(argv[0], (UINT16)CLI_strlen(argv[0]), 16); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT("Sensor Server Address (16-bit in HEX): 0x%04X\n", publish_info.addr.addr); + choice = CLI_strtoi(argv[1], (UINT16)CLI_strlen(argv[1]), 16); + publish_info.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKey Index: 0x%04X\n", publish_info.appkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return retval; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Sensor client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_sensor_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(handle); + retval = API_SUCCESS; + CONSOLE_OUT ( + "[SENSOR_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_SENSOR_CADENCE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SENSOR_CADENCE_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_SENSOR_COLUMN_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SENSOR_COLUMN_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_SENSOR_DESCRIPTOR_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SENSOR_DESCRIPTOR_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_SENSOR_SERIES_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SENSOR_SERIES_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_SENSOR_SETTING_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SENSOR_SETTING_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_SENSOR_SETTINGS_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SENSOR_SETTINGS_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_SENSOR_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_SENSOR_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_sensor_client.h b/src/components/ethermind/mesh/export/cli/model/client/cli_sensor_client.h new file mode 100644 index 0000000..2d11650 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_sensor_client.h @@ -0,0 +1,93 @@ +/** + \file cli_sensor_client.h + + \brief This file defines the Mesh Sensor Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_CLI_SENSOR_CLIENT_ +#define _H_CLI_SENSOR_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_sensor_api.h" +#include "cli_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* sensor client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_sensor); + +/* sensor client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_sensor_setup); + +/* Send Sensor Cadence Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_sensor_cadence_get); + +/* Send Sensor Cadence Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_sensor_cadence_set); + +/* Send Sensor Cadence Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_sensor_cadence_set_unacknowledged); + +/* Send Sensor Column Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_sensor_column_get); + +/* Send Sensor Descriptor Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_sensor_descriptor_get); + +/* Send Sensor Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_sensor_get); + +/* Send Sensor Series Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_sensor_series_get); + +/* Send Sensor Setting Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_sensor_setting_get); + +/* Send Sensor Setting Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_sensor_setting_set); + +/* Send Sensor Setting Set Unacknowledged */ +CLI_CMD_HANDLER_DECL(cli_modelc_sensor_setting_set_unacknowledged); + +/* Send Sensor Settings Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_sensor_settings_get); + +/* Get Model Handle */ +CLI_CMD_HANDLER_DECL(cli_modelc_sensor_get_model_handle); + +/* Set Publish Address */ +CLI_CMD_HANDLER_DECL(cli_modelc_sensor_set_publish_address); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Sensor client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_sensor_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_CLI_SENSOR_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_time_client.c b/src/components/ethermind/mesh/export/cli/model/client/cli_time_client.c new file mode 100644 index 0000000..ab4790d --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_time_client.c @@ -0,0 +1,456 @@ +/** + \file cli_time_client.c + + \brief This file defines the Mesh Time Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "cli_time_client.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +DECL_CONST CLI_COMMAND cli_modelc_time_cmd_list[] = +{ + /* Help */ + { "help", "Help", cli_help }, + + /* Back */ + { "back", "One Level Up", cli_back }, + + /* Root */ + { "root", "Back to Root", cli_root }, + + /* Setup */ + { "setup", "Model Time Setup", cli_modelc_time_setup }, + + /* Get Model Handle */ + { "gethandle", "Get Model Handle", cli_modelc_time_get_model_handle }, + + /* Set Publish Address */ + { "publishaddr", "Set Publish Address ", cli_modelc_time_set_publish_address }, + + /* Send Tai Utc Delta Get */ + { "taideltaget", "Send Tai Utc Delta Get", cli_modelc_tai_utc_delta_get}, + + /* Send Tai Utc Delta Set */ + { "taideltaset", "Send Tai Utc Delta Set", cli_modelc_tai_utc_delta_set}, + + /* Send Time Get */ + { "timeget", "Send Time Get", cli_modelc_time_get}, + + /* Send Time Role Get */ + { "timeroleget", "Send Time Role Get", cli_modelc_time_role_get}, + + /* Send Time Role Set */ + { "timeroleset", "Send Time Role Set", cli_modelc_time_role_set}, + + /* Send Time Set */ + { "timeset", "Send Time Set", cli_modelc_time_set}, + + /* Send Time Zone Get */ + { "timezoneget", "Send Time Zone Get", cli_modelc_time_zone_get}, + + /* Send Time Zone Set */ + { "timezoneset", "Send Time Zone Set", cli_modelc_time_zone_set} + +}; + + + +/* --------------------------------------------- External Global Variables */ +static MS_ACCESS_MODEL_HANDLE appl_time_client_model_handle; + + +/* --------------------------------------------- Function */ +API_RESULT cli_modelc_time(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT("In Model Client - Time\n"); + cli_cmd_stack_push((CLI_COMMAND*)cli_modelc_time_cmd_list, sizeof(cli_modelc_time_cmd_list) / sizeof(CLI_COMMAND)); + retval = cli_help(argc, argv); + return retval; +} + +/* time client CLI entry point */ +API_RESULT cli_modelc_time_setup(UINT32 argc, UCHAR* argv[]) +{ + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + static UCHAR model_initialized = 0x00; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + /** + Register with Access Layer. + */ + retval = API_FAILURE; + + if (0x00 == model_initialized) + { + /* Use Default Element Handle. Index 0 */ + element_handle = MS_ACCESS_DEFAULT_ELEMENT_HANDLE; + retval = MS_time_client_init + ( + element_handle, + &appl_time_client_model_handle, + cli_time_client_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Time Client Initialized. Model Handle: 0x%04X\n", + appl_time_client_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Time Client Initialization Failed. Result: 0x%04X\n", + retval); + } + + model_initialized = 0x01; + } + + return retval; +} + +/* Send Tai Utc Delta Get */ +API_RESULT cli_modelc_tai_utc_delta_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Tai Utc Delta Get\n"); + retval = MS_tai_utc_delta_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Tai Utc Delta Set */ +API_RESULT cli_modelc_tai_utc_delta_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_TAI_UTC_DELTA_SET_STRUCT param; + CONSOLE_OUT + (">> Send Tai Utc Delta Set\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.tai_utc_delta_new = (UINT16)choice; + CONSOLE_OUT("TAI UTC Delta New (15-bit in HEX): 0x%04X\n", param.tai_utc_delta_new); + /* choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); */ + param.padding = (UCHAR)0x00; + CONSOLE_OUT("Padding (1-bit in HEX): 0x%02X\n", param.padding); + CLI_strtoarray_le + ( + argv[1], + CLI_strlen(argv[1]), + ¶m.tai_of_delta_change[0], + 5 + ); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_tai_utc_delta_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Time Get */ +API_RESULT cli_modelc_time_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Time Get\n"); + retval = MS_time_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Time Role Get */ +API_RESULT cli_modelc_time_role_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Time Role Get\n"); + retval = MS_time_role_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Time Role Set */ +API_RESULT cli_modelc_time_role_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_TIME_ROLE_STRUCT param; + CONSOLE_OUT + (">> Send Time Role Set\n"); + + if (1 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.time_role = (UCHAR)choice; + CONSOLE_OUT("Time Role (8-bit in HEX): 0x%02X\n", param.time_role); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_time_role_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + + +/* Send Time Set */ +API_RESULT cli_modelc_time_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_TIME_STRUCT param; + CONSOLE_OUT + (">> Send Time Set\n"); + + if (6 == argc) + { + CLI_strtoarray_le + ( + argv[0], + CLI_strlen(argv[0]), + ¶m.tai_seconds[0], + 5 + ); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.subsecond = (UCHAR)choice; + CONSOLE_OUT("Subsecond (8-bit in HEX): 0x%02X\n", param.subsecond); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.uncertainty = (UCHAR)choice; + CONSOLE_OUT("Uncertainty (8-bit in HEX): 0x%02X\n", param.uncertainty); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.time_authority = (UCHAR)choice; + CONSOLE_OUT("Time Authority (1-bit in HEX): 0x%02X\n", param.time_authority); + choice = CLI_strtoi(argv[4], CLI_strlen(argv[4]), 16); + param.tai_utc_delta = (UINT16)choice; + CONSOLE_OUT("TAI UTC Delta (15-bit in HEX): 0x%04X\n", param.tai_utc_delta); + choice = CLI_strtoi(argv[5], CLI_strlen(argv[5]), 16); + param.time_zone_offset = (UCHAR)choice; + CONSOLE_OUT("Time Zone Offset (8-bit in HEX): 0x%02X\n", param.time_zone_offset); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_time_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Time Zone Get */ +API_RESULT cli_modelc_time_zone_get(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + CONSOLE_OUT + (">> Send Time Zone Get\n"); + retval = MS_time_zone_get(); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Time Zone Set */ +API_RESULT cli_modelc_time_zone_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + MS_TIME_ZONE_SET_STRUCT param; + CONSOLE_OUT + (">> Send Time Zone Set\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.time_zone_offset_new = (UCHAR)choice; + CONSOLE_OUT("Time Zone Offset New (8-bit in HEX): 0x%02X\n", param.time_zone_offset_new); + CLI_strtoarray_le + ( + argv[1], + CLI_strlen(argv[1]), + ¶m.tai_of_zone_change[0], + 5 + ); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_time_zone_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Get Model Handle */ +API_RESULT cli_modelc_time_get_model_handle(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + #if 0 + MS_ACCESS_MODEL_HANDLE model_handle; + retval = MS_time_get_model_handle(&model_handle); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Model Handle 0x%04X\n", model_handle); + } + else + { + CONSOLE_OUT + (">> Get Model Handle Failed. Status 0x%04X\n", retval); + } + + #else + retval = API_FAILURE; + CONSOLE_OUT("To be implemented\n"); + #endif /* 0 */ + return retval; +} + + +/* Set Publish Address */ +API_RESULT cli_modelc_time_set_publish_address(UINT32 argc, UCHAR* argv[]) +{ + int choice; + API_RESULT retval; + MS_ACCESS_MODEL_HANDLE model_handle; + MS_ACCESS_PUBLISH_INFO publish_info; + /* Set Publish Information */ + EM_mem_set(&publish_info, 0, sizeof(publish_info)); + publish_info.addr.use_label = MS_FALSE; + model_handle = appl_time_client_model_handle; + CONSOLE_OUT("Model Handle (16-bit in HEX): 0x%04X\n", model_handle); + + /* Check Number of Arguments */ + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + publish_info.addr.addr = (UINT16)choice; + CONSOLE_OUT("Time Server Address (16-bit in HEX): 0x%04X\n", publish_info.addr.addr); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + publish_info.appkey_index = (UINT16)choice; + CONSOLE_OUT("AppKey Index: 0x%04X\n", publish_info.appkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + publish_info.remote = MS_FALSE; + retval = MS_access_cm_set_model_publication + ( + model_handle, + &publish_info + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT + (">> Publish Address is set Successfully.\n"); + } + else + { + CONSOLE_OUT + (">> Failed to set publish address. Status 0x%04X\n", retval); + } + + return retval; +} + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Time client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_time_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + API_RESULT retval; + retval = API_SUCCESS; + CONSOLE_OUT ( + "[TIME_CLIENT] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_TAI_UTC_DELTA_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_TAI_UTC_DELTA_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_TIME_ROLE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_TIME_ROLE_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_TIME_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_TIME_STATUS_OPCODE\n"); + } + break; + + case MS_ACCESS_TIME_ZONE_STATUS_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_TIME_ZONE_STATUS_OPCODE\n"); + } + break; + } + + return retval; +} + diff --git a/src/components/ethermind/mesh/export/cli/model/client/cli_time_client.h b/src/components/ethermind/mesh/export/cli/model/client/cli_time_client.h new file mode 100644 index 0000000..6cad943 --- /dev/null +++ b/src/components/ethermind/mesh/export/cli/model/client/cli_time_client.h @@ -0,0 +1,84 @@ +/** + \file cli_time_client.h + + \brief This file defines the Mesh Time Model Application Interface + - includes Data Structures and Methods for Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_CLI_TIME_CLIENT_ +#define _H_CLI_TIME_CLIENT_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_time_api.h" +#include "cli_main.h" + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Function */ +/* time client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_time); + +/* time client CLI entry point */ +CLI_CMD_HANDLER_DECL(cli_modelc_time_setup); + +/* Send Tai Utc Delta Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_tai_utc_delta_get); + +/* Send Tai Utc Delta Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_tai_utc_delta_set); + +/* Send Time Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_time_get); + +/* Send Time Role Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_time_role_get); + +/* Send Time Role Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_time_role_set); + +/* Send Time Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_time_set); + +/* Send Time Zone Get */ +CLI_CMD_HANDLER_DECL(cli_modelc_time_zone_get); + +/* Send Time Zone Set */ +CLI_CMD_HANDLER_DECL(cli_modelc_time_zone_set); + +/* Get Model Handle */ +CLI_CMD_HANDLER_DECL(cli_modelc_time_get_model_handle); + +/* Set Publish Address */ +CLI_CMD_HANDLER_DECL(cli_modelc_time_set_publish_address); + +/** + \brief Client Application Asynchronous Notification Callback. + + \par Description + Time client calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT cli_time_client_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +); + +#endif /*_H_CLI_TIME_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/climodel/cli_model.c b/src/components/ethermind/mesh/export/climodel/cli_model.c new file mode 100644 index 0000000..b1b23cc --- /dev/null +++ b/src/components/ethermind/mesh/export/climodel/cli_model.c @@ -0,0 +1,461 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/********************************************************************* + INCLUDES +*/ +#include "cliface.h" +#include "cli_model.h" +#include "vendormodel_server.h" +#include "ltrn_extern.h" + +#define CONSOLE_OUT(...) printf(__VA_ARGS__) +#define CONSOLE_IN(...) scanf(__VA_ARGS__) + + +/********************************************************************* + EXTERNAL VARIABLES +*/ +extern EM_timer_handle thandle; +extern uint8 llState; +extern uint8 llSecondaryState; +extern llGlobalStatistics_t g_pmCounters; +extern UCHAR blebrr_state; +extern uint32 blebrr_advscan_timeout_count; +extern UINT32 blebrr_scanTimeOut; + +extern llGlobalStatistics_t g_pmCounters; +//extern uint32_t g_stop_scan_t1; +//extern uint32_t g_stop_scan_t1_err; +//extern uint8_t llModeDbg[6]; + +extern PROV_DEVICE_S UI_lprov_device; + + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +#if(BLEMESH_ROLE == PROV_ROLE_PROVISIONER) +#else +extern MS_ACCESS_MODEL_HANDLE UI_vendor_defined_server_model_handle; +extern API_RESULT UI_sample_get_net_key(void ); +extern API_RESULT UI_sample_get_device_key(void); +extern API_RESULT UI_sample_check_app_key(void); + +extern void timeout_cb (void* args, UINT16 size); + + + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static API_RESULT cli_vendormodel_send_reliable_pdu( + /* IN */ UINT32 req_opcode, + /* IN */ UINT16 dest_addr, + /* IN */ UINT16 appKey_index, + /* IN */ void* param, + /* IN */ UINT16 len +) +{ + API_RESULT retval; + /* TODO: Check what should be maximum length */ + UCHAR buffer[256]; + UCHAR* pdu_ptr; + UINT16 marker; + retval = API_FAILURE; + marker = 0; + + switch(req_opcode) + { + case MS_ACCESS_VENDORMODEL_WRITECMD_OPCODE: + { + EM_mem_copy(&buffer[marker], param, len); + marker += len; + } + break; + + default: + break; + } + + /* Publish - reliable */ + if (0 == marker) + { + pdu_ptr = NULL; + } + else + { + pdu_ptr = buffer; + } + + retval = MS_access_raw_data + ( + &UI_vendor_defined_server_model_handle, + req_opcode, + dest_addr, + appKey_index, + pdu_ptr, + marker, + MS_FALSE + ); + return retval; +} + + +API_RESULT cli_raw_data(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + UINT16 destnation_address; + UINT16 data_len,appKeyIndex; + UINT8 buffer[256]; + + if( argc < 3 ) + { + printf("Invaild RAW DATA Paraments\n"); + return API_FAILURE; + } + + destnation_address = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + appKeyIndex = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + data_len = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + + if(data_len == 0) + { + printf("No RAW DATA,Return\n"); + return API_FAILURE; + } + + retval = CLI_strtoarray + ( + argv[3], + CLI_strlen(argv[3]), + buffer, + data_len + ); + + if(retval != API_SUCCESS) + { + return retval; + } + + cli_vendormodel_send_reliable_pdu( + MS_ACCESS_VENDORMODEL_WRITECMD_OPCODE, + destnation_address, + appKeyIndex, + buffer, + data_len + ); + printf("destnation_address 0x%04X data_len 0x%02X\n",destnation_address,data_len); + return API_SUCCESS; +} +#endif + +API_RESULT cli_get_information(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + MS_NET_ADDR addr; + UINT8 features; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + retval = MS_access_cm_get_primary_unicast_address(&addr); + + if(retval != API_SUCCESS) + { + return API_FAILURE; + } + + MS_access_cm_get_features(&features); + dbg_printf("[ATMSH81]%04X%02X",addr,features); + return API_SUCCESS; +} + +#if(BLEMESH_ROLE == PROV_ROLE_PROVISIONER) +#else +API_RESULT cli_disp_key(UINT32 argc, UCHAR* argv[]) +{ + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + UI_sample_get_net_key(); + UI_sample_get_device_key(); + UI_sample_check_app_key(); + return API_SUCCESS; +} +#endif + +static void ll_dumpConnectionInfo(void ) +{ + printf("========== LL PM counters ================\r\n"); + printf("ll_send_undirect_adv_cnt = %d\r\n", g_pmCounters.ll_send_undirect_adv_cnt); + printf("ll_send_nonconn_adv_cnt = %d\r\n", g_pmCounters.ll_send_nonconn_adv_cnt); + printf("ll_send_scan_adv_cnt = %d\r\n", g_pmCounters.ll_send_scan_adv_cnt); + printf("ll_send_hdc_dir_adv_cnt = %d\r\n", g_pmCounters.ll_send_hdc_dir_adv_cnt); + printf("ll_send_ldc_dir_adv_cnt = %d\r\n", g_pmCounters.ll_send_ldc_dir_adv_cnt); + printf("ll_send_conn_adv_cnt = %d\r\n", g_pmCounters.ll_send_conn_adv_cnt); + printf("ll_conn_adv_pending_cnt = %d\r\n", g_pmCounters.ll_conn_adv_pending_cnt); + printf("ll_conn_scan_pending_cnt = %d\r\n", g_pmCounters.ll_conn_scan_pending_cnt); + printf("ll_recv_scan_req_cnt = %d\r\n", g_pmCounters.ll_recv_scan_req_cnt); + printf("ll_send_scan_rsp_cnt = %d\r\n", g_pmCounters.ll_send_scan_rsp_cnt); + printf("ll_recv_conn_req_cnt = %d\r\n", g_pmCounters.ll_recv_conn_req_cnt); + printf("ll_send_conn_rsp_cnt = %d\r\n", g_pmCounters.ll_send_conn_rsp_cnt); + printf("ll_filter_scan_req_cnt = %d\r\n", g_pmCounters.ll_filter_scan_req_cnt); + printf("ll_filter_conn_req_cnt = %d\r\n", g_pmCounters.ll_filter_conn_req_cnt); + printf("ll_recv_adv_pkt_cnt = %d\r\n", g_pmCounters.ll_recv_adv_pkt_cnt); + printf("ll_send_scan_req_cnt = %d\r\n", g_pmCounters.ll_send_scan_req_cnt); + printf("ll_recv_scan_rsp_cnt = %d\r\n", g_pmCounters.ll_recv_scan_rsp_cnt); + printf("ll_conn_succ_cnt = %d\r\n", g_pmCounters.ll_conn_succ_cnt); + printf("ll_link_lost_cnt = %d\r\n", g_pmCounters.ll_link_lost_cnt); + printf("ll_link_estab_fail_cnt = %d\r\n", g_pmCounters.ll_link_estab_fail_cnt); + printf("ll_rx_peer_cnt = %d\r\n", g_pmCounters.ll_rx_peer_cnt); + printf("ll_evt_shc_err = %d\r\n", g_pmCounters.ll_evt_shc_err); + printf("ll_trigger_err = %d\r\n", g_pmCounters.ll_trigger_err); + printf("ll_rfifo_rst_err = %d\r\n", g_pmCounters.ll_rfifo_rst_err); + printf("ll_rfifo_rst_cnt = %d\r\n", g_pmCounters.ll_rfifo_rst_cnt); + printf("ll_rfifo_read_err = %d\r\n", g_pmCounters.ll_rfifo_read_err); + printf("\r\n "); +} + +API_RESULT cli_demo_reset(UINT32 argc, UCHAR* argv[]) +{ + UCHAR proxy_state,proxy; + MS_access_cm_get_features_field(&proxy, MS_FEATURE_PROXY); + + if(MS_TRUE == proxy) + { + MS_proxy_fetch_state(&proxy_state); + + if(proxy_state == MS_PROXY_CONNECTED) + blebrr_disconnect_pl(); + } + + #if(BLEMESH_ROLE == PROV_ROLE_PROVISIONER) + MS_access_cm_reset(PROV_ROLE_PROVISIONER); + #else + nvs_reset(NVS_BANK_PERSISTENT); + MS_access_cm_reset(PROV_ROLE_DEVICE); + + if(thandle == EM_TIMER_HANDLE_INIT_VAL) + { + EM_start_timer (&thandle, 3, timeout_cb, NULL, 0); + } + + #endif + printf ("Done\r\n"); + return API_SUCCESS; +} + + + +API_RESULT cli_internal_status(UINT32 argc, UCHAR* argv[]) +{ + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + printf("\r\n===== internal status ============\r\n"); + printf("llState = %d, llSecondaryState = %d\r\n", llState, llSecondaryState); + printf("blebrr_state = %d\r\n", blebrr_state); + printf("blebrr_scanTimOut = %d\r\n", blebrr_scanTimeOut); + printf("\r\n"); + ll_dumpConnectionInfo(); + return API_SUCCESS; +} + +/* Send Config Heartbeat Publication Set */ +API_RESULT cli_modelc_config_heartbeat_publication_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_HEARTBEATPUB_SET_PARAM param; + CONSOLE_OUT + (">> Send Config Heartbeat Publication Set\n"); + + if (6 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.destination = (UINT16)choice; + CONSOLE_OUT("Destination (16-bit in HEX): 0x%04X\n", param.destination); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.countlog = (UCHAR)choice; + CONSOLE_OUT("CountLog (8-bit in HEX): 0x%02X\n", param.countlog); + choice = CLI_strtoi(argv[2], CLI_strlen(argv[2]), 16); + param.periodlog = (UCHAR)choice; + CONSOLE_OUT("PeriodLog (8-bit in HEX): 0x%02X\n", param.periodlog); + choice = CLI_strtoi(argv[3], CLI_strlen(argv[3]), 16); + param.ttl = (UCHAR)choice; + CONSOLE_OUT("TTL (8-bit in HEX): 0x%02X\n", param.ttl); + choice = CLI_strtoi(argv[4], CLI_strlen(argv[4]), 16); + param.features = (UINT16)choice; + CONSOLE_OUT("Features (16-bit in HEX): 0x%04X\n", param.features); + choice = CLI_strtoi(argv[5], CLI_strlen(argv[5]), 16); + param.netkey_index = (UINT16)choice; + CONSOLE_OUT("NetKeyIndex (16-bit in HEX): 0x%04X\n", param.netkey_index); + } + else + { + CONSOLE_OUT("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + retval = MS_config_client_heartbeat_publication_set(¶m); + CONSOLE_OUT + ("retval = 0x%04X\n", retval); + return retval; +} + +API_RESULT cli_on(UINT32 argc, UCHAR* argv[]) +{ +// UI_generic_onoff_set(0x01); + return API_SUCCESS; +} + +API_RESULT cli_off(UINT32 argc, UCHAR* argv[]) +{ +// UI_generic_onoff_set(0x00); + return API_SUCCESS; +} + + +API_RESULT cli_seek(UINT32 argc, UCHAR* argv[]) +{ +// UI_lpn_seek_friend(); + return API_SUCCESS; +} + + +static void set_uuid_octet (UCHAR uuid_0) +{ +} + + +API_RESULT cli_start(UINT32 argc, UCHAR* argv[]) +{ + int val; + + if (1 != argc) + { + printf("Usage: start \r\n"); + return API_FAILURE; + } + + val = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + set_uuid_octet ((UCHAR)val); +// appl_mesh_sample(); + return API_SUCCESS; +} + +API_RESULT cli_group_select(UINT32 argc, UCHAR* argv[]) +{ + UINT16 group; + + if (1 != argc) + { + printf("Usage: group \r\n"); + return API_FAILURE; + } + + group = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + printf("select Mesh Group %d, behavior to be implemented\r\n", group); + return API_SUCCESS; +} + +/* Send Config Key Refresh Phase Set */ +API_RESULT cli_core_modelc_config_key_refresh_phase_set(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_KEYREFRESH_PHASE_SET_PARAM param; + printf + (">> Send Config Key Refresh Phase Set\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.netkey_index = (UINT16)choice; + printf("NetKeyIndex (16-bit in HEX): 0x%04X\n", param.netkey_index); + choice = CLI_strtoi(argv[1], CLI_strlen(argv[1]), 16); + param.transition = (UCHAR)choice; + printf("Transition (8-bit in HEX): 0x%02X\n", param.transition); + } + else + { + printf("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + /* Change Local State as well */ + MS_access_cm_set_key_refresh_phase + ( + 0, /* subnet_handle */ + ¶m.transition /* key_refresh_state */ + ); + param.transition = (UCHAR)choice; + retval = MS_config_client_keyrefresh_phase_set(¶m); + printf + ("retval = 0x%04X\n", retval); + return retval; +} + +/* Send Config Netkey Update */ +API_RESULT cli_core_modelc_config_netkey_update(UINT32 argc, UCHAR* argv[]) +{ + API_RESULT retval; + int choice; + ACCESS_CONFIG_NETKEY_UPDATE_PARAM param; + printf + (">> Send Config Netkey Update\n"); + + if (2 == argc) + { + choice = CLI_strtoi(argv[0], CLI_strlen(argv[0]), 16); + param.netkey_index = (UINT16)choice; + printf("NetKeyIndex (16-bit in HEX): 0x%04X\n", param.netkey_index); + CLI_strtoarray + ( + argv[1], + CLI_strlen(argv[1]), + ¶m.netkey[0], + 16 + ); + } + else + { + printf("Invalid Number of Arguments:0x%04X. Returning.\n", argc); + return API_FAILURE; + } + + /* Set Local NetKey */ + MS_access_cm_add_update_netkey + ( + 0, /* netkey_index */ + MS_ACCESS_CONFIG_NETKEY_UPDATE_OPCODE, /* opcode */ + ¶m.netkey[0] /* net_key */ + ); + retval = MS_config_client_netkey_update(¶m); + printf + ("retval = 0x%04X\n", retval); + return retval; +} + +API_RESULT cli_demo_help(UINT32 argc, UCHAR* argv[]) +{ + UINT32 index; + MS_IGNORE_UNUSED_PARAM(argc); + MS_IGNORE_UNUSED_PARAM(argv); + printf("\r\nCLI Demo\r\n"); + + /* Print all the available commands */ + for (index = 0; index < g_cli_cmd_len; index++) + { + printf(" %s: %s\n", + g_cli_cmd_list[index].cmd, + g_cli_cmd_list[index].desc); + } + + return API_SUCCESS; +} + + + + +/********************************************************************* +*********************************************************************/ diff --git a/src/components/ethermind/mesh/export/climodel/cli_model.h b/src/components/ethermind/mesh/export/climodel/cli_model.h new file mode 100644 index 0000000..7fd1d2d --- /dev/null +++ b/src/components/ethermind/mesh/export/climodel/cli_model.h @@ -0,0 +1,62 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#ifndef _CLI_VENDOR_H +#define _CLI_VENDOR_H + +/********************************************************************* + INCLUDES +*/ +#include "types.h" +#include "rf_phy_driver.h" + +#include "bleMesh.h" + +#include "MS_common.h" + +#include "MS_prov_api.h" + +#include "nvs.h" + +#include "cliface.h" + +#include "mesh_clients.h" +#include "access_extern.h" +#include "MS_config_api.h" +#include "vendormodel_server.h" + +/********************************************************************* + LOCAL FUNCTIONS +*/ +API_RESULT cli_raw_data(UINT32 argc, UCHAR* argv[]); + +API_RESULT cli_get_information(UINT32 argc, UCHAR* argv[]); + +API_RESULT cli_disp_key(UINT32 argc, UCHAR* argv[]); + +API_RESULT cli_demo_reset(UINT32 argc, UCHAR* argv[]); + +API_RESULT cli_internal_status(UINT32 argc, UCHAR* argv[]); + +API_RESULT cli_modelc_config_heartbeat_publication_set(UINT32 argc, UCHAR* argv[]); + +API_RESULT cli_start(UINT32 argc, UCHAR* argv[]); + +API_RESULT cli_on(UINT32 argc, UCHAR* argv[]); + +API_RESULT cli_off(UINT32 argc, UCHAR* argv[]); + +API_RESULT cli_seek(UINT32 argc, UCHAR* argv[]); + +API_RESULT cli_group_select(UINT32 argc, UCHAR* argv[]); + +API_RESULT cli_core_modelc_config_key_refresh_phase_set(UINT32 argc, UCHAR* argv[]); + +API_RESULT cli_core_modelc_config_netkey_update(UINT32 argc, UCHAR* argv[]); + +API_RESULT cli_demo_help(UINT32 argc, UCHAR* argv[]); + +#endif + diff --git a/src/components/ethermind/mesh/export/include/MS_access_api.h b/src/components/ethermind/mesh/export/include/MS_access_api.h new file mode 100644 index 0000000..8e4f08f --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_access_api.h @@ -0,0 +1,1960 @@ + +/** + \file MS_access_api.h + + \brief This file defines the Mesh Access Application Interface - includes + Data Structures and Methods. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_ACCESS_API_ +#define _H_MS_ACCESS_API_ + + +/* --------------------------------------------- Header File Inclusion */ +/* Transport Layer */ +#include "MS_trn_api.h" + +#ifdef MS_STORAGE + #include "nvsto.h" +#endif /* MS_STORAGE */ + +/* --------------------------------------------- Global Definitions */ + +/** + \defgroup access_module ACCESS (Mesh Access Layer) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Access (ACCESS) module to the Application and other upper + layers of the stack. +*/ + +/** + \defgroup access_defines Defines + \{ + Describes defines for the module. +*/ + +/** + \defgroup access_constants Constants + \{ + Describes Constants defined by the module. +*/ + +/** + Maximum Access Packet size. + 32 segments of 12 octets each. +*/ +#define MS_ACCESS_MAX_PKT_SIZE 384 + + +/** Array sizes for use in the Access layer */ +/** Size of Virtual Address (Label UUID) */ +#define MS_ACCESS_VADDR_LABEL_UUID_SIZE 16 +/** Size of NetKey */ +#define MS_ACCESS_NETKEY_SIZE 16 +/** Size of AppKey */ +#define MS_ACCESS_APPKEY_SIZE 16 + +/** Default Node Identifier */ +#define MS_ACCESS_DEFAULT_NODE_ID 0x00 + +/** Default Element Handle */ +#define MS_ACCESS_DEFAULT_ELEMENT_HANDLE 0x00 + +/** Get Request */ +#define MS_ACCESS_GET_REQ 0x01 + +/** Set Request */ +#define MS_ACCESS_SET_REQ 0x02 + +/** Invalid default TTL value */ +#define ACCESS_INVALID_DEFAULT_TTL 0xFF + +/** Maximum TTL value - used as initializer */ +#define ACCESS_MAX_TTL 0x05 //0x7F + +/** Model Specific Request Message Type: Get, Set or Others */ +/** Model Specific Request Message Type: Get */ +#define MS_ACCESS_MODEL_REQ_MSG_T_GET 0 +/** Model Specific Request Message Type: Set */ +#define MS_ACCESS_MODEL_REQ_MSG_T_SET 1 +/** Model Specific Request Message Type: Others */ +#define MS_ACCESS_MODEL_REQ_MSG_T_OTHERS 2 + +/** Key Refersh Phase states */ +/** Key Refersh Phase - Normal */ +#define MS_ACCESS_KEY_REFRESH_PHASE_NORMAL 0x00 +/** Key Refersh Phase - 1 */ +#define MS_ACCESS_KEY_REFRESH_PHASE_1 0x01 +/** Key Refersh Phase - 2 */ +#define MS_ACCESS_KEY_REFRESH_PHASE_2 0x02 +/** Key Refersh Phase - 3 */ +#define MS_ACCESS_KEY_REFRESH_PHASE_3 0x03 + +/** Invalid Access Address */ +#define MS_ACCESS_ADDRESS_INVALID_HANDLE 0xFFFFFFFF + +/** \} */ + +/** \} */ + +/** + \defgroup access_events Events + \{ + This section lists the Asynchronous Events notified to Application by the + Module. +*/ + +/** \} */ + +/** + \defgroup access_marcos Utility Macros + \{ + This section defines the utility macros for use by the application. + +*/ +/** Populates the given element with the Model information */ +#define MS_ACCESS_ASSIGN_ELEMENT(pelement, loc) \ + (pelement)->loc = (loc) + +/** Initializes the SIG model with the given ID and callback information */ +#define MS_ACCESS_INIT_SIG_MODEL(pmodel, id, eh, cb, pub_cb, num_op, op) \ + (pmodel)->model_id.type = MS_ACCESS_MODEL_TYPE_SIG; \ + (pmodel)->model_id.id = (id); \ + (pmodel)->elem_handle = (eh); \ + (pmodel)->cb = (cb); \ + (pmodel)->pub_cb = (pub_cb); \ + (pmodel)->num_opcodes = (num_op); \ + (pmodel)->opcodes = (op) + +/** Initializes the Vendor model with the given ID and callback information */ +#define MS_ACCESS_INIT_VENDOR_MODEL(pmodel, id, eh, cb, pub_cb, num_op, op) \ + (pmodel)->model_id.type = MS_ACCESS_MODEL_TYPE_VENDOR; \ + (pmodel)->model_id.id = (id); \ + (pmodel)->elem_handle = (eh); \ + (pmodel)->cb = (cb); \ + (pmodel)->pub_cb = (pub_cb); \ + (pmodel)->num_opcodes = (num_op); \ + (pmodel)->opcodes = (op) + +/** \} */ + +/* --------------------------------------------- Data Types/ Structures */ + +/** Access Model Handle */ +typedef UINT16 MS_ACCESS_MODEL_HANDLE; + + +/** + \defgroup access_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ +/** + Access Layer Application Asynchronous Notification Callback. + + Access Layer calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param saddr 16 bit Source Address. + \param daddr 16 bit Destination Address. + \param subnet_handle Subnet Handle. + \param appkey_handle AppKey Handle. + \param opcode Opcode. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef API_RESULT (* MS_ACCESS_MODEL_CB) +( + MS_ACCESS_MODEL_HANDLE* handle, + MS_NET_ADDR saddr, + MS_NET_ADDR daddr, + MS_SUBNET_HANDLE subnet_handle, + MS_APPKEY_HANDLE appkey_handle, + UINT32 opcode, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; + +/** + Access Layer Model Publication Timeout Callback. + + Access Layer calls the registered callback to indicate Publication Timeout + for the associated model. + + \param handle Model Handle. + \param blob Blob if any or NULL. +*/ +typedef API_RESULT (* MS_ACCESS_MODEL_PUBLISH_TIMEOUT_CB) +( + MS_ACCESS_MODEL_HANDLE* handle, + void* data_param +) DECL_REENTRANT; +/** \} */ + +/** + \defgroup access_structures Structures + \{ +*/ + +/** SIG Model ID */ +typedef UINT16 MS_ACCESS_MODEL_ID_SIG; + +/** Vendor Model ID */ +typedef UINT32 MS_ACCESS_MODEL_ID_VENDOR; + +/** Access Node ID */ +typedef UINT8 MS_ACCESS_NODE_ID; + +/** Access Element Handle */ +typedef UINT8 MS_ACCESS_ELEMENT_HANDLE; + +/** Access Address Handle */ +typedef UINT32 MS_ACCESS_ADDRESS_HANDLE; + +/** Device Key Handle */ +typedef UINT32 MS_ACCESS_DEV_KEY_HANDLE; + +/** Model ID datatype */ +typedef struct _MS_ACCESS_MODEL_ID +{ + /** Vendor/SIG ID */ + UINT32 id; + + /** + Model type + - SIG or Vendor + */ + UCHAR type; + +} MS_ACCESS_MODEL_ID; + +/** + Data structure for model. + + Models could be bluetooth SIG defined or vendor defined. +*/ +typedef struct _MS_ACCESS_MODEL +{ + /** Model ID */ + MS_ACCESS_MODEL_ID model_id; + + /** Associated Element Handle */ + MS_ACCESS_ELEMENT_HANDLE elem_handle; + + /** + Callback function pointer to receive packets from the underlying + protocol layers + */ + MS_ACCESS_MODEL_CB cb; + + /** + Callback function called when Publication Timer expires. + Set to NULL if model does not support periodic publication. + */ + MS_ACCESS_MODEL_PUBLISH_TIMEOUT_CB pub_cb; + + /** Number of Opcodes */ + UINT16 num_opcodes; + + /** List of Opcodes */ + DECL_CONST UINT32* opcodes; + +} MS_ACCESS_MODEL; + + +/** + Element description format. +*/ +typedef struct _MS_ACCESS_ELEMENT_DESC +{ + /** Location descriptor */ + UINT16 loc; + +} MS_ACCESS_ELEMENT_DESC; + +/** + Unicast/Virtual/Group Address. +*/ +typedef struct _MS_ACCESS_ADDRESS +{ + /** Flag - which field to be used */ + UINT8 use_label; + + /** Address */ + MS_NET_ADDR addr; + + /** Label UUID */ + UINT8 label[MS_LABEL_UUID_LENGTH]; + +} MS_ACCESS_ADDRESS; + +/** + Access Publication related information +*/ +typedef struct _MS_ACCESS_PUBLISH_INFO +{ + /** PublishAddress (Unicast/Virtual/Group) */ + MS_ACCESS_ADDRESS addr; + + /** + - AppKey Index (when set from remote). + - AppKey Handle (when set from locally for Configuration Client). + */ + UINT16 appkey_index; + + /** CredentialFlag */ + UINT8 crden_flag; + + /** PublishTTL */ + UINT8 ttl; + + /** PublishPeriod */ + UINT8 period; + + /** PublishRetransmitCount */ + UINT8 rtx_count; + + /** PublishRetransmitIntervalSteps */ + UINT8 rtx_interval_steps; + + /** Flag - if called from local or remote */ + UINT8 remote; + +} MS_ACCESS_PUBLISH_INFO; + +/** + Context of message received for a specific model instance. + This is required to send response appropriately. +*/ +typedef struct _MS_ACCESS_MODEL_REQ_MSG_CONTEXT +{ + /** Model Handle - for which request is received */ + MS_ACCESS_MODEL_HANDLE handle; + + /** Source Address - oritinator of request */ + MS_NET_ADDR saddr; + + /** Destination Address - of the request */ + MS_NET_ADDR daddr; + + /** Associated Subnet Identifier */ + MS_SUBNET_HANDLE subnet_handle; + + /** Associated AppKey Identifier */ + MS_APPKEY_HANDLE appkey_handle; + +} MS_ACCESS_MODEL_REQ_MSG_CONTEXT; + +/** Uninterpreted/raw received message for a specific model instance. */ +typedef struct _MS_ACCESS_MODEL_REQ_MSG_RAW +{ + /** Request Opcode */ + UINT32 opcode; + + /** Raw received message */ + UCHAR* data_param; + + /** Raw received message length */ + UINT16 data_len; + +} MS_ACCESS_MODEL_REQ_MSG_RAW; + +/** Requested message type for a specific model instance. */ +typedef struct _MS_ACCESS_MODEL_REQ_MSG_T +{ + /** Flag: GET, SET or Others */ + UINT8 type; + + /** Flag: True or False */ + UINT8 to_be_acked; + +} MS_ACCESS_MODEL_REQ_MSG_T; + +/** Model specific state parameters in a request or response message */ +typedef struct _MS_ACCESS_MODEL_STATE_PARAMS +{ + /** State Type */ + UCHAR state_type; + + /** State pointer */ + void* state; + +} MS_ACCESS_MODEL_STATE_PARAMS; + +/** Additional paramters in a Model specific request or response message */ +typedef struct _MS_ACCESS_MODEL_EXT_PARAMS +{ + /** State/Extended Type */ + UCHAR ext_type; + + /** State/Extended data structure pointer */ + void* ext; + +} MS_ACCESS_MODEL_EXT_PARAMS; + +/** + Provisioned Device List Data Structure, containing Primary Element Address + and number of elements. +*/ +typedef struct _MS_PROV_DEV_ENTRY +{ + /** Unicast Address of the first element */ + MS_NET_ADDR uaddr; + + /** Number of Elements */ + UCHAR num_elements; + + /*Receive notify count*/ + UINT16 rcv_flag; +} MS_PROV_DEV_ENTRY; + +/** \} */ + + +/* --------------------------------------------- Function */ + +/** + \defgroup access_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Access Layer APIs. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + \brief Create a new node in the device. + + \par Description + This routine creates a new node in the device. This can be used by the + application to create extra nodes if required in addition to the default + primary node. + + \param [out] node_id Identifier to reference the newly created node. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_create_node (/* OUT */ MS_ACCESS_NODE_ID* node_id); + +/** + \brief Register an element with the access layer. + + \par Description + This routine registers an element that can be populated with the models + information to a specific node in the device identified by the node id. + + \param [in] node_id Node to which the element needs to be registered. This + value is always 0 for the default node. + + \param [in] element Pointer to the element descriptor that needs to be + registered to the node. + + \param [out] element_handle Identifier to reference the newly registered element. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_register_element +( + /* IN */ MS_ACCESS_NODE_ID node_id, + /* IN */ MS_ACCESS_ELEMENT_DESC* element, + /* OUT */ MS_ACCESS_ELEMENT_HANDLE* element_handle +); + +/** + \brief Register a model with the access layer. + + \par Description + This routine registers a model associated with an element with the access layer. + + \param [in] node_id Node to which the model needs to be registered. This + value is always 0 for the default node. + + \param [in] model Pointer to the model descriptor that needs to be + registered to the node. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful registration. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_register_model +( + /* IN */ MS_ACCESS_NODE_ID node_id, + /* IN */ MS_ACCESS_MODEL* model, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle +); + +/** + \brief Get element handle. + + \par Description + This routine searches for the element handle associated with specific element address. + + \param [in] elem_addr Address of the corresponding element. + \param [out] handle Element handle associated with the element address. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_get_element_handle +( + /* IN */ MS_NET_ADDR elem_addr, + /* OUT */ MS_ACCESS_ELEMENT_HANDLE* handle +); + +/** + \brief Get model handle. + + \par Description + This routine searches for the model handle associated with specific model ID. + + \param [in] elem_handle Element Identifier associated with the Model. + \param [in] model_id Model Identifier for which the model handle to be searched. + \param [out] handle Model handle associated with model ID. + If not found, handle will be set as NULL. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_get_model_handle +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE elem_handle, + /* IN */ MS_ACCESS_MODEL_ID model_id, + /* OUT */ MS_ACCESS_MODEL_HANDLE* handle +); + +API_RESULT MS_access_get_appkey_handle +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* OUT */ MS_APPKEY_HANDLE* appkey_handle +); + + +/** + \brief API to publish access layer message. + + \par Description + This routine publishes Access Layer message to the publish address associated with the model. + + \param [in] handle + Access Model Handle for which message to be sent. + + \param [in] opcode + Access Opcode + + \param [in] data_param + Data packet + + \param [in] data_len + Data packet length + + \param [in] reliable + MS_TRUE for reliable message. MS_FALSE otherwise. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_publish +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len, + /* IN */ UINT8 reliable +); + +/** + \brief API to reliably publish access layer message. + + \par Description + This routine reliably publishes Access Layer message to the publish address associated with the model. + + \param [in] handle + Access Model Handle for which message to be sent. + + \param [in] req_opcode + Request Opcode + + \param [in] data_param + Data packet + + \param [in] data_len + Data packet length + + \param [in] rsp_opcode + Response Opcode + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_reliable_publish +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 req_opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len, + /* IN */ UINT32 rsp_opcode +); + +/** + \brief API to reply to access layer message. + + \par Description + This routine replies to Access Layer message. + + \param [in] handle Model Handle. + \param [in] saddr 16 bit Source Address. + \param [in] daddr 16 bit Destination Address. + \param [in] subnet_handle Subnet Handle. + \param [in] appkey_handle AppKey Handle. + \param [in] ttl Time to Live. + \param [in] opcode Access Opcode + \param [in] data_param Access parameter, based on the opcode + \param [in] data_length Access parameter length, based on the opcode + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_reply +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ MS_NET_ADDR saddr, + /* IN */ MS_NET_ADDR daddr, + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ MS_APPKEY_HANDLE appkey_handle, + /* IN */ UINT8 ttl, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_length +); + +/** + \brief API to reply to access layer message and optionally also to publish. + + \par Description + This routine replies to Access Layer message and also publish if requested by application. + + \param [in] handle Model Handle. + \param [in] saddr 16 bit Source Address. + \param [in] daddr 16 bit Destination Address. + \param [in] subnet_handle Subnet Handle. + \param [in] appkey_handle AppKey Handle. + \param [in] ttl Time to Live. + \param [in] opcode Access Opcode + \param [in] data_param Access parameter, based on the opcode + \param [in] data_length Access parameter length, based on the opcode + \param [in] to_publish Flag to indicate if the message also to be published + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_reply_and_publish +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ MS_NET_ADDR saddr, + /* IN */ MS_NET_ADDR daddr, + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ MS_APPKEY_HANDLE appkey_handle, + /* IN */ UINT8 ttl, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len, + /* IN */ UINT8 to_publish +); + +/** + \brief API to send Access PDUs + + \par Description + This routine sends transport PDUs to peer device. + + \param [in] saddr 16 bit Source Address. + \param [in] daddr 16 bit Destination Address. + \param [in] subnet_handle Subnet Handle. + \param [in] appkey_handle AppKey Handle. + \param [in] ttl Time to Live. + \param [in] opcode Access Opcode + \param [in] data_param Access parameter, based on the opcode + \param [in] data_length Access parameter length, based on the opcode + \param [in] reliable If requires lower transport Ack, set reliable as TRUE + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_send_pdu +( + /* IN */ MS_NET_ADDR saddr, + /* IN */ MS_NET_ADDR daddr, + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ MS_APPKEY_HANDLE appkey_handle, + /* IN */ UINT8 ttl, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_length, + /* IN */ UINT8 reliable +); + +/** TBD: add function header */ +API_RESULT MS_access_get_composition_data(/* OUT */ MS_BUFFER* buffer); + +/* Configuration Manager related interfaces */ + +/** + \brief To reset a node + + \par Description + This routine resets a node (other than a Provisioner) and removes it from the network. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_reset(UINT8 role); + +/** + \brief To get the number of elements in local node + + \par Description + This routine retrieves the number of elements in local node. + + \param [out] count Number of elements + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_element_count +( + /* OUT */ UINT8* count +); + +/** + \brief To set primary unicast address + + \par Description + This routine sets primary unicast address. + + \param [in] addr Primary Unicast Address to be set + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_set_primary_unicast_address +( + /* IN */ MS_NET_ADDR addr +); + +/** + \brief To get primary unicast address + + \par Description + This routine gets primary unicast address. + + \param [out] addr Memory location where Primary Unicast Address to be filled + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_primary_unicast_address +( + /* OUT */ MS_NET_ADDR* addr +); + +/** + \brief To set default TTL + + \par Description + This routine sets default TTL. + + \param [in] ttl Default TTL to be set + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_set_default_ttl +( + /* IN */ UINT8 ttl +); + +/** + \brief To get default TTL + + \par Description + This routine gets default TTL. + + \param [in] ttl Memory location where default TTL to be filled + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_default_ttl +( + /* IN */ UINT8* ttl +); + +/** + \brief To set IV Index + + \par Description + This routine sets IV Index. + + \param [in] iv_index IV Index to be set + \param [in] iv_update_flag IV Update Flag + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_set_iv_index +( + /* IN */ UINT32 iv_index, + /* IN */ UINT8 iv_update_flag +); + +/** + \brief To get IV Index + + \par Description + This routine gets IV Index. + + \param [out] iv_index Memory location where IV Index to be filled + \param [out] iv_update_flag Memory location where IV Update Flag to be filled + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_iv_index +( + /* OUT */ UINT32* iv_index, + /* OUT */ UINT8* iv_update_flag +); + +/** + \brief To get IV Index by IVI + + \par Description + This routine gets IV Index based on the IVI in the received packet. + + \param [in] ivi Least Significant bit of the IV Index used + in the nonce to authenticate and encrypt + the Network PDU. + \param [out] iv_index Memory location where IV Index to be filled + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_iv_index_by_ivi +( + /* IN */ UINT8 ivi, + /* OUT */ UINT32* iv_index +); + +/** + \brief To enable/disable a feature + + \par Description + This routine enables/disables a feature field. + + \param [in] enable Enable or Disable + \param [in] feature Relay, proxy, friend or Low Power + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_set_features_field +( + /* IN */ UINT8 enable, + /* IN */ UINT8 feature +); + +/** + \brief To get state of a feature + + \par Description + This routine gets the state of a feature field. + + \param [out] enable Memory location where Enable or Disable status to be filled. + \param [in] feature Relay, proxy, friend or Low Power + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_features_field +( + /* OUT */ UINT8* enable, + /* IN */ UINT8 feature +); + +/** + \brief To get state of all features + + \par Description + This routine gets the state of all features. + + \param [out] features State of Relay, proxy, friend and Low Power field + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_features +( + /* OUT */ UINT8* features +); + +/** Enable Relay Feature */ +#define MS_ENABLE_RELAY_FEATURE() \ + MS_access_cm_set_features_field(MS_ENABLE, MS_FEATURE_RELAY) + +/** Disable Relay Feature */ +#define MS_DISABLE_RELAY_FEATURE() \ + MS_access_cm_set_features_field(MS_DISABLE, MS_FEATURE_RELAY) + +/** Enable Proxy Feature */ +#define MS_ENABLE_PROXY_FEATURE() \ + MS_access_cm_set_features_field(MS_ENABLE, MS_FEATURE_PROXY) + +/** Disable Proxy Feature */ +#define MS_DISABLE_PROXY_FEATURE() \ + MS_access_cm_set_features_field(MS_DISABLE, MS_FEATURE_PROXY) + +/** Enable Friend Feature */ +#define MS_ENABLE_FRIEND_FEATURE() \ + MS_access_cm_set_features_field(MS_ENABLE, MS_FEATURE_FRIEND) + +/** Disable Friend Feature */ +#define MS_DISABLE_FRIEND_FEATURE() \ + MS_access_cm_set_features_field(MS_DISABLE, MS_FEATURE_FRIEND) + +/** Enable Low Power Feature */ +#define MS_ENABLE_LPN_FEATURE() \ + MS_access_cm_set_features_field(MS_ENABLE, MS_FEATURE_LPN) + +/** Disable Low Power Feature */ +#define MS_DISABLE_LPN_FEATURE() \ + MS_access_cm_set_features_field(MS_DISABLE, MS_FEATURE_LPN) + +/** Enable Secure Nework Beacon Feature */ +#define MS_ENABLE_SNB_FEATURE() \ + MS_access_cm_set_features_field(MS_ENABLE, MS_FEATURE_SEC_NET_BEACON) + +/** Disable Secure Nework Beacon Feature */ +#define MS_DISABLE_SNB_FEATURE() \ + MS_access_cm_set_features_field(MS_DISABLE, MS_FEATURE_SEC_NET_BEACON) + + +/** + \brief To get friendship role of the node + + \par Description + This routine gets the current friendship role of the node. + + \param [out] frnd_role Friend role + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_friendship_role +( + /* OUT */ UINT8* frnd_role +); + + +/** + \brief To set friendship role of the node + + \par Description + This routine sets the current friendship role of the node. + + \param [out] frnd_role Friend role + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_set_friendship_role +( + /* IN */ UINT8 frnd_role +); + + +/** + \brief To add Device Key + + \par Description + This routine adds Device Key entry, along with corresponding + Primary Device Address and Number of elements. + + \param [in] dev_key Device Key to be added. + \param [in] uaddr Unicast Address of the first element. + \param [in] num_elements Number of elements. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_add_device_key +( + /* IN */ UINT8* dev_key, + /* IN */ MS_NET_ADDR uaddr, + /* IN */ UINT8 num_elements +); + +/** + \brief To get Device Key + + \par Description + This routine gets Device Key entry. + + \param [in] dev_key_index Device Key Index. + \param [out] dev_key Pointer to Device Key to be returned. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_device_key +( + /* IN */ UINT8 dev_key_index, + /* OUT */ UINT8** dev_key +); + +/** + \brief To remove all Device Keys + + \par Description + This routine removes all Device Keys from table. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_remove_all_device_keys(void); + +/** + \brief To get list of Provisioned Device List + + \par Description + This routine returns list of Provisioned Devices from the Device Key Table. + + \param [in] prov_dev_list Provisioned Device List. + \param [inout] num_entries Size of the Device Key List provided by the caller. + This routine will return the number of entries + in the Device Key Table. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_prov_devices_list +( + /* IN */ MS_PROV_DEV_ENTRY* prov_dev_list, + /* OUT */ UINT16* num_entries, + /* OUT */ UINT16* pointer +); + +/** + \brief To get Device Key Handle + + \par Description + This routine returns Device Key Handle for a given Primary Element Address + entry in Device Key Table. + + \param [in] prim_elem_uaddr Primary element address to be searched + \param [out] handle Device Key Table Handle, if match is found. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_device_key_handle +( + /* IN */ MS_NET_ADDR prim_elem_uaddr, + /* OUT */ MS_ACCESS_DEV_KEY_HANDLE* handle +); +/** + \brief To delete Device Key + + \par Description + This routine returns status for a given Primary Element Address + entry in Device Key Table. + + \param [in] handle Device Key Table Handle, if match is found. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_delete_device_key +( + /* IN */ MS_ACCESS_DEV_KEY_HANDLE handle +); + + +/** + \brief To get AppKey + + \par Description + This routine gets AppKey along with AID entry. + + \param [in] appkey_handle AppKey Handle. + \param [out] app_key Pointer to AppKey to be returned. + \param [out] aid Pointer to AID to be returned. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_app_key +( + /* IN */ MS_APPKEY_HANDLE appkey_handle, + /* OUT */ UINT8** app_key, + /* OUT */ UINT8* aid +); + +/** + \brief To add/update NetKey + + \par Description + This routine adds/updates NetKey entry. Each NetKey is associated with a subnet. + + \param [in] netkey_index Identifies global Index of NetKey. A 12-bit value. + \param [in] opcode To identify Add or Update NetKey + \param [in] net_key Associated NetKey to be added/updated. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_add_update_netkey +( + /* IN */ UINT16 netkey_index, + /* IN */ UINT32 opcode, + /* IN */ UINT8* net_key +); + +/** + \brief To add Security Credential of a LPN or the Friend. + + \par Description + This routine adds NID, privacy and encryption keys associated with a friendship. + + \param [in] subnet_handle Identifies associated subnet. + \param [in] friend_offset Friend Offset. + \param [in] lpn_addr Address of the LPN. + \param [in] friend_addr Address of the Friend. + \param [in] lpn_counter Number of Friend Request messages the LPN has sent. + \param [in] friend_counter Number of Friend Offer messages the Friend has sent. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_add_friend_sec_credential +( + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ UINT16 friend_offset, + /* IN */ MS_NET_ADDR lpn_addr, + /* IN */ MS_NET_ADDR friend_addr, + /* IN */ UINT16 lpn_counter, + /* IN */ UINT16 friend_counter +); + +/** + \brief To delete the Security Credential of a LPN or the Friend. + + \par Description + This routine deletes NID, privacy and encryption keys associated with a friendship. + + \param [in] subnet_handle Identifies associated subnet. + \param [in] friend_index Friend Index. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_delete_friend_sec_credential +( + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ UINT16 friend_index +); + +/** + \brief To find a Subnet associated with the NetKey + + \par Description + This routine finds a Subnet based on the NetKey entry. Each NetKey is associated with a subnet. + + \param [in] netkey_index Identifies global Index of NetKey, corresponding Subnet to be returned. + \param [out] subnet_handle Memory location to be filled with Subnet Handle, if search is successful. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_find_subnet +( + /* IN */ UINT16 netkey_index, + /* OUT */ MS_SUBNET_HANDLE* subnet_handle +); + +/** + \brief To find the Master Subnet associated with the friend security credential, identified by Friend Subnet Handle. + + \par Description + This routine finds the Master Subnet based on the friend security credential, identified by Friend Subnet Handle. + + \param [out] friend_subnet_handle Idetifies the Friend Subnet Handle, corresponding to Friend Subnet Handle. + \param [in] master_subnet_handle Memory location to be filled with Master Subnet Handle, if search is successful. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_find_master_subnet +( + /* IN */ MS_SUBNET_HANDLE friend_subnet_handle, + /* OUT */ MS_SUBNET_HANDLE* master_subnet_handle +); + +/** + \brief To delete NetKey + + \par Description + This routine deletes a NetKey entry. Each NetKey is associated with a subnet. + + \param [in] subnet_handle Handle of the Subnet for which NetKey to be deleted. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_delete_netkey +( + /* IN */ MS_SUBNET_HANDLE subnet_handle +); + +/** + \brief To get NetKey + + \par Description + This routine fetches a NetKey entry. Each NetKey is associated with a subnet. + + \param [in] subnet_handle Handle of the Subnet for which NetKey to be deleted. + \param [out] net_key Netkey associated with the Subnet. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_netkey_at_offset +( + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ UINT8 offset, + /* OUT */ UINT8* net_key +); + + +/** + \brief To get list of all known NetKeys + + \par Description + This routine returns a list of known NetKey Indices. + + \param [inout] netkey_count Caller fills with maximum number of NetKey Indices + that can be stored in 'netkey_index_list'. + This function will update the value with how many NetKey + Indices has been filled. If the number of available + NetKey Indices is more than that can be returned, + maximum possible Indices will be filled and + an appropriate error values will inform the caller, + there are more NetKey Indices (as an information). + \param [out] netkey_index_list Memory to be filled with the available NetKey Indices. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_netkey_index_list +( + /* INOUT */ UINT16* netkey_count, + /* OUT */ UINT16* netkey_index_list +); + +/** + \brief To search for NID + + \par Description + This routine searches for matching NID in subnet table. + + \param [in] nid NID to be searched in all known subnets for match. + \param [inout] subnet_handle Same NID can match with multiple subnets. + Caller will fill this value to indicate from which + subnet handle the search to be started. This function + will return the subnet handle, where the match is found + (in case of match). Caller while searching for the same + NID, in the subsequent call can pass the subnet_handle + received in the previous match for the NID. + For the very first call when searching for a NID, + the caller need to use Invalid Subnet Handle + \ref MS_INVALID_SUBNET_HANDLE. + \param [out] privacy_key Privacy Key associated with the subnet. + \param [out] encrypt_key Encyption Key associated with the subnet. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_lookup_nid +( + /* IN */ UINT8 nid, + /* INOUT */ MS_SUBNET_HANDLE* subnet_handle, + /* OUT */ UINT8* privacy_key, + /* OUT */ UINT8* encrypt_key +); + + +/** + \brief To search for Network ID + + \par Description + This routine searches for matching Network ID in subnet table. + + \param [in] network_id Network ID to be searched in all known subnets for match. + \param [inout] subnet_handle Same NID can match with multiple subnets. + Caller will fill this value to indicate from which + subnet handle the search to be started. This function + will return the subnet handle, where the match is found + (in case of match). Caller while searching for the same + NID, in the subsequent call can pass the subnet_handle + received in the previous match for the NID. + For the very first call when searching for a NID, + the caller need to use Invalid Subnet Handle + \ref MS_INVALID_SUBNET_HANDLE. + \param [out] beacon_key Beacon Key associated with the subnet. + \param [out] is_new_key Flag to indicate if the network ID is associated with + the new Network Key being updated. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_lookup_network_id +( + /* IN */ UINT8* network_id, + /* INOUT */ MS_SUBNET_HANDLE* subnet_handle, + /* OUT */ UINT8* beacon_key, + /* OUT */ UINT8* is_new_key +); + +/** + \brief To search for AID + + \par Description + This routine searches for matching NID in subnet table. + + \param [in] aid AID to be searched in all known AppKeys for match. + \param [inout] appkey_handle Same AID can match with multiple AppKeys. + Caller will fill this value to indicate from which + AppKey handle the search to be started. This function + will return the AppKey handle, where the match is found + (in case of match). Caller while searching for the same + AID, in the subsequent call can pass the appkey_handle + received in the previous match for the AID. + For the very first call when searching for a AID, + the caller need to use Invalid Subnet Handle + \ref MS_INVALID_APPKEY_HANDLE. + \param [out] app_key AppKey associated with the AID. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_lookup_aid +( + /* IN */ UINT8 aid, + /* INOUT */ MS_APPKEY_HANDLE* appkey_handle, + /* OUT */ UINT8* app_key +); + +/** + \brief Set Provisioning Data + + \par Description + This routine configures the provisioning data with Access Layer. + + \param prov_data + Provisioning data received during provisioning procedure. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_set_prov_data +( + /* IN */ PROV_DATA_S* prov_data +); + +API_RESULT MS_access_cm_set_prov_data_provsioner +( + /* IN */ PROV_DATA_S* prov_data +); + + +/** + \brief To get NID associated with a subnet + + \par Description + This routine fetches the NID associated with a subnet. + + \param [in] handle Handle identifing the subnet. + \param [out] nid NID associated with the subnet. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_subnet_nid +( + /* IN */ MS_SUBNET_HANDLE handle, + /* OUT */ UINT8* nid +); + +/** + \brief To get Privacy Key associated with a subnet + + \par Description + This routine fetches the Privacy Key associated with a subnet. + + \param [in] handle Handle identifing the subnet. + \param [out] privacy_key Privacy Key associated with the subnet. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_subnet_privacy_key +( + /* IN */ MS_SUBNET_HANDLE handle, + /* OUT */ UINT8* privacy_key +); + +/** + \brief To get Network ID associated with a subnet + + \par Description + This routine fetches the Netowrk ID associated with a subnet. + + \param [in] handle Handle identifing the subnet. + \param [out] network_id Network ID associated with the subnet. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_subnet_network_id +( + /* IN */ MS_SUBNET_HANDLE handle, + /* OUT */ UINT8* network_id +); + + +/** + \brief To get Beacon Key associated with a subnet + + \par Description + This routine fetches the Beacon Key associated with a subnet. + + \param [in] handle Handle identifing the subnet. + \param [out] beacon_key Beacon Key associated with the subnet. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_subnet_beacon_key +( + /* IN */ MS_SUBNET_HANDLE handle, + /* OUT */ UINT8* beacon_key +); + +/** + \brief To get Identity Key associated with a subnet + + \par Description + This routine fetches the Identity Key associated with a subnet. + + \param [in] handle Handle identifing the subnet. + \param [out] identity_key Identity Key associated with the subnet. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_subnet_identity_key +( + /* IN */ MS_SUBNET_HANDLE handle, + /* OUT */ UINT8* identity_key +); + +/** + \brief To get Encryption Key associated with a subnet + + \par Description + This routine fetches the Encryption Key associated with a subnet. + + \param [in] handle Handle identifing the subnet. + \param [out] encrypt_key Encyption Key associated with the subnet. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_subnet_encryption_key +( + /* IN */ MS_SUBNET_HANDLE handle, + /* OUT */ UINT8* encrypt_key +); + +/** + \brief To get Node Identity + + \par Description + This routine gets Node Identity State of a node + + \param [in] subnet_handle Handle identifing the subnet. + \param [out] id_state Memory location where Node Identity state to be filled. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_node_identity +( + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* OUT */ UINT8* id_state +); + +/** + \brief To set Node Identity + + \par Description + This routine sets Node Identity State of a node + + \param [in] subnet_handle Handle identifing the subnet. + \param [in, out] id_state Node Identity state to be set. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_set_node_identity +( + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* INOUT */ UINT8* id_state +); + + +/** + \brief To get Key Refresh Phase + + \par Description + This routine gets Key Refresh Phase State of a node + + \param [in] subnet_handle Handle identifing the subnet. + \param [out] key_refresh_state Memory location where Key Refresh Phase state to be filled. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_key_refresh_phase +( + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* OUT */ UINT8* key_refresh_state +); + +/** + \brief To set Key Refresh Phase + + \par Description + This routine sets Key Refresh Phase State of a node + + \param [in] subnet_handle Handle identifing the subnet. + \param [in, out] key_refresh_state Key Refresh Phase state to be set. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_set_key_refresh_phase +( + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ UINT8* key_refresh_state +); + +/** + \brief To set Network/Relay Transmit state + + \par Description + This routine sets Network/Relay Transmit state. + + \param [in] tx_state_type Transmit State Type (Network or Relay) + \param [in] tx_state Composite state (3-bits of Tx Count and 5-bits of Tx Interval Steps) + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_set_transmit_state +( + /* IN */ UINT8 tx_state_type, + /* IN */ UINT8 tx_state +); + +/** + \brief To get Network/Relay Transmit state + + \par Description + This routine gets Network/Relay Transmit state. + + \param [in] tx_state_type Transmit State Type (Network or Relay) + \param [out] tx_state Memory location to fill Composite state + (3-bits of Tx Count and 5-bits of Tx Interval Steps) + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_transmit_state +( + /* IN */ UINT8 tx_state_type, + /* OUT */ UINT8* tx_state +); + +/** + \brief To add AppKey + + \par Description + This routine adds AppKey entry. Each AppKey is associated with a subnet. + + \param [in] subnet_handle Handle of the Subnet for which AppKey to be added. + \param [in] appkey_index Identifies global Index of AppKey. A 12-bit value. + \param [in] app_key Associated AppKey to be added. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_add_appkey +( + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ UINT16 appkey_index, + /* IN */ UINT8* app_key +); + +/** + \brief To update/delete AppKey + + \par Description + This routine updates/deletes AppKey entry. Each AppKey is associated with a subnet. + + \param [in] subnet_handle Handle of the Subnet for which AppKey to be updated/deleted. + \param [in] appkey_index Identifies global Index of AppKey. A 12-bit value. + \param [in] opcode To identify Delete or Update NetKey + \param [in] app_key Associated AppKey to be updated. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_update_delete_appkey +( + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ UINT16 appkey_index, + /* IN */ UINT32 opcode, + /* IN */ UINT8* app_key +); + +/** + \brief To update AppKey + + \par Description + This routine/macro updates AppKey entry. Each AppKey is associated with a subnet. + + \param [in] subnet_handle Handle of the Subnet for which AppKey to be updated. + \param [in] appkey_index Identifies global Index of AppKey. A 12-bit value. + \param [in] app_key Associated AppKey to be updated. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_access_cm_update_appkey(sn, aki, ak) \ + MS_access_cm_update_delete_appkey((sn), (aki), MS_ACCESS_CONFIG_APPKEY_UPDATE_OPCODE, (ak)) + +/** + \brief To delete AppKey + + \par Description + This routine/macro deletes AppKey entry. Each AppKey is associated with a subnet. + + \param [in] subnet_handle Handle of the Subnet for which AppKey to be deleted. + \param [in] appkey_index Identifies global Index of AppKey. A 12-bit value. + \param [in] app_key Associated AppKey to be updated. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_access_cm_delete_appkey(sn, aki, ak) \ + MS_access_cm_update_delete_appkey((sn), (aki), MS_ACCESS_CONFIG_APPKEY_DELETE_OPCODE, (ak)) + +/** + \brief To get AppKey Handle for a given AppKey Index + + \par Description + This routine gets AppKey Handle for a given AppKey Index. Each AppKey is associated with a subnet. + + \param [in] subnet_handle Handle of the Subnet for which AppKey to be updated. + \param [in] appkey_index Identifies global Index of AppKey. A 12-bit value. + \param [in] app_key Associated AppKey to be matched. + \param [out] appkey_handle Memory to hold the associated AppKey Handle. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_appkey_handle +( + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ UINT16 appkey_index, + /* IN */ UINT8* app_key, + /* OUT */ MS_APPKEY_HANDLE* appkey_handle +); + +/** + \brief To get list of all known AppKeys + + \par Description + This routine returns a list of known AppKey Indices associated with a subnet. + + \param [in] subnet_handle Handle of the Subnet for which AppKey to be returned. + \param [inout] appkey_count Caller fills with maximum number of AppKey Indices + that can be stored in 'apptkey_index_list'. + This function will update the value with how many AppKey + Indices has been filled. If the number of available + AppKey Indices is more than that can be returned, + maximum possible Indices will be filled and + an appropriate error values will inform the caller, + there are more NetKey Indices (as an information). + \param [out] appkey_index_list Memory to be filled with the available AppKey Indices. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_appkey_index_list +( + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* INOUT */ UINT16* appkey_count, + /* OUT */ UINT16* appkey_index_list +); + +/** + \brief To bind a model with an AppKey + + \par Description + This routine binds a model with an AppKey. + + \param [in] model_handle Model handle identifing the model. + \param [in] appkey_index Identifies global Index of AppKey. A 12-bit value. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_bind_model_app +( + /* IN */ MS_ACCESS_MODEL_HANDLE model_handle, + /* IN */ UINT16 appkey_index +); + +/** + \brief To unbind a model with an AppKey + + \par Description + This routine unbinds a model with an AppKey. + + \param [in] model_handle Model handle identifing the model. + \param [in] appkey_index Identifies global Index of AppKey. A 12-bit value. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_unbind_model_app +( + /* IN */ MS_ACCESS_MODEL_HANDLE model_handle, + /* IN */ UINT16 appkey_index +); + +/** + \brief To get list of all AppKeys associated with a model + + \par Description + This routine returns a list of known AppKey Indices associated with a model. + + \param [in] model_handle Handle of the Model for which AppKey to be returned. + \param [inout] appkey_count Caller fills with maximum number of AppKey Indices + that can be stored in 'apptkey_index_list'. + This function will update the value with how many AppKey + Indices has been filled. If the number of available + AppKey Indices is more than that can be returned, + maximum possible Indices will be filled and + an appropriate error values will inform the caller, + there are more NetKey Indices (as an information). + \param [out] appkey_index_list Memory to be filled with the available AppKey Indices. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_model_app_list +( + /* IN */ MS_ACCESS_MODEL_HANDLE model_handle, + /* INOUT */ UINT16* appkey_count, + /* OUT */ UINT16* appkey_index_list +); + +/** + \brief To set Publication information associated with a model + + \par Description + This routine sets Publication information associated with a model. + + \param [in] model_handle Handle of the Model for which Publication info to be set. + \param [inout] publish_info Publication Information to be set. + If Label UUID is used, on success corresponding + Virtual Address will be filled and returned. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_set_model_publication +( + /* IN */ MS_ACCESS_MODEL_HANDLE model_handle, + /* INOUT */ MS_ACCESS_PUBLISH_INFO* publish_info +); + +/** + \brief To set Publication Fast Period Divisor information associated with a model + + \par Description + This routine sets Publication Fast Period Divisor information associated with a model. + + \param [in] model_handle Handle of the Model for which Publication info to be set. + \param [in] period_divisor The value range for the Health Fast Period Divisor state is + 0 through 15, all other values are prohibited. + This is used to divide the Health Publish Period by 2^n, + where the n is the value of the Health Fast Period Divisor state. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_set_model_publication_period_divisor +( + /* IN */ MS_ACCESS_MODEL_HANDLE model_handle, + /* IN */ UINT8 period_divisor +); + +/** + \brief To get Publication information associated with a model + + \par Description + This routine returns Publication information associated with a model. + + \param [in] model_handle Handle of the Model for which Publication info to be returned. + \param [out] publish_info Memory to be filled with associated Publication info. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_model_publication +( + /* IN */ MS_ACCESS_MODEL_HANDLE model_handle, + /* OUT */ MS_ACCESS_PUBLISH_INFO* publish_info +); + +/** + \brief To add an address to a model subscription list + + \par Description + This routine adds an address to a subscription list of a model + + \param [in] model_handle Handle of the Model for which address to be added in the subscription list. + \param [in] sub_addr Address to be added in subscription list. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_add_model_subscription +( + /* IN */ MS_ACCESS_MODEL_HANDLE model_handle, + /* IN */ MS_ACCESS_ADDRESS* sub_addr +); + +/** + \brief To delete an address to a model subscription list + + \par Description + This routine deletes an address to a subscription list of a model + + \param [in] model_handle Handle of the Model for which address to be deleteed in the subscription list. + \param [in] sub_addr Address to be deleted from subscription list. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_delete_model_subscription +( + /* IN */ MS_ACCESS_MODEL_HANDLE model_handle, + /* IN */ MS_ACCESS_ADDRESS* sub_addr +); + +/** + \brief To discard a model subscription list + + \par Description + This routine discards a subscription list of a model + + \param [in] model_handle Handle of the Model for which the subscription list to be discarded. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_delete_all_model_subscription +( + /* IN */ MS_ACCESS_MODEL_HANDLE model_handle +); + +/** + \brief To get list of subscription addresses of a model + + \par Description + This routine returns a list of subscription addresses of a model. + + \param [in] model_handle Handle of the Model for which the subscription addresses to be returned. + \param [inout] sub_addr_count Caller fills with maximum number of subscription addresses + that can be stored in 'sub_addr_list'. + This function will update the value with how many subscription addresses + has been filled. If the number of available subscription addresses is more than that can be returned, + maximum possible addresses will be filled and an appropriate error values will inform the caller, + there are more subscription addresses (as an information). + \param [out] sub_addr_list Memory to be filled with the available subscription addresses. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_model_subscription_list +( + /* IN */ MS_ACCESS_MODEL_HANDLE model_handle, + /* INOUT */ UINT16* sub_addr_count, + /* OUT */ UINT16* sub_addr_list +); + +/** + \brief To get list of subscription addresses of all the models + + \par Description + This routine returns a consolidated list of subscription addresses of all the models. + + \param [inout] sub_addr_count Caller fills with maximum number of subscription addresses + that can be stored in 'sub_addr_list'. + This function will update the value with how many subscription addresses + has been filled. If the number of available subscription addresses is more than that can be returned, + maximum possible addresses will be filled and an appropriate error values will inform the caller, + there are more subscription addresses (as an information). + \param [out] sub_addr_list Memory to be filled with the available subscription addresses. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_cm_get_all_model_subscription_list +( + /* INOUT */ UINT16* sub_addr_count, + /* OUT */ UINT16* sub_addr_list +); + +/** + \brief To check if valid element address to receive a packet + + \par Description + This routine checks if destination address in a received packet matches + with any of the known element address of local or friend device. + + \param [in] addr Unicast Address to search + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_is_valid_element_address +( + /* IN */ MS_NET_ADDR addr +); + +/** + \brief To check if Fixed Group Address in receive packet to be processed + + \par Description + This routine checks if destination address in a received packet + as a Fixed Group Address to be processed. + + \param [in] addr A valid Fixed Group Address, to be checked + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_is_fixed_group_addr_to_be_processed +( + /* IN */ MS_NET_ADDR addr +); + +/** + \brief To check if valid subscription address to receive a packet + + \par Description + This routine checks if destination address in a received packet matches + with any of the known subscription address of local or friend device. + + \param [in] addr Address to search + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_access_is_valid_subscription_address +( + /* IN */ MS_NET_ADDR addr +); + +#ifdef MS_STORAGE +/** + \brief Get Core Modules storage handle and offset from persistent storage. + + \par Description + This function returns the storage handle and offset for Core Modules. + + \param [out] ps_handle Persistent Storage Handle. + \param [out] offset The memory to be filled with the storage offset information. +*/ +API_RESULT MS_access_ps_get_handle_and_offset +( + /* OUT */ NVSTO_HANDLE* ps_handle, + /* OUT */ UINT32* offset +); +#endif /* MS_STORAGE */ + +#ifdef __cplusplus +}; +#endif + +/** \} */ + +/** \} */ + +#endif /* _H_MS_ACCESS_API_ */ + diff --git a/src/components/ethermind/mesh/export/include/MS_assigned_numbers.h b/src/components/ethermind/mesh/export/include/MS_assigned_numbers.h new file mode 100644 index 0000000..64f2ad1 --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_assigned_numbers.h @@ -0,0 +1,810 @@ + +/** + \file MS_assigned_numbers.h + + This header file describes various definitions from + the Mesh Assigned Numbers Specification. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_ASSIGNED_NUMBERS_ +#define _H_MS_ASSIGNED_NUMBERS_ + +/* --------------------------------- Header File Inclusion */ + +/* --------------------------------- Global Definitions */ +/** Service UUIDs */ +/** Mesh Provisioning Service */ +#define MESH_PROVISIONING_SERVICE 0x1827 +/** Mesh Proxy Service */ +#define MESH_PROXY_SERVICE 0x1828 + +/** Characteristic UUIDs */ +#define MESH_CH_PROVISIONING_DATA_IN 0x2ADB +#define MESH_CH_PROVISIONING_DATA_OUT 0x2ADC +#define MESH_CH_PROXY_DATA_IN 0x2ADD +#define MESH_CH_PROXY_DATA_OUT 0x2ADE + +/** Advertising Type */ +#define MESH_AD_TYPE_PB_ADV 0x29 +#define MESH_AD_TYPE_PKT 0x2A +#define MESH_AD_TYPE_BCON 0x2B + +/** GATT PDU Types */ +#define MESH_GATT_TYPE_NETWORK 0x00 +#define MESH_GATT_TYPE_BEACON 0x01 +#define MESH_GATT_TYPE_PROXY 0x02 +#define MESH_GATT_TYPE_PROV 0x03 + +/** GATT Segmentation & Reassembly (SAR) constants */ +#define MESH_GATT_SAR_COMPLETE 0x00 +#define MESH_GATT_SAR_START 0x01 +#define MESH_GATT_SAR_CONTINUE 0x02 +#define MESH_GATT_SAR_END 0x03 + +/** Model type definitions */ +#define MS_ACCESS_MODEL_TYPE_SIG 0x00 +#define MS_ACCESS_MODEL_TYPE_VENDOR 0x01 + +/** Mesh Nonce Types */ +#define MS_NONCE_T_NETWORK 0x00 +#define MS_NONCE_T_APPLICATION 0x01 +#define MS_NONCE_T_DEVICE 0x02 +#define MS_NONCE_T_PROXY 0x03 + +/** Opcode definitions for the Foundation Model */ + +/** 8-bit Opcodes of Model specific messages */ +#define MS_ACCESS_CONFIG_APPKEY_ADD_OPCODE 0x00 +#define MS_ACCESS_CONFIG_APPKEY_UPDATE_OPCODE 0x01 +#define MS_ACCESS_CONFIG_COMPOSITION_DATA_STATUS_OPCODE 0x02 +#define MS_ACCESS_CONFIG_MODEL_PUBLICATION_SET_OPCODE 0x03 +#define MS_ACCESS_HEALTH_CURRENT_STATUS_OPCODE 0x04 +#define MS_ACCESS_HEALTH_FAULT_STATUS_OPCODE 0x05 +#define MS_ACCESS_CONFIG_HEARTBEAT_PUBLICATION_STATUS_OPCODE 0x06 + +/** 16-bit Opcodes of Model specific messages */ +/** Config AppKey Delete Opcode */ +#define MS_ACCESS_CONFIG_APPKEY_DELETE_OPCODE 0x8000 +/** Config AppKey Get Opcode */ +#define MS_ACCESS_CONFIG_APPKEY_GET_OPCODE 0x8001 +/** Config AppKey List Opcode */ +#define MS_ACCESS_CONFIG_APPKEY_LIST_OPCODE 0x8002 +/** Config AppKey Status Opcode */ +#define MS_ACCESS_CONFIG_APPKEY_STATUS_OPCODE 0x8003 +/** Health Attention Get Opcode */ +#define MS_ACCESS_HEALTH_ATTENTION_GET_OPCODE 0x8004 +/** Health Attention Set Opcode */ +#define MS_ACCESS_HEALTH_ATTENTION_SET_OPCODE 0x8005 +/** Health Attention Set Unacknowledged Opcode */ +#define MS_ACCESS_HEALTH_ATTENTION_SET_UNACKNOWLEDGED_OPCODE 0x8006 +/** Health Attention Status Opcode */ +#define MS_ACCESS_HEALTH_ATTENTION_STATUS_OPCODE 0x8007 +/** Config Composition Data Get Opcode */ +#define MS_ACCESS_CONFIG_COMPOSITION_DATA_GET_OPCODE 0x8008 +/** Config Beacon Get Opcode */ +#define MS_ACCESS_CONFIG_BEACON_GET_OPCODE 0x8009 +/** Config Beacon Set Opcode */ +#define MS_ACCESS_CONFIG_BEACON_SET_OPCODE 0x800A +/** Config Beacon Status Opcode */ +#define MS_ACCESS_CONFIG_BEACON_STATUS_OPCODE 0x800B +/** Config Deafault TTL Get Opcode */ +#define MS_ACCESS_CONFIG_DEFAULT_TTL_GET_OPCODE 0x800C +/** Config Deafault TTL Set Opcode */ +#define MS_ACCESS_CONFIG_DEFAULT_TTL_SET_OPCODE 0x800D +/** Config Deafault TTL Status Opcode */ +#define MS_ACCESS_CONFIG_DEFAULT_TTL_STATUS_OPCODE 0x800E +/** Config Friend Get Opcode */ +#define MS_ACCESS_CONFIG_FRIEND_GET_OPCODE 0x800F +/** Config Friend Set Opcode */ +#define MS_ACCESS_CONFIG_FRIEND_SET_OPCODE 0x8010 +/** Config Friend Status Opcode */ +#define MS_ACCESS_CONFIG_FRIEND_STATUS_OPCODE 0x8011 +/** Config GATT Proxy Get Opcode */ +#define MS_ACCESS_CONFIG_GATT_PROXY_GET_OPCODE 0x8012 +/** Config GATT Proxy Set Opcode */ +#define MS_ACCESS_CONFIG_GATT_PROXY_SET_OPCODE 0x8013 +/** Config GATT Proxy Status Opcode */ +#define MS_ACCESS_CONFIG_GATT_PROXY_STATUS_OPCODE 0x8014 +/** Config Key Refresh Phase Get Opcode */ +#define MS_ACCESS_CONFIG_KEY_REFRESH_PHASE_GET_OPCODE 0x8015 +/** Config Key Refresh Phase Set Opcode */ +#define MS_ACCESS_CONFIG_KEY_REFRESH_PHASE_SET_OPCODE 0x8016 +/** Config Key Refresh Phase Status Opcode */ +#define MS_ACCESS_CONFIG_KEY_REFRESH_PHASE_STATUS_OPCODE 0x8017 +/** Config Model Publication Get Opcode */ +#define MS_ACCESS_CONFIG_MODEL_PUBLICATION_GET_OPCODE 0x8018 +/** Config Model Publication Status Opcode */ +#define MS_ACCESS_CONFIG_MODEL_PUBLICATION_STATUS_OPCODE 0x8019 +/** Config Model Publication Virtual Address Set Opcode */ +#define MS_ACCESS_CONFIG_MODEL_PUBLICATION_VIRTUAL_ADDRESS_SET_OPCODE 0x801A +/** Config Model Subscription Add Opcode */ +#define MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_ADD_OPCODE 0x801B +/** Config Model Subscription Delete Opcode */ +#define MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_DELETE_OPCODE 0x801C +/** Config Model Subscription Delete All Opcode */ +#define MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_DELETE_ALL_OPCODE 0x801D +/** Config Model Subscription Overwrite Opcode */ +#define MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_OVERWRITE_OPCODE 0x801E +/** Config Model Subscription Status Opcode */ +#define MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_STATUS_OPCODE 0x801F +/** Config Model Subscription Virtual Address Add Opcode */ +#define MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_ADD_OPCODE 0x8020 +/** Config Model Subscription Virtual Address Delete Opcode */ +#define MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_DELETE_OPCODE 0x8021 +/** Config Model Subscription Virtual Address Overwrite Opcode */ +#define MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_OVERWRITE_OPCODE 0x8022 +/** Config Network Transmit Get Opcode */ +#define MS_ACCESS_CONFIG_NETWORK_TRANSMIT_GET_OPCODE 0x8023 +/** Config Network Transmit Set Opcode */ +#define MS_ACCESS_CONFIG_NETWORK_TRANSMIT_SET_OPCODE 0x8024 +/** Config Network Transmit Status Opcode */ +#define MS_ACCESS_CONFIG_NETWORK_TRANSMIT_STATUS_OPCODE 0x8025 +/** Config Relay Get Opcode */ +#define MS_ACCESS_CONFIG_RELAY_GET_OPCODE 0x8026 +/** Config Relay Set Opcode */ +#define MS_ACCESS_CONFIG_RELAY_SET_OPCODE 0x8027 +/** Config Relay Status Opcode */ +#define MS_ACCESS_CONFIG_RELAY_STATUS_OPCODE 0x8028 +/** Config SIG Model Subscription Get Opcode */ +#define MS_ACCESS_CONFIG_SIG_MODEL_SUBSCRIPTION_GET_OPCODE 0x8029 +/** Config SIG Model Subscription List Opcode */ +#define MS_ACCESS_CONFIG_SIG_MODEL_SUBSCRIPTION_LIST_OPCODE 0x802A +/** Config Vendor Model Subscription Get Opcode */ +#define MS_ACCESS_CONFIG_VENDOR_MODEL_SUBSCRIPTION_GET_OPCODE 0x802B +/** Config Vendor Model Subscription List Opcode */ +#define MS_ACCESS_CONFIG_VENDOR_MODEL_SUBSCRIPTION_LIST_OPCODE 0x802C +/** Config Low Power Node PollTimeout Get Opcode */ +#define MS_ACCESS_CONFIG_LOW_POWER_NODE_POLLTIMEOUT_GET_OPCODE 0x802D +/** Config Low Power Node PollTimeout Status Opcode */ +#define MS_ACCESS_CONFIG_LOW_POWER_NODE_POLLTIMEOUT_STATUS_OPCODE 0x802E +/** Health Fault Clear Opcode */ +#define MS_ACCESS_HEALTH_FAULT_CLEAR_OPCODE 0x802F +/** Health Fault Clear Unacknowledged Opcode */ +#define MS_ACCESS_HEALTH_FAULT_CLEAR_UNACKNOWLEDGED_OPCODE 0x8030 +/** Health Fault Get Opcode */ +#define MS_ACCESS_HEALTH_FAULT_GET_OPCODE 0x8031 +/** Health Fault Test Opcode */ +#define MS_ACCESS_HEALTH_FAULT_TEST_OPCODE 0x8032 +/** Health Fault Test Unacknowledged Opcode */ +#define MS_ACCESS_HEALTH_FAULT_TEST_UNACKNOWLEDGED_OPCODE 0x8033 +/** Health Period Get Opcode */ +#define MS_ACCESS_HEALTH_PERIOD_GET_OPCODE 0x8034 +/** Health Period Set Opcode */ +#define MS_ACCESS_HEALTH_PERIOD_SET_OPCODE 0x8035 +/** Health Period Set Unacknowledged Opcode */ +#define MS_ACCESS_HEALTH_PERIOD_SET_UNACKNOWLEDGED_OPCODE 0x8036 +/** Health Period Status Opcode */ +#define MS_ACCESS_HEALTH_PERIOD_STATUS_OPCODE 0x8037 +/** Config Heartbeat Publication Get Opcode */ +#define MS_ACCESS_CONFIG_HEARTBEAT_PUBLICATION_GET_OPCODE 0x8038 +/** Config Heartbeat Publication Set Opcode */ +#define MS_ACCESS_CONFIG_HEARTBEAT_PUBLICATION_SET_OPCODE 0x8039 +/** Config Heartbeat Subscription Get Opcode */ +#define MS_ACCESS_CONFIG_HEARTBEAT_SUBSCRIPTION_GET_OPCODE 0x803A +/** Config Heartbeat Subscription Set Opcode */ +#define MS_ACCESS_CONFIG_HEARTBEAT_SUBSCRIPTION_SET_OPCODE 0x803B +/** Config Heartbeat Subscription Status Opcode */ +#define MS_ACCESS_CONFIG_HEARTBEAT_SUBSCRIPTION_STATUS_OPCODE 0x803C +/** Config Model App Bind Opcode */ +#define MS_ACCESS_CONFIG_MODEL_APP_BIND_OPCODE 0x803D +/** Config Model App Status Opcode */ +#define MS_ACCESS_CONFIG_MODEL_APP_STATUS_OPCODE 0x803E +/** Config Model App Unbind Opcode */ +#define MS_ACCESS_CONFIG_MODEL_APP_UNBIND_OPCODE 0x803F +/** Config NetKey Add Opcode */ +#define MS_ACCESS_CONFIG_NETKEY_ADD_OPCODE 0x8040 +/** Config NetKey Delete Opcode */ +#define MS_ACCESS_CONFIG_NETKEY_DELETE_OPCODE 0x8041 +/** Config NetKey Get Opcode */ +#define MS_ACCESS_CONFIG_NETKEY_GET_OPCODE 0x8042 +/** Config NetKey List Opcode */ +#define MS_ACCESS_CONFIG_NETKEY_LIST_OPCODE 0x8043 +/** Config NetKey Status Opcode */ +#define MS_ACCESS_CONFIG_NETKEY_STATUS_OPCODE 0x8044 +/** Config NetKey Update Opcode */ +#define MS_ACCESS_CONFIG_NETKEY_UPDATE_OPCODE 0x8045 +/** Config Node Identity Get Opcode */ +#define MS_ACCESS_CONFIG_NODE_IDENTITY_GET_OPCODE 0x8046 +/** Config Node Identity Set Opcode */ +#define MS_ACCESS_CONFIG_NODE_IDENTITY_SET_OPCODE 0x8047 +/** Config Node Identity Status Opcode */ +#define MS_ACCESS_CONFIG_NODE_IDENTITY_STATUS_OPCODE 0x8048 +/** Config Node Reset Opcode */ +#define MS_ACCESS_CONFIG_NODE_RESET_OPCODE 0x8049 +/** Config Node Reset Status Opcode */ +#define MS_ACCESS_CONFIG_NODE_RESET_STATUS_OPCODE 0x804A +/** Config SIG Model App Get Opcode */ +#define MS_ACCESS_CONFIG_SIG_MODEL_APP_GET_OPCODE 0x804B +/** Config SIG Model App List Opcode */ +#define MS_ACCESS_CONFIG_SIG_MODEL_APP_LIST_OPCODE 0x804C +/** Config Vendor Model App Get Opcode */ +#define MS_ACCESS_CONFIG_VENDOR_MODEL_APP_GET_OPCODE 0x804D +/** Config Vendor Model App List Opcode */ +#define MS_ACCESS_CONFIG_VENDOR_MODEL_APP_LIST_OPCODE 0x804E + +/** Generic OnOff */ +/** Generic OnOff Get Opcode */ +#define MS_ACCESS_GENERIC_ONOFF_GET_OPCODE 0x8201 +/** Generic OnOff Set Opcode */ +#define MS_ACCESS_GENERIC_ONOFF_SET_OPCODE 0x8202 +/** Generic OnOff Set Unacknowledged Opcode */ +#define MS_ACCESS_GENERIC_ONOFF_SET_UNACKNOWLEDGED_OPCODE 0x8203 +/** Generic OnOff Status Opcode */ +#define MS_ACCESS_GENERIC_ONOFF_STATUS_OPCODE 0x8204 + +/** Generic Level */ +/** Generic Level Get Opcode */ +#define MS_ACCESS_GENERIC_LEVEL_GET_OPCODE 0x8205 +/** Generic Level Set Opcode */ +#define MS_ACCESS_GENERIC_LEVEL_SET_OPCODE 0x8206 +/** Generic Level Set Unacknowledged Opcode */ +#define MS_ACCESS_GENERIC_LEVEL_SET_UNACKNOWLEDGED_OPCODE 0x8207 +/** Generic Level Status Opcode */ +#define MS_ACCESS_GENERIC_LEVEL_STATUS_OPCODE 0x8208 +/** Generic Delta Set Opcode */ +#define MS_ACCESS_GENERIC_DELTA_SET_OPCODE 0x8209 +/** Generic Delta Set Unacknowledged Opcode */ +#define MS_ACCESS_GENERIC_DELTA_SET_UNACKNOWLEDGED_OPCODE 0x820A +/** Generic Move Set Opcode */ +#define MS_ACCESS_GENERIC_MOVE_SET_OPCODE 0x820B +/** Generic Move Set Unacknowledged Opcode */ +#define MS_ACCESS_GENERIC_MOVE_SET_UNACKNOWLEDGED_OPCODE 0x820C + +/** Generic Default Transition Time */ +/** Generic Default Transition Time Get Opcode */ +#define MS_ACCESS_GENERIC_DEFAULT_TRANSITION_TIME_GET_OPCODE 0x820D +/** Generic Default Transition Time Set Opcode */ +#define MS_ACCESS_GENERIC_DEFAULT_TRANSITION_TIME_SET_OPCODE 0x820E +/** Generic Default Transition Time Set Unacknowledged Opcode */ +#define MS_ACCESS_GENERIC_DEFAULT_TRANSITION_TIME_SET_UNACKNOWLEDGED_OPCODE 0x820F +/** Generic Default Transition Time Status Opcode */ +#define MS_ACCESS_GENERIC_DEFAULT_TRANSITION_TIME_STATUS_OPCODE 0x8210 + +/** Generic Power OnOff */ +/** Generic Power OnOff Get Opcode */ +#define MS_ACCESS_GENERIC_ONPOWERUP_GET_OPCODE 0x8211 +/** Generic Power OnOff Status Opcode */ +#define MS_ACCESS_GENERIC_ONPOWERUP_STATUS_OPCODE 0x8212 + +/** Generic Power OnOff Setup */ +/** Generic Power OnOff Setup Set Opcode */ +#define MS_ACCESS_GENERIC_ONPOWERUP_SET_OPCODE 0x8213 +/** Generic Power OnOff Setup Set Unacknowledged Opcode */ +#define MS_ACCESS_GENERIC_ONPOWERUP_SET_UNACKNOWLEDGED_OPCODE 0x8214 + +/** Generic Power Level */ +/** Generic Power Level Get Opcode */ +#define MS_ACCESS_GENERIC_POWER_LEVEL_GET_OPCODE 0x8215 +/** Generic Power Level Set Opcode */ +#define MS_ACCESS_GENERIC_POWER_LEVEL_SET_OPCODE 0x8216 +/** Generic Power Level Set Unacknowledged Opcode */ +#define MS_ACCESS_GENERIC_POWER_LEVEL_SET_UNACKNOWLEDGED_OPCODE 0x8217 +/** Generic Power Level Status Opcode */ +#define MS_ACCESS_GENERIC_POWER_LEVEL_STATUS_OPCODE 0x8218 +/** Generic Power Last Get Opcode */ +#define MS_ACCESS_GENERIC_POWER_LAST_GET_OPCODE 0x8219 +/** Generic Power Last Status Opcode */ +#define MS_ACCESS_GENERIC_POWER_LAST_STATUS_OPCODE 0x821A +/** Generic Power Default Get Opcode */ +#define MS_ACCESS_GENERIC_POWER_DEFAULT_GET_OPCODE 0x821B +/** Generic Power Default Status Opcode */ +#define MS_ACCESS_GENERIC_POWER_DEFAULT_STATUS_OPCODE 0x821C +/** Generic Power Range Get Opcode */ +#define MS_ACCESS_GENERIC_POWER_RANGE_GET_OPCODE 0x821D +/** Generic Power Range Status Opcode */ +#define MS_ACCESS_GENERIC_POWER_RANGE_STATUS_OPCODE 0x821E + +/** Generic Power Level Setup */ +/** Generic Power Default Set Opcode */ +#define MS_ACCESS_GENERIC_POWER_DEFAULT_SET_OPCODE 0x821F +/** Generic Power Default Set Unacknowledged Opcode */ +#define MS_ACCESS_GENERIC_POWER_DEFAULT_SET_UNACKNOWLEDGED_OPCODE 0x8220 +/** Generic Power Range Set Opcode */ +#define MS_ACCESS_GENERIC_POWER_RANGE_SET_OPCODE 0x8221 +/** Generic Power Range Set Unacknowledged Opcode */ +#define MS_ACCESS_GENERIC_POWER_RANGE_SET_UNACKNOWLEDGED_OPCODE 0x8222 + +/** Generic Battery */ +/** Generic Battery Get Opcode */ +#define MS_ACCESS_GENERIC_BATTERY_GET_OPCODE 0x8223 +/** Generic Battery Status Opcode */ +#define MS_ACCESS_GENERIC_BATTERY_STATUS_OPCODE 0x8224 + +/** Generic Location */ +/** Generic Location Global Get Opcode */ +#define MS_ACCESS_GENERIC_LOCATION_GLOBAL_GET_OPCODE 0x8225 +/** Generic Location Global Status Opcode */ +#define MS_ACCESS_GENERIC_LOCATION_GLOBAL_STATUS_OPCODE 0x40 +/** Generic Location Local Get Opcode */ +#define MS_ACCESS_GENERIC_LOCATION_LOCAL_GET_OPCODE 0x8226 +/** Generic Location Local Status Opcode */ +#define MS_ACCESS_GENERIC_LOCATION_LOCAL_STATUS_OPCODE 0x8227 + +/** Generic Location Setup */ +/** Generic Location Global Set Opcode */ +#define MS_ACCESS_GENERIC_LOCATION_GLOBAL_SET_OPCODE 0x41 +/** Generic Location Global Set Unacknowledged Opcode */ +#define MS_ACCESS_GENERIC_LOCATION_GLOBAL_SET_UNACKNOWLEDGED_OPCODE 0x42 +/** Generic Location Local Set Opcode */ +#define MS_ACCESS_GENERIC_LOCATION_LOCAL_SET_OPCODE 0x8228 +/** Generic Location Local Set Unacknowledged Opcode */ +#define MS_ACCESS_GENERIC_LOCATION_LOCAL_SET_UNACKNOWLEDGED_OPCODE 0x8229 + +/** Generic Manufacturer Property */ +/** Generic Manufacturer Properties Get Opcode */ +#define MS_ACCESS_GENERIC_MANUFACTURER_PROPERTIES_GET_OPCODE 0x822A +/** Generic Manufacturer Properties Status Opcode */ +#define MS_ACCESS_GENERIC_MANUFACTURER_PROPERTIES_STATUS_OPCODE 0x43 +/** Generic Manufacturer Property Get Opcode */ +#define MS_ACCESS_GENERIC_MANUFACTURER_PROPERTY_GET_OPCODE 0x822B +/** Generic Manufacturer Property Set Opcode */ +#define MS_ACCESS_GENERIC_MANUFACTURER_PROPERTY_SET_OPCODE 0x44 +/** Generic Manufacturer Property Set Unacknowledged Opcode */ +#define MS_ACCESS_GENERIC_MANUFACTURER_PROPERTY_SET_UNACKNOWLEDGED_OPCODE 0x45 +/** Generic Manufacturer Property Status Opcode */ +#define MS_ACCESS_GENERIC_MANUFACTURER_PROPERTY_STATUS_OPCODE 0x46 + +/** Generic Admin Property */ +/** Generic Admin Properties Get Opcode */ +#define MS_ACCESS_GENERIC_ADMIN_PROPERTIES_GET_OPCODE 0x822C +/** Generic Admin Properties Status Opcode */ +#define MS_ACCESS_GENERIC_ADMIN_PROPERTIES_STATUS_OPCODE 0x47 +/** Generic Admin Property Get Opcode */ +#define MS_ACCESS_GENERIC_ADMIN_PROPERTY_GET_OPCODE 0x822D +/** Generic Admin Property Set Opcode */ +#define MS_ACCESS_GENERIC_ADMIN_PROPERTY_SET_OPCODE 0x48 +/** Generic Admin Property Set Unacknowledged Opcode */ +#define MS_ACCESS_GENERIC_ADMIN_PROPERTY_SET_UNACKNOWLEDGED_OPCODE 0x49 +/** Generic Admin Property Status Opcode */ +#define MS_ACCESS_GENERIC_ADMIN_PROPERTY_STATUS_OPCODE 0x4A + +/** Generic User Property */ +/** Generic User Properties Get Opcode */ +#define MS_ACCESS_GENERIC_USER_PROPERTIES_GET_OPCODE 0x822E +/** Generic User Properties Status Opcode */ +#define MS_ACCESS_GENERIC_USER_PROPERTIES_STATUS_OPCODE 0x4B +/** Generic User Property Get Opcode */ +#define MS_ACCESS_GENERIC_USER_PROPERTY_GET_OPCODE 0x822F +/** Generic User Property Set Opcode */ +#define MS_ACCESS_GENERIC_USER_PROPERTY_SET_OPCODE 0x4C +/** Generic User Property Set Unacknowledged Opcode */ +#define MS_ACCESS_GENERIC_USER_PROPERTY_SET_UNACKNOWLEDGED_OPCODE 0x4D +/** Generic User Property Status Opcode */ +#define MS_ACCESS_GENERIC_USER_PROPERTY_STATUS_OPCODE 0x4E + +/** Generic Client Property */ +/** Generic Client Properties Get Opcode */ +#define MS_ACCESS_GENERIC_CLIENT_PROPERTIES_GET_OPCODE 0x4F +/** Generic Client Properties Status Opcode */ +#define MS_ACCESS_GENERIC_CLIENT_PROPERTIES_STATUS_OPCODE 0x50 + +/** Sensor */ +/** Sensor Descriptor Get Opcode */ +#define MS_ACCESS_SENSOR_DESCRIPTOR_GET_OPCODE 0x8230 +/** Sensor Descriptor Status Opcode */ +#define MS_ACCESS_SENSOR_DESCRIPTOR_STATUS_OPCODE 0x51 +/** Sensor Get Opcode */ +#define MS_ACCESS_SENSOR_GET_OPCODE 0x8231 +/** Sensor Status Opcode */ +#define MS_ACCESS_SENSOR_STATUS_OPCODE 0x52 +/** Sensor Column Get Opcode */ +#define MS_ACCESS_SENSOR_COLUMN_GET_OPCODE 0x8232 +/** Sensor Column Status Opcode */ +#define MS_ACCESS_SENSOR_COLUMN_STATUS_OPCODE 0x53 +/** Sensor Series Get Opcode */ +#define MS_ACCESS_SENSOR_SERIES_GET_OPCODE 0x8233 +/** Sensor Series Status Opcode */ +#define MS_ACCESS_SENSOR_SERIES_STATUS_OPCODE 0x54 + +/** Sensor Setup */ +/** Sensor Cadence Get Opcode */ +#define MS_ACCESS_SENSOR_CADENCE_GET_OPCODE 0x8234 +/** Sensor Cadence Set Opcode */ +#define MS_ACCESS_SENSOR_CADENCE_SET_OPCODE 0x55 +/** Sensor Cadence Set Unacknowledged Opcode */ +#define MS_ACCESS_SENSOR_CADENCE_SET_UNACKNOWLEDGED_OPCODE 0x56 +/** Sensor Cadence Status Opcode */ +#define MS_ACCESS_SENSOR_CADENCE_STATUS_OPCODE 0x57 +/** Sensor Settings Get Opcode */ +#define MS_ACCESS_SENSOR_SETTINGS_GET_OPCODE 0x8235 +/** Sensor Settings Status Opcode */ +#define MS_ACCESS_SENSOR_SETTINGS_STATUS_OPCODE 0x58 +/** Sensor Setting Get Opcode */ +#define MS_ACCESS_SENSOR_SETTING_GET_OPCODE 0x8236 +/** Sensor Setting Set Opcode */ +#define MS_ACCESS_SENSOR_SETTING_SET_OPCODE 0x59 +/** Sensor Setting Set Unacknowledged Opcode */ +#define MS_ACCESS_SENSOR_SETTING_SET_UNACKNOWLEDGED_OPCODE 0x5A +/** Sensor Setting Status Opcode */ +#define MS_ACCESS_SENSOR_SETTING_STATUS_OPCODE 0x5B + +/** Time */ +/** Time Get Opcode */ +#define MS_ACCESS_TIME_GET_OPCODE 0x8237 +/** Time Set Opcode */ +#define MS_ACCESS_TIME_SET_OPCODE 0x5C +/** Time Status Opcode */ +#define MS_ACCESS_TIME_STATUS_OPCODE 0x5D +/** Time Role Get Opcode */ +#define MS_ACCESS_TIME_ROLE_GET_OPCODE 0x8238 +/** Time Role Set Opcode */ +#define MS_ACCESS_TIME_ROLE_SET_OPCODE 0x8239 +/** Time Role Status Opcode */ +#define MS_ACCESS_TIME_ROLE_STATUS_OPCODE 0x823A +/** Time Zone Get Opcode */ +#define MS_ACCESS_TIME_ZONE_GET_OPCODE 0x823B +/** Time Zone Set Opcode */ +#define MS_ACCESS_TIME_ZONE_SET_OPCODE 0x823C +/** Time Zone Status Opcode */ +#define MS_ACCESS_TIME_ZONE_STATUS_OPCODE 0x823D +/** Time - TAI UTC Delta Get Opcode */ +#define MS_ACCESS_TAI_UTC_DELTA_GET_OPCODE 0x823E +/** Time - TAI UTC Delta Set Opcode */ +#define MS_ACCESS_TAI_UTC_DELTA_SET_OPCODE 0x823F +/** Time - TAI UTC Delta Status Opcode */ +#define MS_ACCESS_TAI_UTC_DELTA_STATUS_OPCODE 0x8240 + +/** Scene */ +/** Scene Get Opcode */ +#define MS_ACCESS_SCENE_GET_OPCODE 0x8241 +/** Scene Recall Opcode */ +#define MS_ACCESS_SCENE_RECALL_OPCODE 0x8242 +/** Scene Recall Unacknowledged Opcode */ +#define MS_ACCESS_SCENE_RECALL_UNACKNOWLEDGED_OPCODE 0x8243 +/** Scene Status Opcode */ +#define MS_ACCESS_SCENE_STATUS_OPCODE 0x5E +/** Scene Register Get Opcode */ +#define MS_ACCESS_SCENE_REGISTER_GET_OPCODE 0x8244 +/** Scene Register Status Opcode */ +#define MS_ACCESS_SCENE_REGISTER_STATUS_OPCODE 0x8245 + +/** Scene Setup */ +/** Scene Store Opcode */ +#define MS_ACCESS_SCENE_STORE_OPCODE 0x8246 +/** Scene Store Unacknowledged Opcode */ +#define MS_ACCESS_SCENE_STORE_UNACKNOWLEDGED_OPCODE 0x8247 +/** Scene Delete Opcode */ +#define MS_ACCESS_SCENE_DELETE_OPCODE 0x829E +/** Scene Delete Unacknowledged Opcode */ +#define MS_ACCESS_SCENE_DELETE_UNACKNOWLEDGED_OPCODE 0x829F + +/** Scheduler */ +/** Scheduler Action Get Opcode */ +#define MS_ACCESS_SCHEDULER_ACTION_GET_OPCODE 0x8248 +/** Scheduler Action Status Opcode */ +#define MS_ACCESS_SCHEDULER_ACTION_STATUS_OPCODE 0x5F +/** Scheduler Get Opcode */ +#define MS_ACCESS_SCHEDULER_GET_OPCODE 0x8249 +/** Scheduler Status Opcode */ +#define MS_ACCESS_SCHEDULER_STATUS_OPCODE 0x824A + +/** Scheduler Setup */ +/** Scheduler Action Set Opcode */ +#define MS_ACCESS_SCHEDULER_ACTION_SET_OPCODE 0x60 +/** Scheduler Action Set Unacknowledged Opcode */ +#define MS_ACCESS_SCHEDULER_ACTION_SET_UNACKNOWLEDGED_OPCODE 0x61 + +/** Light Lightness */ +/** Light Lightness Get Opcode */ +#define MS_ACCESS_LIGHT_LIGHTNESS_GET_OPCODE 0x824B +/** Light Lightness Set Opcode */ +#define MS_ACCESS_LIGHT_LIGHTNESS_SET_OPCODE 0x824C +/** Light Lightness Set Unacknowledged Opcode */ +#define MS_ACCESS_LIGHT_LIGHTNESS_SET_UNACKNOWLEDGED_OPCODE 0x824D +/** Light Lightness Status Opcode */ +#define MS_ACCESS_LIGHT_LIGHTNESS_STATUS_OPCODE 0x824E +/** Light Lightness Linear Get Opcode */ +#define MS_ACCESS_LIGHT_LIGHTNESS_LINEAR_GET_OPCODE 0x824F +/** Light Lightness Linear Set Opcode */ +#define MS_ACCESS_LIGHT_LIGHTNESS_LINEAR_SET_OPCODE 0x8250 +/** Light Lightness Linear Set Unacknowledged Opcode */ +#define MS_ACCESS_LIGHT_LIGHTNESS_LINEAR_SET_UNACKNOWLEDGED_OPCODE 0x8251 +/** Light Lightness Linear Status Opcode */ +#define MS_ACCESS_LIGHT_LIGHTNESS_LINEAR_STATUS_OPCODE 0x8252 +/** Light Lightness Last Get Opcode */ +#define MS_ACCESS_LIGHT_LIGHTNESS_LAST_GET_OPCODE 0x8253 +/** Light Lightness Last Status Opcode */ +#define MS_ACCESS_LIGHT_LIGHTNESS_LAST_STATUS_OPCODE 0x8254 +/** Light Lightness Default Get Opcode */ +#define MS_ACCESS_LIGHT_LIGHTNESS_DEFAULT_GET_OPCODE 0x8255 +/** Light Lightness Default Status Opcode */ +#define MS_ACCESS_LIGHT_LIGHTNESS_DEFAULT_STATUS_OPCODE 0x8256 +/** Light Lightness Range Get Opcode */ +#define MS_ACCESS_LIGHT_LIGHTNESS_RANGE_GET_OPCODE 0x8257 +/** Light Lightness Range Status Opcode */ +#define MS_ACCESS_LIGHT_LIGHTNESS_RANGE_STATUS_OPCODE 0x8258 + +/** Light Lightness Setup */ +/** Light Lightness Range Set Opcode */ +#define MS_ACCESS_LIGHT_LIGHTNESS_DEFAULT_SET_OPCODE 0x8259 +/** Light Lightness Range Set Unacknowledged Opcode */ +#define MS_ACCESS_LIGHT_LIGHTNESS_DEFAULT_SET_UNACKNOWLEDGED_OPCODE 0x825A +/** Light Lightness Range Set Opcode */ +#define MS_ACCESS_LIGHT_LIGHTNESS_RANGE_SET_OPCODE 0x825B +/** Light Lightness Range Set Unacknowledged Opcode */ +#define MS_ACCESS_LIGHT_LIGHTNESS_RANGE_SET_UNACKNOWLEDGED_OPCODE 0x825C + +/** Light CTL */ +/** Light CTL Get Opcode */ +#define MS_ACCESS_LIGHT_CTL_GET_OPCODE 0x825D +/** Light CTL Set Opcode */ +#define MS_ACCESS_LIGHT_CTL_SET_OPCODE 0x825E +/** Light CTL Set Unacknowledged Opcode */ +#define MS_ACCESS_LIGHT_CTL_SET_UNACKNOWLEDGED_OPCODE 0x825F +/** Light CTL Status Opcode */ +#define MS_ACCESS_LIGHT_CTL_STATUS_OPCODE 0x8260 +/** Light CTL Temperature Get Opcode */ +#define MS_ACCESS_LIGHT_CTL_TEMPERATURE_GET_OPCODE 0x8261 +/** Light CTL Temperature Range Get Opcode */ +#define MS_ACCESS_LIGHT_CTL_TEMPERATURE_RANGE_GET_OPCODE 0x8262 +/** Light CTL Temperature Range Status Opcode */ +#define MS_ACCESS_LIGHT_CTL_TEMPERATURE_RANGE_STATUS_OPCODE 0x8263 +/** Light CTL Temperature Set Opcode */ +#define MS_ACCESS_LIGHT_CTL_TEMPERATURE_SET_OPCODE 0x8264 +/** Light CTL Temperature Set Unacknowledged Opcode */ +#define MS_ACCESS_LIGHT_CTL_TEMPERATURE_SET_UNACKNOWLEDGED_OPCODE 0x8265 +/** Light CTL Temperature Status Opcode */ +#define MS_ACCESS_LIGHT_CTL_TEMPERATURE_STATUS_OPCODE 0x8266 +/** Light CTL Default Get Opcode */ +#define MS_ACCESS_LIGHT_CTL_DEFAULT_GET_OPCODE 0x8267 +/** Light CTL Default Status Opcode */ +#define MS_ACCESS_LIGHT_CTL_DEFAULT_STATUS_OPCODE 0x8268 + +/** Light CTL Setup */ +/** Light CTL Default Set Opcode */ +#define MS_ACCESS_LIGHT_CTL_DEFAULT_SET_OPCODE 0x8269 +/** Light CTL Default Set Unacknowledged Opcode */ +#define MS_ACCESS_LIGHT_CTL_DEFAULT_SET_UNACKNOWLEDGED_OPCODE 0x826A +/** Light CTL Default Range Set Opcode */ +#define MS_ACCESS_LIGHT_CTL_TEMPERATURE_RANGE_SET_OPCODE 0x826B +/** Light CTL Default Range Set Unacknowledged Opcode */ +#define MS_ACCESS_LIGHT_CTL_TEMPERATURE_RANGE_SET_UNACKNOWLEDGED_OPCODE 0x826C + +/** Light HSL */ +/** Light HSL Get Opcode */ +#define MS_ACCESS_LIGHT_HSL_GET_OPCODE 0x826D +/** Light HSL HUE Get Opcode */ +#define MS_ACCESS_LIGHT_HSL_HUE_GET_OPCODE 0x826E +/** Light HSL HUE Set Opcode */ +#define MS_ACCESS_LIGHT_HSL_HUE_SET_OPCODE 0x826F +/** Light HSL HUE Set Unacknowledged Opcode */ +#define MS_ACCESS_LIGHT_HSL_HUE_SET_UNACKNOWLEDGED_OPCODE 0x8270 +/** Light HSL HUE Status Opcode */ +#define MS_ACCESS_LIGHT_HSL_HUE_STATUS_OPCODE 0x8271 +/** Light HSL Saturation Get Opcode */ +#define MS_ACCESS_LIGHT_HSL_SATURATION_GET_OPCODE 0x8272 +/** Light HSL Saturation Set Opcode */ +#define MS_ACCESS_LIGHT_HSL_SATURATION_SET_OPCODE 0x8273 +/** Light HSL Saturation Set Unacknowledged Opcode */ +#define MS_ACCESS_LIGHT_HSL_SATURATION_SET_UNACKNOWLEDGED_OPCODE 0x8274 +/** Light HSL Saturation Status Opcode */ +#define MS_ACCESS_LIGHT_HSL_SATURATION_STATUS_OPCODE 0x8275 +/** Light HSL Set Opcode */ +#define MS_ACCESS_LIGHT_HSL_SET_OPCODE 0x8276 +/** Light HSL Set Unacknowledged Opcode */ +#define MS_ACCESS_LIGHT_HSL_SET_UNACKNOWLEDGED_OPCODE 0x8277 +/** Light HSL Status Opcode */ +#define MS_ACCESS_LIGHT_HSL_STATUS_OPCODE 0x8278 +/** Light HSL Target Get Opcode */ +#define MS_ACCESS_LIGHT_HSL_TARGET_GET_OPCODE 0x8279 +/** Light HSL Target Status Opcode */ +#define MS_ACCESS_LIGHT_HSL_TARGET_STATUS_OPCODE 0x827A +/** Light HSL Default Get Opcode */ +#define MS_ACCESS_LIGHT_HSL_DEFAULT_GET_OPCODE 0x827B +/** Light HSL Default Status Opcode */ +#define MS_ACCESS_LIGHT_HSL_DEFAULT_STATUS_OPCODE 0x827C +/** Light HSL Range Get Opcode */ +#define MS_ACCESS_LIGHT_HSL_RANGE_GET_OPCODE 0x827D +/** Light HSL Range Status Opcode */ +#define MS_ACCESS_LIGHT_HSL_RANGE_STATUS_OPCODE 0x827E + +/** Light HSL Setup */ +/** Light HSL Default Set Opcode */ +#define MS_ACCESS_LIGHT_HSL_DEFAULT_SET_OPCODE 0x827F +/** Light HSL Default Set Unacknowledged Opcode */ +#define MS_ACCESS_LIGHT_HSL_DEFAULT_SET_UNACKNOWLEDGED_OPCODE 0x8280 +/** Light HSL Range Set Opcode */ +#define MS_ACCESS_LIGHT_HSL_RANGE_SET_OPCODE 0x8281 +/** Light HSL Range Set Unacknowledged Opcode */ +#define MS_ACCESS_LIGHT_HSL_RANGE_SET_UNACKNOWLEDGED_OPCODE 0x8282 + +/** Light xyL */ +/** Light xyL Get Opcode */ +#define MS_ACCESS_LIGHT_XYL_GET_OPCODE 0x8283 +/** Light xyL Set Opcode */ +#define MS_ACCESS_LIGHT_XYL_SET_OPCODE 0x8284 +/** Light xyL Set Unacknowledged Opcode */ +#define MS_ACCESS_LIGHT_XYL_SET_UNACKNOWLEDGED_OPCODE 0x8285 +/** Light xyL Status Opcode */ +#define MS_ACCESS_LIGHT_XYL_STATUS_OPCODE 0x8286 +/** Light xyL Target Get Opcode */ +#define MS_ACCESS_LIGHT_XYL_TARGET_GET_OPCODE 0x8287 +/** Light xyL Target Status Opcode */ +#define MS_ACCESS_LIGHT_XYL_TARGET_STATUS_OPCODE 0x8288 +/** Light xyL Default Get Opcode */ +#define MS_ACCESS_LIGHT_XYL_DEFAULT_GET_OPCODE 0x8289 +/** Light xyL Default Status Opcode */ +#define MS_ACCESS_LIGHT_XYL_DEFAULT_STATUS_OPCODE 0x828A +/** Light xyL Range Get Opcode */ +#define MS_ACCESS_LIGHT_XYL_RANGE_GET_OPCODE 0x828B +/** Light xyL Range Status Opcode */ +#define MS_ACCESS_LIGHT_XYL_RANGE_STATUS_OPCODE 0x828C + +/** Light xyL Setup */ +/** Light xyL Default Set Opcode */ +#define MS_ACCESS_LIGHT_XYL_DEFAULT_SET_OPCODE 0x828D +/** Light xyL Default Set Unacknowledged Opcode */ +#define MS_ACCESS_LIGHT_XYL_DEFAULT_SET_UNACKNOWLEDGED_OPCODE 0x828E +/** Light xyL Range Set Opcode */ +#define MS_ACCESS_LIGHT_XYL_RANGE_SET_OPCODE 0x828F +/** Light xyL Range Set Unacknowledged Opcode */ +#define MS_ACCESS_LIGHT_XYL_RANGE_SET_UNACKNOWLEDGED_OPCODE 0x8290 + +/** Light Control */ +/** Light LC Mode Get Opcode */ +#define MS_ACCESS_LIGHT_LC_MODE_GET_OPCODE 0x8291 +/** Light LC Mode Set Opcode */ +#define MS_ACCESS_LIGHT_LC_MODE_SET_OPCODE 0x8292 +/** Light LC Mode Set Unacknowledged Opcode */ +#define MS_ACCESS_LIGHT_LC_MODE_SET_UNACKNOWLEDGED_OPCODE 0x8293 +/** Light LC Mode Status Opcode */ +#define MS_ACCESS_LIGHT_LC_MODE_STATUS_OPCODE 0x8294 +/** Light LC Occupancy Mode Get Opcode */ +#define MS_ACCESS_LIGHT_LC_OM_GET_OPCODE 0x8295 +/** Light LC Occupancy Mode Set Opcode */ +#define MS_ACCESS_LIGHT_LC_OM_SET_OPCODE 0x8296 +/** Light LC Occupancy Mode Set Unacknowledged Opcode */ +#define MS_ACCESS_LIGHT_LC_OM_SET_UNACKNOWLEDGED_OPCODE 0x8297 +/** Light LC Occupancy Mode Status Opcode */ +#define MS_ACCESS_LIGHT_LC_OM_STATUS_OPCODE 0x8298 +/** Light LC Light OnOff Get Opcode */ +#define MS_ACCESS_LIGHT_LC_LIGHT_ONOFF_GET_OPCODE 0x8299 +/** Light LC Light OnOff Set Opcode */ +#define MS_ACCESS_LIGHT_LC_LIGHT_ONOFF_SET_OPCODE 0x829A +/** Light LC Light OnOff Set Unacknowledged Opcode */ +#define MS_ACCESS_LIGHT_LC_LIGHT_ONOFF_SET_UNACKNOWLEDGED_OPCODE 0x829B +/** Light LC Light OnOff Status Opcode */ +#define MS_ACCESS_LIGHT_LC_LIGHT_ONOFF_STATUS_OPCODE 0x829C +/** Light LC Property Get Opcode */ +#define MS_ACCESS_LIGHT_LC_PROPERTY_GET_OPCODE 0x829D +/** Light LC Property Set Opcode */ +#define MS_ACCESS_LIGHT_LC_PROPERTY_SET_OPCODE 0x62 +/** Light LC Property Set Unacknowledged Opcode */ +#define MS_ACCESS_LIGHT_LC_PROPERTY_SET_UNACKNOWLEDGED_OPCODE 0x63 +/** Light LC Property Status Opcode */ +#define MS_ACCESS_LIGHT_LC_PROPERTY_STATUS_OPCODE 0x64 + +/** Invalid Opcode */ +#define MS_ACCESS_INVALID_OPCODE 0xFFFFFFFF + + +/** ---------------------------------------------------------------------------- Model IDs */ +/** SIG defined model IDs */ +/** Model ID - Config Server */ +#define MS_MODEL_ID_CONFIG_SERVER 0x0000 +/** Model ID - Config Client */ +#define MS_MODEL_ID_CONFIG_CLIENT 0x0001 +/** Model ID - Health Server */ +#define MS_MODEL_ID_HEALTH_SERVER 0x0002 +/** Model ID - Health Client */ +#define MS_MODEL_ID_HEALTH_CLIENT 0x0003 + +/** Generic */ +/** Model ID - Generic OnOff Server */ +#define MS_MODEL_ID_GENERIC_ONOFF_SERVER 0x1000 +/** Model ID - Generic OnOff Client */ +#define MS_MODEL_ID_GENERIC_ONOFF_CLIENT 0x1001 +/** Model ID - Generic Level Server */ +#define MS_MODEL_ID_GENERIC_LEVEL_SERVER 0x1002 +/** Model ID - Generic Level Client */ +#define MS_MODEL_ID_GENERIC_LEVEL_CLIENT 0x1003 +/** Model ID - Generic Default Transition Time Server */ +#define MS_MODEL_ID_GENERIC_DEFAULT_TRANSITION_TIME_SERVER 0x1004 +/** Model ID - Generic Default Transition Time Client */ +#define MS_MODEL_ID_GENERIC_DEFAULT_TRANSITION_TIME_CLIENT 0x1005 +/** Model ID - Generic Power OnOff Server */ +#define MS_MODEL_ID_GENERIC_POWER_ONOFF_SERVER 0x1006 +/** Model ID - Generic Power OnOff Setup Server */ +#define MS_MODEL_ID_GENERIC_POWER_ONOFF_SETUP_SERVER 0x1007 +/** Model ID - Generic Power OnOff Client */ +#define MS_MODEL_ID_GENERIC_POWER_ONOFF_CLIENT 0x1008 +/** Model ID - Generic Power Level Server */ +#define MS_MODEL_ID_GENERIC_POWER_LEVEL_SERVER 0x1009 +/** Model ID - Generic Power Level Setup Server */ +#define MS_MODEL_ID_GENERIC_POWER_LEVEL_SETUP_SERVER 0x100A +/** Model ID - Generic Power Level Client */ +#define MS_MODEL_ID_GENERIC_POWER_LEVEL_CLIENT 0x100B +/** Model ID - Generic Battery Server */ +#define MS_MODEL_ID_GENERIC_BATTERY_SERVER 0x100C +/** Model ID - Generic Battery Client */ +#define MS_MODEL_ID_GENERIC_BATTERY_CLIENT 0x100D +/** Model ID - Generic Location Server */ +#define MS_MODEL_ID_GENERIC_LOCATION_SERVER 0x100E +/** Model ID - Generic Location Setup Server */ +#define MS_MODEL_ID_GENERIC_LOCATION_SETUP_SERVER 0x100F +/** Model ID - Generic Location Client */ +#define MS_MODEL_ID_GENERIC_LOCATION_CLIENT 0x1010 +/** Model ID - Generic Admin Property Server */ +#define MS_MODEL_ID_GENERIC_ADMIN_PROPERTY_SERVER 0x1011 +/** Model ID - Generic Manufacturer Property Server */ +#define MS_MODEL_ID_GENERIC_MANUFACTURER_PROPERTY_SERVER 0x1012 +/** Model ID - Generic User Property Server */ +#define MS_MODEL_ID_GENERIC_USER_PROPERTY_SERVER 0x1013 +/** Model ID - Generic Client Property Server */ +#define MS_MODEL_ID_GENERIC_CLIENT_PROPERTY_SERVER 0x1014 +/** Model ID - Generic Property Client */ +#define MS_MODEL_ID_GENERIC_PROPERTY_CLIENT 0x1015 + +/** Sensors */ +/** Model ID - Sensor Server */ +#define MS_MODEL_ID_SENSOR_SERVER 0x1100 +/** Model ID - Sensor Setup Server */ +#define MS_MODEL_ID_SENSOR_SETUP_SERVER 0x1101 +/** Model ID - Sensor Client */ +#define MS_MODEL_ID_SENSOR_CLIENT 0x1102 + +/** Time and Scenes */ +/** Model ID - Time Server */ +#define MS_MODEL_ID_TIME_SERVER 0x1200 +/** Model ID - Time Setup Server */ +#define MS_MODEL_ID_TIME_SETUP_SERVER 0x1201 +/** Model ID - Time Client */ +#define MS_MODEL_ID_TIME_CLIENT 0x1202 +/** Model ID - Scene Server */ +#define MS_MODEL_ID_SCENE_SERVER 0x1203 +/** Model ID - Scene Setup Server */ +#define MS_MODEL_ID_SCENE_SETUP_SERVER 0x1204 +/** Model ID - Scene Client */ +#define MS_MODEL_ID_SCENE_CLIENT 0x1205 +/** Model ID - Scheduler Server */ +#define MS_MODEL_ID_SCHEDULER_SERVER 0x1206 +/** Model ID - Scheduler Setup Server */ +#define MS_MODEL_ID_SCHEDULER_SETUP_SERVER 0x1207 +/** Model ID - Scheduler Client */ +#define MS_MODEL_ID_SCHEDULER_CLIENT 0x1208 + +/** Lighting */ +/** Model ID - Light Lightness Server */ +#define MS_MODEL_ID_LIGHT_LIGHTNESS_SERVER 0x1300 +/** Model ID - Light Lightness Setup Server */ +#define MS_MODEL_ID_LIGHT_LIGHTNESS_SETUP_SERVER 0x1301 +/** Model ID - Light Lightness Client */ +#define MS_MODEL_ID_LIGHT_LIGHTNESS_CLIENT 0x1302 +/** Model ID - Light CTL Server */ +#define MS_MODEL_ID_LIGHT_CTL_SERVER 0x1303 +/** Model ID - Light CTL Setup Server */ +#define MS_MODEL_ID_LIGHT_CTL_SETUP_SERVER 0x1304 +/** Model ID - Light CTL Client */ +#define MS_MODEL_ID_LIGHT_CTL_CLIENT 0x1305 +/** Model ID - Light CTL Temperature Server */ +#define MS_MODEL_ID_LIGHT_CTL_TEMPERATURE_SERVER 0x1306 +/** Model ID - Light HSL Server */ +#define MS_MODEL_ID_LIGHT_HSL_SERVER 0x1307 +/** Model ID - Light HSL Setup Server */ +#define MS_MODEL_ID_LIGHT_HSL_SETUP_SERVER 0x1308 +/** Model ID - Light HSL Client */ +#define MS_MODEL_ID_LIGHT_HSL_CLIENT 0x1309 +/** Model ID - Light HSL HUE Server */ +#define MS_MODEL_ID_LIGHT_HSL_HUE_SERVER 0x130A +/** Model ID - Light HSL Saturation Server */ +#define MS_MODEL_ID_LIGHT_HSL_SATURATION_SERVER 0x130B +/** Model ID - Light xyL Server */ +#define MS_MODEL_ID_LIGHT_XYL_SERVER 0x130C +/** Model ID - Light xyL Setup Server */ +#define MS_MODEL_ID_LIGHT_XYL_SETUP_SERVER 0x130D +/** Model ID - Light xyL Client */ +#define MS_MODEL_ID_LIGHT_XYL_CLIENT 0x130E +/** Model ID - Light LC Server */ +#define MS_MODEL_ID_LIGHT_LC_SERVER 0x130F +/** Model ID - Light LC Setup Server */ +#define MS_MODEL_ID_LIGHT_LC_SETUP_SERVER 0x1310 +/** Model ID - Light LC Client */ +#define MS_MODEL_ID_LIGHT_LC_CLIENT 0x1311 + +#endif /* _H_MS_ASSIGNED_NUMBERS_ */ + diff --git a/src/components/ethermind/mesh/export/include/MS_brr_api.h b/src/components/ethermind/mesh/export/include/MS_brr_api.h new file mode 100644 index 0000000..4d7c450 --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_brr_api.h @@ -0,0 +1,600 @@ + +/** + \file MS_brr_api.h + + \brief This file defines the Mesh Bearer Application Interface - includes + Data Structures and Methods. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_BRR_API_ +#define _H_MS_BRR_API_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_common.h" + +/* --------------------------------------------- Global Definitions */ + +/** + \defgroup brr_module BEARER (Mesh Bearer Layer) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Bearer (BEARER) module to the Application and other upper + layers of the stack. +*/ + +/** + \defgroup brr_defines Defines + \{ + Describes defines for the module. +*/ + +/** + \defgroup brr_constants Constants + \{ + Describes Constants defined by the module. +*/ + +/** Invalid Bearer handle identifier */ +#define BRR_HANDLE_INVALID 0xFF + +/** Bearer Interface events to the above layer */ +#define BRR_IFACE_DOWN 0x00 +#define BRR_IFACE_UP 0x01 +#define BRR_IFACE_DATA 0x02 +#define BRR_IFACE_PROXY_DATA 0x03 + +/** Bearer beacon types - Connectable (Active) and Non-Connectable (Passive) */ +#define BRR_BCON_PASSIVE 0x00 +#define BRR_BCON_ACTIVE 0x01 + +/** Bearer Beacon Operations - Broadcast/Observe */ +#define BRR_BROADCAST 0x00 +#define BRR_OBSERVE 0x01 + +/** Bearer Beacon Actions - Enable/Disable */ +#define BRR_DISABLE 0x00 +#define BRR_ENABLE 0x01 + +/** Maximum PDU size for data received over bearer */ +#define BRR_MAX_PDU_SIZE 65 + +/** Bearer Server Client Roles */ +#define BRR_CLIENT_ROLE 0x00 +#define BRR_SERVER_ROLE 0x01 +#define BRR_INVALID_ROLE 0xFF + +/** Bearer Transmit and Receive operation modes */ +#define BRR_TX 0x01 +#define BRR_RX 0x02 + +/** \} */ + +/** \} */ + +/** + \defgroup brr_events Events + \{ + This section lists the Asynchronous Events notified to Application by the + Module. +*/ + +/** + \defgroup brr_marcos Utility Macros + \{ + Initialization and other Utility Macros offered by the module. +*/ + +/** \} */ +/** \} */ + +/* --------------------------------------------- Data Types/ Structures */ + +/** + \addtogroup brr_defines Defines + \{ +*/ +/** Bearer handle identifier */ +typedef UCHAR BRR_HANDLE; + +/** Bearer Type definitions */ +typedef enum _BRR_TYPE +{ + /** Beacon Bearer */ + BRR_TYPE_BCON, + + /** Advertising Bearer */ + BRR_TYPE_ADV, + + /** Provisioning Advertising Bearer */ + BRR_TYPE_PB_ADV, + + /** GATT Bearer */ + BRR_TYPE_GATT, + + /** Provisioning GATT Bearer */ + BRR_TYPE_PB_GATT, + + /** Number of bearers supported */ + BRR_COUNT + +} BRR_TYPE; + +/* GATT Bearer Message Type Masks */ +#define BRR_SUBTYPE_GATT_T_MASK_BIT_OFFSET 6 +#define BRR_SUBTYPE_GATT_T_MASK (0xC0) +#define BRR_SUBTYPE_GATT_NETWORK_T_MASK ((MESH_GATT_TYPE_NETWORK << BRR_SUBTYPE_GATT_T_MASK_BIT_OFFSET) & (BRR_SUBTYPE_GATT_T_MASK)) +#define BRR_SUBTYPE_GATT_BEACON_T_MASK ((MESH_GATT_TYPE_BEACON << BRR_SUBTYPE_GATT_T_MASK_BIT_OFFSET) & (BRR_SUBTYPE_GATT_T_MASK)) +#define BRR_SUBTYPE_GATT_PROXY_T_MASK ((MESH_GATT_TYPE_PROXY << BRR_SUBTYPE_GATT_T_MASK_BIT_OFFSET) & (BRR_SUBTYPE_GATT_T_MASK)) +#define BRR_SUBTYPE_GATT_PROV_T_MASK ((MESH_GATT_TYPE_PROV << BRR_SUBTYPE_GATT_T_MASK_BIT_OFFSET) & (BRR_SUBTYPE_GATT_T_MASK)) + +/** Bearer Beacon type definitions */ +typedef enum _BRR_BCON_TYPE +{ + /* Unprovisioned Device Beacon */ + BRR_BCON_TYPE_UNPROV_DEVICE, + + /* Secure Network Beacon */ + BRR_BCON_TYPE_SECURE_NET, + + /* Proxy beacon with Network ID */ + BRR_BCON_TYPE_PROXY_NETID, + + /* Proxy beacon with Node Identity */ + BRR_BCON_TYPE_PROXY_NODEID, + + /** Number of Beacon types */ + BRR_BCON_COUNT + +} BRR_BCON_TTYPE; + +/** + \addtogroup brr_structures Structures + \{ +*/ + +/** Bearer information to register */ +typedef struct _BRR_BEARER_INFO +{ + /** Bearer Information */ + MS_BUFFER* binfo; + + /** Data Send routine */ + API_RESULT (*bearer_send)(BRR_HANDLE*, UCHAR, void*, UINT16); + + /** Data Receive routine */ + void (*bearer_recv)(BRR_HANDLE*, UCHAR*, UINT16, MS_BUFFER* info); + + /** Bearer Sleep Interface */ + void (*bearer_sleep)(BRR_HANDLE*); + + /** Bearer Wakeup Interface */ + void (*bearer_wakeup)(BRR_HANDLE*, UINT8 mode); + +} BRR_BEARER_INFO; + +/** Bearer Beacon type data structure */ +typedef struct _BRR_BEACON_INFO +{ + /** + Beacon Action + - Lower Nibble: + > BRR_OBSERVE + > BRR_BROADCAST + + - Higher Nibble: + > BRR_ENABLE + > BRR_DISABLE + */ + UCHAR action; + + /** + Beacon type + - Lower Nibble: + > BRR_BCON_PASSIVE - Non Connectable beacon + > BRR_BCON_ACTIVE - Connectable beacon + + - Higher Nibble (Valid only when Passive) + > BRR_BCON_TYPE_UNPROV_DEVICE + > BRR_BCON_TYPE_SECURE_NET + */ + UCHAR type; + + /** Beacon Broadcast Data */ + UCHAR* bcon_data; + + /** Beacon Broadcast Data length */ + UINT16 bcon_datalen; + + /** URI information in case of Unprovisioned Beacons */ + MS_BUFFER* uri; + +} BRR_BEACON_INFO; + +/** Bearer GATT Channel informartion related data structure */ +typedef struct _BRR_BEARER_CH_INFO +{ + /** Identifies the MTU for the Bearer Channel */ + UINT16 mtu; + + /** Identifies the role for the Bearer channel */ + UCHAR role; + +} BRR_BEARER_CH_INFO; + +/** \} */ +/** \} */ + +/** + \defgroup brr_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ +/** + BEARER Application Asynchronous Notification Callback. + + BEARER calls the registered callback to indicate events occurred to the + application. + + \param brr_type Bearer Type. + \param data Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef API_RESULT (*BRR_NTF_CB) +( + BRR_HANDLE* brr_handle, + UCHAR brr_event, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; + +/** + BEARER Application Asynchronous Notification Callback for Beacons. + + Application registers callback for beacon notification with bearer. + + \param brr_type Bearer Type. + \param data Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef void (*BRR_BCON_CB) +( + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; +/** \} */ + +/** + \addtogroup brr_defines Defines + \{ +*/ + +/** + \addtogroup brr_structures Structures + \{ +*/ + + +/** \} */ + +/** \} */ + +/* --------------------------------------------- Function */ + +/** + \defgroup brr_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Bearer Layer APIs. +*/ +#ifdef __cplusplus +extern "C" { +#endif + +/** + \brief Register Interface with Bearer Layer + + \par Description + This routine registers interface with the Bearer Layer. + Bearer Layer supports single Application, hence this rouine shall be called once. + + \param [in] brr_type + Bearer Type + + \param [in] brr_cb + Details describing Application Notification Callback + + \return API_SUCCESS or an error code indicating reason for failure + +*/ +API_RESULT MS_brr_register +( + /* IN */ BRR_TYPE brr_type, + /* IN */ BRR_NTF_CB brr_cb +); + +/** + \brief Register Beacon Interface with Bearer Layer + + \par Description + This routine registers interface with the Bearer Layer to process Beacons. + Bearer Layer supports single Application, hence this rouine shall be called once. + 1 + \param [in] bcon_type + Beacon type - Unprovisioned Device or Secure Network. + + \param [in] bcon_handler + Callback handler to be registered for the given beacon type. + + \return API_SUCCESS or an error code indicating reason for failure + +*/ +API_RESULT MS_brr_register_beacon_handler +( + /* IN */ UCHAR bcon_type, + /* IN */ void (*bcon_handler) (UCHAR* data, UINT16 datalen) +); + +/** + \brief Add a bearer to Bearer Layer + + \par Description + This routine adds a bearer that is setup by the application + for use by the Mesh Stack. Bearer Layer supports single Application, + hence this rouine shall be called once. + + \param [in] brr_type + Bearer Type + + \param [in] brr_info + Details describing the Bearer being added + + \param [out] brr_handle + Handle to the bearer that is added. Used in data APIs. + + \return API_SUCCESS or an error code indicating reason for failure + +*/ +API_RESULT MS_brr_add_bearer +( + /* IN */ BRR_TYPE brr_type, + /* IN */ BRR_BEARER_INFO* brr_info, + /* OUT */ BRR_HANDLE* brr_handle +); + +/** + \brief Remove a bearer from Bearer Layer + + \par Description + This routine removes a bearer from the Mesh Stack. Bearer Layer + supports single Application, hence this rouine shall be called once. + + \param [in] brr_type + Bearer Type + + \param [out] brr_handle + Handle to the bearer that is added. Used in data APIs. + + \return API_SUCCESS or an error code indicating reason for failure + +*/ +API_RESULT MS_brr_remove_bearer +( + /* IN */ BRR_TYPE brr_type, + /* IN */ BRR_HANDLE* brr_handle +); + +/** + \brief Observe ON/OFF for the beacon type + + \par Description + This routine sends enables/disables the observation procedure + for the given beacon type. + + \param [in] bcon_type + Type of beacon to observe - Active/Passive. + + \param [in] enable + Enable or Disable the observation procedure. + + \return API_SUCCESS or an error code indicating reason for failure + +*/ +API_RESULT MS_brr_observe_beacon +( + /* IN */ UCHAR bcon_type, + /* IN */ UCHAR enable +); + + +/** + \brief API to send Unprovisioned Device Beacon + + \par Description + This routine sends Unprovisioned Device Beacon + + \param [in] type + Active or Passive Broadcast type. + + \param [in] dev_uuid + Device UUID uniquely identifying this device. + + \param [in] oob_info + OOB Information + + \param [in] uri + Optional Parameter. NULL if not present. + Points to the length and payload pointer of the URI string to be + advertised interleaving with the unprovisioned beacon. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_brr_bcast_unprovisioned_beacon +( + /* IN */ UCHAR type, + /* IN */ UCHAR* dev_uuid, + /* IN */ UINT16 oob_info, + /* IN */ MS_BUFFER* uri +); + + +/** + \brief API to broadcast a beacon + + \par Description + This routine sends the beacon of given type on Adv and GATT bearers + + \param [in] type + The type of beacon + + \param [in] packet + Beacon data + + \param [in] length + Beacon data length + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_brr_broadcast_beacon +( + /* IN */ UCHAR type, + /* IN */ UCHAR* packet, + /* IN */ UINT16 length +); + +/** + \brief API to send Proxy Device ADV + + \par Description + This routine sends Proxy Device ADV + + \param [in] type + Proxy ADV Type: + 0x00 - Network ID + 0x01 - Node Identity + + \param [in] data + Data to be advertised by Proxy. + If the "type" is: + 0x00 - Network ID - 8 Bytes of Network ID + 0x01 - Node Identity - 8 Bytes Hash, 8 Bytes Random num + + \param [in] datalen + Length of the data to be advertised by Proxy. + If the "type" is: + 0x00 - Network ID - 8 Bytes of Network ID + 0x01 - Node Identity - 8 Bytes Hash, 8 Bytes Random num + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_brr_start_proxy_adv +( + /* IN */ UCHAR type, + /* IN */ UCHAR* data, + /* IN */ UINT16 datalen +); + +/** + \brief API to disable broadcast of given beacon type + + \par Description + This routine stops advertising of given beacon type. + + \param [in] bcon + The Bearer Beacon (Unprovisioned/Secure Network). + + \param [in] type + The type of braodcast beacon (Active/Passive). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_brr_bcast_end +( + /* IN */ UCHAR bcon, + /* IN */ UCHAR type +); + + +/** + \brief Send a bearer PDU + + \par Description + This routine sends a PDU from the Mesh stack to over the bearer + indicated by the bearer handle. + + \param [in] brr_handle + Bearer handle on which PDU is to be sent. + + \param [in] brr_type + Type of Bearer as in \ref BRR_TYPE. + + \param [in] buffer + PDU data to be sent. + + \return API_SUCCESS or an error code indicating reason for failure + +*/ +API_RESULT MS_brr_send_pdu +( + /* IN */ BRR_HANDLE* brr_handle, + /* IN */ BRR_TYPE brr_type, + /* IN */ MS_BUFFER* buffer +); + +/** + \brief Get the RSSI of current received packet being processed. + + \par Description + This routine returns the RSSI value of the received packet in its + context when called from the Mesh stack. + + \return RSSI value of the current packet in context. + + \note This applies only when the packet is received over ADV bearer + +*/ +UCHAR MS_brr_get_packet_rssi(void); + +/** + \brief Put the bearer to sleep. + + \par Description + This routine requests the underlying bearer interface to sleep. + Default bearer interface is that of advertising bearer. + + \return API_SUCCESS + +*/ +API_RESULT MS_brr_sleep(void); + +/** + \brief Wakeup the bearer. + + \par Description + This routine requests the underlying bearer interface to wakeup. + Default bearer interface is that of advertising bearer. + + \param mode + Identifies the mode (BRR_TX/BRR_RX) for which bearer is requested + for wakeup. + + \return API_SUCCESS + +*/ +API_RESULT MS_brr_wakeup(UINT8 mode); + +#ifdef __cplusplus +}; +#endif + +/** \} */ + +/** \} */ + +#endif /* _H_MS_BRR_API_ */ + diff --git a/src/components/ethermind/mesh/export/include/MS_common.h b/src/components/ethermind/mesh/export/include/MS_common.h new file mode 100644 index 0000000..abc54df --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_common.h @@ -0,0 +1,1039 @@ + +/** + \file MS_common.h + + This Header file describes common declarations for the + EtherMind Mesh modules. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_COMMON_ +#define _H_MS_COMMON_ + +/** + \defgroup ms_common_module MESH Common + \{ +*/ + +/* -------------------------------------------- Header File Inclusion */ +/* The EtherMind OS Abstraction */ +#include "EM_os.h" + +/* The EtherMind Configuration Parameters */ +#include "MS_features.h" + +/* The EtherMind Tunable Constant */ +#include "MS_limits.h" + +/* The Bluetooth Assigned Numbers */ +#include "MS_assigned_numbers.h" + +/* The EtherMind Error Codes */ +#include "MS_error.h" + +/* The EtherMind Debug Library */ +#include "EM_debug.h" + +/* For EM_assert() macro */ +#include "EM_assert.h" + +/* For Status Flag APIs */ +/* #include "MS_status.h" */ + +/* The EtherMind Timer Library */ +#include "EM_timer.h" + +/* EtherMind Platform Specific Initialization & Shutdown Handlers */ +#include "MS_common_pl.h" + +/* For Memory (leak, corruption) Testing */ +#ifdef MEMWATCH + #include "memwatch.h" +#endif /* MEMWATCH */ + +/* TODO: See what should be the order of inclusion */ +#include "MS_model_states.h" + +/* -------------------------------------------- Global Definitions */ + +/** + \cond ignore_this + \{ +*/ + +/* MS_COMMON Debug Macros */ +#ifndef MS_COMMON_NO_DEBUG + #define MS_COMMON_ERR(...) EM_debug_error(MS_MODULE_ID_COMMON, __VA_ARGS__) +#else /* COMMON_NO_DEBUG */ + #define MS_COMMON_ERR EM_debug_null +#endif /* MS_COMMON_NO_DEBUG */ + +#ifdef MS_COMMON_DEBUG + + #define MS_COMMON_TRC(...) EM_debug_trace(MS_MODULE_ID_COMMON, __VA_ARGS__) + #define MS_COMMON_INF(...) EM_debug_info(MS_MODULE_ID_COMMON, __VA_ARGS__) + +#else /* MS_COMMON_DEBUG */ + + #define MS_COMMON_TRC EM_debug_null + #define MS_COMMON_INF EM_debug_null + +#endif /* MS_COMMON_DEBUG */ + +/** \endcond */ + +/** + \defgroup ms_common_defines Defines + \{ +*/ + +/** + \defgroup ms_common_constants Constants + \{ +*/ + +#define MS_STACK_INIT_UNDEFINED 0x00 +#define MS_STACK_INIT_ETHERMIND_INIT 0x01 + +/* Definition for True/False */ +#ifndef MS_FALSE + #define MS_FALSE 0 +#endif /* MS_FALSE */ + +#ifndef MS_TRUE + #define MS_TRUE 1 +#endif /* MS_TRUE */ + +/** \} */ + +/** \} */ + +/* -------------------------------------------- Macros */ + +/** + \defgroup ms_common_utility_macros Utility Macros + \{ +*/ + +/** + Packing Macros. + + Syntax: MS_PACK___BYTE + + Usage: Based on the endian-ness defined for each protocol/profile layer, + appropriate packing macros to be used by each layer. + + Example: HCI is defined as little endian protocol, + so if HCI defines HCI_PACK_2_BYTE for packing a parameter of size 2 byte, + that shall be mapped to MS_PACK_LE_2_BYTE + + By default both the packing and unpaking macros uses pointer to + a single or multi-octet variable which to be packed to or unpacked from + a buffer (unsinged character array). + + For the packing macro, another variation is available, + where the single or multi-octet variable itself is used (not its pointer). + + Syntax: MS_PACK___BYTE_VAL +*/ + +/* Little Endian Packing Macros */ +#define MS_PACK_LE_1_BYTE(dst, src) \ + { \ + UCHAR val; \ + val = (UCHAR)(*(src)); \ + MS_PACK_LE_1_BYTE_VAL((dst), val); \ + } + +#define MS_PACK_LE_1_BYTE_VAL(dst, src) \ + *((UCHAR *)(dst) + 0) = src; + +#define MS_PACK_LE_2_BYTE(dst, src) \ + { \ + UINT16 val; \ + val = (UINT16)(*(src)); \ + MS_PACK_LE_2_BYTE_VAL((dst), val); \ + } + +#define MS_PACK_LE_2_BYTE_VAL(dst, src) \ + *((UCHAR *)(dst) + 0) = (UCHAR)(src); \ + *((UCHAR *)(dst) + 1) = (UCHAR)(src >> 8); + +#define MS_PACK_LE_3_BYTE(dst, src) \ + { \ + UINT32 val; \ + val = (UINT32)(*(src)); \ + MS_PACK_LE_3_BYTE_VAL((dst), val); \ + } + +#define MS_PACK_LE_3_BYTE_VAL(dst, src) \ + *((UCHAR *)(dst) + 0) = (UCHAR)(src);\ + *((UCHAR *)(dst) + 1) = (UCHAR)(src >> 8);\ + *((UCHAR *)(dst) + 2) = (UCHAR)(src >> 16); + +#define MS_PACK_LE_4_BYTE(dst, src) \ + { \ + UINT32 val; \ + val = (UINT32)(*(src)); \ + MS_PACK_LE_4_BYTE_VAL((dst), val); \ + } + +#define MS_PACK_LE_4_BYTE_VAL(dst, src) \ + *((UCHAR *)(dst) + 0) = (UCHAR)(src);\ + *((UCHAR *)(dst) + 1) = (UCHAR)(src >> 8);\ + *((UCHAR *)(dst) + 2) = (UCHAR)(src >> 16);\ + *((UCHAR *)(dst) + 3) = (UCHAR)(src >> 24); + +/* TBD: Update based on 64 Bit, 128 Bit Data Types */ +#define MS_PACK_LE_8_BYTE(dst,val)\ + EM_mem_copy ((dst), (val), 8) + +#define MS_PACK_LE_16_BYTE(dst,val)\ + EM_mem_copy ((dst), (val), 16) + +#define MS_PACK_LE_N_BYTE(dst,val,n)\ + EM_mem_copy ((dst), (val), (n)) + +/* Big Endian Packing Macros */ +#define MS_PACK_BE_1_BYTE(dst, src) \ + { \ + UCHAR val; \ + val = (UCHAR)(*((UCHAR *)(src))); \ + MS_PACK_BE_1_BYTE_VAL((dst), val); \ + } + +#define MS_PACK_BE_1_BYTE_VAL(dst, src) \ + *((UCHAR *)(dst) + 0) = src; + +#define MS_PACK_BE_2_BYTE(dst, src) \ + { \ + UINT16 val; \ + val = (UINT16)(*((UINT16 *)(src))); \ + MS_PACK_BE_2_BYTE_VAL((dst), val); \ + } + +#define MS_PACK_BE_2_BYTE_VAL(dst, src) \ + *((UCHAR *)(dst) + 1) = (UCHAR)(src); \ + *((UCHAR *)(dst) + 0) = (UCHAR)(src >> 8); + +#define MS_PACK_BE_3_BYTE(dst, src) \ + { \ + UINT32 val; \ + val = (UINT32)(*((UINT32 *)(src))); \ + MS_PACK_BE_3_BYTE_VAL((dst), val); \ + } + +#define MS_PACK_BE_3_BYTE_VAL(dst, src) \ + *((UCHAR *)(dst) + 2) = (UCHAR)(src);\ + *((UCHAR *)(dst) + 1) = (UCHAR)(src >> 8);\ + *((UCHAR *)(dst) + 0) = (UCHAR)(src >> 16); + +#define MS_PACK_BE_4_BYTE(dst, src) \ + { \ + UINT32 val; \ + val = (UINT32)(*((UINT32 *)(src))); \ + MS_PACK_BE_4_BYTE_VAL((dst), val); \ + } + +#define MS_PACK_BE_4_BYTE_VAL(dst, src) \ + *((UCHAR *)(dst) + 3) = (UCHAR)(src);\ + *((UCHAR *)(dst) + 2) = (UCHAR)(src >> 8);\ + *((UCHAR *)(dst) + 1) = (UCHAR)(src >> 16);\ + *((UCHAR *)(dst) + 0) = (UCHAR)(src >> 24); + +/* TBD: Update based on 64 Bit, 128 Bit Data Types */ +#define MS_PACK_BE_8_BYTE(dst,val)\ + EM_mem_copy ((dst), (val), 8) + +#define MS_PACK_BE_16_BYTE(dst,val)\ + EM_mem_copy ((dst), (val), 16) + +#define MS_PACK_BE_N_BYTE(dst,val,n)\ + EM_mem_copy ((dst), (val), (n)) + + +/** + Unpacking Macros. + + Syntax: MS_UNPACK___BYTE + + Usage: Based on the endian-ness defined for each protocol/profile layer, + appropriate unpacking macros to be used by each layer. + + Example: HCI is defined as little endian protocol, + so if HCI defines HCI_UNPACK_4_BYTE for unpacking a parameter of size 4 byte, + that shall be mapped to MS_UNPACK_LE_4_BYTE +*/ + +/* Little Endian Unpacking Macros */ +#define MS_UNPACK_LE_1_BYTE(dst,src)\ + *((UCHAR *)(dst)) = (UCHAR)(*((UCHAR *)(src))); + +#define MS_UNPACK_LE_2_BYTE(dst,src)\ + *((UINT16 *)(dst)) = *((src) + 1); \ + *((UINT16 *)(dst)) = *((UINT16 *)(dst)) << 8; \ + *((UINT16 *)(dst)) |= *((src) + 0); + +#define MS_UNPACK_LE_3_BYTE(dst,src)\ + *((UINT32 *)(dst)) = *((src) + 2);\ + *((UINT32 *)(dst)) = (*((UINT32 *)(dst))) << 8;\ + *((UINT32 *)(dst)) |= *((src) + 1);\ + *((UINT32 *)(dst)) = (*((UINT32 *)(dst))) << 8;\ + *((UINT32 *)(dst)) |= *((src) + 0); + +#define MS_UNPACK_LE_4_BYTE(dst,src)\ + *((UINT32 *)(dst)) = *((src) + 3);\ + *((UINT32 *)(dst)) = (*((UINT32 *)(dst))) << 8;\ + *((UINT32 *)(dst)) |= *((src) + 2);\ + *((UINT32 *)(dst)) = (*((UINT32 *)(dst))) << 8;\ + *((UINT32 *)(dst)) |= *((src) + 1);\ + *((UINT32 *)(dst)) = (*((UINT32 *)(dst))) << 8;\ + *((UINT32 *)(dst)) |= *((src) + 0); + +/* TBD: Update based on 64 Bit, 128 Bit Data Types */ +#define MS_UNPACK_LE_8_BYTE(dst,src)\ + EM_mem_copy ((dst), (src), 8) + +#define MS_UNPACK_LE_16_BYTE(dst,src)\ + EM_mem_copy ((dst), (src), 16) + +#define MS_UNPACK_LE_N_BYTE(dst,src,n)\ + EM_mem_copy ((dst), (src), (n)) + +/* Big Endian Unpacking Macros */ +#define MS_UNPACK_BE_1_BYTE(dst,src)\ + *((UCHAR *)(dst)) = (UCHAR)(*((UCHAR *)(src))); + +#define MS_UNPACK_BE_2_BYTE(dst,src)\ + *((UINT16 *)(dst)) = *((src) + 0); \ + *((UINT16 *)(dst)) = *((UINT16 *)(dst)) << 8; \ + *((UINT16 *)(dst)) |= *((src) + 1); + +#define MS_UNPACK_BE_3_BYTE(dst,src)\ + *((UINT32 *)(dst)) = *((src) + 0);\ + *((UINT32 *)(dst)) = (*((UINT32 *)(dst))) << 8;\ + *((UINT32 *)(dst)) |= *((src) + 1);\ + *((UINT32 *)(dst)) = (*((UINT32 *)(dst))) << 8;\ + *((UINT32 *)(dst)) |= *((src) + 2); + +#define MS_UNPACK_BE_4_BYTE(dst,src)\ + *((UINT32 *)(dst)) = *((src) + 0);\ + *((UINT32 *)(dst)) = (*((UINT32 *)(dst))) << 8;\ + *((UINT32 *)(dst)) |= *((src) + 1);\ + *((UINT32 *)(dst)) = (*((UINT32 *)(dst))) << 8;\ + *((UINT32 *)(dst)) |= *((src) + 2);\ + *((UINT32 *)(dst)) = (*((UINT32 *)(dst))) << 8;\ + *((UINT32 *)(dst)) |= *((src) + 3); + +/* TBD: Update based on 64 Bit, 128 Bit Data Types */ +#define MS_UNPACK_BE_8_BYTE(dst,src)\ + EM_mem_copy ((dst), (src), 8) + +#define MS_UNPACK_BE_16_BYTE(dst,src)\ + EM_mem_copy ((dst), (src), 16) + +#define MS_UNPACK_BE_N_BYTE(dst,src,n)\ + EM_mem_copy ((dst), (src), (n)) + +#ifndef MS_DISABLE_MUTEX + +/* Macro to define a Mutex Variable */ +#define MS_DEFINE_MUTEX(mutex) EM_thread_mutex_type mutex; + +/* Macro to define a Mutex Variable with a type qualifier */ +#define MS_DEFINE_MUTEX_TYPE(type, mutex) type EM_thread_mutex_type mutex; + +/* Macro to define a Conditional Variable */ +#define MS_DEFINE_COND(cond) EM_thread_cond_type cond; + +/* Macro to define a Conditional Variable with a type qualifier */ +#define MS_DEFINE_COND_TYPE(type, cond) type EM_thread_cond_type cond; + +/* + Macro to Initialize Mutex. + To be used in void function as it returns no error. +*/ +#define MS_MUTEX_INIT_VOID(mutex, MODULE) \ + if (EM_thread_mutex_init(&(mutex), NULL) < 0) \ + { \ + EM_debug_error( \ + MS_MODULE_ID_##MODULE, \ + "FAILED to Initialize Mutex in " #MODULE ".\n"); \ + return; \ + } + +/* + Macro to Initialize Mutex. + It returns an error if mutex initialization fails. +*/ +#define MS_MUTEX_INIT(mutex, MODULE) \ + if (EM_thread_mutex_init(&(mutex), NULL) < 0) \ + { \ + EM_debug_error( \ + MS_MODULE_ID_##MODULE, \ + "FAILED to Initialize Mutex in " #MODULE ".\n"); \ + return MODULE##_MUTEX_INIT_FAILED; \ + } + +/* + Macro to Initialize Conditional Variable. + To be used in void function as it returns no error. +*/ +#define MS_COND_INIT_VOID(cond, MODULE) \ + if (EM_thread_cond_init(&(cond), NULL) < 0) \ + { \ + EM_debug_error( \ + MS_MODULE_ID_##MODULE, \ + "FAILED to Initialize Conditional Variable in " #MODULE ".\n"); \ + return; \ + } + +/* + Macro to Initialize Conditional Variable. + It returns an error if conditional variable initialization fails. +*/ +#define MS_COND_INIT(cond, MODULE) \ + if (EM_thread_cond_init(&(cond), NULL) < 0) \ + { \ + EM_debug_error( \ + MS_MODULE_ID_##MODULE, \ + "FAILED to Initialize Conditional Variable in " #MODULE ".\n"); \ + return MODULE##_COND_INIT_FAILED; \ + } + +/* + Locks the Module Specific Mutex which prevents any global variable being + overwritten by any function. It returns an error if mutex lock fails. +*/ +#define MS_MUTEX_LOCK(mutex, MODULE) \ + if (EM_thread_mutex_lock(&(mutex)) < 0) \ + { \ + EM_debug_error( \ + MS_MODULE_ID_##MODULE, \ + "FAILED to Lock Mutex in " #MODULE ".\n"); \ + return MODULE##_MUTEX_LOCK_FAILED; \ + } + +/* + Locks the Module Specific Mutex which prevents any global variable being + overwritten by any function. To be used in void function as it + returns no error. +*/ +#define MS_MUTEX_LOCK_VOID(mutex, MODULE) \ + if (EM_thread_mutex_lock(&(mutex)) < 0) \ + { \ + EM_debug_error( \ + MS_MODULE_ID_##MODULE, \ + "FAILED to Lock Mutex in " #MODULE ".\n"); \ + return; \ + } + +/* + Locks the Module Specific Mutex which prevents any global variable being + overwritten by any function. + It returns the error 'value' if mutex lock failes. +*/ +#define MS_MUTEX_LOCK_RETURN_ON_FAILURE(mutex, MODULE, value) \ + if (EM_thread_mutex_lock(&(mutex)) < 0) \ + { \ + EM_debug_error( \ + MS_MODULE_ID_##MODULE, \ + "FAILED to Lock Mutex in " #MODULE ".\n"); \ + return (value); \ + } + +/* + Locks the Module Specific Mutex which prevents any global variable being + overwritten by any function. On failure, only an Error is logged. + It can be used from both void and non-void functions. +*/ +#define MS_MUTEX_LOCK_DONOT_RETURN_ON_FAILURE(mutex, MODULE) \ + if (EM_thread_mutex_lock(&(mutex)) < 0) \ + { \ + EM_debug_error( \ + MS_MODULE_ID_##MODULE, \ + "FAILED to Lock Mutex in " #MODULE ".\n"); \ + } + +/* + Unlocks the Module Specific Mutex which realeses the global variables + to be written into. It returns an error if mutex unlock fails. +*/ +#define MS_MUTEX_UNLOCK(mutex, MODULE) \ + if (EM_thread_mutex_unlock(&(mutex)) < 0) \ + { \ + EM_debug_error( \ + MS_MODULE_ID_##MODULE, \ + "FAILED to Unlock Mutex in " #MODULE ".\n"); \ + return MODULE##_MUTEX_UNLOCK_FAILED; \ + } + +/* + Unlocks the Module Specific Mutex which realeses the global variables + to be written into. To be used in void functions as it returns + no error. +*/ +#define MS_MUTEX_UNLOCK_VOID(mutex, MODULE) \ + if (EM_thread_mutex_unlock(&(mutex)) < 0) \ + { \ + EM_debug_error( \ + MS_MODULE_ID_##MODULE, \ + "FAILED to Unlock Mutex in " #MODULE ".\n"); \ + return; \ + } + +/* + Unlocks the Module Specific Mutex which realeses the global variables + to be written into. + It returns the error 'value' if mutex unlock failes. +*/ +#define MS_MUTEX_UNLOCK_RETURN_ON_FAILURE(mutex, MODULE, value) \ + if (EM_thread_mutex_unlock(&(mutex)) < 0) \ + { \ + EM_debug_error( \ + MS_MODULE_ID_##MODULE, \ + "FAILED to Unlock Mutex in " #MODULE ".\n"); \ + return (value); \ + } + +/* + Unlocks the Module Specific Mutex which realeses the global variables + to be written into. On failure, only Error is logged. + It can be used from both void and non-void functions. +*/ +#define MS_MUTEX_UNLOCK_DONOT_RETURN_ON_FAILURE(mutex, MODULE) \ + if (EM_thread_mutex_unlock(&(mutex)) < 0) \ + { \ + EM_debug_error( \ + MS_MODULE_ID_##MODULE, \ + "FAILED to Unlock Mutex in " #MODULE ".\n"); \ + } + +#else /* MS_DISABLE_MUTEX */ + +/* Macro to define a Mutex Variable */ +#define MS_DEFINE_MUTEX(mutex) + +/* Macro to define a Mutex Variable with a type qualifier */ +#define MS_DEFINE_MUTEX_TYPE(type, mutex) + +/* Macro to define a Conditional Variable */ +#define MS_DEFINE_COND(cond) + +/* Macro to define a Conditional Variable with a type qualifier */ +#define MS_DEFINE_COND_TYPE(type, cond) + +/* + Macro to Initialize Mutex. + To be used in void function as it returns no error. +*/ +#define MS_MUTEX_INIT_VOID(mutex, MODULE) + +/* + Macro to Initialize Mutex. + It returns an error if mutex initialization fails. +*/ +#define MS_MUTEX_INIT(mutex, MODULE) + +/* + Macro to Initialize Conditional Variable. + To be used in void function as it returns no error. +*/ +#define MS_COND_INIT_VOID(cond, MODULE) + +/* + Macro to Initialize Conditional Variable. + It returns an error if conditional variable initialization fails. +*/ +#define MS_COND_INIT(cond, MODULE) + +/* + Locks the Module Specific Mutex which prevents any global variable being + overwritten by any function. It returns an error if mutex lock fails. +*/ +#define MS_MUTEX_LOCK(mutex, MODULE) + +/* + Locks the Module Specific Mutex which prevents any global variable being + overwritten by any function. To be used in void function as it + returns no error. +*/ +#define MS_MUTEX_LOCK_VOID(mutex, MODULE) + +/* + Locks the Module Specific Mutex which prevents any global variable being + overwritten by any function. + It returns the error 'value' if mutex lock failes. +*/ +#define MS_MUTEX_LOCK_RETURN_ON_FAILURE(mutex, MODULE, value) + +/* + Locks the Module Specific Mutex which prevents any global variable being + overwritten by any function. On failure, only an Error is logged. + It can be used from both void and non-void functions. +*/ +#define MS_MUTEX_LOCK_DONOT_RETURN_ON_FAILURE(mutex, MODULE) + +/* + Unlocks the Module Specific Mutex which realeses the global variables + to be written into. It returns an error if mutex unlock fails. +*/ +#define MS_MUTEX_UNLOCK(mutex, MODULE) + +/* + Unlocks the Module Specific Mutex which realeses the global variables + to be written into. To be used in void functions as it returns + no error. +*/ +#define MS_MUTEX_UNLOCK_VOID(mutex, MODULE) + +/* + Unlocks the Module Specific Mutex which realeses the global variables + to be written into. + It returns the error 'value' if mutex unlock failes. +*/ +#define MS_MUTEX_UNLOCK_RETURN_ON_FAILURE(mutex, MODULE, value) + +/* + Unlocks the Module Specific Mutex which realeses the global variables + to be written into. On failure, only Error is logged. + It can be used from both void and non-void functions. +*/ +#define MS_MUTEX_UNLOCK_DONOT_RETURN_ON_FAILURE(mutex, MODULE) + +#endif /* MS_DISABLE_MUTEX */ + +/* Abstractions for bit-wise operation */ +#define MS_EXTRACT_BITNUM(val, bitnum) (((val) >> (bitnum)) & 1) +#define MS_SET_BITNUM(val, bitnum) ((val) |= (1 << (bitnum))) +#define MS_CLR_BITNUM(val, bitnum) ((val) &= (~(1 << (bitnum)))) + +/* Macro to find Minimum and Maximum value */ +#define MS_GET_MIN(a, b) \ + (((a) > (b)) ? (b) : (a)) + +#define MS_GET_MAX(a, b) \ + (((a) > (b)) ? (a) : (b)) + +/* Unreferenced variable macro to avoid compilation warnings */ +#define MS_IGNORE_UNUSED_PARAM(v) (void)(v) + +/* Loop for ever */ +#define MS_LOOP_FOREVER() for(;;) + +#ifdef MS_HAVE_DYNAMIC_CONFIG +#define MS_INIT_CONFIG(config) \ + (config).config_MS_REPLAY_CACHE_SIZE = MS_REPLAY_CACHE_SIZE; \ + (config).config_MS_DEFAULT_COMPANY_ID = MS_DEFAULT_COMPANY_ID; \ + (config).config_MS_DEFAULT_PID = MS_DEFAULT_PID; \ + (config).config_MS_DEFAULT_VID = MS_DEFAULT_VID +#else +#define MS_INIT_CONFIG(config) +#endif /* MS_HAVE_DYNAMIC_CONFIG */ + +#define MS_CONFIG_LIMITS(x) (x) + +#define MS_DEFINE_GLOBAL_ARRAY(type, var, s) \ + type var[(s)] + +#define MS_DECLARE_GLOBAL_ARRAY(type, var, s) \ + extern type var[(s)] + +#define MS_INIT_GLOBAL_ARRAY(type, var, s, i) \ + EM_mem_set(var, (i), ((s) * sizeof(type))) + + +#ifdef MS_HAVE_MODEL_OPCODE_EMPTY_HANDLERS +/* Macro to define an empty model Opcode Handler */ +#define MODEL_OPCODE_HANDLER_EMPTY_DEF(x) \ + static API_RESULT (x) \ + ( \ + MS_ACCESS_MODEL_HANDLE * handle, \ + MS_NET_ADDR saddr, \ + MS_NET_ADDR daddr, \ + MS_SUBNET_HANDLE subnet_handle, \ + MS_APPKEY_HANDLE appkey_handle, \ + UINT32 opcode, \ + UCHAR * data_param, \ + UINT16 data_len \ + ) \ + { \ + API_RESULT retval; \ + \ + MS_IGNORE_UNUSED_PARAM(handle); \ + MS_IGNORE_UNUSED_PARAM(saddr); \ + MS_IGNORE_UNUSED_PARAM(daddr); \ + MS_IGNORE_UNUSED_PARAM(subnet_handle); \ + MS_IGNORE_UNUSED_PARAM(appkey_handle); \ + MS_IGNORE_UNUSED_PARAM(opcode); \ + MS_IGNORE_UNUSED_PARAM(data_param); \ + MS_IGNORE_UNUSED_PARAM(data_len); \ + \ + retval = API_SUCCESS; \ + \ + return retval; \ + } + +/* Callback Handler */ +#define MODEL_OPCODE_HANDLER_CALL(handler) \ + (handler) (handle, saddr, daddr, subnet_handle, appkey_handle, opcode, data_param, data_len) +#else +/* Macro to define an empty model Opcode Handler */ +#define MODEL_OPCODE_HANDLER_EMPTY_DEF(x) + +/* Callback Handler */ +#define MODEL_OPCODE_HANDLER_CALL(handler) +#endif /* MS_HAVE_MODEL_OPCODE_EMPTY_HANDLERS */ + +#define MS_STREAM_REV_ENDIANNESS(s, d, n) \ + { \ + UCHAR i; \ + for (i = 0; i < (n); i++) \ + { \ + (d)[(n - 1) - i] = (s)[i]; \ + } \ + } + +/** \} */ + +/** + \addtogroup ms_common_constants Constants + \{ +*/ + +/* + Module Identifier definitions. + Currently used for runtime debug enable/disable scenario. + In future, this can be used for other purposes as well, + hence these defines are placed under common header file. +*/ +/* Page 4 - Bluetooth Protocol Modules */ +#define MS_MODULE_PAGE_4 0x40000000 + +/* Module - Bit Mask */ +#define MS_MODULE_BIT_MASK_COMMON 0x00000001 +#define MS_MODULE_BIT_MASK_BRR 0x00000002 +#define MS_MODULE_BIT_MASK_NET 0x00000004 +#define MS_MODULE_BIT_MASK_LTRN 0x00000008 +#define MS_MODULE_BIT_MASK_TRN 0x00000010 +#define MS_MODULE_BIT_MASK_ACCESS 0x00000020 +#define MS_MODULE_BIT_MASK_APP 0x00000040 +#define MS_MODULE_BIT_MASK_STBX 0x00000080 +#define MS_MODULE_BIT_MASK_CONFIG 0x00000100 +#define MS_MODULE_BIT_MASK_FSM 0x00000200 +#define MS_MODULE_BIT_MASK_PROV 0x00000400 +#define MS_MODULE_BIT_MASK_MESH_MODEL 0x00000800 + +/* Module ID */ +#define MS_MODULE_ID_COMMON (MS_MODULE_PAGE_4 | MS_MODULE_BIT_MASK_COMMON) +#define MS_MODULE_ID_BRR (MS_MODULE_PAGE_4 | MS_MODULE_BIT_MASK_BRR) +#define MS_MODULE_ID_NET (MS_MODULE_PAGE_4 | MS_MODULE_BIT_MASK_NET) +#define MS_MODULE_ID_LTRN (MS_MODULE_PAGE_4 | MS_MODULE_BIT_MASK_LTRN) +#define MS_MODULE_ID_TRN (MS_MODULE_PAGE_4 | MS_MODULE_BIT_MASK_TRN) +#define MS_MODULE_ID_ACCESS (MS_MODULE_PAGE_4 | MS_MODULE_BIT_MASK_ACCESS) +#define MS_MODULE_ID_APP (MS_MODULE_PAGE_4 | MS_MODULE_BIT_MASK_APP) +#define MS_MODULE_ID_STBX (MS_MODULE_PAGE_4 | MS_MODULE_BIT_MASK_STBX) +#define MS_MODULE_ID_CONFIG (MS_MODULE_PAGE_4 | MS_MODULE_BIT_MASK_CONFIG) +#define MS_MODULE_ID_FSM (MS_MODULE_PAGE_4 | MS_MODULE_BIT_MASK_FSM) +#define MS_MODULE_ID_PROV (MS_MODULE_PAGE_4 | MS_MODULE_BIT_MASK_PROV) +#define MS_MODULE_ID_MESH_MODEL (MS_MODULE_PAGE_4 | MS_MODULE_BIT_MASK_MESH_MODEL) + +/** Device UUID Size */ +#define MS_DEVICE_UUID_SIZE 16 + +/** Beacon Type - Size */ +#define MS_BCON_TYPE_SIZE 1 + +/** Beacon OOB Indicator Size */ +#define MS_BCON_OOB_IND_SIZE 2 + +/** Beacon URI Hash Size */ +#define MS_BCON_URI_HASH_SIZE 4 + +/** Beacon Types */ +/** Unprovisioned Device Beacon Type */ +#define MS_BCON_TYPE_UNPRVSNG_DEV 0x00 + +/* Secure Network Beacon Type */ +#define MS_BCON_TYPE_SECURE 0x01 + +/** Friend Role */ +/* Invalid */ +#define MS_FRND_ROLE_INVALID 0x00 + +/* Friend */ +#define MS_FRND_ROLE_FRIEND 0x01 + +/* LPN */ +#define MS_FRND_ROLE_LPN 0x02 + +/** Relay Feature */ +#define MS_FEATURE_RELAY 0x00 +/** Proxy Feature */ +#define MS_FEATURE_PROXY 0x01 +/** Friend Feature */ +#define MS_FEATURE_FRIEND 0x02 +/** Low Power Feature */ +#define MS_FEATURE_LPN 0x03 + +/** Secure Nework Beacon */ +#define MS_FEATURE_SEC_NET_BEACON 0x04 + +/** Operation: Enable */ +#define MS_ENABLE 0x01 +/** Operation: Disable */ +#define MS_DISABLE 0x00 +/** + Feature not supported. + Used as stutus for Get/Set Friend/Proxy etc., + when the feature is not supported. +*/ +#define MS_NOT_SUPPORTED 0x02 + +/** Network Tx State */ +#define MS_NETWORK_TX_STATE 0x00 +/** Relay Tx State */ +#define MS_RELAY_TX_STATE 0x01 + +/** Label UUID Length. Associated with Virtual Address */ +#define MS_LABEL_UUID_LENGTH 16 + +/** \} */ + +/* -------------------------------------------- Structures/Data Types */ + +/** + \addtogroup ms_common_defines Defines + \{ +*/ + +/** + \defgroup ms_common_structures Structures + \{ +*/ +/** Payload type */ +typedef struct _MS_BUFFER +{ + /* Payload Pointer */ + UCHAR* payload; + + /* Payload Length */ + UINT16 length; + +} MS_BUFFER; + +/** + Dynamic configuration of Mesh Datastructure. + Used only if 'MS_HAVE_DYNAMIC_GLOBAL_ARRAY' is defined. +*/ +typedef struct _MS_CONFIG +{ + /** The size of the Replay Protection cache. */ + UINT16 config_MS_REPLAY_CACHE_SIZE; + + /** Company ID */ + UINT16 config_MS_DEFAULT_COMPANY_ID; + + /** Product ID */ + UINT16 config_MS_DEFAULT_PID; + + /** Vendor ID */ + UINT16 config_MS_DEFAULT_VID; + +} MS_CONFIG; + +/** \} */ + +/** \} */ + +/* -------------------------------------------- Function/API Declarations */ +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef MS_HAVE_DYNAMIC_CONFIG +/* Global Configuration for Mesh Stack */ +extern MS_CONFIG ms_global_config; +#endif /* MS_HAVE_DYNAMIC_CONFIG */ + +/** + \defgroup ms_common_api API Definitions + \{ +*/ + +/** + API to initialize Mesh Stack. This is the first API that the + application should call before any other API. This function + initializes all the internal stack modules and creates necessary tasks. + + \note +*/ + +/** + \brief To initialize Mesh Stack. + + \par Description + API to initialize Mesh Stack. This is the first API that the + application should call before any other API. This function + initializes all the internal stack modules and data structures. + + \param [in] blob + If 'MS_HAVE_DYNAMIC_CONFIG' defined, + application shall provide the desired dynamic configuration + using a pointer to MS_CONFIG data structure instance. + else, + this parameter shall be NULL and ignored by the API. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +void MS_init +( + /* IN */ void* blob +); + +/** + API to turn off Bluetooth Hardware. This API should be called after + \ref MS_init. + + \return + \ref API_RESULT on successful Bluetooth OFF +*/ +API_RESULT MS_shutdown +( + void +); + +/** + \brief To start transition timer. + + \par Description + API to start a transition timer. + + \param [in] transition + State Transition data structure, which includes the timeout, + transition start and complete callback etc. + + \param [out] transition_time_handle + Transition Time Handle, which can be used to stop the transition + timer if required. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_common_start_transition_timer +( + /* IN */ MS_ACCESS_STATE_TRANSITION_TYPE* transition, + /* OUT */ UINT16* transition_time_handle +); + +/** + \brief To stop transition timer. + + \par Description + API to stop a transition timer. + + \param [in] transition_time_handle + Transition Time Handle, returned by the Start Transition Timer + interface. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_common_stop_transition_timer +( + /* IN */ UINT16 transition_time_handle +); + +/** + \brief To get remaining Transition Time. + + \par Description + API to get remaining Transition Time. + + \param [in] transition_time_handle + Transition Time Handle, returned by the Start Transition Timer + interface. + + \param [out] remaining_transition_time + Remaining Transition Time. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_common_get_remaining_transition_time +( + /* IN */ UINT16 transition_time_handle, + /* OUT */ UINT8* remaining_transition_time +); + +/** + \brief To get remaining Transition Time, with offset. + + \par Description + API to get remaining Transition Time with offset in ms. + + \param [in] transition_time_handle + Transition Time Handle, returned by the Start Transition Timer + interface. + + \param [in] offset_in_ms + Offset in ms. + + \param [out] remaining_transition_time + Remaining Transition Time. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_common_get_remaining_transition_time_with_offset +( + /* IN */ UINT16 transition_time_handle, + /* IN */ UINT32 offset_in_ms, + /* OUT */ UINT8* remaining_transition_time +); + +/** + \brief To convert transition time from milisecond. + + \par Description + API to convert transition timer in milisecond to Generic Default + Transition Time state format. + + \param [in] transition_time_in_ms + Transition Time in milisecond. + + \param [out] transition_time + Converted value in Generic Default Transition Time state format. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_common_get_transition_time_from_ms +( + /* IN */ UINT32 transition_time_in_ms, + /* OUT */ UINT8* transition_time +); + +/** + \cond ignore_this Ignore this function while generating doxygen document +*/ + +/* Internal Function */ +API_RESULT ms_common_init_transition_timer(void); + + +/* Internal Function */ +API_RESULT ms_internal_verificaiton_check(void); +/** + \endcond +*/ + +#ifdef __cplusplus +}; +#endif + +/** \} */ + +/** \} */ + +#endif /* _H_MS_COMMON_ */ + diff --git a/src/components/ethermind/mesh/export/include/MS_config_api.h b/src/components/ethermind/mesh/export/include/MS_config_api.h new file mode 100644 index 0000000..486ab2d --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_config_api.h @@ -0,0 +1,1780 @@ + +/** + \file MS_config_api.h + + \brief This file defines the Mesh Configuration Foundation Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_CONFIG_API_ +#define _H_MS_CONFIG_API_ + + +/* --------------------------------------------- Header File Inclusion */ +/* Access Layer */ +#include "MS_access_api.h" + + +/* --------------------------------------------- Global Definitions */ + +/** + \defgroup config_module CONFIG (Mesh Configuration Model) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Configuration Model (CONFIG) module to the Application. +*/ + +/** + \defgroup config_defines Defines + \{ + Describes defines for the module. +*/ + +/** + \defgroup config_constants Constants + \{ + Describes Constants defined by the module. +*/ + +/** + \defgroup config_status Status Codes + \{ + This section lists the Status Codes applicable at the Configuration Model. +*/ + +/** \} */ + +/** \} */ + +/** \} */ + +/** + \defgroup config_events Events + \{ + This section lists the Asynchronous Events notified to Application by the + Module. +*/ + +/** \} */ + +/** + \defgroup config_marcos Utility Macros + \{ + This section defines the utility macros for use by the application. + +*/ + +/** \} */ + +/* --------------------------------------------- Data Types/ Structures */ + +/** + \defgroup config_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ +/** + Configuration Client application Asynchronous Notification Callback. + + Configuration Client calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param opcode Opcode. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef API_RESULT (* MS_CONFIG_MODEL_CB) +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT32 opcode, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; +/** \} */ + +/** + \defgroup config_structures Structures + \{ +*/ + +/** + \defgroup config_cli_structs Configuration Client Data Structures + \{ + This section describes the data structures for use in Configuration Client APIs. +*/ + +/** + Beacon Set parameter structure +*/ +typedef struct _ACCESS_CONFIG_BEACON_SET_PARAM +{ + /** New Secure Network Beacon state */ + UCHAR beacon; + +} ACCESS_CONFIG_BEACON_SET_PARAM; + +/** + Composition Data Get parameter structure +*/ +typedef struct _ACCESS_CONFIG_COMPDATA_GET_PARAM +{ + /** Page number of the Composition Data */ + UCHAR page; + +} ACCESS_CONFIG_COMPDATA_GET_PARAM; + +/** + Default TTL Set parameter structure +*/ +typedef struct _ACCESS_CONFIG_DEFAULT_TTL_SET_PARAM +{ + /** New Default TTL value */ + UCHAR ttl; + +} ACCESS_CONFIG_DEFAULT_TTL_SET_PARAM; + +/** + GATT Proxy Set parameter structure +*/ +typedef struct _ACCESS_CONFIG_GATT_PROXY_SET_PARAM +{ + /** New GATT Proxy state */ + UCHAR proxy; + +} ACCESS_CONFIG_GATT_PROXY_SET_PARAM; + +/** + Relay Set parameter structure +*/ +typedef struct _ACCESS_CONFIG_RELAY_SET_PARAM +{ + /** Relay */ + UCHAR relay; + + /** + Number of retransmissions on advertising bearer for + each Network PDU relayed by the node + - 3 bits validity + */ + UCHAR relay_rtx_count; + + /** + Number of 10-millisecond steps between retransmissions + - 5 bits validity + */ + UCHAR relay_rtx_interval_steps; + +} ACCESS_CONFIG_RELAY_SET_PARAM; + +/** + Model Publication Get parameter structure +*/ +typedef struct _ACCESS_CONFIG_MODELPUB_GET_PARAM +{ + /** Address of the element */ + UINT16 element_address; + + /** SIG Model ID or Vendor Model ID */ + MS_ACCESS_MODEL_ID model; + +} ACCESS_CONFIG_MODELPUB_GET_PARAM; + +/** + Model Publication Set parameter structure +*/ +typedef struct _ACCESS_CONFIG_MODELPUB_SET_PARAM +{ + /** Address of the element */ + UINT16 element_address; + + /** Value of the publish address */ + UINT16 publish_address; + + /** + Index of the application key + - 12 bits validity + */ + UINT16 appkey_index; + + /** + Value of the Friendship Credential Flag + - 1 bit validity + */ + UCHAR credential_flag; + + /** Default TTL value for the outgoing messages */ + UCHAR publish_ttl; + + /** Period for periodic status publishing */ + UCHAR publish_period; + + /** + Number of retransmissions for each published message + - 3 bits validity + */ + UCHAR publish_rtx_count; + + /** + Number of 50-millisecond steps between retransmissions + - 5 bits validity + */ + UCHAR publish_rtx_interval_steps; + + /** SIG Model ID or Vendor Model ID */ + MS_ACCESS_MODEL_ID model; + +} ACCESS_CONFIG_MODELPUB_SET_PARAM; + +/** + Model Publication Virtual Address Set parameter structure +*/ +typedef struct _ACCESS_CONFIG_MODELPUB_VADDR_SET_PARAM +{ + /** Address of the element */ + UINT16 element_address; + + /** Value of the Label UUID publish address */ + UCHAR publish_address[MS_ACCESS_VADDR_LABEL_UUID_SIZE]; + + /** + Index of the application key + - 12 bits validity + */ + UINT16 appkey_index; + + /** + Value of the Friendship Credential Flag + - 1 bit validity + */ + UCHAR credential_flag; + + /** Default TTL value for the outgoing messages */ + UCHAR publish_ttl; + + /** Period for periodic status publishing */ + UCHAR publish_period; + + /** + Number of retransmissions for each published message + - 3 bits validity + */ + UCHAR publish_rtx_count; + + /** + Number of 50-millisecond steps between retransmissions + - 5 bits validity + */ + UCHAR publish_rtx_interval_steps; + + /** SIG Model ID or Vendor Model ID */ + MS_ACCESS_MODEL_ID model; + +} ACCESS_CONFIG_MODELPUB_VADDR_SET_PARAM; + +/** + Model Subscription Add parameter structure +*/ +typedef struct _ACCESS_CONFIG_MODELSUB_ADD_PARAM +{ + /** Address of the element */ + UINT16 element_address; + + /** Value of the address */ + UINT16 address; + + /** SIG Model ID or Vendor Model ID */ + MS_ACCESS_MODEL_ID model; + +} ACCESS_CONFIG_MODELSUB_ADD_PARAM; + +/** + Model Subscription Virtual Address Add parameter structure +*/ +typedef struct _ACCESS_CONFIG_MODELSUB_VADDR_ADD_PARAM +{ + /** Address of the element */ + UINT16 element_address; + + /** Value of the Label UUID */ + UCHAR label[MS_ACCESS_VADDR_LABEL_UUID_SIZE]; + + /** SIG Model ID or Vendor Model ID */ + MS_ACCESS_MODEL_ID model; + +} ACCESS_CONFIG_MODELSUB_VADDR_ADD_PARAM; + +/** + Model Subscription Delete parameter structure +*/ +typedef struct _ACCESS_CONFIG_MODELSUB_DEL_PARAM +{ + /** Address of the element */ + UINT16 element_address; + + /** Value of the address */ + UINT16 address; + + /** SIG Model ID or Vendor Model ID */ + MS_ACCESS_MODEL_ID model; + +} ACCESS_CONFIG_MODELSUB_DEL_PARAM; + +/** + Model Subscription Virtual Address Delete parameter structure +*/ +typedef struct _ACCESS_CONFIG_MODELSUB_VADDR_DEL_PARAM +{ + /** Address of the element */ + UINT16 element_address; + + /** Value of the Label UUID */ + UCHAR label[MS_ACCESS_VADDR_LABEL_UUID_SIZE]; + + /** SIG Model ID or Vendor Model ID */ + MS_ACCESS_MODEL_ID model; + +} ACCESS_CONFIG_MODELSUB_VADDR_DEL_PARAM; + +/** + Model Subscription Overwrite parameter structure +*/ +typedef struct _ACCESS_CONFIG_MODELSUB_OVERWRITE_PARAM +{ + /** Address of the element */ + UINT16 element_address; + + /** Value of the address */ + UINT16 address; + + /** SIG Model ID or Vendor Model ID */ + MS_ACCESS_MODEL_ID model; + +} ACCESS_CONFIG_MODELSUB_OVERWRITE_PARAM; + +/** + Model Subscription Virtual Address Overwrite parameter structure +*/ +typedef struct _ACCESS_CONFIG_MODELSUB_VADDR_OVERWRITE_PARAM +{ + /** Address of the element */ + UINT16 element_address; + + /** Value of the Label UUID */ + UCHAR label[MS_ACCESS_VADDR_LABEL_UUID_SIZE]; + + /** SIG Model ID or Vendor Model ID */ + MS_ACCESS_MODEL_ID model; + +} ACCESS_CONFIG_MODELSUB_VADDR_OVERWRITE_PARAM; + +/** + Model Subscription Delete All parameter structure +*/ +typedef struct _ACCESS_CONFIG_MODELSUB_DELETEALL_PARAM +{ + /** Address of the element */ + UINT16 element_address; + + /** SIG Model ID or Vendor Model ID */ + MS_ACCESS_MODEL_ID model; + +} ACCESS_CONFIG_MODELSUB_DELETEALL_PARAM; + +/** + SIG Model Subscription Get parameter structure +*/ +typedef struct _ACCESS_CONFIG_SIGMODELSUB_GET_PARAM +{ + /** Address of the element */ + UINT16 element_address; + + /** SIG Model ID */ + MS_ACCESS_MODEL_ID_SIG model_id; + +} ACCESS_CONFIG_SIGMODELSUB_GET_PARAM; + +/** + Vendor Model Subscription Get parameter structure +*/ +typedef struct _ACCESS_CONFIG_VENDORMODELSUB_GET_PARAM +{ + /** Address of the element */ + UINT16 element_address; + + /** Vendor Model ID */ + MS_ACCESS_MODEL_ID_VENDOR model_id; + +} ACCESS_CONFIG_VENDORMODELSUB_GET_PARAM; + +/** + Netkey Add parameter structure +*/ +typedef struct _ACCESS_CONFIG_NETKEY_ADD_PARAM +{ + /** Netkey */ + UCHAR netkey[MS_ACCESS_NETKEY_SIZE]; + + /** Netkey Index */ + UINT16 netkey_index; + +} ACCESS_CONFIG_NETKEY_ADD_PARAM; + +/** + Netkey Update parameter structure +*/ +typedef struct _ACCESS_CONFIG_NETKEY_UPDATE_PARAM +{ + /** New Netkey */ + UCHAR netkey[MS_ACCESS_NETKEY_SIZE]; + + /** Netkey Index */ + UINT16 netkey_index; + +} ACCESS_CONFIG_NETKEY_UPDATE_PARAM; + +/** + Netkey Delete parameter structure +*/ +typedef struct _ACCESS_CONFIG_NETKEY_DELETE_PARAM +{ + /** Netkey Index */ + UINT16 netkey_index; + +} ACCESS_CONFIG_NETKEY_DELETE_PARAM; + +/** + Appkey Add parameter structure +*/ +typedef struct _ACCESS_CONFIG_APPKEY_ADD_PARAM +{ + /** Appkey value */ + UCHAR appkey[MS_ACCESS_APPKEY_SIZE]; + + /** + Index of the NetKey and index of the AppKey + - 24 bits valid + */ + UINT16 netkey_index; + UINT16 appkey_index; + +} ACCESS_CONFIG_APPKEY_ADD_PARAM; + +/** + Appkey Update parameter structure +*/ +typedef struct _ACCESS_CONFIG_APPKEY_UPDATE_PARAM +{ + /** New Appkey value */ + UCHAR appkey[MS_ACCESS_APPKEY_SIZE]; + + /** + Index of the NetKey and index of the AppKey + - 24 bits valid + */ + UINT16 netkey_index; + UINT16 appkey_index; + +} ACCESS_CONFIG_APPKEY_UPDATE_PARAM; + +/** + Appkey Delete parameter structure +*/ +typedef struct _ACCESS_CONFIG_APPKEY_DELETE_PARAM +{ + /** + Index of the NetKey and index of the AppKey + - 24 bits valid + * */ + UINT16 netkey_index; + UINT16 appkey_index; + +} ACCESS_CONFIG_APPKEY_DELETE_PARAM; + +/** + Appkey Get parameter structure +*/ +typedef struct _ACCESS_CONFIG_APPKEY_GET_PARAM +{ + /** Index of the NetKey */ + UINT16 netkey_index; + +} ACCESS_CONFIG_APPKEY_GET_PARAM; + +/** + Node Identity Get parameter structure +*/ +typedef struct _ACCESS_CONFIG_NODEID_GET_PARAM +{ + /** Index of the NetKey */ + UINT16 netkey_index; + +} ACCESS_CONFIG_NODEID_GET_PARAM; + +/** + Node Identity Set parameter structure +*/ +typedef struct _ACCESS_CONFIG_NODEID_SET_PARAM +{ + /** Index of the NetKey */ + UINT16 netkey_index; + + /** New Node Identity state */ + UCHAR identity; + +} ACCESS_CONFIG_NODEID_SET_PARAM; + +/** + Model App Bind parameter structure +*/ +typedef struct _ACCESS_CONFIG_MODEL_APP_BIND_PARAM +{ + /** Address of the element */ + UINT16 element_address; + + /** Index of the AppKey */ + UINT16 appkey_index; + + /** SIG Model ID or Vendor Model ID */ + MS_ACCESS_MODEL_ID model; + + /** + Local SIG Model ID or Vendor Model ID. + Used only for MS_config_client_model_app_bind(). + */ + MS_ACCESS_MODEL_ID client_model; + +} ACCESS_CONFIG_MODEL_APP_BIND_PARAM; + +/** + Model App Unbind parameter structure +*/ +typedef struct _ACCESS_CONFIG_MODEL_APP_UNBIND_PARAM +{ + /** Address of the element */ + UINT16 element_address; + + /** Index of the AppKey */ + UINT16 appkey_index; + + /** SIG Model ID or Vendor Model ID */ + MS_ACCESS_MODEL_ID model; + + /** + Local SIG Model ID or Vendor Model ID. + Used only for MS_config_client_model_app_unbind(). + */ + MS_ACCESS_MODEL_ID client_model; + +} ACCESS_CONFIG_MODEL_APP_UNBIND_PARAM; + +/** + SIG Model App Get parameter structure +*/ +typedef struct _ACCESS_CONFIG_SIG_MODEL_APP_GET_PARAM +{ + /** Address of the element */ + UINT16 element_address; + + /** SIG Model ID */ + MS_ACCESS_MODEL_ID_SIG model_id; + +} ACCESS_CONFIG_SIG_MODEL_APP_GET_PARAM; + +/** + Vendor Model App Get parameter structure +*/ +typedef struct _ACCESS_CONFIG_VENDOR_MODEL_APP_GET_PARAM +{ + /** Address of the element */ + UINT16 element_address; + + /** Vendor Model ID */ + MS_ACCESS_MODEL_ID_VENDOR model_id; + +} ACCESS_CONFIG_VENDOR_MODEL_APP_GET_PARAM; + +/** + Friend Set parameter structure +*/ +typedef struct _ACCESS_CONFIG_FRIEND_SET_PARAM +{ + /** New Friend state */ + UCHAR friend; + +} ACCESS_CONFIG_FRIEND_SET_PARAM; + +/** + Key Refresh Phase Get parameter structure +*/ +typedef struct _ACCESS_CONFIG_KEYREFRESH_PHASE_GET_PARAM +{ + /** Netkey Index */ + UINT16 netkey_index; + +} ACCESS_CONFIG_KEYREFRESH_PHASE_GET_PARAM; + +/** + Key Refresh Phase Set parameter structure +*/ +typedef struct _ACCESS_CONFIG_KEYREFRESH_PHASE_SET_PARAM +{ + /** Netkey Index */ + UINT16 netkey_index; + + /** New Key Refresh Phase Transition */ + UCHAR transition; + +} ACCESS_CONFIG_KEYREFRESH_PHASE_SET_PARAM; + +/** + Heartbeat Publication Set parameter structure +*/ +typedef struct _ACCESS_CONFIG_HEARTBEATPUB_SET_PARAM +{ + /** Destination address for Heartbeat messages */ + UINT16 destination; + + /** Number of Heartbeat messages to be sent */ + UCHAR countlog; + + /** Period for sending Heartbeat messages */ + UCHAR periodlog; + + /** TTL to be used when sending Heartbeat messages */ + UCHAR ttl; + + /** + Bit field indicating features that trigger + Heartbeat messages when changed + */ + UINT16 features; + + /** Netkey Index */ + UINT16 netkey_index; + +} ACCESS_CONFIG_HEARTBEATPUB_SET_PARAM; + +/** + Heartbeat Subscription Set parameter structure +*/ +typedef struct _ACCESS_CONFIG_HEARTBEATSUB_SET_PARAM +{ + /** Source address for Heartbeat messages */ + UINT16 source; + + /** Destination address for Heartbeat messages */ + UINT16 destination; + + /** Period for receiving Heartbeat messages */ + UCHAR periodlog; + +} ACCESS_CONFIG_HEARTBEATSUB_SET_PARAM; + +/** + Low Power Node PollTimeout Get parameter structure +*/ +typedef struct _ACCESS_CONFIG_LPNPOLLTIMEOUT_GET_PARAM +{ + /** The unicast address of the Low Power node */ + UINT16 lpn_address; + +} ACCESS_CONFIG_LPNPOLLTIMEOUT_GET_PARAM; + +/** + Network Transmit Set parameter structure +*/ +typedef struct _ACCESS_CONFIG_NETWORK_TRANSMIT_SET_PARAM +{ + /** + Number of transmissions for each Network PDU + originating from the node + - 3 bits validity + */ + UCHAR net_tx_count; + + /** + Number of 10-millisecond steps between transmissions + - 5 bits validity + */ + UCHAR net_tx_interval_steps; + +} ACCESS_CONFIG_NETWORK_TRANSMIT_SET_PARAM; + +/** \} */ + +/** \} */ + + +/* --------------------------------------------- Function */ + +/** + \defgroup config_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Config Model APIs. +*/ + +/** + \defgroup config_cli_api_defs Configuration Client API Definitions + \{ + This section describes the Configuration Client APIs. +*/ + +/** + \brief API to initialize Configuration Client model + + \par Description + This is to initialize Configuration Client model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Configuration Client. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_config_client_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_CONFIG_MODEL_CB appl_cb +); + +API_RESULT MS_config_client_set_publish_address +( + /* IN */ MS_NET_ADDR pub_addr +); + + +/** + \brief API to set configuration server + + \par Description + This is to sets the information about server which is to be configured. + + \param [in] server_addr Address of Configuration Server. + \param [in] dev_key Device Key of Configuration Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_config_client_set_server +( + /* IN */ MS_NET_ADDR server_addr, + /* IN */ UCHAR* dev_key +); + +/** + \brief API to send acknowledged commands + + \par Description + This is to initialize sending acknowledged commands. + + \param [in] req_opcode Request Opcode. + \param [in] param Parameter associated with Request Opcode. + \param [in] rsp_opcode Response Opcode. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_config_client_send_reliable_pdu +( + /* IN */ UINT32 req_opcode, + /* IN */ void* param, + /* IN */ UINT32 rsp_opcode +); + +/** + \brief API to get the secure network beacon state + + \par Description + The Config Beacon Get is an acknowledged message used to get the current + Secure Network Beacon state of a node. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_beacon_get() \ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_BEACON_GET_OPCODE,\ + NULL,\ + MS_ACCESS_CONFIG_BEACON_STATUS_OPCODE \ + ) + +/** + \brief API to set the secure network beacon state + + \par Description + The Config Beacon Set is an acknowledged message used to set the current + Secure Network Beacon state of a node. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_BEACON_SET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_beacon_set(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_BEACON_SET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_BEACON_STATUS_OPCODE \ + ) + +/** + \brief API to get the composition data state + + \par Description + The Config Composition Data Get is an acknowledged message used to read + one page of the Composition Data. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_COMPDATA_GET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_composition_data_get(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_COMPOSITION_DATA_GET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_COMPOSITION_DATA_STATUS_OPCODE \ + ) + +/** + \brief API to get the default TTL state + + \par Description + Config Default TTL Get is an acknowledged message used to get the current + Default TTL state of a node. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_default_ttl_get()\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_DEFAULT_TTL_GET_OPCODE,\ + NULL, \ + MS_ACCESS_CONFIG_DEFAULT_TTL_STATUS_OPCODE \ + ) + +/** + \brief API to set the default TTL state + + \par Description + The Config Default TTL Set is an acknowledged message used to set the + Default TTL state of a node. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_DEFAULT_TTL_SET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_default_ttl_set(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_DEFAULT_TTL_SET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_DEFAULT_TTL_STATUS_OPCODE \ + ) + +/** + \brief API to get the GATT proxy state + + \par Description + The Config GATT Proxy Get is an acknowledged message used to get the GATT + Proxy state of a node. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_gatt_proxy_get()\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_GATT_PROXY_GET_OPCODE,\ + NULL, \ + MS_ACCESS_CONFIG_GATT_PROXY_STATUS_OPCODE \ + ) + +/** + \brief API to set the GATT Proxy state + + \par Description + The Config GATT Proxy Set is an acknowledged message used to set the + GATT Proxy state of a node. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_GATT_PROXY_SET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_gatt_proxy_set(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_GATT_PROXY_SET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_GATT_PROXY_STATUS_OPCODE \ + ) + +/** + \brief API to get the relay state + + \par Description + The Config Relay Get is an acknowledged message used to get the current + Relay and Relay Retransmit states of a node. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_relay_get()\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_RELAY_GET_OPCODE,\ + NULL, \ + MS_ACCESS_CONFIG_RELAY_STATUS_OPCODE \ + ) + +/** + \brief API to set the relay state + + \par Description + The Config Relay Set is an acknowledged message used to set the current + Relay and Relay Retransmit states of a node. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_RELAY_SET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_relay_set(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_RELAY_SET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_RELAY_STATUS_OPCODE \ + ) + +/** + \brief API to get the model publication state + + \par Description + The Config Model Publication Get is an acknowledged message used to get + the publish address and parameters of an outgoing message that originates + from a model. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_MODELPUB_GET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_model_publication_get(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_MODEL_PUBLICATION_GET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_MODEL_PUBLICATION_STATUS_OPCODE \ + ) + +/** + \brief API to set the model publication state + + \par Description + The Config Model Publication Set is an acknowledged message used to set + the Model Publication state of an outgoing message that + originates from a model. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_MODELPUB_SET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_model_publication_set(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_MODEL_PUBLICATION_SET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_MODEL_PUBLICATION_STATUS_OPCODE \ + ) + +/** + \brief API to set the model publication state + + \par Description + The Config Model Publication Set is an acknowledged message used to set + the Model Publication state of an outgoing message that + originates from a model. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_MODELPUB_VADDR_SET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_model_publication_vaddr_set(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_MODEL_PUBLICATION_VIRTUAL_ADDRESS_SET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_MODEL_PUBLICATION_STATUS_OPCODE \ + ) + +/** + \brief API to add subscription address + + \par Description + The Config Model Subscription Add is an acknowledged message used to + add an address to a Subscription List of a model. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_MODELSUB_ADD_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_model_subscription_add(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_ADD_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_STATUS_OPCODE \ + ) + +/** + \brief API to add subscription address + + \par Description + The Config Model Subscription Add is an acknowledged message used to + add an address to a Subscription List of a model. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_MODELSUB_VADDR_ADD_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_model_subscription_vaddr_add(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_ADD_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_STATUS_OPCODE \ + ) + +/** + \brief API to delete subscription address + + \par Description + The Config Model Subscription Delete is an acknowledged message used to + delete a subscription address from the Subscription List of a model. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_MODELSUB_DEL_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_model_subscription_delete(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_DELETE_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_STATUS_OPCODE \ + ) + +/** + \brief API to delete subscription address + + \par Description + The Config Model Subscription Delete is an acknowledged message used to + delete a subscription address from the Subscription List of a model. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_MODELSUB_VADDR_DEL_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_model_subscription_vaddr_delete(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_DELETE_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_STATUS_OPCODE \ + ) + +/** + \brief API to add subscription address to cleared list + + \par Description + The Config Model Subscription Overwrite is an acknowledged message used + to discard the Subscription List and add an address to the cleared + Subscription List of a model. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_MODELSUB_OVERWRITE_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_model_subscription_overwrite(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_OVERWRITE_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_STATUS_OPCODE \ + ) + +/** + \brief API to add subscription address to cleared list + + \par Description + The Config Model Subscription Overwrite is an acknowledged message used + to discard the Subscription List and add an address to the cleared + Subscription List of a model. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_MODELSUB_VADDR_OVERWRITE_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_model_subscription_vaddr_overwrite(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_OVERWRITE_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_STATUS_OPCODE \ + ) + +/** + \brief API to discard subscription list + + \par Description + The Config Model Subscription Delete All is an acknowledged message + used to discard the Subscription List of a model. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_MODELSUB_DELETEALL_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_model_subscription_delete_all(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_DELETE_ALL_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_MODEL_SUBSCRIPTION_STATUS_OPCODE \ + ) + +/** + \brief API to get subscription list + + \par Description + The Config SIG Model Subscription Get is an acknowledged message used to + get the list of subscription addresses of a model within the element. + This message is only for SIG Models. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_SIGMODELSUB_GET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_sig_model_subscription_get(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_SIG_MODEL_SUBSCRIPTION_GET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_SIG_MODEL_SUBSCRIPTION_LIST_OPCODE \ + ) + +/** + \brief API to get subscription list + + \par Description + The Config SIG Model Subscription Get is an acknowledged message used to + get the list of subscription addresses of a model within the element. + This message is only for Vendor Models. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_VENDORMODELSUB_GET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_vendor_model_subscription_get(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_VENDOR_MODEL_SUBSCRIPTION_GET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_VENDOR_MODEL_SUBSCRIPTION_LIST_OPCODE \ + ) + +/** + \brief API to add to Netkey list + + \par Description + The Config NetKey Add is an acknowledged message used to add a NetKey + to a NetKey List on a node. The added NetKey is then used by the node to + authenticate and decrypt messages it receives, as well as authenticate and + encrypt messages it sends. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_NETKEY_ADD_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_netkey_add(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_NETKEY_ADD_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_NETKEY_STATUS_OPCODE \ + ) + +/** + \brief API to update to Netkey list + + \par Description + The Config NetKey Update is an acknowledged message used to update a NetKey + on a node. The updated NetKey is then used by the node to authenticate and + decrypt messages it receives, as well as authenticate and encrypt messages + it sends, as defined by the Key Refresh procedure. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_NETKEY_UPDATE_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_netkey_update(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_NETKEY_UPDATE_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_NETKEY_STATUS_OPCODE \ + ) + +/** + \brief API to delete from Netkey list + + \par Description + The Config NetKey Delete is an acknowledged message used to + delete a NetKey on a NetKey List from a node. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_NETKEY_DELETE_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_netkey_delete(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_NETKEY_DELETE_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_NETKEY_STATUS_OPCODE \ + ) + +/** + \brief API to get Netkey list + + \par Description + The Config NetKey Get is an acknowledged message used to report + all NetKeys known to the node. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_netkey_get()\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_NETKEY_GET_OPCODE,\ + NULL, \ + MS_ACCESS_CONFIG_NETKEY_LIST_OPCODE \ + ) + +/** + \brief API to add to Appkey list + + \par Description + The Config AppKey Add is an acknowledged message used to add an AppKey to + the AppKey List on a node and bind it to the NetKey identified by + NetKeyIndex. The added AppKey can be used by the node only as a pair with + the specified NetKey. The AppKey is used to authenticate and decrypt + messages it receives, as well as authenticate and encrypt messages it sends. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_APPKEY_ADD_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_appkey_add(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_APPKEY_ADD_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_APPKEY_STATUS_OPCODE \ + ) + +/** + \brief API to update to Appkey list + + \par Description + The Config AppKey Update is an acknowledged message used to update an AppKey value + on the AppKey List on a node. The updated AppKey is used by the node to authenticate + and decrypt messages it receives, as well as authenticate and encrypt messages it + sends, as defined by the Key Refresh procedure. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_APPKEY_UPDATE_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_appkey_update(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_APPKEY_UPDATE_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_APPKEY_STATUS_OPCODE \ + ) + +/** + \brief API to delete from Appkey list + + \par Description + The Config AppKey Delete is an acknowledged message used to delete an AppKey + from the AppKey List on a node + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_APPKEY_DELETE_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_appkey_delete(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_APPKEY_DELETE_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_APPKEY_STATUS_OPCODE \ + ) + +/** + \brief API to get the Appkey list + + \par Description + The AppKey Get is an acknowledged message used to report all AppKeys + bound to the NetKey. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_APPKEY_GET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_appkey_get(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_APPKEY_GET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_APPKEY_LIST_OPCODE \ + ) + +/** + \brief API to get the Node Identity state + + \par Description + The Config Node Identity Get is an acknowledged message used to get the + current Node Identity state for a subnet. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_NODEID_GET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_node_identity_get(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_NODE_IDENTITY_GET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_NODE_IDENTITY_STATUS_OPCODE \ + ) + +/** + \brief API to set the Node Identity state + + \par Description + The Config Node Identity Set is an acknowledged message used to set the + current Node Identity state for a subnet. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_NODEID_SET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_node_identity_set(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_NODE_IDENTITY_SET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_NODE_IDENTITY_STATUS_OPCODE \ + ) + +/** + \brief API to bind Appkey to model + + \par Description + The Config Model App Bind is an acknowledged message used to bind an + AppKey to a model. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_MODEL_APP_BIND_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_model_app_bind(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_MODEL_APP_BIND_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_MODEL_APP_STATUS_OPCODE \ + ) + +/** + \brief API to unbind Appkey to model + + \par Description + The Config Model App Unbind is an acknowledged message used to remove the + binding between an AppKey and a model. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_MODEL_APP_UNBIND_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_model_app_unbind(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_MODEL_APP_UNBIND_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_MODEL_APP_STATUS_OPCODE \ + ) + +/** + \brief API to get all SIG model Appkeys + + \par Description + The Config SIG Model App Get is an acknowledged message used to request + report of all AppKeys bound to the SIG Model. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_SIG_MODEL_APP_GET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_sig_model_app_get(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_SIG_MODEL_APP_GET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_SIG_MODEL_APP_LIST_OPCODE \ + ) + +/** + \brief API to get all Vendor model Appkeys + + \par Description + The Config Vendor Model App Get is an acknowledged message used to request + report of all AppKeys bound to the Vendor Model. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_VENDOR_MODEL_APP_GET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_vendor_model_app_get(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_VENDOR_MODEL_APP_GET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_VENDOR_MODEL_APP_LIST_OPCODE \ + ) + +/** + \brief API to reset a node + + \par Description + The Config Node Reset is an acknowledged message used to reset a node + (other than a Provisioner) and remove it from the network. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_node_reset()\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_NODE_RESET_OPCODE,\ + NULL, \ + MS_ACCESS_CONFIG_NODE_RESET_STATUS_OPCODE \ + ) + +/** + \brief API to get friend state + + \par Description + The Config Friend Get is an acknowledged message used to get the + current Friend state of a node. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_friend_get()\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_FRIEND_GET_OPCODE,\ + NULL, \ + MS_ACCESS_CONFIG_FRIEND_STATUS_OPCODE \ + ) + +/** + \brief API to set friend state + + \par Description + The Config Friend Set is an acknowledged message used to set the + Friend state of a node. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_FRIEND_SET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_friend_set(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_FRIEND_SET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_FRIEND_STATUS_OPCODE \ + ) + +/** + \brief API to get key refresh phase state + + \par Description + The Config Key Refresh Phase Get is an acknowledged message used + to get the current Key Refresh Phase state of the identified network key. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_KEYREFRESH_PHASE_GET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_keyrefresh_phase_get(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_KEY_REFRESH_PHASE_GET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_KEY_REFRESH_PHASE_STATUS_OPCODE \ + ) + +/** + \brief API to set key refresh phase state + + \par Description + The Config Key Refresh Phase Set is an acknowledged message used + to set the current Key Refresh Phase state of the identified network key. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_KEYREFRESH_PHASE_SET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_keyrefresh_phase_set(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_KEY_REFRESH_PHASE_SET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_KEY_REFRESH_PHASE_STATUS_OPCODE \ + ) + +/** + \brief API to get heartbeat publication state + + \par Description + The Config Heartbeat Publication Get is an acknowledged message used to get + the current Heartbeat Publication state of an element. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_heartbeat_publication_get()\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_HEARTBEAT_PUBLICATION_GET_OPCODE,\ + NULL, \ + MS_ACCESS_CONFIG_HEARTBEAT_PUBLICATION_STATUS_OPCODE \ + ) + +/** + \brief API to set heartbeat publication state + + \par Description + The Config Heartbeat Publication Set is an acknowledged message + used to set the current Heartbeat Publication state of an element. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_HEARTBEATPUB_SET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_heartbeat_publication_set(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_HEARTBEAT_PUBLICATION_SET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_HEARTBEAT_PUBLICATION_STATUS_OPCODE \ + ) + +/** + \brief API to get heartbeat subscription state + + \par Description + The Config Heartbeat Subscription Get is an acknowledged message used + to get the current Heartbeat Subscription state of an element. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_heartbeat_subscription_get()\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_HEARTBEAT_SUBSCRIPTION_GET_OPCODE,\ + NULL, \ + MS_ACCESS_CONFIG_HEARTBEAT_SUBSCRIPTION_STATUS_OPCODE \ + ) + +/** + \brief API to set heartbeat subscription state + + \par Description + The Config Heartbeat Publication Set is an acknowledged message + used to set the current Heartbeat Subscription state of an element. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_HEARTBEATSUB_SET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_heartbeat_subscription_set(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_HEARTBEAT_SUBSCRIPTION_SET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_HEARTBEAT_SUBSCRIPTION_STATUS_OPCODE \ + ) + +/** + \brief API to get LPN Polltimeout state + + \par Description + The Config Low Power Node PollTimeout Get is an acknowledged message used + to get the current value of PollTimeout timer of the Low Power node within + a Friend node. The message is sent to a Friend node that has claimed to be + handling messages by sending ACKs On Behalf Of (OBO) the indicated Low + Power node. This message should only be sent to a node that has the Friend + feature supported and enabled. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_LPNPOLLTIMEOUT_GET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_lpn_polltimeout_get(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_LOW_POWER_NODE_POLLTIMEOUT_GET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_LOW_POWER_NODE_POLLTIMEOUT_STATUS_OPCODE \ + ) + +/** + \brief API to get Network transmit state + + \par Description + The Config Network Transmit Get is an acknowledged message used to get + the current Network Transmit state of a node. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_network_transmit_get()\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_NETWORK_TRANSMIT_GET_OPCODE,\ + NULL, \ + MS_ACCESS_CONFIG_NETWORK_TRANSMIT_STATUS_OPCODE \ + ) + +/** + \brief API to set Network transmit state + + \par Description + The Config Network Transmit Set is an acknowledged message used to set + the current Network Transmit state of a node. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_CONFIG_NETWORK_TRANSMIT_SET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_config_client_network_transmit_set(param)\ + MS_config_client_send_reliable_pdu \ + (\ + MS_ACCESS_CONFIG_NETWORK_TRANSMIT_SET_OPCODE,\ + (void *)param, \ + MS_ACCESS_CONFIG_NETWORK_TRANSMIT_STATUS_OPCODE \ + ) + +/** \} */ + +/** + \defgroup config_svr_api_defs Configuration Server API Definitions + \{ + This section describes the Configuration Server APIs. +*/ + +/** + \brief API to initialize configuration server model + + \par Description + This is to initialize configuration server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_config_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle +); + + +typedef API_RESULT ( *APP_config_server_CB_t )( + /* IN */ MS_ACCESS_MODEL_HANDLE*, + /* IN */ MS_NET_ADDR, + /* IN */ MS_NET_ADDR, + /* IN */ MS_SUBNET_HANDLE, + /* IN */ MS_APPKEY_HANDLE, + /* IN */ UINT32, + /* IN */ UCHAR*, + /* IN */ UINT16, + /* IN */ API_RESULT, + /* IN */ UINT32, + /* IN */ UCHAR*, + /* IN */ UINT16 ); + +void APP_config_server_CB_init(APP_config_server_CB_t appConfigServerCB); + +/** \} */ + +/** \} */ + +/** \} */ + +#endif /* _H_MS_CONFIG_API_ */ + diff --git a/src/components/ethermind/mesh/export/include/MS_error.h b/src/components/ethermind/mesh/export/include/MS_error.h new file mode 100644 index 0000000..a7d395c --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_error.h @@ -0,0 +1,499 @@ + +/** + \file MS_error.h + + This file lists all the Error Codes returned by EtherMind + Mesh APIs. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_ERROR_ +#define _H_MS_ERROR_ + +/** + \addtogroup ms_common_defines Defines + \{ +*/ + +/** + \defgroup MS_ERROR_CODES Mesh Error Codes + \{ + This section contains all the error codes defined for Mesh stack + and profiles. +

+ \anchor error_code_overview + Theory: +

+ Every API under Mesh Protocol Suite returns \ref API_RESULT, + which is a 2 Byte Unsigned Short variable. The higher order byte + signifies the Module from which the Error has been generated, and + the lower order byte encodes the actual reason of Error. +

+ Each module under Mesh Stack is given unique + Error ID (the higher order byte). Also, for each module the Error + Code (the lower order byte) signifies an unique error situation. +

+ For Mesh Protocol Modules (eg, Transport, Network etc.), Error IDs are + assigned from the range 0x10 to 0x4F. For Profiles, the range + is from 0x50 to 0x7F. +

+ The definition of \ref API_SUCCESS is 0x0000 - which is the 'Success' + return value for an API returning \ref API_RESULT. All other values for + should be treated as Errors. +

+ The definition of \ref API_FAILURE is 0xFFFF - which stands for + "Unknown Error Situation". +

+ Note: +

+ The applications using native/profile Mesh API should NOT do + any check on the basis of \ref API_FAILURE - rather, the correct way to + detect an error situation is by doing a negative check on \ref + API_SUCCESS. +

+ For example, + \code if ( API_FAILURE == MS_access_register_model(x, y, z) ) \endcode + ... Wrong ! +

+

+ \code if ( API_SUCCESS != MS_access_register_model(x, y, z) ) \endcode + ... Correct ! +*/ + +/** + \defgroup ms_error_codes_defines Defines + \{ +*/ + +/** Definition of API_RESULT */ + +#ifndef API_RESULT_DEFINED + typedef UINT16 API_RESULT; + #define API_RESULT_DEFINED +#endif /* API_RESULT_DEFINED */ + +/* Definitions of API_SUCCESS & API_FAILURE */ +#ifdef API_SUCCESS + #undef API_SUCCESS +#endif /* API_SUCCESS */ +/** Status - 'Success' */ +#define API_SUCCESS 0x0000 + +#ifdef API_FAILURE + #undef API_FAILURE +#endif /* API_FAILURE */ +/** Status - 'Failure' */ +#define API_FAILURE 0xFFFF + +/** \} */ + +/* ====================== EtherMind Module Error IDs ====================== */ + +/** + \defgroup ms_error_codes_groups Error Grouping + \{ +*/ + +/** + \defgroup ms_error_codes_groups_std Specification Error Codes (0x00 - 0x0F) + Error IDs for Bluetooth Specification Defined Error Codes (0x00 - 0x0F). + \{ +*/ + +/** Error Codes for Mesh - \ref ms_error_codes_module_mesh */ +#define MS_ERR_ID 0x0000 +/** \cond ignore */ +/** \endcond */ + +/** \} */ + +/** + \defgroup ms_error_codes_groups_core Core Modules (0x10 - 0x1F) + Error IDs for Mesh Core Modules (0x10 - 0x1F). + \{ +*/ + +/** Error Codes for MS Common - \ref ms_error_codes_module_common */ +#define MS_COMMON_ERR_ID 0x1000 +/** Error Codes for Timer - \ref ms_error_codes_module_timer */ +#define TIMER_ERR_ID 0x1200 + +/** \} */ + +/** + \defgroup ms_error_codes_groups_protocols Protocols (0x20 - 0x3F) + Error IDs for Mesh Protocol Modules (0x20 - 0x3F). + \{ +*/ + +/** Error Codes for Bearer - \ref ms_error_codes_module_brr */ +#define BRR_ERR_ID 0x2000 +#define NET_ERR_ID 0x2100 +#define LTRN_ERR_ID 0x2200 +#define TRN_ERR_ID 0x2300 +#define ACCESS_ERR_ID 0x2400 + +#define PROV_ERR_ID 0x3000 + +#define HEALTH_ERR_ID 0x8000 + +/** \} */ + + +/** \} */ + +/** \} */ +/** \} */ + +/* ================== EtherMind Common Reason Error Codes ================= */ + +/** + \addtogroup ms_common_defines Defines + \{ +*/ + +/** + \defgroup ms_error_codes_module_common Common + \{ +*/ + +#define MUTEX_INIT_FAILED 0x0001 +#define COND_INIT_FAILED 0x0002 +#define MUTEX_LOCK_FAILED 0x0003 +#define MUTEX_UNLOCK_FAILED 0x0004 +#define MEMORY_ALLOCATION_FAILED 0x0005 + +/** \} */ +/** \} */ + +/* ======================================= Section 'Mesh' */ +/** + \addtogroup MS_ERROR_CODES + \{ +*/ + +/** + \defgroup ms_error_codes_module_mesh Mesh Result Codes + \{ +*/ +#define MS_SUCCESS (0x0000 | MS_ERR_ID) +/** Invalid Address */ +#define MS_INVALID_ADDRESS (0x0001 | MS_ERR_ID) +/** Invalid Model */ +#define MS_INVALID_MODEL (0x0002 | MS_ERR_ID) +/** Invalid AppKey Index */ +#define MS_INVALID_APPKEY_INDEX (0x0003 | MS_ERR_ID) +/** Invalid NetKey Index */ +#define MS_INVALID_NETKEY_INDEX (0x0004 | MS_ERR_ID) +/** Insufficient Resources */ +#define MS_INSUFFICIENT_RESOURCES (0x0005 | MS_ERR_ID) +/** Key Index Already Stored */ +#define MS_KEY_INDEX_ALREADY_STORED (0x0006 | MS_ERR_ID) +/** Invalid Publish Parameters */ +#define MS_INVALID_PUBLISH_PARAMETER (0x0007 | MS_ERR_ID) +/** Not a Subscribe Model */ +#define MS_NOT_A_SUBSCRIBE_MODEL (0x0008 | MS_ERR_ID) +/** Storage Failure */ +#define MS_STORAGE_FAILURE (0x0009 | MS_ERR_ID) +/** Feature Not Supported */ +#define MS_FEATURE_NOT_SUPPORTED (0x000A | MS_ERR_ID) +/** Cannot Update */ +#define MS_CANNOT_UPDATE (0x000B | MS_ERR_ID) +/** Cannot Remove */ +#define MS_CANNOT_REMOVE (0x000C | MS_ERR_ID) +/** Cannot Bind */ +#define MS_CANNOT_BIND (0x000D | MS_ERR_ID) +/** Temporarily Unable to Change State */ +#define MS_TEMP_UNABLE_TO_CHANGE_STATE (0x000E | MS_ERR_ID) +/** Cannot Set */ +#define MS_CANNOT_SET (0x000F | MS_ERR_ID) +/** Unspecified Error */ +#define MS_UNSPECIFIED_ERROR (0x0010 | MS_ERR_ID) +/** Invalid Binding */ +#define MS_INVALID_BINDING (0x0011 | MS_ERR_ID) + +/** \} */ +/** \} */ + +/* ===================== EtherMind Module Error Codes ===================== */ + +/* ======================================= Section 'Timer' */ +/** + \cond ignore_this + \{ +*/ + +/** + \defgroup ms_error_codes_module_timer Timer + \{ +*/ + +#define TIMER_MUTEX_INIT_FAILED \ + (MUTEX_INIT_FAILED | TIMER_ERR_ID) +#define TIMER_COND_INIT_FAILED \ + (COND_INIT_FAILED | TIMER_ERR_ID) +#define TIMER_MUTEX_LOCK_FAILED \ + (MUTEX_LOCK_FAILED | TIMER_ERR_ID) +#define TIMER_MUTEX_UNLOCK_FAILED \ + (MUTEX_UNLOCK_FAILED | TIMER_ERR_ID) +#define TIMER_MEMORY_ALLOCATION_FAILED \ + (MEMORY_ALLOCATION_FAILED | TIMER_ERR_ID) + +#define TIMER_HANDLE_IS_NULL (0x0011 | TIMER_ERR_ID) +#define TIMER_CALLBACK_IS_NULL (0x0012 | TIMER_ERR_ID) +#define TIMER_QUEUE_EMPTY (0x0013 | TIMER_ERR_ID) +#define TIMER_QUEUE_FULL (0x0014 | TIMER_ERR_ID) +#define TIMER_ENTITY_SEARCH_FAILED (0x0015 | TIMER_ERR_ID) +#define TIMER_NULL_PARAMETER_NOT_ALLOWED (0x0016 | TIMER_ERR_ID) +#define TIMER_TIMEOUT_ZERO_NOT_ALLOWED (0x0017 | TIMER_ERR_ID) + +/** \} */ +/** \} */ + +/* ======================================= Section 'Bearer' */ +/** + \addtogroup brr_defines + \{ +*/ + +/** + \defgroup ms_error_codes_module_brr Error Code + \{ +*/ + +#define BRR_MUTEX_INIT_FAILED \ + (MUTEX_INIT_FAILED | BRR_ERR_ID) +#define BRR_COND_INIT_FAILED \ + (COND_INIT_FAILED | BRR_ERR_ID) +#define BRR_MUTEX_LOCK_FAILED \ + (MUTEX_LOCK_FAILED | BRR_ERR_ID) +#define BRR_MUTEX_UNLOCK_FAILED \ + (MUTEX_UNLOCK_FAILED | BRR_ERR_ID) +#define BRR_MEMORY_ALLOCATION_FAILED \ + (MEMORY_ALLOCATION_FAILED | BRR_ERR_ID) + +#define BRR_INVALID_PARAMETER_VALUE (0x0011 | BRR_ERR_ID) +#define BRR_PARAMETER_OUTSIDE_RANGE (0x0012 | BRR_ERR_ID) +#define BRR_NULL_PARAMETER_NOT_ALLOWED (0x0013 | BRR_ERR_ID) +#define BRR_INTERFACE_NOT_READY (0x0014 | BRR_ERR_ID) +#define BRR_API_NOT_SUPPORTED (0x00FF | BRR_ERR_ID) + +/** \} */ +/** \} */ + +/* ======================================= Section 'Network' */ +/** + \addtogroup net_defines + \{ +*/ + +/** + \defgroup ms_error_codes_module_net Error Code + \{ +*/ + +#define NET_MUTEX_INIT_FAILED \ + (MUTEX_INIT_FAILED | NET_ERR_ID) +#define NET_COND_INIT_FAILED \ + (COND_INIT_FAILED | NET_ERR_ID) +#define NET_MUTEX_LOCK_FAILED \ + (MUTEX_LOCK_FAILED | NET_ERR_ID) +#define NET_MUTEX_UNLOCK_FAILED \ + (MUTEX_UNLOCK_FAILED | NET_ERR_ID) +#define NET_MEMORY_ALLOCATION_FAILED \ + (MEMORY_ALLOCATION_FAILED | NET_ERR_ID) + +#define NET_INVALID_PARAMETER_VALUE (0x0011 | NET_ERR_ID) +#define NET_PARAMETER_OUTSIDE_RANGE (0x0012 | NET_ERR_ID) +#define NET_NULL_PARAMETER_NOT_ALLOWED (0x0013 | NET_ERR_ID) +#define NET_TX_QUEUE_FULL (0x0014 | NET_ERR_ID) +#define NET_TX_QUEUE_EMPTY (0x0015 | NET_ERR_ID) + +/** + Error Codes returned by Network Callback, indicating if it detected + an invalid packet format or if the packet to be further processed, + by the network layer like to be relayed or proxied etc. +*/ +#define NET_INVALID_RX_PKT_FORMAT (0x0016 | NET_ERR_ID) +#define NET_RX_LOCAL_SRC_ADDR_PKT (0x0017 | NET_ERR_ID) +#define NET_POST_PROCESS_RX_PKT (0x0018 | NET_ERR_ID) + +#define NET_API_NOT_SUPPORTED (0x00FF | NET_ERR_ID) + +/** \} */ +/** \} */ + +/* ======================================= Section 'Lower Transport' */ +/** + \addtogroup ltrn_defines + \{ +*/ + +/** + \defgroup ms_error_codes_module_ltrn Error Code + \{ +*/ + +#define LTRN_MUTEX_INIT_FAILED \ + (MUTEX_INIT_FAILED | LTRN_ERR_ID) +#define LTRN_COND_INIT_FAILED \ + (COND_INIT_FAILED | LTRN_ERR_ID) +#define LTRN_MUTEX_LOCK_FAILED \ + (MUTEX_LOCK_FAILED | LTRN_ERR_ID) +#define LTRN_MUTEX_UNLOCK_FAILED \ + (MUTEX_UNLOCK_FAILED | LTRN_ERR_ID) +#define LTRN_MEMORY_ALLOCATION_FAILED \ + (MEMORY_ALLOCATION_FAILED | LTRN_ERR_ID) + +#define LTRN_INVALID_PARAMETER_VALUE (0x0011 | LTRN_ERR_ID) +#define LTRN_PARAMETER_OUTSIDE_RANGE (0x0012 | LTRN_ERR_ID) +#define LTRN_NULL_PARAMETER_NOT_ALLOWED (0x0013 | LTRN_ERR_ID) +#define LTRN_SAR_CTX_ALLOCATION_FAILED (0x0014 | LTRN_ERR_ID) + +/** \} */ +/** \} */ + +/* ======================================= Section 'Transport' */ +/** + \addtogroup trn_defines + \{ +*/ + +/** + \defgroup ms_error_codes_module_trn Error Code + \{ +*/ + +#define TRN_MUTEX_INIT_FAILED \ + (MUTEX_INIT_FAILED | TRN_ERR_ID) +#define TRN_COND_INIT_FAILED \ + (COND_INIT_FAILED | TRN_ERR_ID) +#define TRN_MUTEX_LOCK_FAILED \ + (MUTEX_LOCK_FAILED | TRN_ERR_ID) +#define TRN_MUTEX_UNLOCK_FAILED \ + (MUTEX_UNLOCK_FAILED | TRN_ERR_ID) +#define TRN_MEMORY_ALLOCATION_FAILED \ + (MEMORY_ALLOCATION_FAILED | TRN_ERR_ID) + +#define TRN_INVALID_PARAMETER_VALUE (0x0011 | TRN_ERR_ID) +#define TRN_PARAMETER_OUTSIDE_RANGE (0x0012 | TRN_ERR_ID) +#define TRN_NULL_PARAMETER_NOT_ALLOWED (0x0013 | TRN_ERR_ID) +#define TRN_QUEUE_FULL (0x0014 | TRN_ERR_ID) +#define TRN_QUEUE_EMPTY (0x0015 | TRN_ERR_ID) +#define TRN_INCOMPLETE_PKT_RECEIVED (0x0016 | TRN_ERR_ID) +#define TRN_INVALID_FRNDSHIP_STATE (0x0017 | TRN_ERR_ID) + +#define TRN_API_NOT_SUPPORTED (0x00FF | TRN_ERR_ID) + +/** \} */ +/** \} */ + +/* ======================================= Section 'Access' */ +/** + \addtogroup access_defines + \{ +*/ + +/** + \defgroup ms_error_codes_module_access Error Code + \{ +*/ + +#define ACCESS_MUTEX_INIT_FAILED \ + (MUTEX_INIT_FAILED | ACCESS_ERR_ID) +#define ACCESS_COND_INIT_FAILED \ + (COND_INIT_FAILED | ACCESS_ERR_ID) +#define ACCESS_MUTEX_LOCK_FAILED \ + (MUTEX_LOCK_FAILED | ACCESS_ERR_ID) +#define ACCESS_MUTEX_UNLOCK_FAILED \ + (MUTEX_UNLOCK_FAILED | ACCESS_ERR_ID) +#define ACCESS_MEMORY_ALLOCATION_FAILED \ + (MEMORY_ALLOCATION_FAILED | ACCESS_ERR_ID) + +#define ACCESS_INVALID_PARAMETER_VALUE (0x0011 | ACCESS_ERR_ID) +#define ACCESS_PARAMETER_OUTSIDE_RANGE (0x0012 | ACCESS_ERR_ID) +#define ACCESS_NULL_PARAMETER_NOT_ALLOWED (0x0013 | ACCESS_ERR_ID) + +#define ACCESS_NO_RESOURCE (0x0020 | ACCESS_ERR_ID) +#define ACCESS_NO_MATCH (0x0021 | ACCESS_ERR_ID) +#define ACCESS_INVALID_HANDLE (0x0022 | ACCESS_ERR_ID) +#define ACCESS_MODEL_ALREADY_REGISTERED (0x0023 | ACCESS_ERR_ID) +#define ACCESS_INVALID_SRC_ADDR (0x0024 | ACCESS_ERR_ID) +#define ACCESS_DEV_KEY_TABLE_FULL (0x0025 | ACCESS_ERR_ID) +#define ACCESS_MASTER_NID_ON_LPN (0x0026 | ACCESS_ERR_ID) +#define ACCESS_INVALID_PUBLICATION_STATE (0x0027 | ACCESS_ERR_ID) + +#define ACCESS_API_NOT_SUPPORTED (0x00FF | ACCESS_ERR_ID) + +/** \} */ +/** \} */ + +/* ======================================= Section 'Provisioning' */ +/** + \addtogroup prov_defines + \{ +*/ + +/** + \defgroup ms_error_codes_module_provisioning Error Code + \{ +*/ + +#define PROV_MUTEX_INIT_FAILED \ + (MUTEX_INIT_FAILED | PROV_ERR_ID) +#define PROV_COND_INIT_FAILED \ + (COND_INIT_FAILED | PROV_ERR_ID) +#define PROV_MUTEX_LOCK_FAILED \ + (MUTEX_LOCK_FAILED | PROV_ERR_ID) +#define PROV_MUTEX_UNLOCK_FAILED \ + (MUTEX_UNLOCK_FAILED | PROV_ERR_ID) +#define PROV_MEMORY_ALLOCATION_FAILED \ + (MEMORY_ALLOCATION_FAILED | PROV_ERR_ID) + +#define PROV_INVALID_STATE (0x0011 | PROV_ERR_ID) +#define PROV_INVALID_PARAMETER (0x0012 | PROV_ERR_ID) +#define PROV_CONTEXT_ALLOC_FAILED (0x0013 | PROV_ERR_ID) +#define PROV_CONTEXT_ASSERT_FAILED (0x0014 | PROV_ERR_ID) +#define PROV_CONTEXT_LINK_OPEN (0x0015 | PROV_ERR_ID) +#define PROV_BEARER_ASSERT_FAILED (0x0016 | PROV_ERR_ID) +#define PROV_PROCEDURE_TIMEOUT (0x0017 | PROV_ERR_ID) + +/** \} */ +/** \} */ + +/* ======================================= Section 'Health Server' */ +/** + \addtogroup health_server_defines + \{ +*/ + +/** + \defgroup ms_error_codes_module_health_server Error Code + \{ +*/ + +#define HEALTH_MUTEX_INIT_FAILED \ + (MUTEX_INIT_FAILED | HEALTH_ERR_ID) +#define HEALTH_COND_INIT_FAILED \ + (COND_INIT_FAILED | HEALTH_ERR_ID) +#define HEALTH_MUTEX_LOCK_FAILED \ + (MUTEX_LOCK_FAILED | HEALTH_ERR_ID) +#define HEALTH_MUTEX_UNLOCK_FAILED \ + (MUTEX_UNLOCK_FAILED | HEALTH_ERR_ID) +#define HEALTH_MEMORY_ALLOCATION_FAILED \ + (MEMORY_ALLOCATION_FAILED | HEALTH_ERR_ID) + +#define HEALTH_INVALID_STATE (0x0011 | HEALTH_ERR_ID) +#define HEALTH_INVALID_PARAMETER (0x0012 | HEALTH_ERR_ID) +#define HEALTH_CONTEXT_ALLOC_FAILED (0x0013 | HEALTH_ERR_ID) +#define HEALTH_CONTEXT_ASSERT_FAILED (0x0014 | HEALTH_ERR_ID) + +/** \} */ +/** \} */ + +#endif /* _H_MS_ERROR_ */ + diff --git a/src/components/ethermind/mesh/export/include/MS_generic_battery_api.h b/src/components/ethermind/mesh/export/include/MS_generic_battery_api.h new file mode 100644 index 0000000..a75cdc3 --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_generic_battery_api.h @@ -0,0 +1,292 @@ +/** + \file MS_generic_battery_api.h + + \brief This file defines the Mesh Generic Battery Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_GENERIC_BATTERY_API_ +#define _H_MS_GENERIC_BATTERY_API_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_access_api.h" + + +/* --------------------------------------------- Global Definitions */ +/** + \defgroup generic_battery_module GENERIC_BATTERY (Mesh Generic Battery Model) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Generic OnOff Model (ONOFF) module to the Application. +*/ + + + +/* --------------------------------------------- Data Types/ Structures */ +/** + \defgroup generic_battery_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ + +/** + Generic Battery Server application Asynchronous Notification Callback. + + Generic Battery Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_GENERIC_BATTERY_SERVER_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_MODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; + +/** + Generic Battery Client application Asynchronous Notification Callback. + + Generic Battery Client calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param opcode Opcode. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef API_RESULT (* MS_GENERIC_BATTERY_CLIENT_CB) +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT32 opcode, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; +/** \} */ + +/** + \defgroup generic_battery_structures Structures + \{ +*/ + +/** + The Generic Battery state is a set of four values representing the state of a battery: + - a charge level (Generic Battery Level) + - remaining time to complete discharging (Generic Battery Time to Discharge) + - remaining time to complete charging (Generic Battery Time to Charge) + - flags bit field (Generic Battery Flags) +*/ +typedef struct MS_generic_battery_status_struct +{ + /** + Generic Battery Level. + The Generic Battery Level state is a value ranging from 0 percent through 100 percent. + + Value | Description + ----------|------------ + 0x00-0x64 | The percentage of the charge level. 100% represents fully charged. 0% represents fully discharged. + 0x65-0xFE | Prohibited + 0xFF | The percentage of the charge level is unknown. + */ + UCHAR battery_level; + + /** + The Generic Battery Time to Discharge state is a 24-bit unsigned value ranging from 0 through 0xFFFFFF. + + Value | Description + ------------------|------------ + 0x000000-0xFFFFFE | The remaining time (in minutes) of the discharging process + 0xFFFFFF | The remaining time of the discharging process is not known. + */ + UINT32 time_to_discharge; + + /** + The Generic Battery Time to Charge state is a 24-bit unsigned value ranging from 0 through 0xFFFFFF. + + Value | Description + ------------------|------------ + 0x000000-0xFFFFFE | The remaining time (in minutes) of the charging process + 0xFFFFFF | The remaining time of the charging process is not known. + */ + UINT32 time_to_charge; + + /** + The Generic Battery Flags state is a concatenation of four 2-bit bit fields: Presence, Indicator, Charging, and Serviceability + + Bit | Description + -----|------------ + 0-1 | Generic Battery Flags Presence + 2-3 | Generic Battery Flags Indicator + 4-5 | Generic Battery Flags Charging + 6-7 | Generic Battery Flags Serviceability + */ + UCHAR flags; + +} MS_GENERIC_BATTERY_STATUS_STRUCT; + +/** \} */ + + + +/* --------------------------------------------- Function */ +/** + \defgroup generic_battery_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Generic Battery Model APIs. +*/ +/** + \defgroup generic_battery_ser_api_defs Generic Battery Server API Definitions + \{ + This section describes the Generic Battery Server APIs. +*/ + +/** + \brief API to initialize Generic_Battery Server model + + \par Description + This is to initialize Generic_Battery Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_Battery Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_battery_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_BATTERY_SERVER_CB appl_cb +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_battery_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); +/** \} */ + +/** + \defgroup generic_battery_cli_api_defs Generic Battery Client API Definitions + \{ + This section describes the Generic Battery Client APIs. +*/ + +/** + \brief API to initialize Generic_Battery Client model + + \par Description + This is to initialize Generic_Battery Client model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_Battery Client. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_battery_client_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_BATTERY_CLIENT_CB appl_cb +); + +/** + \brief API to get Generic_Battery client model handle + + \par Description + This is to get the handle of Generic_Battery client model. + + \param [out] model_handle Address of model handle to be filled/returned. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_battery_client_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle +); + +/** + \brief API to send acknowledged commands + + \par Description + This is to initialize sending acknowledged commands. + + \param [in] req_opcode Request Opcode. + \param [in] param Parameter associated with Request Opcode. + \param [in] rsp_opcode Response Opcode. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_battery_client_send_reliable_pdu +( + /* IN */ UINT32 req_opcode, + /* IN */ void* param, + /* IN */ UINT32 rsp_opcode +); + +/** + \brief API to get the Generic Battery state of an element. + + \par Description + Generic Battery Get message is an acknowledged message used to get the Generic Battery state of an element. + The response to the Generic Battery Get message is a Generic Battery Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_battery_get() \ + MS_generic_battery_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_BATTERY_GET_OPCODE,\ + NULL,\ + MS_ACCESS_GENERIC_BATTERY_STATUS_OPCODE\ + ) +/** \} */ +/** \} */ +/** \} */ + +#endif /*_H_MS_GENERIC_BATTERY_API_ */ diff --git a/src/components/ethermind/mesh/export/include/MS_generic_default_transition_time_api.h b/src/components/ethermind/mesh/export/include/MS_generic_default_transition_time_api.h new file mode 100644 index 0000000..9b6614e --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_generic_default_transition_time_api.h @@ -0,0 +1,319 @@ +/** + \file MS_generic_default_transition_time_api.h + + \brief This file defines the Mesh Generic Default Transition Time Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_GENERIC_DEFAULT_TRANSITION_TIME_API_ +#define _H_MS_GENERIC_DEFAULT_TRANSITION_TIME_API_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_access_api.h" +#include "MS_model_states.h" + + +/* --------------------------------------------- Global Definitions */ +/** + \defgroup generic_default_transition_time_module GENERIC_DEFAULT_TRANSITION_TIME (Mesh Generic Default Transition Time Model) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Generic OnOff Model (ONOFF) module to the Application. +*/ + + + +/* --------------------------------------------- Data Types/ Structures */ +/** + \defgroup generic_default_transition_time_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ + +/** + Generic Default Transition Time Server application Asynchronous Notification Callback. + + Generic Default Transition Time Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_GENERIC_DEFAULT_TRANSITION_TIME_SERVER_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_MODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; + +/** + Generic Default Transition Time Client application Asynchronous Notification Callback. + + Generic Default Transition Time Client calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param opcode Opcode. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef API_RESULT (* MS_GENERIC_DEFAULT_TRANSITION_TIME_CLIENT_CB) +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT32 opcode, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; +/** \} */ + +/** + \defgroup generic_default_transition_time_structures Structures + \{ +*/ + +/** + The Generic Default Transition Time state determines how long an element shall take to transition + from a present state to a new state. + This is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + This mechanism covers a wide range of times that may be required by different applications: + - For 100 millisecond step resolution, the range is 0 through 6.2 seconds. + - For 1 second step resolution, the range is 0 through 62 seconds. + - For 10 seconds step resolution, the range is 0 through 620 seconds (10.5 minutes). + - For 10 minutes step resolution, the range is 0 through 620 minutes (10.5 hours). + + The Generic Default Transition Time is calculated using the following formula: + Generic Default Transition Time = Default Transition Step Resolution * Default Transition Number of Steps +*/ +typedef struct MS_generic_default_transition_time_struct +{ + /** + The Default Transition Step Resolution field is a 2-bit bit field that determines + the resolution of the Generic Default Transition Time state. + + Value | Description + ------|------------ + 0b00 | The Default Transition Step Resolution is 100 milliseconds + 0b01 | The Default Transition Step Resolution is 1 second + 0b10 | The Default Transition Step Resolution is 10 seconds + 0b11 | The Default Transition Step Resolution is 10 minutes + */ + UCHAR transition_number_of_steps; + + /** + The Default Transition Number of Steps field is a 6-bit value representing + the number of transition steps. + + Value | Description + ----------|------------ + 0x00 | The Generic Default Transition Time is immediate. + 0x01-0x3E | The number of steps. + 0x3F | The value is unknown. The state cannot be set to this value, + | but an element may report an unknown value if a transition is higher than 0x3E + | or not determined. + */ + UCHAR transition_step_resolution; + +} MS_GENERIC_DEFAULT_TRANSITION_TIME_STRUCT; + +/** \} */ + + + +/* --------------------------------------------- Function */ +/** + \defgroup generic_default_transition_time_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Generic Default Transition Time Model APIs. +*/ +/** + \defgroup generic_default_transition_time_ser_api_defs Generic Default Transition Time Server API Definitions + \{ + This section describes the Generic Default Transition Time Server APIs. +*/ + +/** + \brief API to initialize Generic_Default_Transition_Time Server model + + \par Description + This is to initialize Generic_Default_Transition_Time Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_Default_Transition_Time Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_default_transition_time_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_DEFAULT_TRANSITION_TIME_SERVER_CB appl_cb +); + +/** + \brief API to get default transition time + + \par Description + This is to get default transition time. + + \param [out] default_time Default Transition Time. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_default_transition_time_server_get_time +( + /* OUT */ MS_STATE_GENERIC_DEFAULT_TRANSITION_TIME_STRUCT* default_time +); +/** \} */ + +/** + \defgroup generic_default_transition_time_cli_api_defs Generic Default Transition Time Client API Definitions + \{ + This section describes the Generic Default Transition Time Client APIs. +*/ + +/** + \brief API to initialize Generic_Default_Transition_Time Client model + + \par Description + This is to initialize Generic_Default_Transition_Time Client model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_Default_Transition_Time Client. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_default_transition_time_client_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_DEFAULT_TRANSITION_TIME_CLIENT_CB appl_cb +); + +/** + \brief API to get Generic_Default_Transition_Time client model handle + + \par Description + This is to get the handle of Generic_Default_Transition_Time client model. + + \param [out] model_handle Address of model handle to be filled/returned. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_default_transition_time_client_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle +); + +/** + \brief API to send acknowledged commands + + \par Description + This is to initialize sending acknowledged commands. + + \param [in] req_opcode Request Opcode. + \param [in] param Parameter associated with Request Opcode. + \param [in] rsp_opcode Response Opcode. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_default_transition_time_client_send_reliable_pdu +( + /* IN */ UINT32 req_opcode, + /* IN */ void* param, + /* IN */ UINT32 rsp_opcode +); + +/** + \brief API to get the Generic Default Transition Time state of an element. + + \par Description + Generic Default Transition Time Get is an acknowledged message used to get + the Generic Default Transition Time state of an element. + The response to the Generic Default Transition Time Get message is a Generic Default + Transition Time Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_default_transition_time_get() \ + MS_generic_default_transition_time_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_DEFAULT_TRANSITION_TIME_GET_OPCODE,\ + NULL,\ + MS_ACCESS_GENERIC_DEFAULT_TRANSITION_TIME_STATUS_OPCODE\ + ) + +/** + \brief API to set the Generic Default Transition Time state of an element. + + \par Description + Generic Default Transition Time Set is an acknowledged message used to set + the Generic Default Transition Time state of an element. + The response to the Generic Default Transition Time Set message is a Generic Default + Transition Time Status message. + + \param [in] param Transition Time + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_default_transition_time_set(param) \ + MS_generic_default_transition_time_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_DEFAULT_TRANSITION_TIME_SET_OPCODE,\ + param,\ + MS_ACCESS_GENERIC_DEFAULT_TRANSITION_TIME_STATUS_OPCODE\ + ) + +/** + \brief API to set the Generic Default Transition Time state of an element. + + \par Description + Generic Default Transition Time Set Unacknowledged is an unacknowledged message used to set + the Generic Default Transition Time state of an element. + + \param [in] param Transition Time + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_default_transition_time_set_unacknowledged(param) \ + MS_generic_default_transition_time_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_DEFAULT_TRANSITION_TIME_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) +/** \} */ +/** \} */ +/** \} */ + +#endif /*_H_MS_GENERIC_DEFAULT_TRANSITION_TIME_API_ */ diff --git a/src/components/ethermind/mesh/export/include/MS_generic_level_api.h b/src/components/ethermind/mesh/export/include/MS_generic_level_api.h new file mode 100644 index 0000000..160152e --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_generic_level_api.h @@ -0,0 +1,487 @@ +/** + \file MS_generic_level_api.h + + \brief This file defines the Mesh Generic Level Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_GENERIC_LEVEL_API_ +#define _H_MS_GENERIC_LEVEL_API_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_access_api.h" + + +/* --------------------------------------------- Global Definitions */ +/** + \defgroup generic_level_module GENERIC_LEVEL (Mesh Generic Level Model) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Generic OnOff Model (ONOFF) module to the Application. +*/ + + + +/* --------------------------------------------- Data Types/ Structures */ +/** + \defgroup generic_level_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ + +/** + Generic Level Server application Asynchronous Notification Callback. + + Generic Level Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_GENERIC_LEVEL_SERVER_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_MODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; + +/** + Generic Level Client application Asynchronous Notification Callback. + + Generic Level Client calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param opcode Opcode. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef API_RESULT (* MS_GENERIC_LEVEL_CLIENT_CB) +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT32 opcode, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; +/** \} */ + +/** + \defgroup generic_level_structures Structures + \{ +*/ + +/** + Generic Level Set message parameters +*/ +typedef struct MS_generic_level_set_struct +{ + /** + The target value of the Generic Level state. + + The Generic Level state is a 16-bit signed integer (2’s complement) representing + the state of an element. + */ + UINT16 level; + + /** Transaction Identifier */ + UCHAR tid; + + /** + Transition Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR transition_time; + + /** Message execution delay in 5 milliseconds steps */ + UCHAR delay; + + /** Flag: To represent if optional Transaction time and Delay fields are valid */ + UCHAR optional_fields_present; + +} MS_GENERIC_LEVEL_SET_STRUCT; + +/** + Generic Level Status message parameters +*/ +typedef struct MS_generic_level_status_struct +{ + /** The present value of the Generic Level state. */ + UINT16 present_level; + + /** The target value of the Generic Level state */ + UINT16 target_level; + + /** + Remaining Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR remaining_time; + + /** Flag: To represent if optional fields Target Level and Remaining Time are valid */ + UCHAR optional_fields_present; + +} MS_GENERIC_LEVEL_STATUS_STRUCT; + +/** + Generic Delta Set message parameters. +*/ +typedef struct MS_generic_delta_set_struct +{ + /** The Delta change of the Generic Level state */ + UINT32 delta_level; + + /** Transaction Identifier */ + UCHAR tid; + + /** + Transition Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR transition_time; + + /** Message execution delay in 5 milliseconds steps */ + UCHAR delay; + + /** Flag: To represent if optional Transaction time and Delay fields are valid */ + UCHAR optional_fields_present; + +} MS_GENERIC_DELTA_SET_STRUCT; + +/** + Generic Move Set message parameters. +*/ +typedef struct MS_generic_move_set_struct +{ + /** The Delta Level step to calculate Move speed for the Generic Level state. */ + UINT16 delta_level; + + /** Transaction Identifier */ + UCHAR tid; + + /** + Transition Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR transition_time; + + /** Message execution delay in 5 milliseconds steps */ + UCHAR delay; + + /** Flag: To represent if optional Transaction time and Delay fields are valid */ + UCHAR optional_fields_present; + +} MS_GENERIC_MOVE_SET_STRUCT; + +/** \} */ + + + +/* --------------------------------------------- Function */ +/** + \defgroup generic_level_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Generic Level Model APIs. +*/ +/** + \defgroup generic_level_ser_api_defs Generic Level Server API Definitions + \{ + This section describes the Generic Level Server APIs. +*/ + +/** + \brief API to initialize Generic_Level Server model + + \par Description + This is to initialize Generic_Level Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_Level Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_level_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_LEVEL_SERVER_CB appl_cb +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_level_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); +/** \} */ + +/** + \defgroup generic_level_cli_api_defs Generic Level Client API Definitions + \{ + This section describes the Generic Level Client APIs. +*/ + +/** + \brief API to initialize Generic_Level Client model + + \par Description + This is to initialize Generic_Level Client model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_Level Client. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_level_client_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_LEVEL_CLIENT_CB appl_cb +); + +/** + \brief API to get Generic_Level client model handle + + \par Description + This is to get the handle of Generic_Level client model. + + \param [out] model_handle Address of model handle to be filled/returned. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_level_client_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle +); + +/** + \brief API to send acknowledged commands + + \par Description + This is to initialize sending acknowledged commands. + + \param [in] req_opcode Request Opcode. + \param [in] param Parameter associated with Request Opcode. + \param [in] rsp_opcode Response Opcode. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_level_client_send_reliable_pdu +( + /* IN */ UINT32 req_opcode, + /* IN */ void* param, + /* IN */ UINT32 rsp_opcode +); + +/** + \brief API to get the Generic Level state of an element. + + \par Description + Generic Level Get is an acknowledged message used to get the Generic Level state of an element. + The response to the Generic Level Get message is a Generic Level Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_level_get() \ + MS_generic_level_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_LEVEL_GET_OPCODE,\ + NULL,\ + MS_ACCESS_GENERIC_LEVEL_STATUS_OPCODE\ + ) + +/** + \brief API to set the Generic Level state of an element to a new absolute value. + + \par Description + Generic Level Set is an acknowledged message used to set the Generic Level state of an element + to a new absolute value. + The response to the Generic Level Set message is a Generic Level Status message. + + \param [in] param Generic Level Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_level_set(param) \ + MS_generic_level_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_LEVEL_SET_OPCODE,\ + param,\ + MS_ACCESS_GENERIC_LEVEL_STATUS_OPCODE\ + ) + +/** + \brief API to set the Generic Level state of an element to a new absolute value. + + \par Description + Generic Level Set Unacknowledged is an unacknowledged message used to set + the Generic Level state of an element to a new absolute value. + + \param [in] param Generic Level Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_level_set_unacknowledged(param) \ + MS_generic_level_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_LEVEL_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to set the Generic Level state of an element by a relative value. + + \par Description + Generic Delta Set is an acknowledged message used to set the Generic Level state of an element + by a relative value. The message is transactional, it supports changing the state by a cumulative + value with a sequence of messages that are part of a transaction. + The response to the Generic Delta Set message is a Generic Level Status message. + + \param [in] param Generic Delta Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_delta_set(param) \ + MS_generic_level_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_DELTA_SET_OPCODE,\ + param,\ + MS_ACCESS_GENERIC_LEVEL_STATUS_OPCODE\ + ) + +/** + \brief API to set the Generic Level state of an element by a relative value. + + \par Description + Generic Delta Set Unacknowledged is an unacknowledged message used to set the Generic Level state of an element + by a relative value. + + \param [in] param Generic Delta Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_delta_set_unacknowledged(param) \ + MS_generic_level_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_DELTA_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to start a process of changing the Generic Level state of an element + with a defined transition speed. + + \par Description + Generic Move Set is an acknowledged message used to start a process of changing + the Generic Level state of an element with a defined transition speed. + The response to the Generic Move Set message is a Generic Level Status message. + + \param [in] param Generic Move Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_move_set(param) \ + MS_generic_level_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_MOVE_SET_OPCODE,\ + param,\ + MS_ACCESS_GENERIC_LEVEL_STATUS_OPCODE\ + ) + +/** + \brief API to start a process of changing the Generic Level state of an element + with a defined transition speed. + + \par Description + Generic Move Set Unacknowledged is an unacknowledged message used to start a process + of changing the Generic Level state of an element with a defined transition speed. + + \param [in] param Generic Move Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_move_set_unacknowledged(param) \ + MS_generic_level_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_MOVE_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) +/** \} */ +/** \} */ +/** \} */ + +#endif /*_H_MS_GENERIC_LEVEL_API_ */ diff --git a/src/components/ethermind/mesh/export/include/MS_generic_location_api.h b/src/components/ethermind/mesh/export/include/MS_generic_location_api.h new file mode 100644 index 0000000..7b44f28 --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_generic_location_api.h @@ -0,0 +1,517 @@ +/** + \file MS_generic_location_api.h + + \brief This file defines the Mesh Generic Location Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_GENERIC_LOCATION_API_ +#define _H_MS_GENERIC_LOCATION_API_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_access_api.h" + + +/* --------------------------------------------- Global Definitions */ +/** + \defgroup generic_location_module GENERIC_LOCATION (Mesh Generic Location Model) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Generic OnOff Model (ONOFF) module to the Application. +*/ + + + +/* --------------------------------------------- Data Types/ Structures */ +/** + \defgroup generic_location_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ + +/** + Generic Location Server application Asynchronous Notification Callback. + + Generic Location Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_GENERIC_LOCATION_SERVER_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_MODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; + +/** + Generic Location Client application Asynchronous Notification Callback. + + Generic Location Client calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param opcode Opcode. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef API_RESULT (* MS_GENERIC_LOCATION_CLIENT_CB) +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT32 opcode, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; + +/** + Generic Location Setup Server application Asynchronous Notification Callback. + + Generic Location Setup Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_GENERIC_LOCATION_SETUP_SERVER_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_MODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; +/** \} */ + + +/** + \defgroup generic_location_structures Structures + \{ +*/ + +/** + Generic Location Global Set message parameters. +*/ +typedef struct MS_generic_location_global_struct +{ + /** + Global Coordinates (Latitude). + The Global Latitude field describes the global WGS84 North coordinate of the element. + */ + UINT32 global_latitude; + + /** + Global Coordinates (Longitude). + The Global Longitude field describes the global WGS84 East coordinate of the element. + */ + UINT32 global_longitude; + + /** + Global Altitude. + The Global Altitude field determines the altitude of the device above the WGS84 datum. + It expresses the altitude beyond the WGS84 ellipsoid of the element that exposed its position. + + Value | Description + --------------|------------ + 0x7FFF | Global Altitude is not configured. + 0x7FFE | Global Altitude is greater than or equal to 32766 meters. + 0x8000-0x7FFD | Global Altitude is (field value) from -32768 meters through 32765 meters. + */ + UINT16 global_altitude; + +} MS_GENERIC_LOCATION_GLOBAL_STRUCT; + +/** + Generic Location Local Set message parameters. +*/ +typedef struct MS_generic_location_local_struct +{ + /** + Local Coordinates (North). + The Local North field describes the North coordinate of the device using a local coordinate system. + It is relative to the north orientation on a predefined map. + + The Local North value is encoded in decimeters and has a range of -32767 decimeters through 32767 decimeters. + The value 0x8000 means the Local North information is not configured. + */ + UINT16 local_north; + + /** + Local Coordinates (East). + The Local East field describes the East coordinate of the device using a local coordinate system. + It is relative to the east orientation of a predefined map. + + The Local East value is encoded decimeters and it ranges from -32767 decimeters through 32767 decimeters. + The value 0x8000 means the Local East information is not configured. + */ + UINT16 local_east; + + /** + Local Altitude. + The Local Altitude field determines the altitude of the device relative to the Generic Location Global Altitude. + + Value | Description + --------------|------------ + 0x7FFF | Local Altitude is not configured. + 0x7FFE | Local Altitude is greater than or equal to 32766 meters. + 0x8000-0x7FFD | Local Altitude is (field value) from -32768 meters through 32765 meters. + */ + UINT16 local_altitude; + + /** + Floor Number. + + The Floor Number field describes the floor number where the element is installed. + The floor number, N, is encoded as X = N + 20, where X is the encoded floor number. + Floor number = -20 (X=0) has a special meaning, indicating the floor -20, and also any floor below that. + Floor number = 232 (X=252) has a special meaning, indicating the floor 232, and also any floor above that. + + Encoded Value X | Floor number N + ----------------|--------------- + 0x00 | Floor -20 or any floor below -20. + 0x01-0xFB | Floor number N, encoded as X = N + 20. + 0xFC | Floor 232 or any floor above 232. + 0xFD | Ground floor. Floor 0. + 0xFE | Ground floor. Floor 1. + 0xFF | Not configured + + Note: The reason for having two definitions of ground floor (0 or 1) is to allow for + different conventions applicable in different countries. + */ + UCHAR floor_number; + + /** + Uncertainty. + The Uncertainty field is a 16-bit bit field that describes the uncertainty of + the location information the element exposes. + + bits | Field | Description + ------|-------------|------------ + 0 | Stationary | This bit indicates whether the device broadcasting the location information + has a stationary location or is mobile. (0 = Stationary, 1 = Mobile) + 1-7 | RFU | Reserved for Future Use + 8-11 | Update Time | This value (x) is a 4-bit value ranging from 0 through 15. + It represents the time (t) elapsed since the last update of the device's position, + measured in seconds using the following formula: t=2^(x-3) + The represented range is from 0.125 seconds through 4096 seconds. + Note: If 'stationary' is set, this value can be ignored. + 12-15 | Precision | This value (y) is a 4-bit value ranging from 0 through 15. + It represents a location precision with the formula: Precision = 2^(y-3) + The represented range is from 0.125 meters through 4096 meters. + */ + UINT16 uncertainty; + +} MS_GENERIC_LOCATION_LOCAL_STRUCT; + +/** \} */ + + + +/* --------------------------------------------- Function */ +/** + \defgroup generic_location_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Generic Location Model APIs. +*/ +/** + \defgroup generic_location_ser_api_defs Generic Location Server API Definitions + \{ + This section describes the Generic Location Server APIs. +*/ + +/** + \brief API to initialize Generic_Location Server model + + \par Description + This is to initialize Generic_Location Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_Location Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_location_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_LOCATION_SERVER_CB appl_cb +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_location_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief API to initialize Generic_Location_Setup Server model + + \par Description + This is to initialize Generic_Location_Setup Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_Location_Setup Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_location_setup_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_LOCATION_SETUP_SERVER_CB appl_cb +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_location_setup_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); +/** \} */ + +/** + \defgroup generic_location_cli_api_defs Generic Location Client API Definitions + \{ + This section describes the Generic Location Client APIs. +*/ + +/** + \brief API to initialize Generic_Location Client model + + \par Description + This is to initialize Generic_Location Client model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_Location Client. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_location_client_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_LOCATION_CLIENT_CB appl_cb +); + +/** + \brief API to get Generic_Location client model handle + + \par Description + This is to get the handle of Generic_Location client model. + + \param [out] model_handle Address of model handle to be filled/returned. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_location_client_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle +); + +/** + \brief API to send acknowledged commands + + \par Description + This is to initialize sending acknowledged commands. + + \param [in] req_opcode Request Opcode. + \param [in] param Parameter associated with Request Opcode. + \param [in] rsp_opcode Response Opcode. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_location_client_send_reliable_pdu +( + /* IN */ UINT32 req_opcode, + /* IN */ void* param, + /* IN */ UINT32 rsp_opcode +); + +/** + \brief API to get the selected fields of the Generic Location state of an element. + + \par Description + Generic Location Global Get message is an acknowledged message used to get the selected fields + of the Generic Location state of an element. + The response to the Generic Location Global Get message is a Generic Location Global Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_location_global_get() \ + MS_generic_location_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_LOCATION_GLOBAL_GET_OPCODE,\ + NULL,\ + MS_ACCESS_GENERIC_LOCATION_GLOBAL_STATUS_OPCODE\ + ) + +/** + \brief API to set the selected fields of the Generic Location state of an element. + + \par Description + Generic Location Global Set is an acknowledged message used to set the selected fields of the Generic Location state of an element. + The response to the Generic Location Global Set message is a Generic Location Global Status message. + + \param [in] param Generic Location Global Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_location_global_set(param) \ + MS_generic_location_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_LOCATION_GLOBAL_SET_OPCODE,\ + param,\ + MS_ACCESS_GENERIC_LOCATION_GLOBAL_STATUS_OPCODE\ + ) + +/** + \brief API to set the selected fields of the Generic Location state of an element. + + \par Description + Generic Location Global Set Unacknowledged is an unacknowledged message used to set the selected fields + of the Generic Location state of an element. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_location_global_set_unacknowledged(param) \ + MS_generic_location_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_LOCATION_GLOBAL_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the selected fields of the Generic Location state of an element. + + \par Description + Generic Location Local Get message is an acknowledged message used to get the selected fields + of the Generic Location state of an element. + The response to the Generic Location Local Get message is a Generic Location Local Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_location_local_get() \ + MS_generic_location_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_LOCATION_LOCAL_GET_OPCODE,\ + NULL,\ + MS_ACCESS_GENERIC_LOCATION_LOCAL_STATUS_OPCODE\ + ) + +/** + \brief API to set the selected fields of the Generic Location state of an element. + + \par Description + Generic Location Local Set is an acknowledged message used to set the selected fields + of the Generic Location state of an element. + The response to the Generic Location Local Set message is a Generic Location Local Status message. + + \param [in] param Generic Location Local Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_location_local_set(param) \ + MS_generic_location_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_LOCATION_LOCAL_SET_OPCODE,\ + param,\ + MS_ACCESS_GENERIC_LOCATION_LOCAL_STATUS_OPCODE\ + ) + +/** + \brief API to set the selected fields of the Generic Location state of an element. + + \par Description + Generic Location Local Set Unacknowledged is an unacknowledged message used to set the selected fields + of the Generic Location state of an element. + + \param [in] param Generic Location Local Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_location_local_set_unacknowledged(param) \ + MS_generic_location_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_LOCATION_LOCAL_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) +/** \} */ +/** \} */ +/** \} */ + +#endif /*_H_MS_GENERIC_LOCATION_API_ */ diff --git a/src/components/ethermind/mesh/export/include/MS_generic_onoff_api.h b/src/components/ethermind/mesh/export/include/MS_generic_onoff_api.h new file mode 100644 index 0000000..f67b528 --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_generic_onoff_api.h @@ -0,0 +1,337 @@ +/** + \file MS_generic_onoff_api.h + + \brief This file defines the Mesh Generic Onoff Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_GENERIC_ONOFF_API_ +#define _H_MS_GENERIC_ONOFF_API_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_access_api.h" + + +/* --------------------------------------------- Global Definitions */ +/** + \defgroup generic_onoff_module GENERIC_ONOFF (Mesh Generic Onoff Model) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Generic OnOff Model (ONOFF) module to the Application. +*/ + + + +/* --------------------------------------------- Data Types/ Structures */ +/** + \defgroup generic_onoff_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ + +/** + Generic Onoff Server application Asynchronous Notification Callback. + + Generic Onoff Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_GENERIC_ONOFF_SERVER_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_MODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; + +/** + Generic Onoff Client application Asynchronous Notification Callback. + + Generic Onoff Client calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param opcode Opcode. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef API_RESULT (* MS_GENERIC_ONOFF_CLIENT_CB) +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT32 opcode, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; +/** \} */ + +/** + \defgroup generic_onoff_structures Structures + \{ +*/ + +/** + Generic OnOff Set message parameters. +*/ +typedef struct MS_generic_onoff_set_struct +{ + /** The target value of the Generic OnOff state */ + UCHAR onoff; + + /** Transaction Identifier */ + UCHAR tid; + + /** + Transition Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR transition_time; + + /** Message execution delay in 5 milliseconds steps */ + UCHAR delay; + + /** Flag: To represent if optional Transaction time and Delay fields are valid */ + UCHAR optional_fields_present; + +} MS_GENERIC_ONOFF_SET_STRUCT; + +/** + Generic OnOff Status message parameters. +*/ +typedef struct MS_generic_onoff_status_struct +{ + /** The present value of the Generic OnOff state. */ + UCHAR present_onoff; + + /** The target value of the Generic OnOff state */ + UCHAR target_onoff; + + /** + Remaining Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR remaining_time; + + /** Flag: To represent if optional fields Target OnOff and Remaining Time are valid */ + UCHAR optional_fields_present; + +} MS_GENERIC_ONOFF_STATUS_STRUCT; + +/** \} */ + + + +/* --------------------------------------------- Function */ +/** + \defgroup generic_onoff_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Generic Onoff Model APIs. +*/ +/** + \defgroup generic_onoff_ser_api_defs Generic Onoff Server API Definitions + \{ + This section describes the Generic Onoff Server APIs. +*/ + +/** + \brief API to initialize Generic_Onoff Server model + + \par Description + This is to initialize Generic_Onoff Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_Onoff Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_onoff_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_ONOFF_SERVER_CB appl_cb +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_onoff_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); +/** \} */ + +/** + \defgroup generic_onoff_cli_api_defs Generic Onoff Client API Definitions + \{ + This section describes the Generic Onoff Client APIs. +*/ + +/** + \brief API to initialize Generic_Onoff Client model + + \par Description + This is to initialize Generic_Onoff Client model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_Onoff Client. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_onoff_client_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_ONOFF_CLIENT_CB appl_cb +); + +/** + \brief API to get Generic_Onoff client model handle + + \par Description + This is to get the handle of Generic_Onoff client model. + + \param [out] model_handle Address of model handle to be filled/returned. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_onoff_client_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle +); + +/** + \brief API to send acknowledged commands + + \par Description + This is to initialize sending acknowledged commands. + + \param [in] req_opcode Request Opcode. + \param [in] param Parameter associated with Request Opcode. + \param [in] rsp_opcode Response Opcode. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_onoff_client_send_reliable_pdu +( + /* IN */ UINT32 req_opcode, + /* IN */ void* param, + /* IN */ UINT32 rsp_opcode +); + +/** + \brief API to get Generic OnOff state + + \par Description + The Generic OnOff Get is an acknowledged message used to get the Generic OnOff + state of an element. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_onoff_get() \ + MS_generic_onoff_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_ONOFF_GET_OPCODE,\ + NULL,\ + MS_ACCESS_GENERIC_ONOFF_STATUS_OPCODE\ + ) + +/** + \brief API to set Generic OnOff state + + \par Description + The Generic OnOff Set is an acknowledged message used to get the Generic OnOff + state of an element. + + \param [in] param + Pointer to the structure populated as in \ref MS_GENERIC_ONOFF_SET_STRUCT + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_onoff_set(param) \ + MS_generic_onoff_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_ONOFF_SET_OPCODE,\ + param,\ + MS_ACCESS_GENERIC_ONOFF_STATUS_OPCODE\ + ) + +/** + \brief API to set Generic OnOff state unacknowledged + + \par Description + The Generic OnOff Set is an unacknowledged message used to get the Generic OnOff + state of an element. + + \param [in] param + Pointer to the structure populated as in \ref MS_GENERIC_ONOFF_SET_STRUCT + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_onoff_set_unacknowledged(param) \ + MS_generic_onoff_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_ONOFF_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) +/** \} */ +/** \} */ +/** \} */ + +#endif /*_H_MS_GENERIC_ONOFF_API_ */ diff --git a/src/components/ethermind/mesh/export/include/MS_generic_power_level_api.h b/src/components/ethermind/mesh/export/include/MS_generic_power_level_api.h new file mode 100644 index 0000000..490670f --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_generic_power_level_api.h @@ -0,0 +1,594 @@ +/** + \file MS_generic_power_level_api.h + + \brief This file defines the Mesh Generic Power Level Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_GENERIC_POWER_LEVEL_API_ +#define _H_MS_GENERIC_POWER_LEVEL_API_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_access_api.h" + + +/* --------------------------------------------- Global Definitions */ +/** + \defgroup generic_power_level_module GENERIC_POWER_LEVEL (Mesh Generic Power Level Model) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Generic OnOff Model (ONOFF) module to the Application. +*/ + + + +/* --------------------------------------------- Data Types/ Structures */ +/** + \defgroup generic_power_level_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ + +/** + Generic Power Level Server application Asynchronous Notification Callback. + + Generic Power Level Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_GENERIC_POWER_LEVEL_SERVER_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_MODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; + +/** + Generic Power Level Client application Asynchronous Notification Callback. + + Generic Power Level Client calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param opcode Opcode. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef API_RESULT (* MS_GENERIC_POWER_LEVEL_CLIENT_CB) +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT32 opcode, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; + +/** + Generic Power Level Setup Server application Asynchronous Notification Callback. + + Generic Power Level Setup Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_GENERIC_POWER_LEVEL_SETUP_SERVER_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_MODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; +/** \} */ + +/** + \defgroup generic_power_level_structures Structures + \{ +*/ + +/** + Generic Power Level Set message parameters. +*/ +typedef struct MS_generic_power_level_set_struct +{ + /** The target value of the Generic Power Actual state */ + UINT16 power; + + /** Transaction Identifier */ + UCHAR tid; + + /** + Transition Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR transition_time; + + /** Message execution delay in 5 milliseconds steps */ + UCHAR delay; + + /** Flag: To represent if optional Transaction time and Delay fields are valid */ + UCHAR optional_fields_present; + +} MS_GENERIC_POWER_LEVEL_SET_STRUCT; + +/** + Generic Power Level Status message parameters. +*/ +typedef struct MS_generic_power_level_status_struct +{ + /** The present value of the Generic Power Actual state. */ + UINT16 present_power; + + /** The target value of the Generic Power Actual state. */ + UINT16 target_power; + + /** + Remaining Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR remaining_time; + + /** Flag: To represent if optional fields Target Power and Remaining Time are valid */ + UCHAR optional_fields_present; + +} MS_GENERIC_POWER_LEVEL_STATUS_STRUCT; + +/** + Generic Power Last Status message parameters. +*/ +typedef struct MS_generic_power_last_status_struct +{ + /** The value of the Generic Power Last state. */ + UINT16 power; + +} MS_GENERIC_POWER_LAST_STATUS_STRUCT; + +/** + Generic Power Default Status message parameters. +*/ +typedef struct MS_generic_power_default_status_struct +{ + /** The value of the Generic Power Default state. */ + UINT16 power; + +} MS_GENERIC_POWER_DEFAULT_STATUS_STRUCT; + +/** + Generic Power Range Status message parameters. +*/ +typedef struct MS_generic_power_range_status_struct +{ + /** Status Code for the requesting message. */ + UCHAR status; + + /** The value of the Generic Power Range Min field of the Generic Power Range state. */ + UINT16 range_min; + + /** The value of the Generic Power Range Max field of the Generic Power Range state. */ + UINT16 range_max; + +} MS_GENERIC_POWER_RANGE_STATUS_STRUCT; + +/** + Generic Power Default Status message parameters. +*/ +typedef struct MS_generic_power_default_set_struct +{ + /** The value of the Generic Power Default state. */ + UINT16 power; + +} MS_GENERIC_POWER_DEFAULT_SET_STRUCT; + +/** + Generic Power Range Set message parameters. +*/ +typedef struct MS_generic_power_range_set_struct +{ + /** The value of the Generic Power Min field of the Generic Power Range state. */ + UINT16 range_min; + + /** The value of the Generic Power Range Max field of the Generic Power Range state. */ + UINT16 range_max; + +} MS_GENERIC_POWER_RANGE_SET_STRUCT; +/** \} */ + + + +/* --------------------------------------------- Function */ +/** + \defgroup generic_power_level_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Generic Power Level Model APIs. +*/ +/** + \defgroup generic_power_level_ser_api_defs Generic Power Level Server API Definitions + \{ + This section describes the Generic Power Level Server APIs. +*/ + +/** + \brief API to initialize Generic_Power_Level Server model + + \par Description + This is to initialize Generic_Power_Level Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_Power_Level Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_power_level_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_POWER_LEVEL_SERVER_CB appl_cb +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_power_level_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief API to initialize Generic_Power_Level_Setup Server model + + \par Description + This is to initialize Generic_Power_Level_Setup Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_Power_Level_Setup Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_power_level_setup_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_POWER_LEVEL_SETUP_SERVER_CB appl_cb +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_power_level_setup_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); +/** \} */ + +/** + \defgroup generic_power_level_cli_api_defs Generic Power Level Client API Definitions + \{ + This section describes the Generic Power Level Client APIs. +*/ + +/** + \brief API to initialize Generic_Power_Level Client model + + \par Description + This is to initialize Generic_Power_Level Client model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_Power_Level Client. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_power_level_client_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_POWER_LEVEL_CLIENT_CB appl_cb +); + +/** + \brief API to get Generic_Power_Level client model handle + + \par Description + This is to get the handle of Generic_Power_Level client model. + + \param [out] model_handle Address of model handle to be filled/returned. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_power_level_client_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle +); + +/** + \brief API to send acknowledged commands + + \par Description + This is to initialize sending acknowledged commands. + + \param [in] req_opcode Request Opcode. + \param [in] param Parameter associated with Request Opcode. + \param [in] rsp_opcode Response Opcode. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_power_level_client_send_reliable_pdu +( + /* IN */ UINT32 req_opcode, + /* IN */ void* param, + /* IN */ UINT32 rsp_opcode +); + +/** + \brief API to get the Generic Power Actual state of an element. + + \par Description + Generic Power Level Get message is an acknowledged message used to get the Generic Power Actual state of an element. + The response to the Generic Power Level Get message is a Generic Power Level Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_power_level_get() \ + MS_generic_power_level_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_POWER_LEVEL_GET_OPCODE,\ + NULL,\ + MS_ACCESS_GENERIC_POWER_LEVEL_STATUS_OPCODE\ + ) + +/** + \brief API to set the Generic Power Actual state of an element. + + \par Description + Generic Power Level Set is an acknowledged message used to set the Generic Power Actual state of an element. + The response to the Generic Power Level Set message is a Generic Power Level Status message. + + \param [in] param Generic Power Level Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_power_level_set(param) \ + MS_generic_power_level_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_POWER_LEVEL_SET_OPCODE,\ + param,\ + MS_ACCESS_GENERIC_POWER_LEVEL_STATUS_OPCODE\ + ) + +/** + \brief API to set the Generic Power Actual state of an element. + + \par Description + Generic Power Level Set Unacknowledged is an unacknowledged message used + to set the Generic Power Actual state of an element. + + \param [in] param Generic Power Level Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_power_level_set_unacknowledged(param) \ + MS_generic_power_level_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_POWER_LEVEL_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the Generic Power Last state of an element. + + \par Description + Generic Power Last Get is an acknowledged message used to get the Generic Power Last state of an element. + The response to a Generic Power Last Get message is a Generic Power Last Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_power_last_get() \ + MS_generic_power_level_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_POWER_LAST_GET_OPCODE,\ + NULL,\ + MS_ACCESS_GENERIC_POWER_LAST_STATUS_OPCODE\ + ) + +/** + \brief API to get the Generic Power Default state of an element. + + \par Description + Generic Power Default Get is an acknowledged message used to get the Generic Power Default state of an element. + The response to a Generic Power Default Get message is a Generic Power Default Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_power_default_get() \ + MS_generic_power_level_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_POWER_DEFAULT_GET_OPCODE,\ + NULL,\ + MS_ACCESS_GENERIC_POWER_DEFAULT_STATUS_OPCODE\ + ) + +/** + \brief API to set the Generic Power Default state of an element. + + \par Description + Generic Power Default Set is an acknowledged message used to set the Generic Power Default state of an element. + The response to the Generic Power Default Set message is a Generic Power Default Status message. + + \param [in] param Generic Power Default Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_power_default_set(param) \ + MS_generic_power_level_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_POWER_DEFAULT_SET_OPCODE,\ + param,\ + MS_ACCESS_GENERIC_POWER_DEFAULT_STATUS_OPCODE\ + ) + +/** + \brief API to set the Generic Power Default state of an element. + + \par Description + Generic Power Default Set Unacknowledged is an unacknowledged message used to set + the Generic Power Default state of an element. + + \param [in] param Generic Power Default Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_power_default_set_unacknowledged(param) \ + MS_generic_power_level_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_POWER_DEFAULT_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the Generic Power Range state of an element. + + \par Description + Generic Power Range Get is an acknowledged message used to get the Generic Power Range state of an element. + The response to the Generic Power Range Get message is a Generic Power Range Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_power_range_get() \ + MS_generic_power_level_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_POWER_RANGE_GET_OPCODE,\ + NULL,\ + MS_ACCESS_GENERIC_POWER_RANGE_STATUS_OPCODE\ + ) + +/** + \brief API to set the Generic Power Range state of an element. + + \par Description + Generic Power Range Set is an acknowledged message used to set the Generic Power Range state of an element. + The response to the Generic Power Range Set message is a Generic Power Range Status message. + + \param [in] param Generic Power Range Set message` + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_power_range_set(param) \ + MS_generic_power_level_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_POWER_RANGE_SET_OPCODE,\ + param,\ + MS_ACCESS_GENERIC_POWER_RANGE_STATUS_OPCODE\ + ) + +/** + \brief API to set the Generic Power Range state of an element. + + \par Description + Generic Power Range Set Unacknowledged is an unacknowledged message used to set + the Generic Power Range state of an element. + + \param [in] param Generic Power Range Set message` + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_power_range_set_unacknowledged(param) \ + MS_generic_power_level_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_POWER_RANGE_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) +/** \} */ +/** \} */ +/** \} */ + +#endif /* _H_MS_GENERIC_POWER_LEVEL_API_ */ diff --git a/src/components/ethermind/mesh/export/include/MS_generic_power_onoff_api.h b/src/components/ethermind/mesh/export/include/MS_generic_power_onoff_api.h new file mode 100644 index 0000000..d931dfd --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_generic_power_onoff_api.h @@ -0,0 +1,365 @@ +/** + \file MS_generic_power_onoff_api.h + + \brief This file defines the Mesh Generic Power Onoff Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_GENERIC_POWER_ONOFF_API_ +#define _H_MS_GENERIC_POWER_ONOFF_API_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_access_api.h" + + +/* --------------------------------------------- Global Definitions */ +/** + \defgroup generic_power_onoff_module GENERIC_POWER_ONOFF (Mesh Generic Power Onoff Model) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Generic OnOff Model (ONOFF) module to the Application. +*/ + + + +/* --------------------------------------------- Data Types/ Structures */ +/** + \defgroup generic_power_onoff_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ + +/** + Generic Power Onoff Server application Asynchronous Notification Callback. + + Generic Power Onoff Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_GENERIC_POWER_ONOFF_SERVER_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_MODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; + +/** + Generic Power Onoff Client application Asynchronous Notification Callback. + + Generic Power Onoff Client calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param opcode Opcode. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef API_RESULT (* MS_GENERIC_POWER_ONOFF_CLIENT_CB) +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT32 opcode, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; + +/** + Generic Power Onoff Setup Server application Asynchronous Notification Callback. + + Generic Power Onoff Setup Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_GENERIC_POWER_ONOFF_SETUP_SERVER_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_MODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; +/** \} */ + +/** + \defgroup generic_power_onoff_structures Structures + \{ +*/ + +/** + Generic OnPowerUp Set message parameters. +*/ +typedef struct MS_generic_onpowerup_struct +{ + /** + The Generic OnPowerUp state is an enumeration representing the behavior of an element when powered up. + + Value | Description + ----------|------------ + 0x00 | Off. After being powered up, the element is in an off state. + 0x01 | Default. After being powered up, the element is in an On state and uses default state values. + 0x02 | Restore. If a transition was in progress when powered down, the element restores the target + state when powered up. Otherwise the element restores the state it was in when powered down. + 0x03-0xFF | Prohibited + */ + UCHAR onpowerup; + +} MS_GENERIC_ONPOWERUP_STRUCT; + +/** \} */ + + + +/* --------------------------------------------- Function */ +/** + \defgroup generic_power_onoff_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Generic Power Onoff Model APIs. +*/ +/** + \defgroup generic_power_onoff_ser_api_defs Generic Power Onoff Server API Definitions + \{ + This section describes the Generic Power Onoff Server APIs. +*/ + +/** + \brief API to initialize Generic_Power_Onoff Server model + + \par Description + This is to initialize Generic_Power_Onoff Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_Power_Onoff Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_power_onoff_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_POWER_ONOFF_SERVER_CB appl_cb +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_power_onoff_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief API to initialize Generic_Power_Onoff_Setup Server model + + \par Description + This is to initialize Generic_Power_Onoff_Setup Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_Power_Onoff_Setup Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_power_onoff_setup_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_POWER_ONOFF_SETUP_SERVER_CB appl_cb +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_power_onoff_setup_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); +/** \} */ + +/** + \defgroup generic_power_onoff_cli_api_defs Generic Power Onoff Client API Definitions + \{ + This section describes the Generic Power Onoff Client APIs. +*/ + +/** + \brief API to initialize Generic_Power_Onoff Client model + + \par Description + This is to initialize Generic_Power_Onoff Client model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_Power_Onoff Client. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_power_onoff_client_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_POWER_ONOFF_CLIENT_CB appl_cb +); + +/** + \brief API to get Generic_Power_Onoff client model handle + + \par Description + This is to get the handle of Generic_Power_Onoff client model. + + \param [out] model_handle Address of model handle to be filled/returned. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_power_onoff_client_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle +); + +/** + \brief API to send acknowledged commands + + \par Description + This is to initialize sending acknowledged commands. + + \param [in] req_opcode Request Opcode. + \param [in] param Parameter associated with Request Opcode. + \param [in] rsp_opcode Response Opcode. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_power_onoff_client_send_reliable_pdu +( + /* IN */ UINT32 req_opcode, + /* IN */ void* param, + /* IN */ UINT32 rsp_opcode +); + +/** + \brief API to get the Generic OnPowerUp state of an element. + + \par Description + Generic OnPowerUp Get is an acknowledged message used to get the Generic OnPowerUp state of an element. + The response to the Generic OnPowerUp Get message is a Generic OnPowerUp Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_onpowerup_get() \ + MS_generic_power_onoff_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_ONPOWERUP_GET_OPCODE,\ + NULL,\ + MS_ACCESS_GENERIC_ONPOWERUP_STATUS_OPCODE\ + ) + +/** + \brief API to set the Generic OnPowerUp state of an element. + + \par Description + Generic OnPowerUp Set is an acknowledged message used to set the Generic OnPowerUp state of an element. + The response to the Generic OnPowerUp Set message is a Generic OnPowerUp Status message. + + \param [in] param Generic OnPowerUp Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_onpowerup_set(param) \ + MS_generic_power_onoff_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_ONPOWERUP_SET_OPCODE,\ + param,\ + MS_ACCESS_GENERIC_ONPOWERUP_STATUS_OPCODE\ + ) + +/** + \brief API to set the Generic OnPowerUp state of an element. + + \par Description + Generic OnPowerUp Set Unacknowledged is an unacknowledged message used to set + the Generic OnPowerUp state of an element. + + \param [in] param Generic OnPowerUp Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_onpowerup_set_unacknowledged(param) \ + MS_generic_power_onoff_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_ONPOWERUP_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) +/** \} */ +/** \} */ +/** \} */ + +#endif /* _H_MS_GENERIC_POWER_ONOFF_API_ */ diff --git a/src/components/ethermind/mesh/export/include/MS_generic_property_api.h b/src/components/ethermind/mesh/export/include/MS_generic_property_api.h new file mode 100644 index 0000000..7e35787 --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_generic_property_api.h @@ -0,0 +1,910 @@ +/** + \file MS_generic_property_api.h + + \brief This file defines the Mesh Generic User, Admin, Manufacturer and Client Property Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_GENERIC_PROPERTY_API_ +#define _H_MS_GENERIC_PROPERTY_API_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_access_api.h" + + +/* --------------------------------------------- Global Definitions */ +/** + \defgroup generic_property_module GENERIC_PROPERTY (Mesh Generic Property Model) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Generic Property Model (GENERIC_PROPERTY) module to the Application. +*/ + +/** Generic Manufacturer Properties */ +#define MS_GENERIC_PROP_TYPE_MANUFACTURER 0x00 + +/** Generic Admin Properties */ +#define MS_GENERIC_PROP_TYPE_ADMIN 0x01 + +/** Generic User Properties */ +#define MS_GENERIC_PROP_TYPE_USER 0x02 + +/** User Access field values */ +/** User Access - Prohibited */ +#define MS_GENERIC_USER_ACCESS_PROHIBITED 0x00 +/** User Access - the device property can be read */ +#define MS_GENERIC_USER_ACCESS_READ 0x01 +/** User Access - the device property can be written */ +#define MS_GENERIC_USER_ACCESS_WRITE 0x02 +/** User Access - the device property can be read and written */ +#define MS_GENERIC_USER_ACCESS_READ_WRITE 0x03 + +#define MS_GENERIC_USER_ACCESS_INVALID_PROPERTY_ID 0xFF + +/** Device Property - Light Control Time Occupancy Delay */ +#define MS_DEV_PROP_LIGHT_CONTROL_TIME_OCCUPANCY_DELAY 0x003A + +/** Device Property - Light Control Time Fade On */ +#define MS_DEV_PROP_LIGHT_CONTROL_TIME_FADE_ON 0x0037 + +/** Device Property - Light Control Time Run On */ +#define MS_DEV_PROP_LIGHT_CONTROL_TIME_RUN_ON 0x003C + +/** Device Property - Light Control Time Fade */ +#define MS_DEV_PROP_LIGHT_CONTROL_TIME_FADE 0x0036 + +/** Device Property - Light Control Time Prolong */ +#define MS_DEV_PROP_LIGHT_CONTROL_TIME_PROLONG 0x003B + +/** Device Property - Light Control Time Fade Standby Auto */ +#define MS_DEV_PROP_LIGHT_CONTROL_TIME_FADE_STANDBY_AUTO 0x0038 + +/** Device Property - Light Control Time Fade Standby Manual */ +#define MS_DEV_PROP_LIGHT_CONTROL_TIME_FADE_STANDBY_MANUAL 0x0039 + +/** Device Property - Light Control Lightness On */ +#define MS_DEV_PROP_LIGHT_CONTROL_LIGHTNESS_ON 0x002E + +/** Device Property - Light Control Lightness Prolong */ +#define MS_DEV_PROP_LIGHT_CONTROL_LIGHTNESS_PROLONG 0x002F + +/** Device Property - Light Control Lightness Standby */ +#define MS_DEV_PROP_LIGHT_CONTROL_LIGHTNESS_STANDBY 0x0030 + +/** Device Property - Light Control Ambient LuxLevel On */ +#define MS_DEV_PROP_LIGHT_CONTROL_AMBIENT_LUXLEVEL_ON 0x002B + +/** Device Property - Light Control Ambient LuxLevel Prolong */ +#define MS_DEV_PROP_LIGHT_CONTROL_AMBIENT_LUXLEVEL_PROLONG 0x002C + +/** Device Property - Light Control Ambient LuxLevel Standby */ +#define MS_DEV_PROP_LIGHT_CONTROL_AMBIENT_LUXLEVEL_STANDBY 0x002D + +/** Device Property - Light Control Regulator Kiu */ +#define MS_DEV_PROP_LIGHT_CONTROL_REGULATOR_KIU 0x0033 + +/** Device Property - Light Control Regulator Kid */ +#define MS_DEV_PROP_LIGHT_CONTROL_REGULATOR_KID 0x0032 + +/** Device Property - Light Control Regulator Kpu */ +#define MS_DEV_PROP_LIGHT_CONTROL_REGULATOR_KPU 0x0035 + +/** Device Property - Light Control Regulator Kpd */ +#define MS_DEV_PROP_LIGHT_CONTROL_REGULATOR_KPD 0x0034 + +/** Device Property - Light Control Regulator Accuracy */ +#define MS_DEV_PROP_LIGHT_CONTROL_REGULATOR_ACCURACY 0x0031 + +/** Device Property - Motion Sensed */ +#define MS_DEV_PROP_MOTION_SENSED 0x0042 + +/** Device Property - Time Since Motion Sensed */ +#define MS_DEV_PROP_TIME_SINCE_MOTION_SENSED 0x0068 + +/** Device Property - People Count */ +#define MS_DEV_PROP_PEOPLE_COUNT 0x004C + +/** Device Property - Presence Detected */ +#define MS_DEV_PROP_PRESENCE_DETECTED 0x004D + +/** Device Property - Present Ambient Light Level */ +#define MS_DEV_PROP_PRESENT_AMBIENT_LIGHT_LEVEL 0x004E + + +/* --------------------------------------------- Data Types/ Structures */ +/** + \defgroup generic_property_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ + +/** + Generic Property Server application Asynchronous Notification Callback. + + Generic Property Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_GENERIC_PROPERTY_SERVER_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_MODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; + +/** + Generic Property Client application Asynchronous Notification Callback. + + Generic Property Client calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param opcode Opcode. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef API_RESULT (* MS_GENERIC_PROPERTY_CLIENT_CB) +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT32 opcode, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; +/** \} */ + +/** + \defgroup generic_property_structures Structures + \{ +*/ + +/** + Generic User Properties Status message parameters. +*/ +typedef struct MS_generic_user_properties_status_struct +{ + /** + A sequence of N User Property IDs present within an element, + where N is the number of device property IDs included in the message. + */ + UINT16* user_property_ids; + + /** Number of User Property IDs */ + UINT16 user_property_ids_count; + +} MS_GENERIC_USER_PROPERTIES_STATUS_STRUCT; + +/** + Generic User Property Get message parameters. +*/ +typedef struct MS_generic_user_property_get_struct +{ + /** Property ID identifying a Generic User Property. */ + UINT16 user_property_id; + +} MS_GENERIC_USER_PROPERTY_GET_STRUCT; + +/** + Generic User Property Set message parameters. +*/ +typedef struct MS_generic_user_property_set_struct +{ + /** Property ID identifying a Generic User Property */ + UINT16 user_property_id; + + /** Raw value for the User Property */ + UCHAR* user_property_value; + + /** Raw value length for the User Property */ + UINT16 user_property_value_len; + +} MS_GENERIC_USER_PROPERTY_SET_STRUCT; + +/** + Generic User Property Status message parameters. +*/ +typedef struct MS_generic_user_property_status_struct +{ + /** Property ID identifying a Generic User Property. */ + UINT16 user_property_id; + + /** Enumeration indicating user access. */ + UCHAR user_access; + + /** Raw value for the User Property */ + UCHAR* user_property_value; + + /** Raw value length for the User Property */ + UINT16 user_property_value_len; + + /** Flag: To represent if optional fields User Access and Raw Value are valid */ + UCHAR optional_fields_present; + +} MS_GENERIC_USER_PROPERTY_STATUS_STRUCT; + +/** + Generic Admin Properties Status message parameters. +*/ +typedef struct MS_generic_admin_properties_status_struct +{ + /** + A sequence of N Admin Property IDs present within an element, + where N is the number of device property IDs included in the message. + */ + UINT16* admin_property_ids; + + /** Number of Admin Property IDs */ + UINT16 admin_property_ids_count; + +} MS_GENERIC_ADMIN_PROPERTIES_STATUS_STRUCT; + +/** + Generic Admin Property Get message parameters. +*/ +typedef struct MS_generic_admin_property_get_struct +{ + /** Property ID identifying a Generic Admin Property. */ + UINT16 admin_property_id; + +} MS_GENERIC_ADMIN_PROPERTY_GET_STRUCT; + +/** + Generic Admin Property Set message parameters. +*/ +typedef struct MS_generic_admin_property_set_struct +{ + /** Property ID identifying a Generic Admin Property. */ + UINT16 admin_property_id; + + /** Enumeration indicating user access. */ + UCHAR admin_user_access; + + /** Raw value for the Admin Property */ + UCHAR* admin_property_value; + + /** Raw value length for the Admin Property */ + UINT16 admin_property_value_len; + +} MS_GENERIC_ADMIN_PROPERTY_SET_STRUCT; + +/** + Generic Admin Property Status message parameters. +*/ +typedef struct MS_generic_admin_property_status_struct +{ + /** Property ID identifying a Generic Admin Property */ + UINT16 admin_property_id; + + /** Enumeration indicating user access (Optional) */ + UCHAR admin_user_access; + + /** Raw value for the Admin Property */ + UCHAR* admin_property_value; + + /** Raw value length for the Admin Property */ + UINT16 admin_property_value_len; + +} MS_GENERIC_ADMIN_PROPERTY_STATUS_STRUCT; + +/** + Generic Manufacturer Properties Status message parameters. +*/ +typedef struct MS_generic_manufacturer_properties_status_struct +{ + /** + A sequence of N Manufacturer Property IDs present within an element, + where N is the number of device property IDs included in the message. + */ + UINT16* manufacturer_property_ids; + + /** Number of Manufacturer Property IDs */ + UINT16 manufacturer_property_ids_count; + +} MS_GENERIC_MANUFACTURER_PROPERTIES_STATUS_STRUCT; + +/** + Generic Manufacturer Property Get message parameters. +*/ +typedef struct MS_generic_manufacturer_property_get_struct +{ + /** Property ID identifying a Generic Manufacturer Property */ + UINT16 manufacturer_property_id; + +} MS_GENERIC_MANUFACTURER_PROPERTY_GET_STRUCT; + +/** + Generic Manufacturer Property Set message parameters. +*/ +typedef struct MS_generic_manufacturer_property_set_struct +{ + /** Property ID identifying a Generic Manufacturer Property */ + UINT16 manufacturer_property_id; + + /** Enumeration indicating user access */ + UCHAR manufacturer_user_access; + +} MS_GENERIC_MANUFACTURER_PROPERTY_SET_STRUCT; + +/** + Generic Manufacturer Property Status message parameters. +*/ +typedef struct MS_generic_manufacturer_property_status_struct +{ + /** Property ID identifying a Generic Manufacturer Property */ + UINT16 manufacturer_property_id; + + /** Enumeration indicating user access */ + UCHAR manufacturer_user_access; + + /** Raw value for the Manufacturer Property */ + UCHAR* manufacturer_property_value; + + /** Raw value length for the Manufacturer Property */ + UINT16 manufacturer_property_value_len; + +} MS_GENERIC_MANUFACTURER_PROPERTY_STATUS_STRUCT; + +/** + Generic Client Properties Get message parameters. +*/ +typedef struct MS_generic_client_properties_get_struct +{ + /** A starting Client Property ID present within an element */ + UINT16 client_property_id; + +} MS_GENERIC_CLIENT_PROPERTIES_GET_STRUCT; + +/** + Generic Client Properties Status message parameters. +*/ +typedef struct MS_generic_client_properties_status_struct +{ + /** + A sequence of N Client Property IDs present within an element, + where N is the number of device property IDs included in the message. + */ + UINT16* client_property_ids; + + /** Number of Client Property IDs */ + UINT16 client_property_ids_count; + +} MS_GENERIC_CLIENT_PROPERTIES_STATUS_STRUCT; + +/** \} */ + + + +/* --------------------------------------------- Function */ +/** + \defgroup generic_property_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Generic Property Model APIs. +*/ +/** + \defgroup generic_user_property_ser_api_defs Generic User Property Server API Definitions + \{ + This section describes the Generic User Property Server APIs. +*/ + +/** + \brief API to initialize Generic_User_Property Server model + + \par Description + This is to initialize Generic_User_Property Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_User_Property Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_user_property_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_PROPERTY_SERVER_CB appl_cb +); + +/** + \brief API to initialize Generic_Admin_Property Server model + + \par Description + This is to initialize Generic_Admin_Property Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_Admin_Property Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_admin_property_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_PROPERTY_SERVER_CB appl_cb +); + +/** + \brief API to initialize Generic_Manufacturer_Property Server model + + \par Description + This is to initialize Generic_Manufacturer_Property Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_Manufacturer_Property Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_manufacturer_property_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_PROPERTY_SERVER_CB appl_cb +); + +/** + \brief API to initialize Generic_Client_Property Server model + + \par Description + This is to initialize Generic_Client_Property Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_Client_Property Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_client_property_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_PROPERTY_SERVER_CB appl_cb +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_user_property_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_admin_property_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_manufacturer_property_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_client_property_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** \} */ + +/** + \defgroup generic_property_cli_api_defs Generic Property Client API Definitions + \{ + This section describes the Generic Property Client APIs. +*/ + +/** + \brief API to initialize Generic_Property Client model + + \par Description + This is to initialize Generic_Property Client model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Generic_Property Client. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_property_client_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_GENERIC_PROPERTY_CLIENT_CB appl_cb +); + +/** + \brief API to get Generic_Property client model handle + + \par Description + This is to get the handle of Generic_Property client model. + + \param [out] model_handle Address of model handle to be filled/returned. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_property_client_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle +); + +/** + \brief API to send acknowledged commands + + \par Description + This is to initialize sending acknowledged commands. + + \param [in] req_opcode Request Opcode. + \param [in] param Parameter associated with Request Opcode. + \param [in] rsp_opcode Response Opcode. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_generic_property_client_send_reliable_pdu +( + /* IN */ UINT32 req_opcode, + /* IN */ void* param, + /* IN */ UINT32 rsp_opcode +); + +/** + \brief API to get the list of Generic User Property states of an element. + + \par Description + Generic User Properties Get is an acknowledged message used to get the list of Generic User Property states of an element. + The response to the Generic User Properties Get message is a Generic User Properties Status message. + The message has no parameters. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_user_properties_get() \ + MS_generic_property_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_USER_PROPERTIES_GET_OPCODE,\ + NULL,\ + MS_ACCESS_GENERIC_USER_PROPERTIES_STATUS_OPCODE\ + ) + +/** + \brief API to get the Generic User Property state of an element. + + \par Description + Generic User Property Get is an acknowledged message used to get the Generic User Property state of an element. + The response to the Generic User Property Get message is a Generic User Property Status message. + + \param [in] param Generic User Property Get message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_user_property_get(param) \ + MS_generic_property_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_USER_PROPERTY_GET_OPCODE,\ + param,\ + MS_ACCESS_GENERIC_USER_PROPERTY_STATUS_OPCODE\ + ) + +/** + \brief API to set the Generic User Property state of an element. + + \par Description + Generic User Property Set is an acknowledged message used to set the Generic User Property state of an element. + The response to the Generic User Property Set message is a Generic User Property Status message. + + \param [in] param Generic User Property Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_user_property_set(param) \ + MS_generic_property_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_USER_PROPERTY_SET_OPCODE,\ + param,\ + MS_ACCESS_GENERIC_USER_PROPERTY_STATUS_OPCODE\ + ) + +/** + \brief API to set the Generic User Property state of an element. + + \par Description + Generic User Property Set Unacknowledged is an unacknowledged message used to set + the Generic User Property state of an element. + + \param [in] param Generic User Property Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_user_property_set_unacknowledged(param) \ + MS_generic_property_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_USER_PROPERTY_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the list of Generic Admin Property states of an element. + + \par Description + Generic Admin Properties Get is an acknowledged message used to get the list of Generic Admin Property states of an element. + The response to the Generic Admin Properties Get message is a Generic Admin Properties Status message. + The message has no parameters. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_admin_properties_get() \ + MS_generic_property_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_ADMIN_PROPERTIES_GET_OPCODE,\ + NULL,\ + MS_ACCESS_GENERIC_ADMIN_PROPERTIES_STATUS_OPCODE\ + ) + +/** + \brief API to get the Generic Admin Property state of an element. + + \par Description + Generic Admin Property Get is an acknowledged message used to get the Generic Admin Property state of an element. + The response to the Generic Admin Property Get message is a Generic Admin Property Status message. + + \param [in] param Generic Admin Property Get message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_admin_property_get(param) \ + MS_generic_property_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_ADMIN_PROPERTY_GET_OPCODE,\ + param,\ + MS_ACCESS_GENERIC_ADMIN_PROPERTY_STATUS_OPCODE\ + ) + +/** + \brief API to set the Generic Admin Property state of an element. + + \par Description + Generic Admin Property Set is an acknowledged message used to set the Generic Admin Property state of an element. + The response to the Generic Admin Property Set message is a Generic Admin Property Status message. + + \param [in] param Generic Admin Property Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_admin_property_set(param) \ + MS_generic_property_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_ADMIN_PROPERTY_SET_OPCODE,\ + param,\ + MS_ACCESS_GENERIC_ADMIN_PROPERTY_STATUS_OPCODE\ + ) + +/** + \brief API to set the Generic Admin Property state of an element. + + \par Description + Generic Admin Property Set Unacknowledged is an unacknowledged message used to set + the Generic Admin Property state of an element. + + \param [in] param Generic Admin Property Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_admin_property_set_unacknowledged(param) \ + MS_generic_property_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_ADMIN_PROPERTY_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the list of Generic Manufacturer Property states of an element. + + \par Description + Generic Manufacturer Properties Get is an acknowledged message used to get + the list of Generic Manufacturer Property states of an element. + The response to the Generic Manufacturer Properties Get message + is a Generic Manufacturer Properties Status message. + The message has no parameters. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_manufacturer_properties_get() \ + MS_generic_property_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_MANUFACTURER_PROPERTIES_GET_OPCODE,\ + NULL,\ + MS_ACCESS_GENERIC_MANUFACTURER_PROPERTIES_STATUS_OPCODE\ + ) + +/** + \brief API to get the Generic Manufacturer Property state of an element. + + \par Description + Generic Manufacturer Property Get is an acknowledged message used to get the Generic Manufacturer Property state of an element. + The response to the Generic Manufacturer Property Get message is a Generic Manufacturer Property Status message. + + \param [in] param Generic Manufacturer Property Get message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_manufacturer_property_get(param) \ + MS_generic_property_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_MANUFACTURER_PROPERTY_GET_OPCODE,\ + param,\ + MS_ACCESS_GENERIC_MANUFACTURER_PROPERTY_STATUS_OPCODE\ + ) + +/** + \brief API to the Generic Manufacturer Property User Access state of an element. + + \par Description + Generic Manufacturer Property Set is an acknowledged message used to set the Generic Manufacturer Property User Access state of an element. + The response to the Generic Manufacturer Property Set message is a Generic Manufacturer Property Status message. + + \param [in] param Generic Manufacturer Property Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_manufacturer_property_set(param) \ + MS_generic_property_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_MANUFACTURER_PROPERTY_SET_OPCODE,\ + param,\ + MS_ACCESS_GENERIC_MANUFACTURER_PROPERTY_STATUS_OPCODE\ + ) + +/** + \brief API to the Generic Manufacturer Property User Access state of an element. + + \par Description + The Generic Manufacturer Property Set Unacknowledged is an unacknowledged message used to set the Generic Manufacturer Property User Access state of an element. + + \param [in] param Generic Manufacturer Property Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_manufacturer_property_set_unacknowledged(param) \ + MS_generic_property_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_MANUFACTURER_PROPERTY_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the list of Generic Client Property states of an element. + + \par Description + Generic Client Properties Get is an acknowledged message used to get the list of Generic Client Property states of an element. + The response to the Generic Client Properties Get message is a Generic Client Properties Status message. + + \param [in] param Generic Client Properties Get message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_generic_client_properties_get(param) \ + MS_generic_property_client_send_reliable_pdu \ + (\ + MS_ACCESS_GENERIC_CLIENT_PROPERTIES_GET_OPCODE,\ + param,\ + MS_ACCESS_GENERIC_CLIENT_PROPERTIES_STATUS_OPCODE\ + ) +/** \} */ +/** \} */ +/** \} */ + +#endif /*_H_MS_GENERIC_PROPERTY_API_ */ diff --git a/src/components/ethermind/mesh/export/include/MS_health_client_api.h b/src/components/ethermind/mesh/export/include/MS_health_client_api.h new file mode 100644 index 0000000..a5b10d5 --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_health_client_api.h @@ -0,0 +1,421 @@ +/** + \file MS_health_client_api.h + + \brief This file defines the Mesh Health Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_HEALTH_CLIENT_API_ +#define _H_MS_HEALTH_CLIENT_API_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_access_api.h" + + +/* --------------------------------------------- Global Definitions */ +/** + \defgroup health_module HEALTH (Mesh Health Model) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Health Model (HEALTH) module to the Application. +*/ + + + +/* --------------------------------------------- Data Types/ Structures */ +/** + \defgroup health_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ + +/** + Health Client application Asynchronous Notification Callback. + + Health Client calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param opcode Opcode. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef API_RESULT (* MS_HEALTH_CLIENT_CB) +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT32 opcode, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; +/** \} */ + +/** + \defgroup health_structures Structures + \{ +*/ + +/** + Health Status message parameters +*/ +typedef struct MS_health_status_struct +{ + /** Identifier of a performed test */ + UCHAR test_id; + + /** 16-bit Bluetooth assigned Company Identifier */ + UINT16 company_id; + + /** The FaultArray field contains a sequence of 1-octet fault values */ + UCHAR* faultarray; + + /** Number of fault values in the FaultArray */ + UINT16 faultarray_len; + +} MS_HEALTH_STATUS_STRUCT; + +/** + Health Fault Get clear message parameters +*/ +typedef struct MS_health_fault_get_clear_struct +{ + /** 16-bit Bluetooth assigned Company Identifier */ + UINT16 company_id; + +} MS_HEALTH_FAULT_GET_CLEAR_STRUCT; + +/** + Health Fault Test message parameters +*/ +typedef struct MS_health_fault_test_struct +{ + /** Identifier of a performed test */ + UCHAR test_id; + + /** 16-bit Bluetooth assigned Company Identifier */ + UINT16 company_id; + +} MS_HEALTH_FAULT_TEST_STRUCT; + +/** + Health Period message parameters +*/ +typedef struct MS_health_period_struct +{ + /** + Divider for the Publish Period. + Modified Publish Period is used for sending Current Health Status messages + when there are active faults to communicate. + */ + UCHAR fastperioddivisor; + +} MS_HEALTH_PERIOD_STRUCT; + +/** + Health Attention message parameters +*/ +typedef struct MS_health_attention_struct +{ + /** Value of the Attention Timer state */ + UCHAR attention; + +} MS_HEALTH_ATTENTION_STRUCT; + +/** \} */ + + + +/* --------------------------------------------- Function */ +/** + \defgroup health_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Health Model APIs. +*/ +/** + \defgroup health_cli_api_defs Health Client API Definitions + \{ + This section describes the Health Client APIs. +*/ + +/** + \brief API to initialize Health Client model + + \par Description + This is to initialize Health Client model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Health Client. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_health_client_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_HEALTH_CLIENT_CB appl_cb +); + +/** + \brief API to get Health client model handle + + \par Description + This is to get the handle of Health client model. + + \param [out] model_handle Address of model handle to be filled/returned. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_health_client_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle +); + +/** + \brief API to send acknowledged commands + + \par Description + This is to initialize sending acknowledged commands. + + \param [in] req_opcode Request Opcode. + \param [in] param Parameter associated with Request Opcode. + \param [in] rsp_opcode Response Opcode. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_health_client_send_reliable_pdu +( + /* IN */ UINT32 req_opcode, + /* IN */ void* param, + /* IN */ UINT32 rsp_opcode +); + +/** + \brief API to report the registered fault state + + \par Description + The Health Fault Get is an acknowledged message used to get the current + Registered Fault state identified by Company ID of an element. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_HEALTH_FAULT_GET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_health_fault_get(param) \ + MS_health_client_send_reliable_pdu \ + (\ + MS_ACCESS_HEALTH_FAULT_GET_OPCODE,\ + param,\ + MS_ACCESS_HEALTH_FAULT_STATUS_OPCODE\ + ) + +/** + \brief API to clear the registered fault state + + \par Description + The Health Fault Clear Unacknowledged is an unacknowledged message used + to clear the current Registered Fault state identified by Company ID of an element. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_HEALTH_FAULT_CLEAR_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_health_fault_clear_unacknowledged(param) \ + MS_health_client_send_reliable_pdu \ + (\ + MS_ACCESS_HEALTH_FAULT_CLEAR_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to clear the registered fault state + + \par Description + The Health Fault Clear is an acknowledged message used to clear the + current Registered Fault state identified by Company ID of an element. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_HEALTH_FAULT_CLEAR_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_health_fault_clear(param) \ + MS_health_client_send_reliable_pdu \ + (\ + MS_ACCESS_HEALTH_FAULT_CLEAR_OPCODE,\ + param,\ + MS_ACCESS_HEALTH_FAULT_STATUS_OPCODE\ + ) + +/** + \brief API to invoke a self-test procedure + + \par Description + The Health Fault Test is an acknowledged message used to invoke a self-test + procedure of an element. The procedure is implementation specific and may + result in changing the Health Fault state of an element. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_HEALTH_FAULT_TEST_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_health_fault_test(param) \ + MS_health_client_send_reliable_pdu \ + (\ + MS_ACCESS_HEALTH_FAULT_TEST_OPCODE,\ + param,\ + MS_ACCESS_HEALTH_FAULT_STATUS_OPCODE\ + ) + +/** + \brief API to invoke a self-test procedure + + \par Description + The Health Fault Test Unacknowledged is an unacknowledged message used + to invoke a self-test procedure of an element. The procedure is implementation + specific and may result in changing the Health Fault state of an element. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_health_fault_test_unacknowledged(param) \ + MS_health_client_send_reliable_pdu \ + (\ + MS_ACCESS_HEALTH_FAULT_TEST_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the health period state + + \par Description + The Health Period Get is an acknowledged message used to get the + current Health Period state of an element. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_health_period_get() \ + MS_health_client_send_reliable_pdu \ + (\ + MS_ACCESS_HEALTH_PERIOD_GET_OPCODE,\ + NULL,\ + MS_ACCESS_HEALTH_PERIOD_STATUS_OPCODE\ + ) + +/** + \brief API to set the health period state + + \par Description + The Health Period Set Unacknowledged is an unacknowledged message used + to set the current Health Period state of an element. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_HEALTH_PERIOD_SET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_health_period_set_unacknowledged(param) \ + MS_health_client_send_reliable_pdu \ + (\ + MS_ACCESS_HEALTH_PERIOD_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to set the health period state + + \par Description + The Health Period Set is an acknowledged message used to set the + current Health Period state of an element. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_HEALTH_PERIOD_SET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_health_period_set(param) \ + MS_health_client_send_reliable_pdu \ + (\ + MS_ACCESS_HEALTH_PERIOD_SET_OPCODE,\ + param,\ + MS_ACCESS_HEALTH_PERIOD_STATUS_OPCODE\ + ) + +/** + \brief API to get the attention state + + \par Description + The Health Attention Get is an acknowledged message used to get + the current Attention Timer state of an element. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_health_attention_get() \ + MS_health_client_send_reliable_pdu \ + (\ + MS_ACCESS_HEALTH_ATTENTION_GET_OPCODE,\ + NULL,\ + MS_ACCESS_HEALTH_ATTENTION_STATUS_OPCODE\ + ) + +/** + \brief API to set the attention state + + \par Description + The Health Attention Set is an acknowledged message used to set the + Attention Timer state of an element. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_HEALTH_ATTENTION_SET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_health_attention_set(param) \ + MS_health_client_send_reliable_pdu \ + (\ + MS_ACCESS_HEALTH_ATTENTION_SET_OPCODE,\ + param,\ + MS_ACCESS_HEALTH_ATTENTION_STATUS_OPCODE\ + ) + +/** + \brief API to set the attention state + + \par Description + The Health Attention Set Unacknowledged is an unacknowledged message + used to set the Attention Timer state of an element. + + \param [in] param + Pointer to the structure populated as in \ref ACCESS_HEALTH_ATTENTION_SET_PARAM + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_health_attention_set_unacknowledged(param) \ + MS_health_client_send_reliable_pdu \ + (\ + MS_ACCESS_HEALTH_ATTENTION_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) +/** \} */ +/** \} */ +/** \} */ + +#endif /* _H_MS_HEALTH_CLIENT_API_ */ diff --git a/src/components/ethermind/mesh/export/include/MS_health_server_api.h b/src/components/ethermind/mesh/export/include/MS_health_server_api.h new file mode 100644 index 0000000..8294f97 --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_health_server_api.h @@ -0,0 +1,276 @@ +/** + \file MS_health_server_api.h + + \brief This file defines the Mesh Health Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_HEALTH_SERVER_API_ +#define _H_MS_HEALTH_SERVER_API_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_access_api.h" + + +/* --------------------------------------------- Global Definitions */ +/** + \defgroup health_fault_values Fault Values + \{ + This section lists the Fault Values defined for Health Model. +*/ + +/** Health Model - Fault Values */ +/** No Fault */ +#define MS_HEALTH_FAULT_NO_FAULT 0x00 +/** Battery Low Warning */ +#define MS_HEALTH_FAULT_BATTERY_LOW_WARNING 0x01 +/** Battery Low Error */ +#define MS_HEALTH_FAULT_BATTERY_LOW_ERROR 0x02 +/** Supply Voltage Too Low Warning */ +#define MS_HEALTH_FAULT_SUPPLY_VOLTAGE_TOO_LOW_WARNING 0x03 +/** Supply Voltage Too Low Error */ +#define MS_HEALTH_FAULT_SUPPLY_VOLTAGE_TOO_LOW_ERROR 0x04 +/** Supply Voltage Too High Warning */ +#define MS_HEALTH_FAULT_SUPPLY_VOLTAGE_TOO_HIGH_WARNING 0x05 +/** Supply Voltage Too High Error */ +#define MS_HEALTH_FAULT_SUPPLY_VOLTAGE_TOO_HIGH_ERROR 0x06 +/** Power Supply Interrupted Warning */ +#define MS_HEALTH_FAULT_POWER_SUPPLY_INTERRUPTED_WARNING 0x07 +/** Power Supply Interrupted Error */ +#define MS_HEALTH_FAULT_POWER_SUPPLY_INTERRUPTED_ERROR 0x08 +/** No Load Warning */ +#define MS_HEALTH_FAULT_NO_LOAD_WARNING 0x09 +/** No Load Error */ +#define MS_HEALTH_FAULT_NO_LOAD_ERROR 0x0A +/** Overload Warning */ +#define MS_HEALTH_FAULT_OVERLOAD_WARNING 0x0B +/** Overload Error */ +#define MS_HEALTH_FAULT_OVERLOAD_ERROR 0x0C +/** Overheat Warning */ +#define MS_HEALTH_FAULT_OVERHEAT_WARNING 0x0D +/** Overheat Error */ +#define MS_HEALTH_FAULT_OVERHEAT_ERROR 0x0E +/** Condensation Warning */ +#define MS_HEALTH_FAULT_CONDENSATION_WARNING 0x0F +/** Condensation Error */ +#define MS_HEALTH_FAULT_CONDENSATION_ERROR 0x10 +/** Vibration Warning */ +#define MS_HEALTH_FAULT_VIBRATION_WARNING 0x11 +/** Vibration Error */ +#define MS_HEALTH_FAULT_VIBRATION_ERROR 0x12 +/** Configuration Warning */ +#define MS_HEALTH_FAULT_CONFIGURATION_WARNING 0x13 +/** Configuration Error */ +#define MS_HEALTH_FAULT_CONFIGURATION_ERROR 0x14 +/** Element Not Calibrated Warning */ +#define MS_HEALTH_FAULT_ELEMENT_NOT_CALIBRATED_WARNING 0x15 +/** Element Not Calibrated Error */ +#define MS_HEALTH_FAULT_ELEMENT_NOT_CALIBRATED_ERROR 0x16 +/** Memory Warning */ +#define MS_HEALTH_FAULT_MEMORY_WARNING 0x17 +/** Memory Error */ +#define MS_HEALTH_FAULT_MEMORY_ERROR 0x18 +/** Self-Test Warning */ +#define MS_HEALTH_FAULT_SELF_TEST_WARNING 0x19 +/** Self-Test Error */ +#define MS_HEALTH_FAULT_SELF_TEST_ERROR 0x1A +/** Input Too Low Warning */ +#define MS_HEALTH_FAULT_INPUT_TOO_LOW_WARNING 0x1B +/** Input Too Low Error */ +#define MS_HEALTH_FAULT_INPUT_TOO_LOW_ERROR 0x1C +/** Input Too High Warning */ +#define MS_HEALTH_FAULT_INPUT_TOO_HIGH_WARNING 0x1D +/** Input Too High Error */ +#define MS_HEALTH_FAULT_INPUT_TOO_HIGH_ERROR 0x1E +/** Input No Change Warning */ +#define MS_HEALTH_FAULT_INPUT_NO_CHANGE_WARNING 0x1F +/** Input No Change Error */ +#define MS_HEALTH_FAULT_INPUT_NO_CHANGE_ERROR 0x20 +/** Actuator Blocked Warning */ +#define MS_HEALTH_FAULT_ACTUATOR_BLOCKED_WARNING 0x21 +/** Actuator Blocked Error */ +#define MS_HEALTH_FAULT_ACTUATOR_BLOCKED_ERROR 0x22 +/** Housing Opened Warning */ +#define MS_HEALTH_FAULT_HOUSING_OPENED_WARNING 0x23 +/** Housing Opened Error */ +#define MS_HEALTH_FAULT_HOUSING_OPENED_ERROR 0x24 +/** Tamper Warning */ +#define MS_HEALTH_FAULT_TAMPER_WARNING 0x25 +/** Tamper Error */ +#define MS_HEALTH_FAULT_TAMPER_ERROR 0x26 +/** Device Moved Warning */ +#define MS_HEALTH_FAULT_DEVICE_MOVED_WARNING 0x27 +/** Device Moved Error */ +#define MS_HEALTH_FAULT_DEVICE_MOVED_ERROR 0x28 +/** Device Dropped Warning */ +#define MS_HEALTH_FAULT_DEVICE_DROPPED_WARNING 0x29 +/** Device Dropped Error */ +#define MS_HEALTH_FAULT_DEVICE_DROPPED_ERROR 0x2A +/** Overflow Warning */ +#define MS_HEALTH_FAULT_OVERFLOW_WARNING 0x2B +/** Overflow Error */ +#define MS_HEALTH_FAULT_OVERFLOW_ERROR 0x2C +/** Empty Warning */ +#define MS_HEALTH_FAULT_EMPTY_WARNING 0x2D +/** Empty Error */ +#define MS_HEALTH_FAULT_EMPTY_ERROR 0x2E +/** Internal Bus Warning */ +#define MS_HEALTH_FAULT_INTERNAL_BUS_WARNING 0x2F +/** Internal Bus Error */ +#define MS_HEALTH_FAULT_INTERNAL_BUS_ERROR 0x30 +/** Mechanism Jammed Warning */ +#define MS_HEALTH_FAULT_MECHANISM_JAMMED_WARNING 0x31 +/** Mechanism Jammed Error*/ +#define MS_HEALTH_FAULT_MECHANISM_JAMMED_ERROR 0x32 + +/* 0x33 - 0x7F: Reserved for Future Use */ +/* 0x80 - 0xFF: Vendor Specific Warning / Error */ + +/** \} */ + +/** + \defgroup health_server_events Health Server Events + \{ + This section lists the Application Events defined for Health Server Model. +*/ + +/** Attention Start */ +#define MS_HEALTH_SERVER_ATTENTION_START 0x01 + +/** Attention Restart */ +#define MS_HEALTH_SERVER_ATTENTION_RESTART 0x02 + +/** Attention Stop */ +#define MS_HEALTH_SERVER_ATTENTION_STOP 0x03 + +/** \} */ + + +/* --------------------------------------------- Data Types/ Structures */ +/** + \brief Health Server application Asynchronous Notification Callback. + + \par Description + Health Server calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param event_type Health Server Event type. + \param event_param Parameter associated with the event if any or NULL. + \param param_len Size of the event parameter data. 0 if event param is NULL. +*/ +typedef API_RESULT (* MS_HEALTH_SERVER_CB) +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT8 event_type, + UINT8* event_param, + UINT16 param_len +) DECL_REENTRANT; + + +/** + Health Server Self Test Function. +*/ +/* TODO: Add context of the Health Server, so that associated current/registered fault can be updated */ +typedef void (* MS_HEALTH_SERVER_SELF_TEST_FN)(UINT8 test_id, UINT16 company_id); + +/** + Health Server Self Test Funtion Structure. +*/ +typedef struct _MS_HEALTH_SERVER_SELF_TEST +{ + /** Test ID */ + UINT8 test_id; + + /** Self Test Function */ + MS_HEALTH_SERVER_SELF_TEST_FN self_test_fn; + +} MS_HEALTH_SERVER_SELF_TEST; + + +/* --------------------------------------------- Function */ +/** + \brief API to initialize Health Server model + + \par Description + This is to initialize Health Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] company_id + Company Identifier + + \param [in] self_tests + List of Self Tests that can be run. + + \param [in] num_self_tests + Number of Self Tests in the list. + + \param [in] appl_cb Application Callback to be used by the Health Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_health_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ UINT16 company_id, + /* IN */ MS_HEALTH_SERVER_SELF_TEST* self_tests, + /* IN */ UINT32 num_self_tests, + /* IN */ MS_HEALTH_SERVER_CB appl_cb +); + +/** + \brief API to report self-test fault + + \par Description + This is to report fault observed during self-test procedure. + + \param [in] model_handle + Model Handle identifying the Health Server model instance. + + \param [in] test_id + Identifier of the self-test + + \param [in] company_id + Company Identifier + + \param [in] fault_code + Fault value indicating the error. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_health_server_report_fault +( + /* IN */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ UINT8 test_id, + /* IN */ UINT16 company_id, + /* IN */ UINT8 fault_code +); + +/** + \cond ignore_this Ignore this fundtion while generating doxygen document +*/ + +API_RESULT MS_health_server_publish_current_status +( + UCHAR* status, + UINT16 length +); +/** + \endcond +*/ + +#endif /*_H_MS_HEALTH_SERVER_API_ */ diff --git a/src/components/ethermind/mesh/export/include/MS_light_ctl_api.h b/src/components/ethermind/mesh/export/include/MS_light_ctl_api.h new file mode 100644 index 0000000..e6d6543 --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_light_ctl_api.h @@ -0,0 +1,727 @@ +/** + \file MS_light_ctl_api.h + + \brief This file defines the Mesh Light Ctl Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_LIGHT_CTL_API_ +#define _H_MS_LIGHT_CTL_API_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_access_api.h" + + +/* --------------------------------------------- Global Definitions */ +/** + \defgroup light_ctl_module LIGHT_CTL (Mesh Light Ctl Model) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Generic OnOff Model (ONOFF) module to the Application. +*/ + + + +/* --------------------------------------------- Data Types/ Structures */ +/** + \defgroup light_ctl_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ + +/** + Light Ctl Server application Asynchronous Notification Callback. + + Light Ctl Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_LIGHT_CTL_SERVER_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_MODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; + +/** + Light Ctl Temperature Server application Asynchronous Notification Callback. + + Light Ctl Temperature Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_LIGHT_CTL_TEMPERATURE_SERVER_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_MODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; + +/** + Light Ctl Client application Asynchronous Notification Callback. + + Light Ctl Client calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param opcode Opcode. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef API_RESULT (* MS_LIGHT_CTL_CLIENT_CB) +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT32 opcode, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; +/** \} */ + +/** + \defgroup light_ctl_structures Structures + \{ +*/ + +/** + Light CTL Set message parameters. +*/ +typedef struct MS_light_ctl_set_struct +{ + /** The target value of the Light CTL Lightness state. */ + UINT16 ctl_lightness; + + /** The target value of the Light CTL Temperature state. */ + UINT16 ctl_temperature; + + /** The target value of the Light CTL Delta UV state. */ + UINT16 ctl_delta_uv; + + /** Transaction Identifier */ + UCHAR tid; + + /** + Transition Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR transition_time; + + /** Message execution delay in 5 milliseconds steps */ + UCHAR delay; + + /** Flag: To represent if optional Transaction time and Delay fields are valid */ + UCHAR optional_fields_present; + +} MS_LIGHT_CTL_SET_STRUCT; + +/** + Light CTL Status message parameters. +*/ +typedef struct MS_light_ctl_status_struct +{ + /** The present value of the Light CTL Lightness state */ + UINT16 present_ctl_lightness; + + /** The present value of the Light CTL Temperature state */ + UINT16 present_ctl_temperature; + + /** The target value of the Light CTL Lightness state (Optional) */ + UINT16 target_ctl_lightness; + + /** The target value of the Light CTL Temperature state */ + UINT16 target_ctl_temperature; + + /** + Remaining Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR remaining_time; + + /** Flag: To represent if optional fields Target CTL Lightness and Temperature are valid */ + UCHAR optional_fields_present; + +} MS_LIGHT_CTL_STATUS_STRUCT; + +/** + Light CTL Temperature Set message parameters. +*/ +typedef struct MS_light_ctl_temperature_set_struct +{ + /** The target value of the Light CTL Temperature state. */ + UINT16 ctl_temperature; + + /** The target value of the Light CTL Delta UV state. */ + UINT16 ctl_delta_uv; + + /** Transaction Identifier */ + UCHAR tid; + + /** + Transition Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR transition_time; + + /** Message execution delay in 5 milliseconds steps */ + UCHAR delay; + + /** Flag: To represent if optional Transaction time and Delay fields are valid */ + UCHAR optional_fields_present; + +} MS_LIGHT_CTL_TEMPERATURE_SET_STRUCT; + +/** + Light CTL Temperature Status message parameters. +*/ +typedef struct MS_light_ctl_temperature_status_struct +{ + /** The present value of the Light CTL Temperature state. */ + UINT16 present_ctl_temperature; + + /** The present value of the Light CTL Delta UV state */ + UINT16 present_ctl_delta_uv; + + /** The target value of the Light CTL Temperature state (Optional) */ + UINT16 target_ctl_temperature; + + /** The target value of the Light CTL Delta UV state */ + UINT16 target_ctl_delta_uv; + + /** + Remaining Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR remaining_time; + + /** Flag: To represent if optional fields Target CTL Temperature, Delta UV and Remaining Time are valid */ + UCHAR optional_fields_present; + +} MS_LIGHT_CTL_TEMPERATURE_STATUS_STRUCT; + +/** + Light CTL Default Set message parameters. +*/ +typedef struct MS_light_ctl_default_set_struct +{ + /** The value of the Light Lightness Default state. */ + UINT16 lightness; + + /** The value of the Light CTL Temperature Default state. */ + UINT16 temperature; + + /** The value of the Light CTL Delta UV Default state. */ + UINT16 delta_uv; + +} MS_LIGHT_CTL_DEFAULT_SET_STRUCT; + +/** + Light CTL Default Status message parameters. +*/ +typedef struct MS_light_ctl_default_status_struct +{ + /** The value of the Light Lightness Default state */ + UINT16 lightness; + + /** The value of the Light CTL Temperature Default state */ + UINT16 temperature; + + /** The value of the Light CTL Delta UV Default state */ + UINT16 delta_uv; + +} MS_LIGHT_CTL_DEFAULT_STATUS_STRUCT; + +/** + Light CTL Temperature Range Set message parameters. +*/ +typedef struct MS_light_ctl_temperature_range_set_struct +{ + /** The value of the Temperature Range Min field of the Light CTL Temperature Range state */ + UINT16 range_min; + + /** The value of the Temperature Range Max field of the Light CTL Temperature Range state */ + UINT16 range_max; + +} MS_LIGHT_CTL_TEMPERATURE_RANGE_SET_STRUCT; + +/** + Light CTL Temperature Range Status message parameters. +*/ +typedef struct MS_light_ctl_temperature_range_status_struct +{ + /** Status Code for the requesting message. */ + UCHAR status_code; + + /** The value of the Temperature Range Min field of the Light CTL Temperature Range state */ + UINT16 range_min; + + /** The value of the Temperature Range Max field of the Light CTL Temperature Range state */ + UINT16 range_max; + +} MS_LIGHT_CTL_TEMPERATURE_RANGE_STATUS_STRUCT; + +/** \} */ + + + +/* --------------------------------------------- Function */ +/** + \defgroup light_ctl_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Light Ctl Model APIs. +*/ +/** + \defgroup light_ctl_ser_api_defs Light Ctl Server API Definitions + \{ + This section describes the Light Ctl Server APIs. +*/ + +/** + \brief API to initialize Light_Ctl Server model + + \par Description + This is to initialize Light_Ctl Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] ctl_model_handle + Model identifier associated with the Light CTL model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in, out] ctl_setup_model_handle + Model identifier associated with the Light CTL Setup model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Light_Ctl Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_ctl_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* ctl_model_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* ctl_setup_model_handle, + /* IN */ MS_LIGHT_CTL_SERVER_CB appl_cb +); + +/** + \brief API to initialize Light_Ctl_Temperature Server model + + \par Description + This is to initialize Light_Ctl_Temperature Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Light_Ctl_Temperature Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_ctl_temperature_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_LIGHT_CTL_TEMPERATURE_SERVER_CB appl_cb +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_ctl_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_ctl_temperature_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** \} */ + +/** + \defgroup light_ctl_cli_api_defs Light Ctl Client API Definitions + \{ + This section describes the Light Ctl Client APIs. +*/ + +/** + \brief API to initialize Light_Ctl Client model + + \par Description + This is to initialize Light_Ctl Client model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Light_Ctl Client. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_ctl_client_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_LIGHT_CTL_CLIENT_CB appl_cb +); + +/** + \brief API to get Light_Ctl client model handle + + \par Description + This is to get the handle of Light_Ctl client model. + + \param [out] model_handle Address of model handle to be filled/returned. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_ctl_client_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle +); + +/** + \brief API to send acknowledged commands + + \par Description + This is to initialize sending acknowledged commands. + + \param [in] req_opcode Request Opcode. + \param [in] param Parameter associated with Request Opcode. + \param [in] rsp_opcode Response Opcode. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_ctl_client_send_reliable_pdu +( + /* IN */ UINT32 req_opcode, + /* IN */ void* param, + /* IN */ UINT32 rsp_opcode +); + +/** + \brief API to get the Light CTL state of an element. + + \par Description + Light CTL Get is an acknowledged message used to get the Light CTL state of an element. + The response to the Light CTL Get message is a Light CTL Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_ctl_get() \ + MS_light_ctl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_CTL_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_CTL_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light CTL Lightness state, Light CTL Temperature state, and the Light CTL Delta UV state of an element. + + \par Description + Light CTL Set is an acknowledged message used to set the Light CTL Lightness state, Light CTL Temperature state, + and the Light CTL Delta UV state of an element. + The response to the Light CTL Set message is a Light CTL Status message. + + \param [in] param Light CTL Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_ctl_set(param) \ + MS_light_ctl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_CTL_SET_OPCODE,\ + param,\ + MS_ACCESS_LIGHT_CTL_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light CTL Lightness state, Light CTL Temperature state, and the Light CTL Delta UV state of an element. + + \par Description + Light CTL Set Unacknowledged is an unacknowledged message used to set the Light CTL Lightness state, Light CTL Temperature state, + and the Light CTL Delta UV state of an element + + \param [in] param Light CTL Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_ctl_set_unacknowledged(param) \ + MS_light_ctl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_CTL_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the Light CTL Temperature state of an element. + + \par Description + Light CTL Temperature Get is an acknowledged message used to get the Light CTL Temperature state of an element. + The response to the Light CTL Temperature Get message is a Light CTL Temperature Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_ctl_temperature_get() \ + MS_light_ctl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_CTL_TEMPERATURE_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_CTL_TEMPERATURE_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light CTL Temperature state and the Light CTL Delta UV state of an element. + + \par Description + The Light CTL Temperature Set is an acknowledged message used to set the Light CTL Temperature state + and the Light CTL Delta UV state of an element. + The response to the Light CTL Temperature Set message is a Light CTL Temperature Status message. + + \param [in] param Light CTL Temperature Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_ctl_temperature_set(param) \ + MS_light_ctl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_CTL_TEMPERATURE_SET_OPCODE,\ + param,\ + MS_ACCESS_LIGHT_CTL_TEMPERATURE_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light CTL Temperature state and the Light CTL Delta UV state of an element. + + \par Description + The Light CTL Temperature Set Unacknowledged is an unacknowledged message used to set the Light CTL Temperature state + and the Light CTL Delta UV state of an element + + \param [in] param Light CTL Temperature Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_ctl_temperature_set_unacknowledged(param) \ + MS_light_ctl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_CTL_TEMPERATURE_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the Light CTL Temperature Default and Light CTL Delta UV Default states of an element. + + \par Description + Light CTL Default Get is an acknowledged message used to get the Light CTL Temperature Default and Light CTL Delta UV Default states of an element. + The response to the Light CTL Default Get message is a Light CTL Default Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_ctl_default_get() \ + MS_light_ctl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_CTL_DEFAULT_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_CTL_DEFAULT_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light CTL Temperature Default state and the Light CTL Delta UV Default state of an element. + + \par Description + The Light CTL Default Set is an acknowledged message used to set the Light CTL Temperature Default state + and the Light CTL Delta UV Default state of an element. + The response to the Light CTL Set message is a Light CTL Status message. + + \param [in] param Light CTL Default Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_ctl_default_set(param) \ + MS_light_ctl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_CTL_DEFAULT_SET_OPCODE,\ + param,\ + MS_ACCESS_LIGHT_CTL_DEFAULT_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light CTL Temperature Default state and the Light CTL Delta UV Default state of an element. + + \par Description + The Light CTL Default Set Unacknowledged is an unacknowledged message used to set the Light CTL Temperature + Default state and the Light CTL Delta UV Default state of an element. + + \param [in] param Light CTL Default Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_ctl_default_set_unacknowledged(param) \ + MS_light_ctl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_CTL_DEFAULT_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the Light CTL Temperature Range state of an element. + + \par Description + The Light CTL Temperature Range Get is an acknowledged message used to get the Light CTL Temperature Range state of an element. + The response to the Light CTL Temperature Range Get message is a Light CTL Temperature Range Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_ctl_temperature_range_get() \ + MS_light_ctl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_CTL_TEMPERATURE_RANGE_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_CTL_TEMPERATURE_RANGE_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light CTL Temperature Range state of an element. + + \par Description + Light CTL Temperature Range Set Unacknowledged is an unacknowledged message used to set + the Light CTL Temperature Range state of an element. + + \param [in] param Light CTL Temperature Range Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_ctl_temperature_range_set(param) \ + MS_light_ctl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_CTL_TEMPERATURE_RANGE_SET_OPCODE,\ + param,\ + MS_ACCESS_LIGHT_CTL_TEMPERATURE_RANGE_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light CTL Temperature Range state of an element. + + \par Description + Light CTL Temperature Range Set is an acknowledged message used to set the Light CTL Temperature Range state of an element. + The response to the Light CTL Temperature Range Get message is a Light CTL Temperature Range Status message. + + \param [in] param Light CTL Temperature Range Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_ctl_temperature_range_set_unacknowledged(param) \ + MS_light_ctl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_CTL_TEMPERATURE_RANGE_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) +/** \} */ +/** \} */ +/** \} */ + +#endif /*_H_MS_LIGHT_CTL_API_ */ diff --git a/src/components/ethermind/mesh/export/include/MS_light_hsl_api.h b/src/components/ethermind/mesh/export/include/MS_light_hsl_api.h new file mode 100644 index 0000000..3eb319e --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_light_hsl_api.h @@ -0,0 +1,963 @@ +/** + \file MS_light_hsl_api.h + + \brief This file defines the Mesh Light Hsl Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_LIGHT_HSL_API_ +#define _H_MS_LIGHT_HSL_API_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_access_api.h" + + +/* --------------------------------------------- Global Definitions */ +/** + \defgroup light_hsl_module LIGHT_HSL (Mesh Light Hsl Model) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Generic OnOff Model (ONOFF) module to the Application. +*/ + + + +/* --------------------------------------------- Data Types/ Structures */ +/** + \defgroup light_hsl_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ + +/** + Light Hsl Server application Asynchronous Notification Callback. + + Light Hsl Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_LIGHT_HSL_SERVER_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_MODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; + +/** + Light Hsl Hue Server application Asynchronous Notification Callback. + + Light Hsl Hue Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_LIGHT_HSL_HUE_SERVER_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_MODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; + +/** + Light Hsl Saturation Server application Asynchronous Notification Callback. + + Light Hsl Saturation Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_LIGHT_HSL_SATURATION_SERVER_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_MODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; + +/** + Light Hsl Client application Asynchronous Notification Callback. + + Light Hsl Client calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param opcode Opcode. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef API_RESULT (* MS_LIGHT_HSL_CLIENT_CB) +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT32 opcode, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; +/** \} */ + +/** + \defgroup light_hsl_structures Structures + \{ +*/ + +/** + Light HSL Set message parameters. +*/ +typedef struct MS_light_hsl_set_struct +{ + /** The target value of the Light HSL Lightness state */ + UINT16 hsl_lightness; + + /** The target value of the Light HSL Hue state */ + UINT16 hsl_hue; + + /** The target value of the Light HSL Saturation state */ + UINT16 hsl_saturation; + + /** Transaction Identifier */ + UCHAR tid; + + /** + Transition Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR transition_time; + + /** Message execution delay in 5 milliseconds steps */ + UCHAR delay; + + /** Flag: To represent if optional Transaction time and Delay fields are valid */ + UCHAR optional_fields_present; + +} MS_LIGHT_HSL_SET_STRUCT; + +/** + Light HSL Status message parameters. +*/ +typedef struct MS_light_hsl_status_struct +{ + /** The present value of the Light HSL Lightness state */ + UINT16 hsl_lightness; + + /** The present value of the Light HSL Hue state */ + UINT16 hsl_hue; + + /** The present value of the Light HSL Saturation state */ + UINT16 hsl_saturation; + + /** + Remaining Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR remaining_time; + + /** Flag: To represent if optional field Remaining Time is valid */ + UCHAR optional_fields_present; + +} MS_LIGHT_HSL_STATUS_STRUCT; + +/** + Light HSL Target Status message parameters. +*/ +typedef struct MS_light_hsl_target_status_struct +{ + /** The target value of the Light HSL Lightness state */ + UINT16 hsl_lightness_target; + + /** The target value of the Light HSL Hue state */ + UINT16 hsl_hue_target; + + /** The target Light HSL Saturation state */ + UINT16 hsl_saturation_target; + + /** + Remaining Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR remaining_time; + + /** Flag: To represent if optional field Remaining Time is valid */ + UCHAR optional_fields_present; + +} MS_LIGHT_HSL_TARGET_STATUS_STRUCT; + +/** + Light HSL Default Set message parameters. +*/ +typedef struct MS_light_hsl_default_set_struct +{ + /** The value of the Light Lightness Default state */ + UINT16 lightness; + + /** The value of the Light HSL Hue Default state */ + UINT16 hue; + + /** The value of the Light HSL Saturation Default state */ + UINT16 saturation; + +} MS_LIGHT_HSL_DEFAULT_SET_STRUCT; + +/** + Light HSL Default Status message parameters. +*/ +typedef struct MS_light_hsl_default_status_struct +{ + /** The value of the Light Lightness Default state */ + UINT16 lightness; + + /** The value of the Light HSL Hue Default state */ + UINT16 hue; + + /** The value of the Light HSL Saturation Default state */ + UINT16 saturation; + +} MS_LIGHT_HSL_DEFAULT_STATUS_STRUCT; + +/** + Light HSL Range Set message parameters. +*/ +typedef struct MS_light_hsl_range_set_struct +{ + /** The value of the Hue Range Min field of the Light HSL Hue Range state */ + UINT16 hue_range_min; + + /** The value of the Hue Range Max field of the Light HSL Hue Range state */ + UINT16 hue_range_max; + + /** The value of the Saturation Range Min field of the Light HSL Saturation Range state */ + UINT16 saturation_range_min; + + /** The value of the Saturation Range Max field of the Light HSL Saturation Range state */ + UINT16 saturation_range_max; + +} MS_LIGHT_HSL_RANGE_SET_STRUCT; + +/** + Light HSL Range Status message parameters. +*/ +typedef struct MS_light_hsl_range_status_struct +{ + /** Status Code for the requesting message. */ + UCHAR status_code; + + /** The value of the Hue Range Min field of the Light HSL Hue Range state */ + UINT16 hue_range_min; + + /** The value of the Hue Range Max field of the Light HSL Hue Range state */ + UINT16 hue_range_max; + + /** The value of the Saturation Range Min field of the Light HSL Saturation Range state */ + UINT16 saturation_range_min; + + /** The value of the Saturation Range Max field of the Light HSL Saturation Range state */ + UINT16 saturation_range_max; + +} MS_LIGHT_HSL_RANGE_STATUS_STRUCT; + +/** + Light HSL Hue Set message parameters. +*/ +typedef struct MS_light_hsl_hue_set_struct +{ + /** The target value of the Light HSL Hue state. */ + UINT16 hue; + + /** Transaction Identifier */ + UCHAR tid; + + /** + Transition Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR transition_time; + + /** Message execution delay in 5 milliseconds steps */ + UCHAR delay; + + /** Flag: To represent if optional Transaction time and Delay fields are valid */ + UCHAR optional_fields_present; + +} MS_LIGHT_HSL_HUE_SET_STRUCT; + +/** + Light HSL Hue Status message parameters. +*/ +typedef struct MS_light_hsl_hue_status_struct +{ + /** The present value of the Light HSL Hue state */ + UINT16 present_hue; + + /** The target value of the Light HSL Hue state (Optional) */ + UINT16 target_hue; + + /** + Remaining Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR remaining_time; + + /** Flag: To represent if optional fields Target Hue and Remaining Time are valid */ + UCHAR optional_fields_present; + +} MS_LIGHT_HSL_HUE_STATUS_STRUCT; + +/** + Light HSL Saturation Set message parameters. +*/ +typedef struct MS_light_hsl_saturation_set_struct +{ + /** The target value of the Light HSL Saturation state. */ + UINT16 saturation; + + /** Transaction Identifier */ + UCHAR tid; + + /** + Transition Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR transition_time; + + /** Message execution delay in 5 milliseconds steps */ + UCHAR delay; + + /** Flag: To represent if optional Transaction time and Delay fields are valid */ + UCHAR optional_fields_present; + +} MS_LIGHT_HSL_SATURATION_SET_STRUCT; + +/** + Light HSL Saturation Status message parameters. +*/ +typedef struct MS_light_hsl_saturation_status_struct +{ + /** The present value of the Light HSL Saturation state. */ + UINT16 present_saturation; + + /** The target value of the Light HSL Saturation state. (Optional) */ + UINT16 target_saturation; + + /** + Remaining Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR remaining_time; + + /** Flag: To represent if optional fields Target Saturation and Remaining Time are valid */ + UCHAR optional_fields_present; + +} MS_LIGHT_HSL_SATURATION_STATUS_STRUCT; + +/** \} */ + + + +/* --------------------------------------------- Function */ +/** + \defgroup light_hsl_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Light Hsl Model APIs. +*/ +/** + \defgroup light_hsl_ser_api_defs Light Hsl Server API Definitions + \{ + This section describes the Light Hsl Server APIs. +*/ + +/** + \brief API to initialize Light_Hsl Server model + + \par Description + This is to initialize Light_Hsl Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] hsl_model_handle + Model identifier associated with the Light HSL model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in, out] hsl_setup_model_handle + Model identifier associated with the Light HSL Setup model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Light_Hsl Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_hsl_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* hsl_model_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* hsl_setup_model_handle, + /* IN */ MS_LIGHT_HSL_SERVER_CB appl_cb +); + +/** + \brief API to initialize Light_Hsl_Hue Server model + + \par Description + This is to initialize Light_Hsl_Hue Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Light_Hsl_Hue Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_hsl_hue_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_LIGHT_HSL_HUE_SERVER_CB appl_cb +); + +/** + \brief API to initialize Light_Hsl_Saturation Server model + + \par Description + This is to initialize Light_Hsl_Saturation Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Light_Hsl_Saturation Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_hsl_saturation_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_LIGHT_HSL_SATURATION_SERVER_CB appl_cb +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_hsl_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_hsl_hue_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_hsl_saturation_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); +/** \} */ + +/** + \defgroup light_hsl_cli_api_defs Light Hsl Client API Definitions + \{ + This section describes the Light Hsl Client APIs. +*/ + +/** + \brief API to initialize Light_Hsl Client model + + \par Description + This is to initialize Light_Hsl Client model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Light_Hsl Client. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_hsl_client_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_LIGHT_HSL_CLIENT_CB appl_cb +); + +/** + \brief API to get Light_Hsl client model handle + + \par Description + This is to get the handle of Light_Hsl client model. + + \param [out] model_handle Address of model handle to be filled/returned. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_hsl_client_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle +); + +/** + \brief API to send acknowledged commands + + \par Description + This is to initialize sending acknowledged commands. + + \param [in] req_opcode Request Opcode. + \param [in] param Parameter associated with Request Opcode. + \param [in] rsp_opcode Response Opcode. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_hsl_client_send_reliable_pdu +( + /* IN */ UINT32 req_opcode, + /* IN */ void* param, + /* IN */ UINT32 rsp_opcode +); + +/** + \brief API to get the Light HSL Lightness, Light HSL Hue, and Light HSL Saturation states of an element. + + \par Description + The Light HSL Get is an acknowledged message used to get the Light HSL Lightness, Light HSL Hue, and Light HSL Saturation states of an element. + The response to the Light HSL Get message is a Light HSL Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_hsl_get() \ + MS_light_hsl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_HSL_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_HSL_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light HSL Lightness state, Light HSL Hue state, and the Light HSL Saturation state of an element. + + \par Description + The Light HSL Set Unacknowledged is an unacknowledged message used to set the Light HSL Lightness state, Light HSL Hue state, + and the Light HSL Saturation state of an element. + + \param [in] param Light HSL Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_hsl_set(param) \ + MS_light_hsl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_HSL_SET_OPCODE,\ + param,\ + MS_ACCESS_LIGHT_HSL_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light HSL Lightness state, Light HSL Hue state, and the Light HSL Saturation state of an element. + + \par Description + The Light HSL Set is an acknowledged message used to set the Light HSL Lightness state, Light HSL Hue state, + and the Light HSL Saturation state of an element. + The response to the Light HSL Set message is a Light HSL Status message. + + \param [in] param Light HSL Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_hsl_set_unacknowledged(param) \ + MS_light_hsl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_HSL_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the target Light HSL Lightness, Light HSL Hue, and Light HSL Saturation states of an element. + + \par Description + Light HSL Target Get is an acknowledged message used to get the target Light HSL Lightness, Light HSL Hue, + and Light HSL Saturation states of an element. + The response to the Light HSL Target Get message is a Light HSL Target Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_hsl_target_get() \ + MS_light_hsl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_HSL_TARGET_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_HSL_TARGET_STATUS_OPCODE\ + ) + +/** + \brief API to to get the Light Lightness Default, the Light HSL Hue Default, and Light HSL Saturation Default states of an element. + + \par Description + Light HSL Default Get is an acknowledged message used to get the Light Lightness Default, the Light HSL Hue Default, + and Light HSL Saturation Default states of an element. + The response to the Light HSL Default Get message is a Light HSL Default Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_hsl_default_get() \ + MS_light_hsl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_HSL_DEFAULT_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_HSL_DEFAULT_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light Lightness Default, the Light HSL Hue Default, and Light HSL Saturation Default states of an element. + + \par Description + Light HSL Default Set is an acknowledged message used to set the Light Lightness Default, the Light HSL Hue Default, + and Light HSL Saturation Default states of an element. + The response to the Light HSL Default Set message is a Light HSL Default Status message. + + \param [in] param Light HSL Default Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_hsl_default_set(param) \ + MS_light_hsl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_HSL_DEFAULT_SET_OPCODE,\ + param,\ + MS_ACCESS_LIGHT_HSL_DEFAULT_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light Lightness Default, the Light HSL Hue Default, and Light HSL Saturation Default states of an element. + + \par Description + Light HSL Default Set Unacknowledged is an unacknowledged message used to set the Light Lightness Default, the Light HSL Hue Default, + and Light HSL Saturation Default states of an element. + + \param [in] param Light HSL Default Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_hsl_default_set_unacknowledged(param) \ + MS_light_hsl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_HSL_DEFAULT_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the Light HSL Hue Range and Light HSL Saturation Range states of an element. + + \par Description + The Light HSL Range Get is an acknowledged message used to get the Light HSL Hue Range and Light HSL Saturation Range states of an element. + The response to the Light HSL Range Get message is a Light HSL Range Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_hsl_range_get() \ + MS_light_hsl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_HSL_RANGE_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_HSL_RANGE_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light HSL Hue Range and Light HSL Saturation Range states of an element. + + \par Description + Light HSL Range Set is an acknowledged message used to set the Light HSL Hue Range and Light HSL Saturation Range states of an element. + The response to the Light HSL Range Set message is a Light HSL Range Status message. + + \param [in] param Light HSL Range Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_hsl_range_set(param) \ + MS_light_hsl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_HSL_RANGE_SET_OPCODE,\ + param,\ + MS_ACCESS_LIGHT_HSL_RANGE_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light HSL Hue Range and Light HSL Saturation Range states of an element. + + \par Description + Light HSL Range Set Unacknowledged is an unacknowledged message used to set the Light HSL Hue Range and Light HSL Saturation Range states of an element. + + \param [in] param Light HSL Range Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_hsl_range_set_unacknowledged(param) \ + MS_light_hsl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_HSL_RANGE_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the Light HSL Hue state of an element. + + \par Description + The Light HSL Hue Get is an acknowledged message used to get the Light HSL Hue state of an element. + The response to the Light HSL Hue Get message is a Light HSL Hue Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_hsl_hue_get() \ + MS_light_hsl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_HSL_HUE_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_HSL_HUE_STATUS_OPCODE\ + ) + +/** + \brief API to set the target Light HSL Hue state of an element. + + \par Description + The Light HSL Hue Set is an acknowledged message used to set the target Light HSL Hue state of an element. + The response to the Light HSL Hue Set message is a Light HSL Hue Status message. + + \param [in] param Light HSL Hue Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_hsl_hue_set(param) \ + MS_light_hsl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_HSL_HUE_SET_OPCODE,\ + param,\ + MS_ACCESS_LIGHT_HSL_HUE_STATUS_OPCODE\ + ) + +/** + \brief API to set the target Light HSL Hue state of an element. + + \par Description + The Light HSL Hue Set Unacknowledged is an unacknowledged message used to + set the target Light HSL Hue state of an element. + + \param [in] param Light HSL Hue Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_hsl_hue_set_unacknowledged(param) \ + MS_light_hsl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_HSL_HUE_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the Light HSL Saturation state of an element. + + \par Description + The Light HSL Saturation Get is an acknowledged message used to get the Light HSL Saturation state of an element. + The response to the Light HSL Saturation Get message is a Light HSL Saturation Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_hsl_saturation_get() \ + MS_light_hsl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_HSL_SATURATION_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_HSL_SATURATION_STATUS_OPCODE\ + ) + +/** + \brief API to set the target Light HSL Saturation state of an element. + + \par Description + The Light HSL Saturation Set is an acknowledged message used to set the target Light HSL Saturation state of an element. + The response to the Light HSL Saturation Set message is a Light HSL Saturation Status message. + + \param [in] param Light HSL Saturation Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_hsl_saturation_set(param) \ + MS_light_hsl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_HSL_SATURATION_SET_OPCODE,\ + param,\ + MS_ACCESS_LIGHT_HSL_SATURATION_STATUS_OPCODE\ + ) + +/** + \brief API to set the target Light HSL Saturation state of an element. + + \par Description + The Light HSL Saturation Set Unacknowledged is an unacknowledged message + used to set the target Light HSL Saturation state of an element. + + \param [in] param Light HSL Saturation Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_hsl_saturation_set_unacknowledged(param) \ + MS_light_hsl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_HSL_SATURATION_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) +/** \} */ +/** \} */ +/** \} */ + +#endif /*_H_MS_LIGHT_HSL_API_ */ diff --git a/src/components/ethermind/mesh/export/include/MS_light_lc_api.h b/src/components/ethermind/mesh/export/include/MS_light_lc_api.h new file mode 100644 index 0000000..ee002f5 --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_light_lc_api.h @@ -0,0 +1,570 @@ +/** + \file MS_light_lc_api.h + + \brief This file defines the Mesh Light Lc Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_LIGHT_LC_API_ +#define _H_MS_LIGHT_LC_API_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_access_api.h" + + +/* --------------------------------------------- Global Definitions */ +/** + \defgroup light_lc_module LIGHT_LC (Mesh Light Lc Model) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Generic OnOff Model (ONOFF) module to the Application. +*/ + + + +/* --------------------------------------------- Data Types/ Structures */ +/** + \defgroup light_lc_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ + +/** + Light Lc Server application Asynchronous Notification Callback. + + Light Lc Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_LIGHT_LC_SERVER_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_MODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; + +/** + Light Lc Client application Asynchronous Notification Callback. + + Light Lc Client calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param opcode Opcode. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef API_RESULT (* MS_LIGHT_LC_CLIENT_CB) +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT32 opcode, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; +/** \} */ + +/** + \defgroup light_lc_structures Structures + \{ +*/ + +/** + Light LC Mode Set/Status message parameters. +*/ +typedef struct MS_light_lc_mode_struct +{ + /** The target value of the Light LC Mode state */ + UCHAR mode; + +} MS_LIGHT_LC_MODE_STRUCT; + +typedef struct MS_light_lc_om_struct +{ + /** The target value of the Light LC Occupancy Mode state */ + UCHAR mode; + +} MS_LIGHT_LC_OM_STRUCT; + +/** + Light LC Light OnOff Set message parameters. +*/ +typedef struct MS_light_lc_light_onoff_set_struct +{ + /** The target value of the Light LC Light OnOff state */ + UCHAR light_onoff; + + /** Transaction Identifier */ + UCHAR tid; + + /** + Transition Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR transition_time; + + /** Message execution delay in 5 milliseconds steps */ + UCHAR delay; + + /** Flag: To represent if optional Transaction time and Delay fields are valid */ + UCHAR optional_fields_present; + +} MS_LIGHT_LC_LIGHT_ONOFF_SET_STRUCT; + +/** + Light LC Light OnOff Status message parameters. +*/ +typedef struct MS_light_lc_light_onoff_status_struct +{ + /** The present value of the Light LC Light OnOff state */ + UCHAR present_light_onoff; + + /** The target value of the Light LC Light OnOff state (Optional) */ + UCHAR target_light_onoff; + + /** + Remaining Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR remaining_time; + + /** Flag: To represent if optional fields Target LC Light OnOff and Remaining Time are valid */ + UCHAR optional_fields_present; + +} MS_LIGHT_LC_LIGHT_ONOFF_STATUS_STRUCT; + +/** + Light LC Property Get message parameters. +*/ +typedef struct MS_light_lc_property_get_struct +{ + /** Property ID identifying a Light LC Property. */ + UINT16 light_lc_property_id; + +} MS_LIGHT_LC_PROPERTY_GET_STRUCT; + +/** + Light LC Property Set message parameters. +*/ +typedef struct MS_light_lc_property_set_struct +{ + /** Property ID identifying a Light LC Property. */ + UINT16 light_lc_property_id; + + /** Raw value for the Light LC Property */ + UCHAR* light_lc_property_value; + + /** Raw value length for the Light LC Property */ + UINT16 light_lc_property_value_len; + +} MS_LIGHT_LC_PROPERTY_SET_STRUCT; + +/** + Light LC Property Status message parameters. +*/ +typedef struct MS_light_lc_property_status_struct +{ + /** Property ID identifying a Light LC Property. */ + UINT16 light_lc_property_id; + + /** Raw value for the Light LC Property */ + UCHAR* light_lc_property_value; + + /** Raw value length for the Light LC Property */ + UINT16 light_lc_property_value_len; + +} MS_LIGHT_LC_PROPERTY_STATUS_STRUCT; + +/** \} */ + + + +/* --------------------------------------------- Function */ +/** + \defgroup light_lc_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Light Lc Model APIs. +*/ +/** + \defgroup light_lc_ser_api_defs Light Lc Server API Definitions + \{ + This section describes the Light Lc Server APIs. +*/ + +/** + \brief API to initialize Light_Lc Server model + + \par Description + This is to initialize Light_Lc Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] lc_model_handle + Model identifier associated with the Light LC model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in, out] lc_setup_model_handle + Model identifier associated with the Light LC Setup model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Light_Lc Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_lc_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* lc_model_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* lc_setup_model_handle, + /* IN */ MS_LIGHT_LC_SERVER_CB appl_cb +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_lc_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); +/** \} */ + +/** + \defgroup light_lc_cli_api_defs Light Lc Client API Definitions + \{ + This section describes the Light Lc Client APIs. +*/ + +/** + \brief API to initialize Light_Lc Client model + + \par Description + This is to initialize Light_Lc Client model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Light_Lc Client. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_lc_client_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_LIGHT_LC_CLIENT_CB appl_cb +); + +/** + \brief API to get Light_Lc client model handle + + \par Description + This is to get the handle of Light_Lc client model. + + \param [out] model_handle Address of model handle to be filled/returned. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_lc_client_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle +); + +/** + \brief API to send acknowledged commands + + \par Description + This is to initialize sending acknowledged commands. + + \param [in] req_opcode Request Opcode. + \param [in] param Parameter associated with Request Opcode. + \param [in] rsp_opcode Response Opcode. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_lc_client_send_reliable_pdu +( + /* IN */ UINT32 req_opcode, + /* IN */ void* param, + /* IN */ UINT32 rsp_opcode +); + +/** + \brief API to get the Light LC Mode state of an element. + + \par Description + Light LC Mode Get is an acknowledged message used to get the Light LC Mode state of an element. + The response to the Light LC Mode Get message is a Light LC Mode Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lc_mode_get() \ + MS_light_lc_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LC_MODE_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_LC_MODE_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light LC Mode state of an element. + + \par Description + The Light LC Mode Set is an acknowledged message used to set the Light LC Mode state of an element. + The response to the Light LC Mode Set message is a Light LC Mode Status message. + + \param [in] param Light LC Mode Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lc_mode_set(param) \ + MS_light_lc_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LC_MODE_SET_OPCODE,\ + param,\ + MS_ACCESS_LIGHT_LC_MODE_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light LC Mode state of an element. + + \par Description + The Light LC Mode Set Unacknowledged is an unacknowledged message used to + set the Light LC Mode state of an element. + + \param [in] param Light LC Mode Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lc_mode_set_unacknowledged(param) \ + MS_light_lc_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LC_MODE_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the Light LC Occupancy Mode state of an element. + + \par Description + Light LC OM Get is an acknowledged message used to get the Light LC Occupancy Mode state of an element. + The response to the Light LC OM Get message is a Light LC OM Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lc_om_get() \ + MS_light_lc_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LC_OM_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_LC_OM_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light LC Occupancy Mode state of an element. + + \par Description + The Light LC OM Set is an acknowledged message used to set the Light LC Occupancy Mode state of an element. + The response to the Light LC OM Set message is a Light LC OM Status message. + + \param [in] param Light LC OM Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lc_om_set(param) \ + MS_light_lc_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LC_OM_SET_OPCODE,\ + param,\ + MS_ACCESS_LIGHT_LC_OM_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light LC Occupancy Mode state of an element. + + \par Description + The Light LC OM Set Unacknowledged is an unacknowledged message used to set + the Light LC Occupancy Mode state of an element. + + \param [in] param Light LC OM Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lc_om_set_unacknowledged(param) \ + MS_light_lc_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LC_OM_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the Light LC Light OnOff state of an element. + + \par Description + Light LC Light OnOff Get is an acknowledged message used to get the Light LC Light OnOff state of an element. + The response to the Light LC Light OnOff Get message is a Light LC Light OnOff Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lc_light_onoff_get() \ + MS_light_lc_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LC_LIGHT_ONOFF_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_LC_LIGHT_ONOFF_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light LC Light OnOff state of an element. + + \par Description + The Light LC Light OnOff Set is an acknowledged message used to set the Light LC Light OnOff state of an element. + The response to the Light LC Light OnOff Set message is a Light LC Light OnOff Status message. + + \param [in] param Light LC Light OnOff Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lc_light_onoff_set(param) \ + MS_light_lc_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LC_LIGHT_ONOFF_SET_OPCODE,\ + param,\ + MS_ACCESS_LIGHT_LC_LIGHT_ONOFF_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light LC Light OnOff state of an element. + + \par Description + The Light LC Light OnOff Set Unacknowledged is an unacknowledged message + used to set the Light LC Light OnOff state of an element. + + \param [in] param Light LC Light OnOff Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lc_light_onoff_set_unacknowledged(param) \ + MS_light_lc_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LC_LIGHT_ONOFF_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to to get the Light LC Property state of an element. + + \par Description + Light LC Property Get is an acknowledged message used to get the Light LC Property state of an element. + The response to the Light LC Property Get message is a Light LC Property Status message. + + \param [in] param Light LC Property Get message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lc_property_get(param) \ + MS_light_lc_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LC_PROPERTY_GET_OPCODE,\ + param,\ + MS_ACCESS_LIGHT_LC_PROPERTY_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light LC Property state of an element. + + \par Description + The Light LC Property Set is an acknowledged message used to set the Light LC Property state of an element. + The response to the Light LC Property Set message is a Light LC Property Status message. + + \param [in] param Light LC Property Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lc_property_set(param) \ + MS_light_lc_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LC_PROPERTY_SET_OPCODE,\ + param,\ + MS_ACCESS_LIGHT_LC_PROPERTY_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light LC Property state of an element. + + \par Description + The Light LC Property Set Unacknowledged is an unacknowledged message used + to set the Light LC Property state of an element. + + \param [in] param Light LC Property Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lc_property_set_unacknowledged(param) \ + MS_light_lc_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LC_PROPERTY_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) +/** \} */ +/** \} */ +/** \} */ + +#endif /*_H_MS_LIGHT_LC_API_ */ diff --git a/src/components/ethermind/mesh/export/include/MS_light_lightness_api.h b/src/components/ethermind/mesh/export/include/MS_light_lightness_api.h new file mode 100644 index 0000000..df4d6f0 --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_light_lightness_api.h @@ -0,0 +1,718 @@ +/** + \file MS_light_lightness_api.h + + \brief This file defines the Mesh Light Lightness Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_LIGHT_LIGHTNESS_API_ +#define _H_MS_LIGHT_LIGHTNESS_API_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_access_api.h" + + +/* --------------------------------------------- Global Definitions */ +/** + \defgroup light_lightness_module LIGHT_LIGHTNESS (Mesh Light Lightness Model) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Generic OnOff Model (ONOFF) module to the Application. +*/ + + + +/* --------------------------------------------- Data Types/ Structures */ +/** + \defgroup light_lightness_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ + +/** + Light Lightness Server application Asynchronous Notification Callback. + + Light Lightness Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_LIGHT_LIGHTNESS_SERVER_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_MODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; + +/** + Light Lightness Setup Server application Asynchronous Notification Callback. + + Light Lightness Setup Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_LIGHT_LIGHTNESS_SETUP_SERVER_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_MODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; + +/** + Light Lightness Client application Asynchronous Notification Callback. + + Light Lightness Client calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param opcode Opcode. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef API_RESULT (* MS_LIGHT_LIGHTNESS_CLIENT_CB) +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT32 opcode, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; +/** \} */ + +/** + \defgroup light_lightness_structures Structures + \{ +*/ + +/** + Light Lightness Set message parameters. +*/ +typedef struct MS_light_lightness_set_struct +{ + /** The target value of the Light Lightness Actual state. */ + UINT16 lightness; + + /** Transaction Identifier */ + UCHAR tid; + + /** + Transition Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR transition_time; + + /** Message execution delay in 5 milliseconds steps */ + UCHAR delay; + + /** Flag: To represent if optional Transaction time and Delay fields are valid */ + UCHAR optional_fields_present; + +} MS_LIGHT_LIGHTNESS_SET_STRUCT; + +/** + Light Lightness Status message parameters. +*/ +typedef struct MS_light_lightness_status_struct +{ + /** The present value of the Light Lightness Actual state. */ + UINT16 present_lightness; + + /** The target value of the Light Lightness Actual state. (Optional) */ + UINT16 target_lightness; + + /** + Remaining Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR remaining_time; + + /** Flag: To represent if optional fields Target Light Lightness Actual and Remaining Time are valid */ + UCHAR optional_fields_present; + +} MS_LIGHT_LIGHTNESS_STATUS_STRUCT; + +/** + Light Lightness Linear Set message parameters. +*/ +typedef struct MS_light_lightness_linear_set_struct +{ + /** The target value of the Light Lightness Linear state. */ + UINT16 lightness; + + /** Transaction Identifier */ + UCHAR tid; + + /** + Transition Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR transition_time; + + /** Message execution delay in 5 milliseconds steps */ + UCHAR delay; + + /** Flag: To represent if optional Transaction time and Delay fields are valid */ + UCHAR optional_fields_present; + +} MS_LIGHT_LIGHTNESS_LINEAR_SET_STRUCT; + +/** + Light Lightness Linear Status message parameters. +*/ +typedef struct MS_light_lightness_linear_status_struct +{ + /** The present value of the Light Lightness Linear state */ + UINT16 present_lightness; + + /** The target value of the Light Lightness Linear state (Optional) */ + UINT16 target_lightness; + + /** + Remaining Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR remaining_time; + + /** Flag: To represent if optional fields Target Light Lightness Linear and Remaining Time are valid */ + UCHAR optional_fields_present; + +} MS_LIGHT_LIGHTNESS_LINEAR_STATUS_STRUCT; + +/** + Light Lightness Last Status message parameters. +*/ +typedef struct MS_light_lightness_last_status_struct +{ + /** The value of the Light Lightness Last */ + UINT16 lightness; + +} MS_LIGHT_LIGHTNESS_LAST_STATUS_STRUCT; + +/** + Light Lightness Default Set message parameters. +*/ +typedef struct MS_light_lightness_default_set_struct +{ + /** The value of the Light Lightness Default state */ + UINT16 lightness; + +} MS_LIGHT_LIGHTNESS_DEFAULT_SET_STRUCT; + +/** + Light Lightness Range Set message parameters. +*/ +typedef struct MS_light_lightness_range_set_struct +{ + /** The value of the Lightness Range Min field of the Light Lightness Range state */ + UINT16 range_min; + + /** The value of the Lightness Range Max field of the Light Lightness Range state */ + UINT16 range_max; + +} MS_LIGHT_LIGHTNESS_RANGE_SET_STRUCT; + +/** + Light Lightness Range Status message parameters. +*/ +typedef struct MS_light_lightness_range_status_struct +{ + /** Status Code for the requesting message. */ + UCHAR status_code; + + /** The value of the Lightness Range Min field of the Light Lightness Range state */ + UINT16 range_min; + + /** The value of the Lightness Range Max field of the Light Lightness Range state */ + UINT16 range_max; + +} MS_LIGHT_LIGHTNESS_RANGE_STATUS_STRUCT; + +/** + Light Lightness Default Status message parameters. +*/ +typedef struct MS_light_lightness_default_status_struct +{ + /** The value of the Light Lightness Default state */ + UINT16 lightness; + +} MS_LIGHT_LIGHTNESS_DEFAULT_STATUS_STRUCT; + +typedef struct MS_light_lightness_last_or_default_status_struct +{ + UINT16 lightness; + +} MS_LIGHT_LIGHTNESS_LAST_OR_DEFAULT_STATUS_STRUCT; + +/** \} */ + + + +/* --------------------------------------------- Function */ +/** + \defgroup light_lightness_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Light Lightness Model APIs. +*/ +/** + \defgroup light_lightness_ser_api_defs Light Lightness Server API Definitions + \{ + This section describes the Light Lightness Server APIs. +*/ + +/** + \brief API to initialize Light_Lightness Server model + + \par Description + This is to initialize Light_Lightness Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Light_Lightness Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_lightness_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_LIGHT_LIGHTNESS_SERVER_CB appl_cb +); + +/** + \brief API to initialize Light_Lightness_Setup Server model + + \par Description + This is to initialize Light_Lightness_Setup Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Light_Lightness_Setup Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_lightness_setup_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_LIGHT_LIGHTNESS_SETUP_SERVER_CB appl_cb +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_lightness_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_lightness_setup_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); +/** \} */ + +/** + \defgroup light_lightness_cli_api_defs Light Lightness Client API Definitions + \{ + This section describes the Light Lightness Client APIs. +*/ + +/** + \brief API to initialize Light_Lightness Client model + + \par Description + This is to initialize Light_Lightness Client model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Light_Lightness Client. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_lightness_client_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_LIGHT_LIGHTNESS_CLIENT_CB appl_cb +); + +/** + \brief API to get Light_Lightness client model handle + + \par Description + This is to get the handle of Light_Lightness client model. + + \param [out] model_handle Address of model handle to be filled/returned. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_lightness_client_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle +); + +/** + \brief API to send acknowledged commands + + \par Description + This is to initialize sending acknowledged commands. + + \param [in] req_opcode Request Opcode. + \param [in] param Parameter associated with Request Opcode. + \param [in] rsp_opcode Response Opcode. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_lightness_client_send_reliable_pdu +( + /* IN */ UINT32 req_opcode, + /* IN */ void* param, + /* IN */ UINT32 rsp_opcode +); + +/** + \brief API to get the Light Lightness Actual state of an element. + + \par Description + Light Lightness Get is an acknowledged message used to get the Light Lightness Actual state of an element. + The response to the Light Lightness Get message is a Light Lightness Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lightness_get() \ + MS_light_lightness_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LIGHTNESS_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_LIGHTNESS_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light Lightness Actual state of an element. + + \par Description + The Light Lightness Set is an acknowledged message used to set the Light Lightness Actual state of an element. + The response to the Light Lightness Set message is a Light Lightness Status message. + + \param [in] param Light Lightness Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lightness_set(param) \ + MS_light_lightness_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LIGHTNESS_SET_OPCODE,\ + param,\ + MS_ACCESS_LIGHT_LIGHTNESS_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light Lightness Actual state of an element. + + \par Description + The Light Lightness Set Unacknowledged is an unacknowledged message used to + set the Light Lightness Actual state of an element. + + \param [in] param Light Lightness Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lightness_set_unacknowledged(param) \ + MS_light_lightness_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LIGHTNESS_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the Light Lightness Linear state of an element. + + \par Description + Light Lightness Linear Get is an acknowledged message used to get the Light Lightness Linear state of an element. + The response to the Light Lightness Linear Get message is a Light Lightness Linear Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lightness_linear_get() \ + MS_light_lightness_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LIGHTNESS_LINEAR_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_LIGHTNESS_LINEAR_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light Lightness Linear state of an element. + + \par Description + The Light Lightness Linear Set is an acknowledged message used to set the Light Lightness Linear state of an element. + The response to the Light Lightness Linear Set message is a Light Lightness Linear Status message. + + \param [in] param Light Lightness Linear Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lightness_linear_set(param) \ + MS_light_lightness_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LIGHTNESS_LINEAR_SET_OPCODE,\ + param,\ + MS_ACCESS_LIGHT_LIGHTNESS_LINEAR_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light Lightness Linear state of an element. + + \par Description + The Light Lightness Linear Set Unacknowledged is an unacknowledged message + used to set the Light Lightness Linear state of an element. + + \param [in] param Light Lightness Linear Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lightness_linear_set_unacknowledged(param) \ + MS_light_lightness_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LIGHTNESS_LINEAR_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the Light Lightness Last state of an element. + + \par Description + Light Lightness Last Get is an acknowledged message used to get the Light Lightness Last state of an element. + The response to the Light Lightness Last Get message is a Light Lightness Last Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lightness_last_get() \ + MS_light_lightness_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LIGHTNESS_LAST_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_LIGHTNESS_LAST_STATUS_OPCODE\ + ) + +/** + \brief API to get the Light Lightness Default state of an element. + + \par Description + Light Lightness Default Get is an acknowledged message used to get the Light Lightness Default state of an element. + The response to the Light Lightness Default Get message is a Light Lightness Default Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lightness_default_get() \ + MS_light_lightness_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LIGHTNESS_DEFAULT_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_LIGHTNESS_DEFAULT_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light Lightness Default state of an element. + + \par Description + The Light Lightness Default Set is an acknowledged message used to set the Light Lightness Default state of an element. + The response to the Light Lightness Default Set message is a Light Lightness Default Status message. + + \param [in] param Light Lightness Default Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lightness_default_set(param) \ + MS_light_lightness_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LIGHTNESS_DEFAULT_SET_OPCODE,\ + param,\ + MS_ACCESS_LIGHT_LIGHTNESS_DEFAULT_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light Lightness Default state of an element. + + \par Description + The Light Lightness Default Set Unacknowledged is an unacknowledged message + used to set the Light Lightness Default state of an element. + + \param [in] param Light Lightness Default Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lightness_default_set_unacknowledged(param) \ + MS_light_lightness_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LIGHTNESS_DEFAULT_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the Light Lightness Range state of an element. + + \par Description + The Light Lightness Range Get is an acknowledged message used to get the Light Lightness Range state of an element. + The response to the Light Lightness Range Get message is a Light Lightness Range Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lightness_range_get() \ + MS_light_lightness_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LIGHTNESS_RANGE_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_LIGHTNESS_RANGE_STATUS_OPCODE\ + ) + +/** + \brief API to acknowledged message used to set the Light Lightness Range state of an element. + + \par Description + Light Lightness Range Set is an acknowledged message used to set the Light Lightness Range state of an element. + The response to the Light Lightness Range Get message is a Light Lightness Range Status message. + + \param [in] param Light Lightness Range Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lightness_range_set(param) \ + MS_light_lightness_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LIGHTNESS_RANGE_SET_OPCODE,\ + param,\ + MS_ACCESS_LIGHT_LIGHTNESS_RANGE_STATUS_OPCODE\ + ) + +/** + \brief API to acknowledged message used to set the Light Lightness Range state of an element. + + \par Description + Light Lightness Range Set Unacknowledged is an unacknowledged message used + to set the Light Lightness Range state of an element. + + \param [in] param Light Lightness Range Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_lightness_range_set_unacknowledged(param) \ + MS_light_lightness_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_LIGHTNESS_RANGE_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) +/** \} */ +/** \} */ +/** \} */ + +#endif /*_H_MS_LIGHT_LIGHTNESS_API_ */ diff --git a/src/components/ethermind/mesh/export/include/MS_light_xyl_api.h b/src/components/ethermind/mesh/export/include/MS_light_xyl_api.h new file mode 100644 index 0000000..8465baf --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_light_xyl_api.h @@ -0,0 +1,590 @@ +/** + \file MS_light_xyl_api.h + + \brief This file defines the Mesh Light Xyl Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_LIGHT_XYL_API_ +#define _H_MS_LIGHT_XYL_API_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_access_api.h" + + +/* --------------------------------------------- Global Definitions */ +/** + \defgroup light_xyl_module LIGHT_XYL (Mesh Light Xyl Model) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Generic OnOff Model (ONOFF) module to the Application. +*/ + + + +/* --------------------------------------------- Data Types/ Structures */ +/** + \defgroup light_xyl_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ + +/** + Light Xyl Server application Asynchronous Notification Callback. + + Light Xyl Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_LIGHT_XYL_SERVER_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_MODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; + +/** + Light Xyl Client application Asynchronous Notification Callback. + + Light Xyl Client calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param opcode Opcode. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef API_RESULT (* MS_LIGHT_XYL_CLIENT_CB) +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT32 opcode, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; +/** \} */ + +/** + \defgroup light_xyl_structures Structures + \{ +*/ + +/** + Light xyL Set message parameters. +*/ +typedef struct MS_light_xyl_set_struct +{ + /** The target value of the Light xyL Lightness state */ + UINT16 xyl_lightness; + + /** The target value of the Light xyL x state */ + UINT16 xyl_x; + + /** The target value of the Light xyL y state */ + UINT16 xyl_y; + + /** Transaction Identifier */ + UCHAR tid; + + /** + Transition Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR transition_time; + + /** Message execution delay in 5 milliseconds steps */ + UCHAR delay; + + /** Flag: To represent if optional Transaction time and Delay fields are valid */ + UCHAR optional_fields_present; + +} MS_LIGHT_XYL_SET_STRUCT; + +/** + Light xyL Status Unacknowledged message parameters. +*/ +typedef struct MS_light_xyl_status_struct +{ + /** The present value of the Light xyL Lightness state */ + UINT16 xyl_lightness; + + /** The present value of the Light xyL x state */ + UINT16 xyl_x; + + /** The present value of the Light xyL y state */ + UINT16 xyl_y; + + /** + Remaining Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR remaining_time; + + /** Flag: To represent if optional field Remaining Time is valid */ + UCHAR optional_fields_present; + +} MS_LIGHT_XYL_STATUS_STRUCT; + +/** + Light xyL Target Status Unacknowledged message parameters. +*/ +typedef struct MS_light_xyl_target_status_struct +{ + /** The target value of the Light xyL Lightness state */ + UINT16 target_xyl_lightness; + + /** The target value of the Light xyL x state */ + UINT16 target_xyl_x; + + /** The target value of the Light xyL y state */ + UINT16 target_xyl_y; + + /** + Remaining Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR remaining_time; + + /** Flag: To represent if optional field Remaining Time is valid */ + UCHAR optional_fields_present; + +} MS_LIGHT_XYL_TARGET_STATUS_STRUCT; + +/** + Light HSL Default Set message parameters. +*/ +typedef struct MS_light_xyl_default_set_struct +{ + /** The value of the Light Lightness Default state */ + UINT16 lightness; + + /** The value of the Light xyL x Default state */ + UINT16 xyl_x; + + /** The value of the Light xyL y Default state */ + UINT16 xyl_y; + +} MS_LIGHT_XYL_DEFAULT_SET_STRUCT; + +/** + Light xyL Default Status message parameters. +*/ +typedef struct MS_light_xyl_default_status_struct +{ + /** The value of the Light Lightness Default state */ + UINT16 lightness; + + /** The value of the Light xyL x Default state */ + UINT16 xyl_x; + + /** The value of the Light xyL y Default state */ + UINT16 xyl_y; + +} MS_LIGHT_XYL_DEFAULT_STATUS_STRUCT; + +/** + Light xyL Range Set message parameters. +*/ +typedef struct MS_light_xyl_range_set_struct +{ + /** The value of the xyL x Range Min field of the Light xyL x Range state */ + UINT16 xyl_x_range_min; + + /** The value of the xyL x Range Max field of the Light xyL x Range state */ + UINT16 xyl_x_range_max; + + /** The value of the xyL y Range Min field of the Light xyL y Range state */ + UINT16 xyl_y_range_min; + + /** The value of the xyL y Range Max field of the Light xyL y Range state */ + UINT16 xyl_y_range_max; + +} MS_LIGHT_XYL_RANGE_SET_STRUCT; + +/** + Light xyL Range Status message parameters. +*/ +typedef struct MS_light_xyl_range_status_struct +{ + /** Status Code for the requesting message. */ + UCHAR status_code; + + /** The value of the xyL x Range Min field of the Light xyL x Range state */ + UINT16 xyl_x_range_min; + + /** The value of the xyL x Range Max field of the Light xyL x Range state */ + UINT16 xyl_x_range_max; + + /** The value of the xyL y Range Min field of the Light xyL y Range state */ + UINT16 xyl_y_range_min; + + /** The value of the xyL y Range Max field of the Light xyL y Range state */ + UINT16 xyl_y_range_max; + +} MS_LIGHT_XYL_RANGE_STATUS_STRUCT; + +/** \} */ + + + +/* --------------------------------------------- Function */ +/** + \defgroup light_xyl_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Light Xyl Model APIs. +*/ +/** + \defgroup light_xyl_ser_api_defs Light Xyl Server API Definitions + \{ + This section describes the Light Xyl Server APIs. +*/ + +/** + \brief API to initialize Light_Xyl Server model + + \par Description + This is to initialize Light_Xyl Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] xyl_model_handle + Model identifier associated with the Light xyl model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in, out] xyl_setup_model_handle + Model identifier associated with the Light xyl Setup model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Light_Xyl Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_xyl_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* xyl_model_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* xyl_setup_model_handle, + /* IN */ MS_LIGHT_XYL_SERVER_CB appl_cb +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_xyl_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); +/** \} */ + +/** + \defgroup light_xyl_cli_api_defs Light Xyl Client API Definitions + \{ + This section describes the Light Xyl Client APIs. +*/ + +/** + \brief API to initialize Light_Xyl Client model + + \par Description + This is to initialize Light_Xyl Client model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Light_Xyl Client. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_xyl_client_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_LIGHT_XYL_CLIENT_CB appl_cb +); + +/** + \brief API to get Light_Xyl client model handle + + \par Description + This is to get the handle of Light_Xyl client model. + + \param [out] model_handle Address of model handle to be filled/returned. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_xyl_client_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle +); + +/** + \brief API to send acknowledged commands + + \par Description + This is to initialize sending acknowledged commands. + + \param [in] req_opcode Request Opcode. + \param [in] param Parameter associated with Request Opcode. + \param [in] rsp_opcode Response Opcode. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_light_xyl_client_send_reliable_pdu +( + /* IN */ UINT32 req_opcode, + /* IN */ void* param, + /* IN */ UINT32 rsp_opcode +); + +/** + \brief API to get the Light xyL Lightness, Light xyL x, and Light xyL y states of an element. + + \par Description + The Light xyL Get is an acknowledged message used to get the Light xyL + Lightness, Light xyL x, and Light xyL y states of an element. + Upon receiving a Light xyL Get message, the element shall respond with a Light xyL Status message. + The response to the Light xyL Get message is a Light xyL Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_xyl_get() \ + MS_light_xyl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_XYL_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_XYL_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light xyL Lightness, Light xyL x state, and the Light xyL y states of an element. + + \par Description + The Light xyL Set is an acknowledged message used to set the Light xyL Lightness, Light xyL x state, and the Light xyL y states of an element. + The response to the Light xyL Set message is a Light xyL Status message. + + \param [in] param Light xyL Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_xyl_set(param) \ + MS_light_xyl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_XYL_SET_OPCODE,\ + param,\ + MS_ACCESS_LIGHT_XYL_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light xyL Lightness, Light xyL x state, and the Light xyL y states of an element. + + \par Description + The Light xyL Set Unacknowledged is an unacknowledged message used to set + the Light xyL Lightness, Light xyL x, and the Light xyL y states of an + element. + + \param [in] param Light xyL Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_xyl_set_unacknowledged(param) \ + MS_light_xyl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_XYL_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the target Light xyL Lightness, Light xyL x, and Light xyL y states of an element. + + \par Description + The Light xyL Target Get is an acknowledged message used to get the target Light xyL Lightness, Light xyL x, and Light xyL y states of an element. + The response to the Light xyL Target Get message is a Light xyL Target Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_xyl_target_get() \ + MS_light_xyl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_XYL_TARGET_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_XYL_TARGET_STATUS_OPCODE\ + ) + +/** + \brief API to get the Light Lightness Default, the Light xyL x Default, and Light xyL y Default states of an element. + + \par Description + Light xyL Default Get is an acknowledged message used to get the Light Lightness Default, the Light xyL x Default, and Light xyL y Default states of an element. + The response to the Light xyL Default Get message is a Light xyL Default Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_xyl_default_get() \ + MS_light_xyl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_XYL_DEFAULT_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_XYL_DEFAULT_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light Lightness Default, the Light xyL x Default, and Light xyL y Default states of an element. + + \par Description + Light xyL Default Set is an acknowledged message used to set the Light Lightness Default, the Light xyL x Default, and Light xyL y Default states of an element. + The response to the Light xyL Default Set message is a Light xyL Default Status message. + + \param [in] param Light HSL Default Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_xyl_default_set(param) \ + MS_light_xyl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_XYL_DEFAULT_SET_OPCODE,\ + param,\ + MS_ACCESS_LIGHT_XYL_DEFAULT_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light Lightness Default, the Light xyL x Default, and Light xyL y Default states of an element. + + \par Description + Light xyL Default Set Unacknowledged is an unacknowledged message used to + set the Light Lightness Default, the Light xyL x Default, and Light xyL y + Default states of an element. + + \param [in] param Light HSL Default Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_xyl_default_set_unacknowledged(param) \ + MS_light_xyl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_XYL_DEFAULT_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the Light xyL x Range and Light xyL y Range states of an element. + + \par Description + The Light xyL Range Get is an acknowledged message used to get the Light xyL x Range and Light xyL y Range states of an element. + The response to the Light xyL Range Get message is a Light xyL Range Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_xyl_range_get() \ + MS_light_xyl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_XYL_RANGE_GET_OPCODE,\ + NULL,\ + MS_ACCESS_LIGHT_XYL_RANGE_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light xyL x Range and Light xyL y Range states of an element. + + \par Description + Light xyL Range Set is an acknowledged message used to set the Light xyL x Range and Light xyL y Range states of an element. + The response to the Light xyL Range Set message is a Light xyL Range Status message. + + \param [in] param Light xyL Range Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_xyl_range_set(param) \ + MS_light_xyl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_XYL_RANGE_SET_OPCODE,\ + param,\ + MS_ACCESS_LIGHT_XYL_RANGE_STATUS_OPCODE\ + ) + +/** + \brief API to set the Light xyL x Range and Light xyL y Range states of an element. + + \par Description + Light xyL Range Set Unacknowledged is an unacknowledged message used to set + the Light xyL x Range and Light xyL y Range states of an element. + + \param [in] param Light xyL Range Set message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_light_xyl_range_set_unacknowledged(param) \ + MS_light_xyl_client_send_reliable_pdu \ + (\ + MS_ACCESS_LIGHT_XYL_RANGE_SET_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) +/** \} */ +/** \} */ +/** \} */ + +#endif /*_H_MS_LIGHT_XYL_API_ */ diff --git a/src/components/ethermind/mesh/export/include/MS_ltrn_api.h b/src/components/ethermind/mesh/export/include/MS_ltrn_api.h new file mode 100644 index 0000000..78d8392 --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_ltrn_api.h @@ -0,0 +1,250 @@ + +/** + \file MS_ltrn_api.h + + \brief This file defines the Mesh Lower Transport Application Interface - includes + Data Structures and Methods. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_LTRN_API_ +#define _H_MS_LTRN_API_ + + +/* --------------------------------------------- Header File Inclusion */ +/* Network API Header File */ +#include "MS_net_api.h" + +/* --------------------------------------------- Global Definitions */ + +/** + \defgroup ltrn_module LTRANSPORT (Mesh Lower Transport Layer) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Lower Transport (LTRANSPORT) module to the Application and other upper + layers of the stack. +*/ + +/** + \defgroup ltrn_defines Defines + \{ + Describes defines for the module. +*/ + +/** + \defgroup ltrn_constants Constants + \{ + Describes Constants defined by the module. +*/ + +/** Unsgemented Access Message */ +#define MS_UNSEGMENTED_ACCESS_MSG 0x00 + +/** Segmented Access Message */ +#define MS_SEGMENTED_ACCESS_MSG 0x01 + +/** Unsegmented Control Message */ +#define MS_UNSEGMENTED_CTRL_MSG 0x02 + +/** Segmented Control Message */ +#define MS_SEGMENTED_CTRL_MSG 0x03 + +/** Transport Message Type */ +typedef UCHAR MS_TRN_MSG_TYPE; + +/** Transport Layer Control Packet */ +#define MS_TRN_CTRL_PKT 0x01 + +/** Access Layer Packet */ +#define MS_TRN_ACCESS_PKT 0x00 + +/** \} */ + +/** + \defgroup ltrn_events Events + \{ + This section lists the Asynchronous Events notified to Application by the + Module. +*/ +/** \} */ +/** \} */ + +/** + \defgroup ltrn_marcos Utility Macros + \{ + Initialization and other Utility Macros offered by the module. +*/ + +/** \} */ + +/* --------------------------------------------- Data Types/ Structures */ + +/** + \addtogroup ltrn_defines Defines + \{ +*/ + +/** + \addtogroup ltrn_structures Structures + \{ +*/ +/** LPN Handle */ +typedef UINT8 LPN_HANDLE; + + +/** \} */ + +/** \} */ + +/** + \defgroup ltrn_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ +/** + Lower TRANSPORT Application Asynchronous Notification Callback. + + Lower TRANSPORT calls the registered callback to indicate events occurred to the + application. + + \param net_hdr Network Header. + \param subnet_handle Associated Subnet Handle. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef API_RESULT (*LTRN_NTF_CB) +( + MS_NET_HEADER* net_hdr, + MS_SUBNET_HANDLE subnet_handle, + UCHAR szmic, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; +/** \} */ + +/** + \addtogroup ltrn_defines Defines + \{ +*/ + +/** + \addtogroup ltrn_structures Structures + \{ +*/ + +/** \} */ + +/** \} */ + +/** TCF (Transport Control Field) - Transport Field Value */ + + +/* --------------------------------------------- Function */ + +/** + \defgroup ltrn_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Lower Transport Layer APIs. +*/ +#ifdef __cplusplus +extern "C" { +#endif + +/** + \brief Register Inerface with Lower Transport Layer + + \par Description + This routine registers interface with the Lower Transport Layer. + Transport Layer supports single Application, hence this rouine shall be called once. + + \param [in] ltrn_cb + Upper Layer Notification Callback + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_ltrn_register +( + /* IN */ LTRN_NTF_CB ltrn_cb +); + +/** + \brief API to send transport PDUs + + \par Description + This routine sends transport PDUs to peer device. + + \param [in] src_addr + Source Address + + \param [in] dst_addr + Destination Address + + \param [in] subnet_handle + Handle identifying the Subnet + + \param [in] msg_type + Transport Message Type + + \param [in] ttl + Time to Live + + \param [in] akf + Application Key Flag + + \param [in] aid + Application Key Identifier + + \param [in] seq_num + Sequence Number to be used for the Packet + + \param [in] buffer + Transport Packet + + \param [in] buffer_len + Transport Packet Length + + \param [in] reliable + If requires lower transport Ack, set reliable as TRUE + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_ltrn_send_pdu +( + /* IN */ MS_NET_ADDR src_addr, + /* IN */ MS_NET_ADDR dst_addr, + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ MS_TRN_MSG_TYPE msg_type, + /* IN */ UINT8 ttl, + /* IN */ UINT8 akf, + /* IN */ UINT8 aid, + /* IN */ UINT32 seq_num, + /* IN */ UCHAR* buffer, + /* IN */ UINT16 buffer_len, + /* IN */ UINT8 reliable +); + +/** + \brief To clear all Segmentation and Reassembly Contexts + + \par Description + This routine clears all Segmentation and Reassembly Contexts. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_ltrn_clear_sar_contexts(void); + +#ifdef __cplusplus +}; +#endif + +/** \} */ + +/** \} */ + +#endif /* _H_MS_LTRN_API_ */ + diff --git a/src/components/ethermind/mesh/export/include/MS_model_states.h b/src/components/ethermind/mesh/export/include/MS_model_states.h new file mode 100644 index 0000000..64d849e --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_model_states.h @@ -0,0 +1,1396 @@ +/** + \file MS_model_states.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_MODEL_STATES_ +#define _H_MS_MODEL_STATES_ + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ +/** Model State Type Defines */ +#define MS_STATE_GENERIC_ONOFF_T 0 +#define MS_STATE_GENERIC_LEVEL_T 1 +#define MS_STATE_GENERIC_DEFAULT_TRANSITION_TIME_T 2 +#define MS_STATE_GENERIC_ONPOWERUP_T 3 +#define MS_STATE_GENERIC_POWER_ACTUAL_T 4 +#define MS_STATE_GENERIC_POWER_LAST_T 5 +#define MS_STATE_GENERIC_POWER_DEFAULT_T 6 +#define MS_STATE_GENERIC_POWER_RANGE_T 7 +#define MS_STATE_GENERIC_POWER_LEVEL_T 8 +#define MS_STATE_GENERIC_BATTERY_T 9 +#define MS_STATE_GENERIC_LOCATION_GLOBAL_T 10 +#define MS_STATE_GENERIC_LOCATION_LOCAL_T 11 +#define MS_STATE_GENERIC_LOCATION_T 12 +#define MS_STATE_GENERIC_USER_PROPERTY_T 13 +#define MS_STATE_GENERIC_ADMIN_PROPERTY_T 14 +#define MS_STATE_GENERIC_MANUFACTURER_PROPERTY_T 15 +#define MS_STATE_GENERIC_PROPERTY_ID_T 16 +#define MS_STATE_GENERIC_PROPERTY_IDS_T 17 +#define MS_STATE_SENSOR_PROPERTY_ID_T 18 +#define MS_STATE_SENSOR_DESCRIPTOR_T 19 +#define MS_STATE_SENSOR_SETTINGS_T 20 +#define MS_STATE_SENSOR_SETTING_T 21 +#define MS_STATE_SENSOR_CADENCE_T 22 +#define MS_STATE_SENSOR_DATA_PROPERTY_ID_T 23 +#define MS_STATE_SENSOR_DATA_T 24 +#define MS_STATE_SENSOR_COLUMN_STATUS_T 25 +#define MS_STATE_SENSOR_SERIES_COLUMN_T 26 + +#define MS_STATE_TIME_T 27 +#define MS_STATE_TIME_ZONE_T 28 +#define MS_STATE_TIME_TAI_UTC_DELTA_T 29 +#define MS_STATE_TIME_ROLE_T 30 +#define MS_STATE_SCENE_NUMBER_T 31 +#define MS_STATE_SCENE_STATUS_T 32 +#define MS_STATE_SCENE_REGISTER_STATUS_T 33 +#define MS_STATE_SCHEDULER_SCHEDULES_T 34 +#define MS_STATE_SCHEDULER_ENTRY_INDEX_T 35 +#define MS_STATE_SCHEDULER_ENTRY_T 36 +#define MS_STATE_LIGHT_LIGHTNESS_LINEAR_T 37 +#define MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T 38 +#define MS_STATE_LIGHT_LIGHTNESS_LAST_T 39 +#define MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T 40 +#define MS_STATE_LIGHT_LIGHTNESS_RANGE_T 41 +#define MS_STATE_LIGHT_LIGHTNESS_T 42 +#define MS_STATE_LIGHT_CTL_T 43 +#define MS_STATE_LIGHT_CTL_DEFAULT_T 44 +#define MS_STATE_LIGHT_CTL_TEMPERATURE_T 45 +#define MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_T 46 +#define MS_STATE_LIGHT_HSL_T 47 +#define MS_STATE_LIGHT_HSL_TARGET_T 48 +#define MS_STATE_LIGHT_HSL_DEFAULT_T 49 +#define MS_STATE_LIGHT_HSL_HUE_T 50 +#define MS_STATE_LIGHT_HSL_SATURATION_T 51 +#define MS_STATE_LIGHT_HSL_RANGE_T 52 +#define MS_STATE_LIGHT_XYL_T 53 +#define MS_STATE_LIGHT_XYL_TARGET_T 54 +#define MS_STATE_LIGHT_XYL_DEFAULT_T 55 +#define MS_STATE_LIGHT_XYL_RANGE_T 56 +#define MS_STATE_LIGHT_LC_MODE_T 57 +#define MS_STATE_LIGHT_LC_OM_T 58 +#define MS_STATE_LIGHT_LC_LIGHT_ONOFF_T 59 +#define MS_STATE_LIGHT_LC_PROPERTY_ID_T 60 +#define MS_STATE_LIGHT_LC_PROPERTY_T 61 + +#define MS_STATE_GENERIC_USER_PROPERTY_IDS_T 62 +#define MS_STATE_GENERIC_ADMIN_PROPERTY_IDS_T 63 +#define MS_STATE_GENERIC_MANUFACTURER_PROPERTY_IDS_T 64 +#define MS_STATE_GENERIC_CLIENT_PROPERTY_IDS_T 65 + +#define MS_STATE_SCENE_STORE_T 66 +#define MS_STATE_SCENE_RECALL_T 67 +#define MS_STATE_SCENE_DELETE_T 68 + +#define MS_STATE_DELTA_LEVEL_T 69 +#define MS_STATE_MOVE_LEVEL_T 70 + +/* Additional supporting structure type defines */ +#define MS_EXT_TID_AND_TRANSITION_STRUCT_T 128 +#define MS_EXT_STATUS_STRUCT_T 129 +#define MS_STATE_SENSOR_SERIES_T 130 + +/** + Generic OnOff state is a Boolean value that represents the state of an + element +*/ +typedef struct MS_state_generic_onoff_struct +{ + /** Generic On/Off */ + UINT8 onoff; + + /** Target On/Off - Used in response path */ + UINT8 target_onoff; + + /** Last On/Off */ + UINT8 last_onoff; + + /** TID - Used in request path */ + UINT8 tid; + + /** + Transition Time - Used in request path. + Used as remaining time in response path. + */ + UINT8 transition_time; + + /** Delay - Used in request path */ + UINT8 delay; + + /** Transition Timer Handle */ + UINT16 transition_time_handle; + +} MS_STATE_GENERIC_ONOFF_STRUCT; + +/** + Generic Level state is a 16-bit signed integer (2-s complement) representing + the state of an element +*/ +typedef struct MS_state_generic_level_struct +{ + /** Generic Level */ + UINT16 level; + + /** Delta Level */ + UINT32 delta_level; + + /** Move Level */ + UINT16 move_level; + + /* TID - Used in received path */ + UINT8 tid; + + /* Optional */ + /* Transition Time */ + UINT8 transition_time; + + /* Delay */ + UINT8 delay; + + /** Target Level */ + UINT16 target_level; + +} MS_STATE_GENERIC_LEVEL_STRUCT; + +/** + Generic Default Transition Time state determines how long an element shall + take to transition from a present state to a new state +*/ +typedef struct MS_state_generic_default_transition_time_struct +{ + /** The number of Steps */ + UCHAR default_transition_number_of_steps; + + /** The resolution of the Default Transition Number of Steps field */ + UCHAR default_transition_step_resolution; +} MS_STATE_GENERIC_DEFAULT_TRANSITION_TIME_STRUCT; + +/** + Generic OnPowerUp state is an enumeration representing the behavior of an + element when powered up +*/ +typedef struct MS_state_generic_onpowerup_struct +{ + /** Generic OnPowerUp */ + UCHAR onpowerup; +} MS_STATE_GENERIC_ONPOWERUP_STRUCT; + +/** + Generic Power Actual state determines the linear percentage of the maximum + power level of an element, representing a range from 0 percent through 100 + percent +*/ +typedef struct MS_state_generic_power_actual_struct +{ + /** Generic Power Actual */ + UINT16 power_actual; + + /* TID - Used only in request path */ + UINT8 tid; + + /** Generic Power Target - Used only in response path */ + UINT16 power_target; + + /** + Transition Time - Used in request path + Used as Remaining Time in response path + */ + UINT8 transition_time; + + /* Delay - Used only in request path */ + UINT8 delay; + + /** Transition Timer Handle */ + UINT16 transition_time_handle; + +} MS_STATE_GENERIC_POWER_ACTUAL_STRUCT; + +/** + Generic Power Last state is a 16-bit value representing a percentage ranging + from (1/65535) percent to 100 percent +*/ +typedef struct MS_state_generic_power_last_struct +{ + /** Generic Power Last */ + UINT16 power_last; +} MS_STATE_GENERIC_POWER_LAST_STRUCT; + +/** Generic Power Default state is a 16-bit value ranging from 0 through 65535 */ +typedef struct MS_state_generic_power_default_struct +{ + /** Generic Power Default */ + UINT16 power_default; +} MS_STATE_GENERIC_POWER_DEFAULT_STRUCT; + +/** + Generic Power Range state determines the minimum and maximum power levels of + an element relative to the maximum power level an element can output +*/ +typedef struct MS_state_generic_power_range_struct +{ + /** Generic Power Range - Minimum */ + UINT16 power_range_min; + + /** Generic Power Range - Maximum */ + UINT16 power_range_max; + + /** Status - Used only in the response path */ + UINT8 status; + +} MS_STATE_GENERIC_POWER_RANGE_STRUCT; + +/** + Generic Power Level state is a composite state that includes a Generic Power + Actual state, a Generic Power Last state, a Generic Power Default state, and + a Generic Power Range state +*/ +typedef struct MS_state_generic_power_level_struct +{ + /** Generic Power Actual */ + MS_STATE_GENERIC_POWER_ACTUAL_STRUCT generic_power_actual; + + /** Generic Power Last */ + MS_STATE_GENERIC_POWER_LAST_STRUCT generic_power_last; + + /** Generic Power Default */ + MS_STATE_GENERIC_POWER_DEFAULT_STRUCT generic_power_default; + + /** Generic Power Range */ + MS_STATE_GENERIC_POWER_RANGE_STRUCT generic_power_range; +} MS_STATE_GENERIC_POWER_LEVEL_STRUCT; + +/** + Generic Battery state is a set of four values representing the state of a + battery +*/ +typedef struct MS_state_generic_battery_struct +{ + /** + Generic Battery Level state is a value ranging from 0 percent through 100 + percent + */ + UCHAR generic_battery_level; + + /** + Generic Battery Time to Discharge state is a 24-bit unsigned value ranging + from 0 through 0xFFFFFF + */ + UINT32 generic_battery_time_to_discharge; + + /** + Generic Battery Time to Charge state is a 24-bit unsigned value ranging from + 0 through 0xFFFFFF + */ + UINT32 generic_battery_time_to_charge; + + /** + Generic Battery Flags state is a concatenation of four 2-bit bit fields: + Presence, Indicator, Charging, and Serviceability + */ + UCHAR generic_battery_flags; +} MS_STATE_GENERIC_BATTERY_STRUCT; + +/** Generic Global Location state defines location information of an element */ +typedef struct MS_state_generic_location_global_struct +{ + /** Global Coordinates (Latitude) */ + UINT32 global_latitude; + + /** Global Coordinates (Longitude) */ + UINT32 global_longitude; + + /** Global Altitude */ + UINT16 global_altitude; +} MS_STATE_GENERIC_LOCATION_GLOBAL_STRUCT; + +/** Generic Local Location state defines location information of an element */ +typedef struct MS_state_generic_location_local_struct +{ + /** Local Coordinates (North) */ + UINT16 local_north; + + /** Local Coordinates (East) */ + UINT16 local_east; + + /** Local Altitude */ + UINT16 local_altitude; + + /** Floor Number */ + UCHAR floor_number; + + /** Uncertainty */ + UINT16 uncertainty; +} MS_STATE_GENERIC_LOCATION_LOCAL_STRUCT; + +/** + Generic Location state is a composite state that includes a Generic Location + Global state and a Generic Location Local state +*/ +typedef struct MS_state_generic_location_struct +{ + /** Global Location */ + MS_STATE_GENERIC_LOCATION_GLOBAL_STRUCT global_location; + + /** Local Location */ + MS_STATE_GENERIC_LOCATION_LOCAL_STRUCT local_location; +} MS_STATE_GENERIC_LOCATION_STRUCT; + + +/** + Generic Property is a state representing a device property of an element. + The properties can be one of the following + - Manufacturer Properties + - Admin Properties + - User Properties +*/ +typedef struct MS_state_generic_property_struct +{ + /** + User Property ID field is a 2-octet Assigned Number value referencing a + property + */ + UINT16 property_id; + + /** Property Type - Manufacturer/Admin/User */ + UINT8 property_type; + + /** + User Access field is an enumeration indicating whether the device property + can be read or written as a Generic Admin/User Property + */ + UCHAR access; + + /** User Property Value field is a conditional field */ + UCHAR* property_value; + UINT16 property_value_len; + +} MS_STATE_GENERIC_PROPERTY_STRUCT; + + +/** Generic User Property is a state representing a device property of an element */ +typedef struct MS_state_generic_user_property_struct +{ + /** + User Property ID field is a 2-octet Assigned Number value referencing a + device property + */ + UINT16 property_id; + + /** + User Access field is an enumeration indicating whether the device property + can be read or written as a Generic User Property + */ + UCHAR user_access; + + /** User Property Value field is a conditional field */ + UCHAR* property_value; + UINT16 property_value_len; +} MS_STATE_GENERIC_USER_PROPERTY_STRUCT; + +/** + Generic Admin Property is a state representing a device property of an + element that can be read or written +*/ +typedef struct MS_state_generic_admin_property_struct +{ + /** + Admin Property ID field is a 2-octet Assigned Number value referencing a + device property + */ + UINT16 property_id; + + /** + Admin User Access field is an enumeration indicating whether the device + property can be read or written as a Generic User Property + */ + UCHAR user_access; + + /** Admin Property Value field is a conditional field */ + UCHAR* property_value; + UINT16 property_value_len; +} MS_STATE_GENERIC_ADMIN_PROPERTY_STRUCT; + +/** + Generic Manufacturer Property is a state representing a device property of an + element that is programmed by a manufacturer and can be read +*/ +typedef struct MS_state_generic_manufacturer_property_struct +{ + /** + Manufacturer Property ID field is a 2-octet Assigned Number value that + references a device property + */ + UINT16 property_id; + + /** + Manufacturer User Access field is an enumeration indicating whether or not + the device property can be read as a Generic User Property + */ + UCHAR user_access; + + /** Manufacturer Property Value field is a conditional field */ + UCHAR* property_value; + UINT16 property_value_len; +} MS_STATE_GENERIC_MANUFACTURER_PROPERTY_STRUCT; + +/** + Generic Property ID a read-only state representing a device property that an + element supports +*/ +typedef struct MS_state_generic_property_id_struct +{ + /** + Property ID field is a 2-octet Assigned Number value that references a device + property + */ + UINT16 property_id; +} MS_STATE_GENERIC_PROPERTY_ID_STRUCT; + +/** + Generic Property IDs a state representing a set of device properties that an + element supports +*/ +typedef struct MS_state_generic_property_ids_struct +{ + /** + Property IDs field is a set of 2-octet Assigned Number value that references + a set of device properties + */ + UINT16* property_ids; + UINT16 property_ids_count; +} MS_STATE_GENERIC_PROPERTY_IDS_STRUCT; + +/** + Sensor Property ID field is a 2-octet value referencing a device property + that describes the meaning and the format of data reported by a sensor +*/ +typedef struct MS_state_sensor_property_id_struct +{ + /** + Sensor Property ID field is a 2-octet value referencing a device property + that describes the meaning and the format of data reported by a sensor + */ + UINT16 property_id; +} MS_STATE_SENSOR_PROPERTY_ID_STRUCT; + +/** Sensor Descriptor state represents the attributes describing the sensor data */ +typedef struct MS_state_sensor_descriptor_struct +{ + /** + Sensor Property ID field is a 2-octet value referencing a device property + that describes the meaning and the format of data reported by a sensor + */ + UINT16 sensor_property_id; + + /** + Sensor Positive Tolerance field is a 12-bit value representing the magnitude + of a possible positive error associated with the measurements that the sensor + is reporting + */ + UINT16 sensor_positive_tolerance; + + /** + Sensor Negative Tolerance field is a 12-bit value representing the magnitude + of a possible negative error associated with the measurements that the sensor + is reporting + */ + UINT16 sensor_negative_tolerance; + + /** + Sensor Sampling Function field specifies the averaging operation or type of + sampling function applied to the measured value + */ + UCHAR sensor_sampling_function; + + /** + Sensor Measurement Period field specifies a uint8 value n that represents the + averaging time span, accumulation time, or measurement period in seconds over + which the measurement is taken + */ + UCHAR sensor_measurement_period; + + /** + measurement reported by a sensor is internally refreshed at the frequency + indicated in the Sensor Update Interval field + */ + UCHAR sensor_update_interval; + + /** Status - used in response to indicate if other fields to be included */ + UINT8 status; + +} MS_STATE_SENSOR_DESCRIPTOR_STRUCT; + +/** Sensor Settings state controls parameters of a sensor */ +typedef struct MS_state_sensor_settings_struct +{ + /** Property ID of a sensor */ + UINT16 sensor_property_id; + + /** Property ID of a setting within a sensor */ + UINT16* setting_property_ids; + UINT16 setting_property_ids_count; + +} MS_STATE_SENSOR_SETTINGS_STRUCT; + +/** Sensor Setting state controls parameters of a sensor */ +typedef struct MS_state_sensor_setting_struct +{ + /** Property ID of a sensor */ + UINT16 sensor_property_id; + + /** Property ID of a setting within a sensor */ + UINT16 sensor_setting_property_id; + + /** Read/Write access rights for the setting */ + UCHAR sensor_setting_access; + + /** Raw value of a setting within a sensor */ + UCHAR* sensor_setting_raw; + UINT16 sensor_setting_raw_len; + + /* Status - used in response path */ + UINT8 status; + +} MS_STATE_SENSOR_SETTING_STRUCT; + +/** Sensor Cadence state controls the cadence of sensor reports */ +typedef struct MS_state_sensor_cadence_struct +{ + /** Property ID of a sensor */ + UINT16 sensor_property_id; + + /** Divisor for the Publish Period */ + UCHAR fast_cadence_period_divisor; + + /** Defines the unit and format of the Status Trigger Delta fields */ + UCHAR status_trigger_type; + + /** Delta down value that triggers a status message */ + UCHAR* status_trigger_delta_down; + UINT16 status_trigger_delta_down_len; + + /** Delta up value that triggers a status message */ + UCHAR* status_trigger_delta_up; + UINT16 status_trigger_delta_up_len; + + /** Minimum interval between two consecutive Status messages */ + UCHAR status_min_interval; + + /** Low value for the fast cadence range */ + UCHAR* fast_cadence_low; + UINT16 fast_cadence_low_len; + + /** High value for the fast cadence range */ + UCHAR* fast_cadence_high; + UINT16 fast_cadence_high_len; + + /** Status - used in response path */ + UINT8 status; + +} MS_STATE_SENSOR_CADENCE_STRUCT; + +/** + The Sensor Data state is a sequence of one or more pairs of Sensor Property + ID and Raw Value fields, with each Raw Value field size and representation + defined by the characteristics referenced by the Sensor Property ID +*/ +typedef struct MS_state_sensor_data_struct +{ + /** ID of the 1st device property of the sensor */ + UINT16 property_id_1; + + /** + Raw Value field with a size and representation defined by the 1st device + property + */ + UCHAR* raw_value_1; + UINT16 raw_value_1_len; + + /** ID of the 2nd device property of the sensor */ + UINT16 property_id_2; + + /** + Raw Value field with a size and representation defined by the 2nd device + property + */ + UCHAR* raw_value_2; + UINT16 raw_value_2_len; + + /** ID of the nth device property of the sensor */ + UINT16 property_id_n; + + /** + Raw Value field with a size and representation defined by the nth device + property + */ + UCHAR* raw_value_n; + UINT16 raw_value_n_len; + + /** Status - used in response path */ + UINT8 status; + +} MS_STATE_SENSOR_DATA_STRUCT; + +/** + Values measured by sensors may be organized as arrays (and represented as + series of columns, such as histograms +*/ +typedef struct MS_state_sensor_series_column_struct +{ + /** Property describing the data series of the sensor */ + UINT16 sensor_property_id; + + /** Raw value representing the left corner of a column on the X axis */ + UCHAR* sensor_raw_value_x; + UINT16 sensor_raw_value_x_len; + + /** Raw value representing the width of the column */ + UCHAR* sensor_column_width; + UINT16 sensor_column_width_len; + + /** Raw value representing the height of the column on the Y axis */ + UCHAR* sensor_raw_value_y; + UINT16 sensor_raw_value_y_len; + + /** Status - used in response path */ + UINT8 status; + +} MS_STATE_SENSOR_SERIES_COLUMN_STRUCT; + +/** + Mesh defines times based on International Atomic Time (TAI). The base + representation of times is the number of seconds after 00:00:00 TAI on + 2000-01-01 (that is, 1999-12-31T23:59:28 UTC) +*/ +typedef struct MS_state_time_struct +{ + /** Current TAI time in seconds since the epoch. */ + UCHAR tai_seconds[5]; + + /** The sub-second time in units of 1/256s. */ + UCHAR subsecond; + + /** Estimated uncertainty in 10-millisecond steps. */ + UCHAR uncertainty; + + /** + 0 = No Time Authority. The element does not have a trusted OOB source of + time, such as GPS or NTP. 1 = Time Authority. The element has a trusted OOB + source of time, such as GPS or NTP or a battery-backed, properly initialized + RTC. + */ + UCHAR time_authority; + + /** Current difference between TAI and UTC in seconds */ + UINT16 tai_utc_delta; + + /** The local time zone offset in 15-minute increments */ + UCHAR time_zone_offset; +} MS_STATE_TIME_STRUCT; + +/** Time Zone */ +typedef struct MS_state_time_zone_struct +{ + /** + Current local time zone offset. + Meaningful only in 'Time Zone Status' response. + */ + UCHAR time_zone_offset_current; + + /** Upcoming local time zone offset. */ + UCHAR time_zone_offset_new; + + /** Absolute TAI time when the Time Zone Offset will change from Current to New. */ + UCHAR tai_of_zone_change[5]; +} MS_STATE_TIME_ZONE_STRUCT; + +/** TAI-UTC Delta */ +typedef struct MS_state_time_tai_utc_delta_struct +{ + /** + Current difference between TAI and UTC in seconds. + Meaningful only in 'TAI-UTC Delta Status' response. + */ + UINT16 tai_utc_delta_current; + + /** Upcoming difference between TAI and UTC in seconds. */ + UINT16 tai_utc_delta_new; + + /** Always 0b0. Other values are Prohibited. */ + UCHAR padding; + + /** TAI Seconds time of the upcoming TAI-UTC Delta change */ + UCHAR tai_of_delta_change[5]; +} MS_STATE_TIME_TAI_UTC_DELTA_STRUCT; + +/** The Time Role state of an element */ +typedef struct MS_state_time_role_struct +{ + /** Time Role */ + UCHAR role; +} MS_STATE_TIME_ROLE_STRUCT; + +/** The state to identify a scene */ +typedef struct MS_state_scene_number_struct +{ + /** The number to identify a scene */ + UINT16 number; +} MS_STATE_SCENE_NUMBER_STRUCT; + +/** The current status of a currently active scene */ +typedef struct MS_state_scene_status_struct +{ + /** Status Code */ + UCHAR status_code; + + /** Scene Number of a current scene. */ + UINT16 current_scene; + + /** Scene Number of a target scene. */ + UINT16 target_scene; + + /* Remaining Time */ + UINT8 remaining_time; + +} MS_STATE_SCENE_STATUS_STRUCT; + +/** The current status of scene register */ +typedef struct MS_state_scene_register_status_struct +{ + /** Status Code */ + UCHAR status_code; + + /** Scene Number of a current scene. */ + UINT16 current_scene; + + /** A list of scenes stored within an element */ + UINT16* scenes; + UINT16 scenes_count; +} MS_STATE_SCENE_REGISTER_STATUS_STRUCT; + +/** The current Schedule Register state of an element. */ +typedef struct MS_state_scheduler_schedules_struct +{ + /** Bit field indicating defined Actions in the Schedule Register */ + UINT16 schedules; +} MS_STATE_SCHEDULER_SCHEDULES_STRUCT; + +/** The entry index of the Schedule Register state */ +typedef struct MS_state_scheduler_entry_index_struct +{ + /** Index of the Schedule Register entry */ + UCHAR index; +} MS_STATE_SCHEDULER_ENTRY_INDEX_STRUCT; + +/** The entry of the Schedule Register state */ +typedef struct MS_state_scheduler_entry_struct +{ + /** Index of the Schedule Register entry */ + UCHAR index; + + /** Scheduled year for the action */ + UCHAR year; + + /** Scheduled month for the action */ + UINT16 month; + + /** Scheduled day of the month for the action */ + UCHAR day; + + /** Scheduled hour for the action */ + UCHAR hour; + + /** Scheduled minute for the action */ + UCHAR minute; + + /** Scheduled second for the action */ + UCHAR second; + + /** Schedule days of the week for the action */ + UCHAR dayofweek; + + /** Action to be performed at the scheduled time */ + UCHAR action; + + /** Transition time for this action */ + UCHAR transition_time; + + /** Scene number to be used for some actions */ + UINT16 scene_number; + +} MS_STATE_SCHEDULER_ENTRY_STRUCT; + +/** + Light Lightness Linear state represents the lightness of a light on a linear + scale +*/ +typedef struct MS_state_light_lightness_linear_struct +{ + /** Light Lightness Linear */ + UINT16 lightness_linear; + + /** Light Lightness Target - Used in response path. */ + UINT16 lightness_target; + + /** TID - Used in request path */ + UINT8 tid; + + /** + Transition Time - Used in request path. + Used as remaining time in response path. + */ + UINT8 transition_time; + + /** Delay - Used in request path */ + UINT8 delay; + +} MS_STATE_LIGHT_LIGHTNESS_LINEAR_STRUCT; + +/** + Light Lightness Actual state represents the lightness of a light on a + perceptually uniform lightness scale +*/ +typedef struct MS_state_light_lightness_actual_struct +{ + /** Light Lightness Actual */ + UINT16 lightness_actual; + + /** Light Lightness Target - Used in response path. */ + UINT16 lightness_target; + + /** TID - Used in request path */ + UINT8 tid; + + /** + Transition Time - Used in request path. + Used as remaining time in response path. + */ + UINT8 transition_time; + + /** Delay - Used in request path */ + UINT8 delay; + + /** Transition Timer Handle */ + UINT16 transition_time_handle; + +} MS_STATE_LIGHT_LIGHTNESS_ACTUAL_STRUCT; + +/** + Light Lightness Last state represents the lightness of a light on a + perceptually uniform lightness scale +*/ +typedef struct MS_state_light_lightness_last_struct +{ + /** Light Lightness Last */ + UINT16 lightness_last; +} MS_STATE_LIGHT_LIGHTNESS_LAST_STRUCT; + +/** + Light Lightness Default state is a value ranging from 0x0000 to 0xFFFF, + representing a default lightness level for the Light Lightness Actual state +*/ +typedef struct MS_state_light_lightness_default_struct +{ + /** Light Lightness Default */ + UINT16 lightness_default; +} MS_STATE_LIGHT_LIGHTNESS_DEFAULT_STRUCT; + +/** + Light Lightness Range state determines the minimum and maximum lightness of + an element +*/ +typedef struct MS_state_light_lightness_range_struct +{ + /** Light Lightness Range Min */ + UINT16 lightness_range_min; + + /** Light Lightness Range Max */ + UINT16 lightness_range_max; +} MS_STATE_LIGHT_LIGHTNESS_RANGE_STRUCT; + +/** + Light Lightness state is a composite state that includes the Light Lightness + Linear, the Light Lightness Actual, the Light Lightness Last, and the Light + Lightness Default states +*/ +typedef struct MS_state_light_lightness_struct +{ + /** + Light Lightness Linear state represents the lightness of a light on a linear + scale + */ + MS_STATE_LIGHT_LIGHTNESS_LINEAR_STRUCT light_lightness_linear; + + /** + Light Lightness Actual state represents the lightness of a light on a + perceptually uniform lightness scale + */ + MS_STATE_LIGHT_LIGHTNESS_ACTUAL_STRUCT light_lightness_actual; + + /** + Light Lightness Last state represents the lightness of a light on a + perceptually uniform lightness scale + */ + MS_STATE_LIGHT_LIGHTNESS_LAST_STRUCT light_lightness_last; + + /** + Light Lightness Default state is a value ranging from 0x0000 to 0xFFFF, + representing a default lightness level for the Light Lightness Actual state + */ + MS_STATE_LIGHT_LIGHTNESS_DEFAULT_STRUCT light_lightness_default; + + /** + Light Lightness Range state. + */ + MS_STATE_LIGHT_LIGHTNESS_RANGE_STRUCT light_lightness_range; + + /** Status field used only for the Range Status */ + UINT8 range_status; + +} MS_STATE_LIGHT_LIGHTNESS_STRUCT; + +/** + Light CTL state is a composite state that includes the Light CTL Lightness, + the Light CTL Temperature and the Light CTL Delta UV states +*/ +typedef struct MS_state_light_ctl_struct +{ + /** Light CTL Lightness */ + UINT16 ctl_lightness; + + /** Target Light CTL Lightness - Used in response path */ + UINT16 target_ctl_lightness; + + /** Light CTL Temperature */ + UINT16 ctl_temperature; + + /** Terget Light CTL Temperature - Used in response path */ + UINT16 target_ctl_temperature; + + /** Light CTL Delta UV */ + UINT16 ctl_delta_uv; + + /** TID - Used in request path */ + UINT8 tid; + + /** + Transition Time - Used in request path. + Used as remaining time in response path. + */ + UINT8 transition_time; + + /** Delay - Used in request path */ + UINT8 delay; + +} MS_STATE_LIGHT_CTL_STRUCT; + +/** + Light CTL Default state is a composite state that includes the Light CTL + Lightness, the Light CTL Temperature and the Light CTL Delta UV states +*/ +typedef struct MS_state_light_ctl_default_struct +{ + /** Light CTL Lightness */ + UINT16 ctl_lightness; + + /** Light CTL Temperature */ + UINT16 ctl_temperature; + + /** Light CTL Delta UV */ + UINT16 ctl_delta_uv; +} MS_STATE_LIGHT_CTL_DEFAULT_STRUCT; + +/** + Light CTL Temperature state is a composite state that includes the Light CTL + Temperature and the Light CTL Delta UV states +*/ +typedef struct MS_state_light_ctl_temperature_struct +{ + /** Light CTL Temperature */ + UINT16 ctl_temperature; + + /** Target Light CTL Temperature - Used in response path */ + UINT16 target_ctl_temperature; + + /** Light CTL Delta UV */ + UINT16 ctl_delta_uv; + + /** Target Light CTL Delta UV - Used in response path */ + UINT16 target_ctl_delta_uv; + + /** TID - Used in request path */ + UINT8 tid; + + /** + Transition Time - Used in request path. + Used as remaining time in response path. + */ + UINT8 transition_time; + + /** Delay - Used in request path */ + UINT8 delay; + +} MS_STATE_LIGHT_CTL_TEMPERATURE_STRUCT; + +/** + Light CTL Temperature Range state determines the minimum and maximum color + temperatures of tunable white light an element is capable of emitting +*/ +typedef struct MS_state_light_ctl_temperature_range_struct +{ + /** CTL Temperature Range Min */ + UINT16 ctl_temperature_range_min; + + /** CTL Temperature Range Max */ + UINT16 ctl_temperature_range_max; + + /** Status - Used in response path */ + UINT8 status; + +} MS_STATE_LIGHT_CTL_TEMPERATURE_RANGE_STRUCT; + +/** + Light HSL state is a composite state that includes the Light HSL Lighness, + the Light HSL Hue and the Light HSL Saturation states +*/ +typedef struct MS_state_light_hsl_struct +{ + /** The perceived lightness of a light emitted by the element */ + UINT16 hsl_lightness; + + /** Target Perceived lightness - used in the response path */ + UINT16 target_hsl_lightness; + + /** The 16-bit value representing the hue */ + UINT16 hsl_hue; + + /** Target hue - used in the response path */ + UINT16 target_hsl_hue; + + /** The saturation of a color light */ + UINT16 hsl_saturation; + + /** Target saturation - used in the response path */ + UINT16 target_hsl_saturation; + + /** TID - Used in request path */ + UINT8 tid; + + /** + Transition Time - Used in request path. + Used as remaining time in response path. + */ + UINT8 transition_time; + + /** Delay - Used in request path */ + UINT8 delay; + + /** Transition Timer Handle */ + UINT16 transition_time_handle; + +} MS_STATE_LIGHT_HSL_STRUCT; + +/** + Light HSL Target state is a composite state that includes the Light HSL + Lighness, the Light HSL Hue and the Light HSL Saturation states +*/ +typedef struct MS_state_light_hsl_target_struct +{ + /** The perceived lightness of a light emitted by the element */ + UINT16 hsl_lightness; + + /** The 16-bit value representing the hue */ + UINT16 hsl_hue; + + /** The saturation of a color light */ + UINT16 hsl_saturation; +} MS_STATE_LIGHT_HSL_TARGET_STRUCT; + +/** + Light HSL Default state is a composite state that includes the Light HSL + Lighness, the Light HSL Hue and the Light HSL Saturation states +*/ +typedef struct MS_state_light_hsl_default_struct +{ + /** The perceived lightness of a light emitted by the element */ + UINT16 hsl_lightness; + + /** The 16-bit value representing the hue */ + UINT16 hsl_hue; + + /** The saturation of a color light */ + UINT16 hsl_saturation; +} MS_STATE_LIGHT_HSL_DEFAULT_STRUCT; + +/** Light HSL Hue */ +typedef struct MS_state_light_hsl_hue_struct +{ + /** The 16-bit value representing the hue */ + UINT16 hsl_hue; +} MS_STATE_LIGHT_HSL_HUE_STRUCT; + +/** Light HSL Saturation */ +typedef struct MS_state_light_hsl_saturation_struct +{ + /** The saturation of a color light */ + UINT16 hsl_saturation; +} MS_STATE_LIGHT_HSL_SATURATION_STRUCT; + +/** + Light HSL Range state is a composite state that includes Minimum and Maximum + of the Light HSL Hue and the Light HSL Saturation states +*/ +typedef struct MS_state_light_hsl_range_struct +{ + /** The value of the Hue Range Min field of the Light HSL Hue Range state */ + UINT16 hue_range_min; + + /** The value of the Hue Range Max field of the Light HSL Hue Range state */ + UINT16 hue_range_max; + + /** + The value of the Saturation Range Min field of the Light HSL Saturation Range + state + */ + UINT16 saturation_range_min; + + /** + The value of the Saturation Range Max field of the Light HSL Saturation Range + state + */ + UINT16 saturation_range_max; + + /** Status - Used only in response path */ + UINT8 status; + +} MS_STATE_LIGHT_HSL_RANGE_STRUCT; + +/** + Light xyL state is a composite state that includes the xyL Lightness, the + Light xyL x and the Light xyL y states +*/ +typedef struct MS_state_light_xyl_struct +{ + /** The perceived lightness of a light emitted by the element */ + UINT16 xyl_lightness; + + /** Target perceived lightness - used in response path */ + UINT16 target_xyl_lightness; + + /** The 16-bit value representing the x coordinate of a CIE1931 color light */ + UINT16 xyl_x; + + /** Target x coordinate - used in response path */ + UINT16 target_xyl_x; + + /** The 16-bit value representing the y coordinate of a CIE1931 color light */ + UINT16 xyl_y; + + /** Target y coordinate - used in response path */ + UINT16 target_xyl_y; + + /** TID - Used in request path */ + UINT8 tid; + + /** + Transition Time - Used in request path. + Used as remaining time in response path. + */ + UINT8 transition_time; + + /** Delay - Used in request path */ + UINT8 delay; + + /** Transition Timer Handle */ + UINT16 transition_time_handle; + +} MS_STATE_LIGHT_XYL_STRUCT; + +/** + Light xyL target state is a composite state that includes the xyL Lightness, + the Light xyL x and the Light xyL y states +*/ +typedef struct MS_state_light_xyl_target_struct +{ + /** The perceived lightness of a light emitted by the element */ + UINT16 xyl_lightness; + + /** The 16-bit value representing the x coordinate of a CIE1931 color light */ + UINT16 xyl_x; + + /** The 16-bit value representing the y coordinate of a CIE1931 color light */ + UINT16 xyl_y; +} MS_STATE_LIGHT_XYL_TARGET_STRUCT; + +/** + Light xyL default state is a composite state that includes the xyL Lightness, + the Light xyL x and the Light xyL y states +*/ +typedef struct MS_state_light_xyl_default_struct +{ + /** The perceived lightness of a light emitted by the element */ + UINT16 xyl_lightness; + + /** The 16-bit value representing the x coordinate of a CIE1931 color light */ + UINT16 xyl_x; + + /** The 16-bit value representing the y coordinate of a CIE1931 color light */ + UINT16 xyl_y; +} MS_STATE_LIGHT_XYL_DEFAULT_STRUCT; + +/** + Light xyL Range state determines the minimum and maximum values of the Light + xyL x and syL y state of an element +*/ +typedef struct MS_state_light_xyl_range_struct +{ + /** The minimum value of a Light xyL x state of an element */ + UINT16 xyl_x_range_min; + + /** The maximum value of a Light xyL x state of an element */ + UINT16 xyl_x_range_max; + + /** The minimum value of a Light xyL y state of an element */ + UINT16 xyl_y_range_min; + + /** The maximum value of a Light xyL y state of an element */ + UINT16 xyl_y_range_max; + + /** Status - Used in the response path */ + UINT8 status; + +} MS_STATE_LIGHT_XYL_RANGE_STRUCT; + +/** Light LC Mode state */ +typedef struct MS_state_light_lc_mode_struct +{ + /** Light LC Mode state - present */ + UCHAR present_mode; + + /** Light LC Mode state - target */ + UCHAR target_mode; + +} MS_STATE_LIGHT_LC_MODE_STRUCT; + +/** Light LC Occupancy Mode state */ +typedef struct MS_state_light_lc_om_struct +{ + /** Light LC Occupancy Mode state - present */ + UCHAR present_mode; + + /** Light LC Occupancy Mode state - target */ + UCHAR target_mode; + +} MS_STATE_LIGHT_LC_OM_STRUCT; + +/** Light LC Light OnOff State */ +typedef struct MS_state_light_lc_light_onoff_struct +{ + /** Light LC Light OnOff State */ + UCHAR present_light_onoff; + + /** Light LC Light OnOff State */ + UCHAR target_light_onoff; + + /** TID - Used in request path */ + UINT8 tid; + + /** + Transition Time - Used in request path. + Used as remaining time in response path. + */ + UINT8 transition_time; + + /** Delay - Used in request path */ + UINT8 delay; + +} MS_STATE_LIGHT_LC_LIGHT_ONOFF_STRUCT; + +/** Property ID identifying a Light LC Property */ +typedef struct MS_state_light_lc_property_id_struct +{ + /** Property ID identifying a Light LC Property */ + UINT16 property_id; +} MS_STATE_LIGHT_LC_PROPERTY_ID_STRUCT; + +/** Light LC Property state */ +typedef struct MS_state_light_lc_property_struct +{ + /** Property ID identifying a Light LC Property */ + UINT16 property_id; + + /** Raw value for the Light LC Property */ + UCHAR* property_value; + UINT16 property_value_len; +} MS_STATE_LIGHT_LC_PROPERTY_STRUCT; + + +/* Additional supporting structure defines */ + +/** + TID and Transition is a structure which contains Transaction ID (TID) as mandatory field. + Other two fields, Transition Time and Delay are optional. + + TID field is a transaction identifier indicating whether the message is a new message or + a retransmission of a previously sent message. + + If present, the Transition Time field identifies the time that an element will take + to transition to the target state from the present state. + + The Delay field shall be present when the Transition Time field is present. + It identifies the message execution delay, representing a time interval between receiving + the message by a model and executing the associated model behaviors. +*/ +typedef struct MS_ext_tid_and_transition_struct +{ + UCHAR tid; + UCHAR transition_time; + UCHAR delay; + UCHAR optional_fields_present; + +} MS_EXT_TID_AND_TRANSITION_STRUCT; + +/** + The Status Code field identifies the Status Code for the last operation. +*/ +typedef struct MS_ext_status_struct +{ + UCHAR status; + +} MS_EXT_STATUS_STRUCT; + +/* State Transition data structure */ +typedef struct _MS_ACCESS_STATE_TRANSITION_TYPE +{ + /* Transition Timer */ + EM_timer_handle transition_timer_handle; + + /* Transition State. Initial/delay/transition */ + UINT8 transition_state; + + /* Delay */ + UINT8 delay; + + /* Transition Time */ + UINT8 transition_time; + + /* Transition Start Callback */ + void (* transition_start_cb)(void*); + + /* Transition Complete Callback */ + void (* transition_complete_cb)(void*); + + /* Blob/Context */ + void* blob; + +} MS_ACCESS_STATE_TRANSITION_TYPE; + +/* --------------------------------------------- Function */ +#endif /*_H_MS_MODEL_STATES_ */ diff --git a/src/components/ethermind/mesh/export/include/MS_net_api.h b/src/components/ethermind/mesh/export/include/MS_net_api.h new file mode 100644 index 0000000..624bb07 --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_net_api.h @@ -0,0 +1,849 @@ + +/** + \file MS_net_api.h + + \brief This file defines the Mesh Network Layer Interface - includes + Data Structures and Methods. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_NET_API_ +#define _H_MS_NET_API_ + + +/* --------------------------------------------- Header File Inclusion */ +/* Bearer Layer */ +#include "MS_brr_api.h" +#include "MS_prov_api.h" + +/* --------------------------------------------- Global Definitions */ + +/** + \defgroup net_module NETWORK (Mesh Network Layer) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Network (NETWORK) module to the Application and other upper + layers of the stack. +*/ + +/** + \defgroup net_defines Defines + \{ + Describes defines for the module. +*/ + +/** + \defgroup net_constants Constants + \{ + Describes Constants defined by the module. +*/ + +/** + \defgroup net_addressing Addressing + \{ + Describes five basic type of addresses, the Network Layer defines. +*/ + +/** + Unassigned Address. + An unassigned address is an address that means that the component of a node + has not been configured yet or no address has been allocated. + + An unassigned address shall not be used in a source or destination address + field of a message. + + A Primary Component shall not have an unassigned address. + A Secondary Component may have an unassigned address. + A component with an unassigned address is inactive (i.e., it cannot send + nor receive and process messages). +*/ +#define MS_NET_ADDR_UNASSIGNED 0x0000 +/** Network Address Type - Invalid */ +#define MS_NET_ADDR_TYPE_INVALID 0x00 + +/** + Unicast Address. + A unicast address is a unique address allocated to each component within a node. + A unicast address has bit 15 cleared to zero. + The unicast address shall not have the value 0x0000, + and therefore can have any value from 0x0001 to 0x7FFF inclusive. + + A unicast address is allocated to a primary component of an unprovisioned + device by the Provisioner during provisioning for the lifetime of the node + on the network. + + A unicast address can be allocated to any secondary component within + an already provisioned node. + + A unicast address shall be used in the source address field of a message + and can be used in a destination address field of a message. + A message sent to a unicast address will be processed by at most one node + or one component within a node. +*/ +/** Bitmask for Network Address Type - Unicast */ +#define MS_NET_ADDR_UNICAST_BIT_MASK 0x8000 +/** Comparison value for Network Address Type - Unicast */ +#define MS_NET_ADDR_UNICAST_COMPARE 0x0000 +/** Network Address Type - Unicast */ +#define MS_NET_ADDR_TYPE_UNICAST 0x01 + +/** + Virtual Address. + A virtual address is an address that is similar to a group address, + in that multiple devices may know such an address. + This type of address is used to identify a label to which devices + may publish or subscribe. + The label referred to by a given virtual address is uniquely identified + by a 128-bit UUID, called virtual label UUID. + + The format of a Virtual Address is 10vv vvvv vvvv vvvv. + The fourteen v-bits are the least significant bits of the following calculation: + v = AES-CMAC (virtual label UUID, "vtad")[0-13] +*/ +/** Bitmask for Network Address Type - Virtual */ +#define MS_NET_ADDR_VIRTUAL_BIT_MASK 0xC000 +/** Comparison value for Network Address Type - Virtual */ +#define MS_NET_ADDR_VIRTUAL_COMPARE 0x8000 +/** Network Address Type - Virtual */ +#define MS_NET_ADDR_TYPE_VIRTUAL 0x02 + +/** + Group Address. + A group address is an address that is programmed into zero or more nodes or + components within nodes. + A group address has bit 15 set to one and bit 14 set to one. + The group address shall not have the value 0xFFFF, and therefore can have + any value from 0xC000 to 0xFFFE. + A group address shall only be used in the destination address field of a message. + A message sent to a group address will be processed by all the nodes that know + this group address. +*/ +/** Bitmask for Network Address Type - Group */ +#define MS_NET_ADDR_GROUP_BIT_MASK 0xC000 +/** Comparison value for Network Address Type - Group */ +#define MS_NET_ADDR_GROUP_COMPARE 0xC000 +/** Network Address Type - Group */ +#define MS_NET_ADDR_TYPE_GROUP 0x03 + +/** + Fixed Group Addresses are all-proxies, all-friends, all-relays and all-nodes. + + Note: Fixed Group Addresses in the range 0xFF00 - 0xFFFB are Reserved for Future. +*/ +/** Fixed Group Address - All-Proxies */ +#define MS_NET_ADDR_ALL_PROXIES 0xFFFC +/** Fixed Group Address - All-Friends */ +#define MS_NET_ADDR_ALL_FRIENDS 0xFFFD +/** Fixed Group Address - All-Relays */ +#define MS_NET_ADDR_ALL_RELAYS 0xFFFE +/** Fixed Group Address - All-Nodes */ +#define MS_NET_ADDR_ALL_NODES 0xFFFF + +/** + Address Validity + + | Address Type | Valid in Source Address Field | Valid in Destination Address Field | + | :----------: | :----------------------------: | :--------------------------------: | + | Unassigned | No | No | + | Unicast | Yes | Yes | + | Virtual | No | Yes | + | Group | No | Yes | + | Broadcast | No | Yes | +*/ + +/** Network Layer Feature Idenfiers */ +/** Network Layer Feature - Proxy */ +#define MS_NET_FEATURE_PROXY 0x00 +/** Network Layer Feature - Relay */ +#define MS_NET_FEATURE_RELAY 0x01 + +/** Primary Subnet - NetKey Index is 0x000 */ +#define MS_PRIMARY_SUBNET 0x000 + +/** Invalid Subnet Handle */ +#define MS_INVALID_SUBNET_HANDLE 0xFFFF + +/** Invalid AppKey Handle */ +#define MS_INVALID_APPKEY_HANDLE 0xFFFF + +/** \} */ + +/** + \defgroup net_proxy Proxy + \{ + Describes Network Layer Proxy Feature related defines. +*/ +/** GATT Proxy Filter Types */ +/** GATT Proxy Filter Type - Whitelist */ +#define MS_PROXY_WHITELIST_FILTER 0x00 +/** GATT Proxy Filter Type - Blacklist */ +#define MS_PROXY_BLACKLIST_FILTER 0x01 + +/** GATT Proxy Configuration Opcodes */ +/** GATT Proxy Configuration - Set Filter Opcode */ +#define MS_PROXY_SET_FILTER_OPCODE 0x00 +/** GATT Proxy Configuration - Add to Filter Opcode */ +#define MS_PROXY_ADD_TO_FILTER_OPCODE 0x01 +/** GATT Proxy Configuration - Remove From Filter Opcode */ +#define MS_PROXY_REM_FROM_FILTER_OPCODE 0x02 +/** GATT Proxy Configuration - Filter Status Opcode */ +#define MS_PROXY_FILTER_STATUS_OPCODE 0x03 + +/** GATT Proxy ADV Modes */ +/** Network ID Type */ +#define MS_PROXY_NET_ID_ADV_MODE 0x01 +/** Node Idetity Type */ +#define MS_PROXY_NODE_ID_ADV_MODE 0x02 + +/** \} */ + +/** \} */ + +/** + \defgroup net_events Events + \{ + This section lists the Asynchronous Events notified to Application by the + Module. +*/ + +/** GATT Proxy Events */ +/** GATT Proxy Event - Interface UP */ +#define MS_PROXY_UP_EVENT 0x00 +/** GATT Proxy Event - Interface Down */ +#define MS_PROXY_DOWN_EVENT 0x01 +/** GATT Proxy Event - Status */ +#define MS_PROXY_STATUS_EVENT 0x02 + +/** \} */ + +/** + \defgroup net_proxy states + \{ + This section lists the various states of Proxy Module exposed by it to + other Modules. +*/ + +/** + GATT Proxy States. + + | Proxy Callback | Proxy Iface | Error Code + |------------------|--------------|------------------- + | NULL | Down | MS_PROXY_NULL + | NULL | Up | MS_PROXY_NULL + | !NULL | Down | MS_PROXY_READY + | !NULL | UP | MS_PROXY_CONNECTED +*/ +/** GATT Proxy State - Invalid/Not Initialized */ +#define MS_PROXY_NULL 0x00 +/** GATT Proxy State - Ready/Initialized */ +#define MS_PROXY_READY 0x01 +/** GATT Proxy State - Connected */ +#define MS_PROXY_CONNECTED 0x02 + + +/* Secure Beacon Network Timer (minimum of 10 s) */ +extern EM_timer_handle ms_snb_timer_handle; + +extern EM_timer_handle ms_iv_update_timer_handle; + +extern EM_timer_handle net_key_refresh_timer_handle; + +/* Secure Beacon Network Beacon Timeout value - default 10s */ +#define MS_SNB_TIMEOUT (10 * 1000) /* in ms */ + + +/** \} */ +/** \} */ + +/** + \defgroup net_marcos Utility Macros + \{ + Initialization and other Utility Macros offered by the module. +*/ + +/** \} */ + +/* --------------------------------------------- Data Types/ Structures */ + +/** + \addtogroup net_defines Defines + \{ +*/ + +/** + \addtogroup net_structures Structures + \{ +*/ + +/** Network Address Type */ +typedef UINT16 MS_NET_ADDR; + +/** Subnet Handle */ +typedef UINT16 MS_SUBNET_HANDLE; + +/** AppKey Handle */ +typedef UINT16 MS_APPKEY_HANDLE; + +/** Address Type */ +typedef UCHAR MS_NET_ADDR_TYPE; + +/** Network Header Type */ +typedef struct _MS_NET_HEADER +{ + /** Least significant bit of IV Index - 1 bit */ + UINT8 ivi; + + /** + Value derived from the NetKey used to identify + the Encrytion Key and Privacy Key used to secure + this PDU - 7 bits + */ + UINT8 nid; + + /** Network Control - 1 bit */ + UINT8 ctl; + + /** Time To Live - 7 bits */ + UINT8 ttl; + + /** 16 Bit Source Address */ + MS_NET_ADDR saddr; + + /** 16 Bit Destination Address */ + MS_NET_ADDR daddr; + + /** 24 bit sequence number - currently filled only in recption path */ + UINT32 seq_num; + +} MS_NET_HEADER; + +/** Data structures for filter type and address list */ +typedef UCHAR PROXY_FILTER_TYPE; + +/** Proxy Address */ +typedef MS_NET_ADDR PROXY_ADDR; + +/** Network Interface Handle */ +typedef UINT8 NETIF_HANDLE; + +/** Current Sequence Number and Block State */ +typedef struct _NET_SEQ_NUMBER_STATE +{ + /** Current Sequence Number */ + UINT32 seq_num; + + /** Block Sequence number - maximum available */ + UINT32 block_seq_num_max; + +} NET_SEQ_NUMBER_STATE; + +/** \} */ + +/** \} */ + +/** + \defgroup net_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ +/** + NETWORK Application Asynchronous Notification Callback. + + NETWORK calls the registered callback to indicate events occurred to the + application. + + \param brr_type Bearer Type. + \param net_hdr Network Header. + \param subnet_handle Associated Subnet Handle. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. + + \return + - \ref NET_POST_PROCESS_RX_PKT: To inform Network Layer if the packet to be + further processed, e.g. to be relayed or proxied etc. + + - Any Other Result/Error Code defined in MS_error.h: Ignored by Network Layer. +*/ +typedef API_RESULT (*NET_NTF_CB) +( + MS_NET_HEADER* net_hdr, + MS_SUBNET_HANDLE subnet_handle, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; + +/** + Network Proxy Application Asynchronous Notification Callback. + + NETWORK PROXY calls the registered callback to indicate events occurred to the + application. + + \param handle Network Interface Handle. + \param p_evt Proxy Event. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef void (*PROXY_NTF_CB) +( + NETIF_HANDLE* handle, + UCHAR p_evt, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; +/** \} */ + +/** + \defgroup net_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Network Layer APIs. +*/ + +/** + Macro to check if Unicast Address +*/ +#define MS_IS_UNICAST_ADDR(addr) \ + (((MS_NET_ADDR_UNASSIGNED != (addr)) && \ + (MS_NET_ADDR_UNICAST_COMPARE == ((addr) & MS_NET_ADDR_UNICAST_BIT_MASK))) \ + ? MS_TRUE : MS_FALSE) + +/** + Macro to check if Virtual Address +*/ +#define MS_IS_VIRTUAL_ADDR(addr) \ + ((MS_NET_ADDR_VIRTUAL_COMPARE == ((addr) & MS_NET_ADDR_VIRTUAL_BIT_MASK)) \ + ? MS_TRUE : MS_FALSE) + +/** + Macro to check if Group Address +*/ +#define MS_IS_GROUP_ADDR(addr) \ + ((MS_NET_ADDR_GROUP_COMPARE == ((addr) & MS_NET_ADDR_GROUP_BIT_MASK)) \ + ? MS_TRUE : MS_FALSE) + +/** + Source address shall be Unicast Address. +*/ +#define NET_IS_VALID_SRC_ADDR(addr) \ + MS_IS_UNICAST_ADDR(addr) + +/** + Destination address + - Shall not be Unassigned Address. + - Control Message shall not be a Virtual Address. +*/ +#define NET_IS_VALID_DST_ADDR(addr, ctl) \ + (((MS_NET_ADDR_UNASSIGNED != (addr)) && \ + ((0x01 != (ctl)) || (MS_FALSE == MS_IS_VIRTUAL_ADDR(addr)))) \ + ? MS_TRUE : MS_FALSE) + +#ifdef MS_PROXY_CLIENT +/* GATT Proxy Client Related defines */ +/** + \brief Set Proxy WhiteList Filter. + + \par Description This function is used by the Proxy Client + to set the filter type on the Proxy Server to \ref MS_PROXY_WHITELIST_FILTER. + + \param [in] nh Network Interface Handle + \param [in] sh Subnet Handle + + \note This API will be used by the Proxy Client only. + + \return API_SUCCESS or Error Code on failure +*/ +#define MS_proxy_set_whitelist_filter(nh,sh) \ + MS_proxy_set_filter \ + ( \ + (nh), \ + (sh), \ + MS_PROXY_WHITELIST_FILTER \ + ); + +/** + \brief Set Proxy BlackList Filter. + + \par Description This function is used by the Proxy Client + to set the filter type on the Proxy Server to \ref MS_PROXY_BLACKLIST_FILTER. + + \param [in] nh Network Interface Handle + \param [in] sh Subnet Handle + + \note This API will be used by the Proxy Client only. + + \return API_SUCCESS or Error Code on failure +*/ +#define MS_proxy_set_blacklist_filter(nh,sh) \ + MS_proxy_set_filter \ + ( \ + (nh), \ + (sh), \ + MS_PROXY_BLACKLIST_FILTER \ + ); + +/** + \brief Add addressess to Proxy Filter List. + + \par Description This function is used by the Proxy Client + to add Addressess to the Proxy Server's filter List. + + \param [in] nh Network Interface Handle + \param [in] sh Subnet Handle + \param [in] a Pointer to List of Address to be added + \param [in] c Count of Addressess present in the provided List + + \note This API will be used by the Proxy Client only. + + \return API_SUCCESS or Error Code on failure +*/ +#define MS_proxy_add_to_list(nh,sh,a,c) \ + MS_proxy_filter_op \ + ( \ + (nh), \ + (sh), \ + MS_PROXY_ADD_TO_FILTER_OPCODE, \ + (a), \ + (c) \ + ); + +/** + \brief Delete addresses from Proxy Filter List. + + \par Description This function is used by the Proxy Client + to delete/remove Addresses from the Proxy Server's filter List. + + \param [in] nh Network Interface Handle + \param [in] sh Subnet Handle + \param [in] a Pointer to List of Address to be deleted/removed + \param [in] c Count of Addressess present in the provided List + + \note This API will be used by the Proxy Client only. + + \return API_SUCCESS or Error Code on failure +*/ +#define MS_proxy_del_from_list(nh,sh,a,c) \ + MS_proxy_filter_op \ + ( \ + (nh), \ + (sh), \ + MS_PROXY_REM_FROM_FILTER_OPCODE, \ + (a), \ + (c) \ + ); +#endif /* MS_PROXY_CLIENT */ + +/* --------------------------------------------- Function */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + \brief Register Inerface with NETWORK Layer + + \par Description + This routine registers interface with the NETWORK Layer. + NETWORK Layer supports only one upper layer, hence this routine shall be called once. + + \param [in] net_cb + Upper Layer Notification Callback + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_net_register +( + /* IN */ NET_NTF_CB net_cb +); + +/** + \brief API to send Secure Network Beacon + + \par Description + This routine sends Secure Network Beacon for the + given subnet handle + + \param [in] subnet_handle + Subnet handle of the network to be broadcasted. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_net_broadcast_secure_beacon +( + /* IN */ MS_SUBNET_HANDLE subnet_handle +); + +/** + \brief API to send NETWORK PDUs + + \par Description + This routine sends NETWORK PDUs to peer device. + + \param [in] hdr + Network Header + + \param [in] subnet_handle + Subnet Handle + + \param [in] buffer + Lower Transport Payload + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_net_send_pdu +( + /* IN */ MS_NET_HEADER* hdr, + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ MS_BUFFER* buffer, + /* IN */ UINT8 is_seg +); + +/** + \brief To get address type. + + \par Description + This routine is to get address type for a given address. + + \param [in] addr Input Network Address + + \return One of the following address type + \ref MS_NET_ADDR_TYPE_INVALID + \ref MS_NET_ADDR_TYPE_UNICAST + \ref MS_NET_ADDR_TYPE_VIRTUAL + \ref MS_NET_ADDR_TYPE_GROUP +*/ +MS_NET_ADDR_TYPE MS_net_get_address_type +( + /* IN */ MS_NET_ADDR addr +); + +/** + \brief Register Interface with NETWORK PROXY Layer + + \par Description + This routine registers interface with the NETWORK PROXY Layer. + NETWORK PROXY Layer supports only one upper layer, hence this rouine shall be called once. + + \param [in] proxy_cb + Upper Layer Notification Callback + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_proxy_register +( + /* IN */ PROXY_NTF_CB proxy_cb +); + +/** + \brief Check if the Proxy Module is ready to handle Proxy Messages/Events + + \par Description + This routine returns the current state of the Proxy. The valid states of + proxy are: + 1. MS_PROXY_NULL - If no callback registered by Upper Layers + 2. MS_PROXY_READY - If callback registered and Proxy not connected + 3. MS_PROXY_CONNECTED - if callback registered and Proxy connected + + \param [out] proxy_state returns the current state of the Proxy + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_proxy_fetch_state (UCHAR* proxy_state); + +#ifdef MS_PROXY_CLIENT +/** + \cond ignore_this Ignore this block while generating doxygen document +*/ +/** + \brief Set Proxy Server's Filter Type. + + \par Description This function is used by the Proxy Client + to set the filter type on the Proxy Server. + + \param [in] handle Network Interface Handle + \param [in] subnet_handle Subnet Handle + \param [in] type Type of the Proxy Filter to be set. Either + \ref MS_PROXY_WHITELIST_FILTER or + \ref MS_PROXY_BLACKLIST_FILTER + + \note This API will be used by the Proxy Client only. + + \return API_SUCCESS or Error Code on failure +*/ +API_RESULT MS_proxy_set_filter +( + /* IN */ NETIF_HANDLE* handle, + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ PROXY_FILTER_TYPE type +); + +/** + \brief Add or Delete/Remove addresses to/from Proxy Filter List. + + \par Description This function is used by the Proxy Client + to add/delete Addresses to/from the Proxy Server's filter List. + + \param [in] handle Network Interface Handle + \param [in] subnet_handle Subnet Handle + \param [in] opcode Operation to be performed. Either + \ref MS_PROXY_ADD_TO_FILTER_OPCODE or + \ref MS_PROXY_REM_FROM_FILTER_OPCODE + \param [in] addr Pointer to List of Address to be added/deleted + \param [in] addr_count Count of Addresses present in the provided List + + \note This API will be used by the Proxy Client only. + + \return API_SUCCESS or Error Code on failure +*/ +API_RESULT MS_proxy_filter_op +( + /* IN */ NETIF_HANDLE* handle, + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ UCHAR opcode, + /* IN */ PROXY_ADDR* addr, + /* IN */ UINT16 addr_count +); +/** + \endcond +*/ +#endif /* MS_PROXY_CLIENT */ + +/* Function to Start ADV using Proxy */ +#ifdef MS_PROXY_SERVER +/** + \brief Start Connectable Advertisements for a Proxy Server. + + \par Description This function is used by the Proxy Server + to start Connectable Undirected Advertisements. + + \param [in] subnet_handle Subnet Handle which the Proxy Server is + part of. + \param [in] proxy_adv_mode Mode of Proxy Advertisements. This could + be of two types + \ref MS_PROXY_NET_ID_ADV_MODE or + \ref MS_PROXY_NODE_ID_ADV_MODE + + \note This API will be used by the Proxy Server only. + + \return API_SUCCESS or Error Code on failure +*/ +API_RESULT MS_proxy_server_adv_start +( + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ UCHAR proxy_adv_mode +); + +API_RESULT MS_proxy_server_stop_timer(void); + + +/** + \brief Stop Connectable Advertisements for a Proxy Server. + + \par Description This function is used by the Proxy Server + to stop Connectable Undirected Advertisements. + + \note This API will be used by the Proxy Server only. + + \return API_SUCCESS or Error Code on failure +*/ +API_RESULT MS_proxy_server_adv_stop (void); +#endif /* MS_PROXY_SERVER */ + +/** + \brief To allocate Sequence Number. + + \par Description This function is used to allocate + Sequence Number. + + \param [out] seq_num Location where SeqNum to be filled. + + \return API_SUCCESS or Error Code on failure +*/ +API_RESULT MS_net_alloc_seq_num(/* OUT */ UINT32* seq_num); + +API_RESULT MS_net_start_iv_update_timer(UINT8 timer_flag,UINT8 reset_en); + +void MS_net_stop_iv_update_timer(void); + +/** + \brief To get current Sequence Number state. + + \par Description This function is used to get current + Sequence Number state. + + \param [out] seq_num_state Location where Seq Number state to be filled. + + \return API_SUCCESS or Error Code on failure +*/ +API_RESULT MS_net_get_seq_num_state(/* OUT */ NET_SEQ_NUMBER_STATE* seq_num_state); + +/** + \brief To set current Sequence Number state. + + \par Description This function is used to set current + Sequence Number state. + + \param [in] seq_num_state Location from where Seq Number state to be taken. + + \return API_SUCCESS or Error Code on failure +*/ +API_RESULT MS_net_set_seq_num_state(/* IN */ NET_SEQ_NUMBER_STATE* seq_num_state); + +/* Start Secure Network Beacon Timer */ +void MS_net_start_snb_timer +( + /* IN */ MS_SUBNET_HANDLE subnet_handle +); + +/* Stop Timer */ +void MS_net_stop_snb_timer +( + /* IN */ MS_SUBNET_HANDLE subnet_handle +); + +void MS_net_iv_update_rcv_pro +( + /* IN */ UINT32 iv_index, + /* IN */ UINT8 iv_update_flag +); + +void MS_net_key_refresh +( + /* IN */ MS_NET_ADDR* key_refresh_whitelist, + /* IN */ UINT16 num, + /* IN */ UINT8* new_net_key +); + + +/* Start Secure Network Beacon Timer */ +void MS_net_start_key_refresh_timer +( + /* IN */ UINT16 context, + /* IN */ UINT32 time +); + +/* Stop Key refresh Timer */ +void MS_net_stop_key_refresh_timer +( + void +); + + +void MS_net_key_refresh_init(void); + + + + +#ifdef __cplusplus +}; +#endif + +/** \} */ + +/** \} */ + +#endif /* _H_MS_NET_API_ */ + diff --git a/src/components/ethermind/mesh/export/include/MS_prov_api.h b/src/components/ethermind/mesh/export/include/MS_prov_api.h new file mode 100644 index 0000000..c72987f --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_prov_api.h @@ -0,0 +1,815 @@ + +/** + \file MS_prov_api.h + + \brief This file defines the Mesh Provisioning Application Interface - includes + Data Structures and Methods. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_PROV_API_ +#define _H_MS_PROV_API_ + + +/* --------------------------------------------- Header File Inclusion */ +/* Bearer Layer */ +#include "MS_brr_api.h" + +/* --------------------------------------------- Global Definitions */ + +/** + \defgroup prov_module PROVISIONING (Mesh Provisioning Layer) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Provisioning module to the Application and other upper + layers of the stack. +*/ + +/** + \defgroup prov_defines Defines + \{ + Describes defines for the module. +*/ + +/** + \defgroup prov_constants Constants + \{ + Describes Constants defined by the module. +*/ + +/** Provisiong Roles */ +#define PROV_ROLE_DEVICE 0x01 +#define PROV_ROLE_PROVISIONER 0x02 + +/** Provisioning Bearer Types */ +#define PROV_BRR_ADV 0x01 +#define PROV_BRR_GATT 0x02 + +/** Provisioning PDU Types */ +#define PROV_PDU_TYPE_INVITE 0x00 +#define PROV_PDU_TYPE_CAPAB 0x01 +#define PROV_PDU_TYPE_START 0x02 +#define PROV_PDU_TYPE_PUBKEY 0x03 +#define PROV_PDU_TYPE_INPUT_CMPLT 0x04 +#define PROV_PDU_TYPE_CONF 0x05 +#define PROV_PDU_TYPE_RAND 0x06 +#define PROV_PDU_TYPE_DATA 0x07 +#define PROV_PDU_TYPE_COMPLETE 0x08 +#define PROV_PDU_TYPE_FAILED 0x09 + +/** Provisioning algorithm values */ +#define PROV_ALGO_EC_FIPS_P256 0x00 + +/** Provisioning public key values */ +#define PROV_PUBKEY_NO_OOB 0x00 +#define PROV_PUBKEY_OOB 0x01 + +/** Provisioning authentication method values */ +#define PROV_AUTH_OOB_NONE 0x00 +#define PROV_AUTH_OOB_STATIC 0x01 +#define PROV_AUTH_OOB_OUTPUT 0x02 +#define PROV_AUTH_OOB_INPUT 0x03 + +/** Provisioning Output OOB action values */ +#define PROV_OOOB_ACTION_BLINK 0x00 +#define PROV_OOOB_ACTION_BEEP 0x01 +#define PROV_OOOB_ACTION_VIBRATE 0x02 +#define PROV_OOOB_ACTION_NUMERIC 0x03 +#define PROV_OOOB_ACTION_ALPHANUMERIC 0x04 + +/** Provisioning Input OOB action values */ +#define PROV_IOOB_ACTION_PUSH 0x00 +#define PROV_IOOB_ACTION_TWIST 0x01 +#define PROV_IOOB_ACTION_NUMERIC 0x02 +#define PROV_IOOB_ACTION_ALPHANUMERIC 0x03 + +/** Provisioning algorithm support masks */ +#define PROV_MASK_ALGO_EC_FIPS_P256 (1 << 0) + +/** Provisioning public key supported type masks */ +#define PROV_MASK_PUBKEY_OOBINFO (1 << 0) + +/** Provisioning static oob supported type masks */ +#define PROV_MASK_STATIC_OOBINFO (1 << 0) + +/** Output OOB actions supported masks */ +#define PROV_MASK_OOOB_ACTION_BLINK (1 << 0) +#define PROV_MASK_OOOB_ACTION_BEEP (1 << 1) +#define PROV_MASK_OOOB_ACTION_VIBRATE (1 << 2) +#define PROV_MASK_OOOB_ACTION_NUMERIC (1 << 3) +#define PROV_MASK_OOOB_ACTION_ALPHANUMERIC (1 << 4) + +/** Input OOB actions supported masks */ +#define PROV_MASK_IOOB_ACTION_PUSH (1 << 0) +#define PROV_MASK_IOOB_ACTION_TWIST (1 << 1) +#define PROV_MASK_IOOB_ACTION_NUMERIC (1 << 2) +#define PROV_MASK_IOOB_ACTION_ALPHANUMERIC (1 << 3) + +/** + \defgroup prov_control Control Constants + \{ + Control constants defined by the specification. +*/ + +/** Number of Fragments - Start of New Transaction */ +#define PROV_PCF_NUM_FRGMNTS 0x00 + +/** Control Message */ +#define PROV_PCF_CTRL_MSG 0x01 + +/** Fragment Index - Continuation of a transaction */ +#define PROV_PCF_CONTINU_FRGMNT 0x02 + +/** Transport Specific Messaging (only used by PB ADV) */ +#define PROV_PCF_TX_SPECIFIC 0x03 + +/** \} */ + +/** + \defgroup prov_advtxopcodes ADV Transport Opcodes + \{ + Specification defined transport Opcodes for PB-ADV bearer. +*/ + +/* Link Open Request */ +#define PROV_PB_ADV_OPEN_REQ 0x00 + +/* Link Open Confirm */ +#define PROV_PB_ADV_OPEN_CNF 0x01 + +/* Link Close Indication */ +#define PROV_PB_ADV_CLOSE_IND 0x02 + +/** \} */ + +/** + \defgroup prov_gatttxopcodes GATT Transport Opcodes + \{ + Implementation specific transport Opcodes for PB-GATT bearer. +*/ + +/* Link Open Indication */ +#define PROV_PB_GATT_OPEN_IND 0xF1 + +/* Link Close Indication */ +#define PROV_PB_GATT_CLOSE_IND 0xF0 + +/** \} */ + +/** + \defgroup prov_errorcode Error Codes + \{ + Describes Error Codes defined by the specification. +*/ + +/** Provisioning Failure Error Codes */ +#define PROV_ERR_PROHIBITED 0x00 +#define PROV_ERR_INVALID_PDU 0x01 +#define PROV_ERR_INVALID_FORMAT 0x02 +#define PROV_ERR_UNEXPECTED_PDU 0x03 +#define PROV_ERR_CONFIRMATION_FAILED 0x04 +#define PROV_ERR_OUT_OF_RESOURCES 0x05 +#define PROV_ERR_DECRYPTION_FAILED 0x06 +#define PROV_ERR_UNEXPECTED_ERROR 0x07 +#define PROV_ERR_CANNOT_ASSIGN_ADDRESS 0x08 + +/** Provisioning LinkClose Error codes */ +#define PROV_CLOSE_REASON_SUCCESS 0x00 +#define PROV_CLOSE_REASON_TIMEOUT 0x01 +#define PROV_CLOSE_REASON_FAIL 0x02 +/** \} */ + +/** Provisioning array size requirements */ +#define PROV_KEY_NETKEY_SIZE 16 +#define PROV_OOB_VALUE_SIZE 16 +#define PROV_URI_HASH_SIZE 4 + +/** Provisioning OOB type masks for ADV data */ +#define PROV_OOB_TYPE_OTHER (1 << 0) +#define PROV_OOB_TYPE_URI (1 << 1) +#define PROV_OOB_TYPE_2DMRC (1 << 2) +#define PROV_OOB_TYPE_BARCODE (1 << 3) +#define PROV_OOB_TYPE_NFC (1 << 4) +#define PROV_OOB_TYPE_NUMBER (1 << 5) +#define PROV_OOB_TYPE_STRING (1 << 6) +#define PROV_OOB_TYPE_ONBOX (1 << 11) +#define PROV_OOB_TYPE_INSIDEBOX (1 << 12) +#define PROV_OOB_TYPE_ONPIECEOFPAPER (1 << 13) +#define PROV_OOB_TYPE_INSIDEMANUAL (1 << 14) +#define PROV_OOB_TYPE_ONDEVICE (1 << 15) + +/** Invalid Provisioning Handle */ +#define PROV_HANDLE_INVALID 0xFF + +/** \} */ + +/** + \defgroup prov_events Events + \{ + This section lists the Asynchronous Events notified to Application by the + Module. +*/ + +/** + This event indicates the availability of an unprovisioned device beacon, + with the following values as parameters in the + \ref PROV_UI_NOTIFY_CB callback. + + \param [in] phandle Pointer to the Provisioning context handle + \param [in] event_type \ref PROV_EVT_UNPROVISIONED_BEACON. + \param [in] event_result \ref API_SUCCESS. + \param [in] event_data Pointer to the array with the UUID of the device. + \param [in] event_datalen MS_DEVICE_UUID_SIZE + + \note This event is received by the Provisioner application. On reception of + this event, the application shall make use of the MS_prov_bind() to initiate + the provisioning procedure. + + \return \ref API_SUCCESS (always) +*/ +#define PROV_EVT_UNPROVISIONED_BEACON 0x01 + +/** + This event indicates that the provisioning procedure capability exchange is + complete, with the following values as parameters in the + \ref PROV_UI_NOTIFY_CB callback. + + \param [in] phandle Pointer to the Provisioning context handle + \param [in] event_type \ref PROV_EVT_PROVISIONING_SETUP. + \param [in] event_result \ref API_SUCCESS on successful procedure completion, else + an Error Code. + \param [in] event_data When local provisioner, this contains peer device + capabilities and when local device, this contains the attention timeout + value. + \param [in] event_datalen When local provisioner, sizeof(\ref + PROV_CAPABILITIES_S) and when local device, sizeof(UINT32). + + \note When local provisioner, the appliation shall select the required + capability from the received capabilities and choose to start the procedure + by calling \ref MS_prov_start(). + + \return \ref API_SUCCESS (always) +*/ +#define PROV_EVT_PROVISIONING_SETUP 0x02 + +/** + This event indicates to the application the OOB random data that is to be + displayed on the UI via the \ref PROV_UI_NOTIFY_CB callback. + + \param [in] phandle Pointer to the Provisioning context handle + \param [in] event_type \ref PROV_EVT_OOB_DISPLAY. + \param [in] event_result \ref API_SUCCESS on successful procedure completion, else + an Error Code. + \param [in] event_data Pointer to OOB information as in \ref PROV_OOB_TYPE_S. + \param [in] event_datalen sizeof (\ref PROV_OOB_TYPE_S). + + \return \ref API_SUCCESS (always) +*/ +#define PROV_EVT_OOB_DISPLAY 0x03 + +/** + This event indicates to the application requesting for OOB random data that + is to be used in the procedure via the \ref PROV_UI_NOTIFY_CB callback. + + \param [in] phandle Pointer to the Provisioning context handle + \param [in] event_type \ref PROV_EVT_OOB_ENTRY. + \param [in] event_result \ref API_SUCCESS on successful procedure completion, else + an Error Code. + \param [in] event_data \ref Pointer to OOB information as in \ref PROV_OOB_TYPE_S. + \param [in] event_datalen sizeof (\ref PROV_OOB_TYPE_S). + + \return \ref API_SUCCESS (always) +*/ +#define PROV_EVT_OOB_ENTRY 0x04 + +/** + This event indicates to the application that the peer device has completed the + Input of OOB when this capability is negotiated via the + \ref PROV_UI_NOTIFY_CB callback. + + \param [in] phandle Pointer to the Provisioning context handle + \param [in] event_type \ref PROV_EVT_DEVINPUT_COMPLETE. + \param [in] event_result \ref API_SUCCESS on successful procedure completion, else + an Error Code. + \param [in] event_data NULL. + \param [in] event_datalen 0. + + \note This event is generated only for the provisioner application. + + \return \ref API_SUCCESS (always) +*/ +#define PROV_EVT_DEVINPUT_COMPLETE 0x05 + +/** + This event indicates to the application requesting for Provisional data to be + sent to the peer device via the \ref PROV_UI_NOTIFY_CB callback. + + \param [in] phandle Pointer to the Provisioning context handle + \param [in] event_type \ref PROV_EVT_PROVDATA_INFO_REQ. + \param [in] event_result \ref API_SUCCESS on successful procedure completion, else + an Error Code. + \param [in] event_data NULL. + \param [in] event_datalen 0. + + \note This event is generated only for the provisioner application. + + \return \ref API_SUCCESS (always) +*/ +#define PROV_EVT_PROVDATA_INFO_REQ 0x06 + +/** + This event indicates to the application the Provisional data received + from the Provisioner via the \ref PROV_UI_NOTIFY_CB callback. + + \param [in] phandle Pointer to the Provisioning context handle + \param [in] event_type \ref PROV_EVT_PROVDATA_INFO. + \param [in] event_result \ref API_SUCCESS on successful procedure completion, else + an Error Code. + \param [in] event_data Pointer to the provisioning data \ref PROV_DATA_S. + \param [in] event_datalen sizeof(\ref PROV_DATA_S). + + \note This event is generated only for the device application. + + \return \ref API_SUCCESS (always) +*/ +#define PROV_EVT_PROVDATA_INFO 0x07 + +/** + This event indicates to the application that the provisioning procedure + is complete via the \ref PROV_UI_NOTIFY_CB callback. + + \param [in] phandle Pointer to the Provisioning context handle + \param [in] event_type \ref PROV_EVT_PROVISIONING_COMPLETE. + \param [in] event_result \ref API_SUCCESS on successful procedure completion, else + an Error Code. + \param [in] event_data NULL. + \param [in] event_datalen 0. + + \return \ref API_SUCCESS (always) +*/ +#define PROV_EVT_PROVISIONING_COMPLETE 0x08 + +/** \} */ + +/** \} */ + +/* --------------------------------------------- Structures/Data Types */ + +/** + \addtogroup prov_defines Defines + \{ +*/ + +/** + \defgroup prov_structures Structures + \{ +*/ + +/** Role of the device */ +typedef UCHAR PROV_ROLE; + +/** Bearer for the provisioning session */ +typedef UCHAR PROV_BRR; + +/** Handle to reference the active provisioning context */ +typedef UCHAR PROV_HANDLE; + +/** Device Information used for Provisioning */ +typedef struct _PROV_DEVICE_S +{ + /** + Device UUID - + Used in unprovisioned device beacon and Provisioning Invite + */ + UCHAR uuid[MS_DEVICE_UUID_SIZE]; + + /** OOB Information */ + UINT16 oob; + + /** URI if any, to be given in encoded form */ + MS_BUFFER* uri; + +} PROV_DEVICE_S; + +/** OOB type for provisioning */ +typedef struct _PROV_OOB_TYPE_S +{ + /** OOB Action information */ + UINT16 action; + + /** OOB Size information */ + UCHAR size; + +} PROV_OOB_TYPE_S; + +/** Device capabilities used for Provisioning */ +typedef struct _PROV_CAPABILITIES_S +{ + /** Number of Elements */ + UCHAR num_elements; + + /** Supported algorithms */ + UINT16 supp_algorithms; + + /** Public key type */ + UCHAR supp_pubkey; + + /** Static OOB type */ + UCHAR supp_soob; + + /** Output OOB information */ + PROV_OOB_TYPE_S ooob; + + /** Input OOB information */ + PROV_OOB_TYPE_S ioob; + +} PROV_CAPABILITIES_S; + +/** Provisioning method information */ +typedef struct _PROV_METHOD_S +{ + /** Algorithm selected */ + UCHAR algorithm; + + /** Public key usage */ + UCHAR pubkey; + + /** Authentication type */ + UCHAR auth; + + /** OOB type */ + PROV_OOB_TYPE_S oob; + +} PROV_METHOD_S; + +/** Data exchanged during Provisiong procedure */ +typedef struct _PROV_DATA_S +{ + /** NetKey */ + UCHAR netkey[PROV_KEY_NETKEY_SIZE]; + + /** Index of the NetKey */ + UINT16 keyid; + + /** + Flags bitmask + bit 0: Key Refresh Flag. + 0: Not-In-Phase2 + 1: In-Phase2 + bit 1: IV Update Flag + 0: Normal operation + 1: IV Update active + + bits 2-7: RFU + */ + UCHAR flags; + + /** Current value of the IV index */ + UINT32 ivindex; + + /** Unicast address of the primary element */ + UINT16 uaddr; + +} PROV_DATA_S; + +/** \} */ +/** \} */ + +/** + \defgroup prov_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ + +/** + Provisioning Application Asynchronous Notification Callback. + + Provisioning calls the registered callback to indicate events occurred to the + application. + + \param phandle Handle that identifies the provisioning context. + \param event_type Event type from any of the events in \ref prov_events. + \param event_result API_SUCCESS or any error code. + \param event_data Data associated with the event if any or NULL. + \param event_datalen Size of the event data. 0 if event data is NULL. +*/ +typedef API_RESULT (* PROV_UI_NOTIFY_CB) +( + PROV_HANDLE* phandle, + UCHAR event_type, + API_RESULT event_result, + void* event_data, + UINT16 event_datalen +); + +/** \} */ + +/* --------------------------------------------- Macros */ +/** + \defgroup prov_marcos Utility Macros + \{ + Initialization and other Utility Macros offered by the module. +*/ + +/** + \brief Setup the Device for provisioning + + \par Description This function configures the application as an Unprovisioned + device over Advertising channel bearer and sets it ready for provisioning. + + \param [in] pdev Pointer to the device strcuture \ref PROV_DEVICE_S. + \param [in] tmo The setup timeout value + \param [out] phdl The handle to the context setup on successful allocation + + \return API_SUCCESS or Error Code on failure +*/ +#define MS_prov_setup_device_pbadv(pdev, tmo, phdl) \ + MS_prov_setup (PROV_ROLE_DEVICE, PROV_BRR_ADV, (pdev), (tmo), (phdl)) + +/** + \brief Setup the Provisioner for provisioning + + \par Description This function configures the application as a Provisioner + over Advertising channel bearer and sets it ready for provisioning. + + \param [in] tmo The setup timeout value + \param [out] phdl The handle to the context setup on successful allocation + + \return API_SUCCESS or Error Code on failure +*/ +#define MS_prov_setup_provisioner_pbadv(tmo, phdl) \ + MS_prov_setup (PROV_ROLE_PROVISIONER, PROV_BRR_ADV, NULL, (tmo), (phdl)) + +/** + \brief Setup the device for provisioning + + \par Description This function configures the application as an Unprovisioned + device over GATT channel bearer and sets it ready for provisioning. + + \param [in] pdev Pointer to the device strcuture \ref PROV_DEVICE_S. + \param [in] tmo The setup timeout value + \param [out] phdl The handle to the context setup on successful allocation + + \return API_SUCCESS or Error Code on failure +*/ +#define MS_prov_setup_device_pbgatt(pdev, tmo, phdl) \ + MS_prov_setup (PROV_ROLE_DEVICE, PROV_BRR_GATT, (pdev), (tmo), (phdl)) + +/** + \brief Setup the Provisioner for provisioning + + \par Description This function configures the application as a Provisioner + over GATT channel bearer and sets it ready for provisioning. + + \param [in] tmo The setup timeout value + \param [out] phdl The handle to the context setup on successful allocation + + \return API_SUCCESS or Error Code on failure +*/ +#define MS_prov_setup_provisioner_pbgatt(tmo, phdl) \ + MS_prov_setup (PROV_ROLE_PROVISIONER, PROV_BRR_GATT, NULL, (tmo), (phdl)) + +/** + \brief Start Provisioning on the select set of device capabilities. + + \par Description This function is used by the provisioner application to start + the procedure using the selected set of capabilities of the unprovisioned + device. + + \param [in] phandle Provisioning context to be used. + \param [in] pmethod Pointer to the structure with selected method. + + \note This API will be used by the provisioner only, in response to the + \ref PROV_EVT_PROVISIONING_SETUP event + + \return API_SUCCESS or Error Code on failure +*/ +#define MS_prov_start(phandle, pmethod) \ + MS_prov_send_pdu ((phandle), PROV_PDU_TYPE_START, (pmethod), sizeof(PROV_METHOD_S)) + +/** + \brief Input Authentication value from Device/Provisioner application. + + \par Description This function is used to receive the Authval from the + application and use it for the algorithm. When the application is that of a + device, it also sends the input complete message to the provisioner in the + given context. + + \param [in] phandle Provisioning context to be used. + \param [in] pauth Authentication Value (UINT32 *) or (UCHAR *) + \param [in] size Size of pauth + + \note This API will be used in response to the + \ref PROV_EVT_OOB_ENTRY event + + \return API_SUCCESS or Error Code on failure +*/ +#define MS_prov_input_authval(phandle, pauth, size) \ + MS_prov_send_pdu ((phandle), PROV_PDU_TYPE_INPUT_CMPLT, (pauth), (size)) + +/** + \brief Send provisioning data to the device. + + \par Description This function is used by the provisioning application to send + the provisioning data to the device after authentication is complete. + + \param [in] phandle Provisioning context to be used. + \param [in] pdata Pointer to the Provisioning data structre as in \ref + PROV_DATA_S + + \note This API will be used by the provisioner only, in response to the + \ref PROV_EVT_PROVDATA_INFO_REQ event + + \return API_SUCCESS or Error Code on failure +*/ +#define MS_prov_data(phandle, pdata) \ + MS_prov_send_pdu ((phandle), PROV_PDU_TYPE_DATA, (pdata), sizeof (PROV_DATA_S)) + +/** \} */ + +/* --------------------------------------------- External Global Definitions */ +/** Global Provisioning Role */ +extern UCHAR prov_role; + + +/* --------------------------------------------- API Declarations */ + +/** + \defgroup prvsng_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Provisioning Layer APIs. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + \brief Register provisioning capabilities and callback + + \par Description This function registers the provisioning capabilities of the + application along with the application callback to notify events during the + provisioning procedure. + + \param [in] pcapab Pointer to the provisioning capabilities structure \ref PROV_CAPABILITIES_S + \param [in] cb Application callback function pointer + + \return API_SUCCESS or Error Code on failure +*/ +API_RESULT MS_prov_register +( + /* IN */ PROV_CAPABILITIES_S* pcapab, + /* IN */ PROV_UI_NOTIFY_CB cb +); + +API_RESULT MS_prov_stop_interleave_timer +( + void +); + + +/** + \brief Setup the device for provisioning + + \par Description This function configures the device to get in a provisionable + state by specifying the role, bearer and creating a context. + + \param [in] role Provisioniong role to be setup - Device or Provisioner. + \param [in] bearer Provisioning bearer to be setup - PB-ADV or PB-GATT + \param [in] pdevice Pointer to the device strcuture \ref PROV_DEVICE_S + containing the UUID to be beaconed. This parameter is used only when the + role is PROV_ROLE_DEVICE and ignored otherwise. + \param [in] timeout The time period for which the setup shall be active. + + \return API_SUCCESS or Error Code on failure +*/ +API_RESULT MS_prov_setup +( + /* IN */ PROV_ROLE role, + /* IN */ PROV_BRR bearer, + /* IN */ PROV_DEVICE_S* pdevice, + /* IN */ UINT16 gatt_timeout, + /* IN */ UINT16 adv_timeout +); + +/** + \brief Bind to the peer device for provisioning + + \par Description This function establishes a provisioning link with the peer device + and exchanges the capabilities for provisioning. + + \param [in] bearer Provisioning bearer on which to be bound - PB-ADV or PB-GATT + \param [in] pdevice Pointer to the device strcuture \ref PROV_DEVICE_S. + \param [in] attention The attention duration in seconds to be configured by the + device. This parameter is dont care if the role is PROV_ROLE_DEVICE. + \param [out] phandle The handle to the context setup on successful allocation. + + \note This API is for use by the Provisioner application only upon + reception of an Unprovisioned Device Beacon. + + \return API_SUCCESS or Error Code on failure +*/ +API_RESULT MS_prov_bind +( + /* IN */ PROV_BRR bearer, + /* IN */ PROV_DEVICE_S* pdevice, + /* IN */ UCHAR attention, + /* OUT */ PROV_HANDLE* phandle +); + +/** + \brief Send provisioning PDUs to the peer. + + \par Description This function is used by the provisioning application to send + the provisioning PDUs to the peer device during the procedure. + + \param [in] phandle Provisioning context to be used. + \param [in] pdu Following PDU types are handled - + PROV_PDU_TYPE_START + PROV_PDU_TYPE_INPUT_CMPLT + PROV_PDU_TYPE_DATA + \param [in] pdata Pointer to the data corresponding to the above PDUs + \param [in] datalen Size of the pdata + + \return API_SUCCESS or Error Code on failure +*/ +API_RESULT MS_prov_send_pdu +( + /* IN */ PROV_HANDLE* phandle, + /* IN */ UCHAR pdu, + /* IN */ void* pdata, + /* IN */ UINT16 datalen +); + +/** + \brief Set the display authval. + + \par Description This function shall be used by the provisioning application + to set the authval being displayed to the user on receiving \ref + PROV_EVT_OOB_DISPLAY event with the respective OOB Action and Size. + + \param [in] phandle Provisioning context to be used. + \param [in] pdata Pointer to the Authval (UINT32 *) or (UCHAR *) + \param [in] datalen Size of the pdata + + \return API_SUCCESS or Error Code on failure +*/ +API_RESULT MS_prov_set_authval +( + /* IN */ PROV_HANDLE* phandle, + /* IN */ void* pdata, + /* IN */ UINT16 datalen +); + +/** + \brief Abort the provisioning procedure + + \par Description + This API can be used by the application to abort the ongoing provisioning + procedure. This routine closes the provisioning link with the reason as + specified. + + \param [in] phandle Provisioning context to be used. + \param [in] reason Reason for termination. + + \return API_SUCCESS or Error Code on failure +*/ +API_RESULT MS_prov_abort +( + PROV_HANDLE* phandle, + UCHAR reason +); + +/** + \brief Utility API to fetch current ECDH Public Key to be used for + Provisioning + + \par Description + This API can be used by the application to fetch the current ECDH P256 + Public Key which is to be used for the Provisioning Procedure. + + \param [out] public_key to a pointer of \ref UCHAR array of length + \ref PROV_PUBKEY_SIZE + + \return API_SUCCESS or Error Code on failure +*/ +API_RESULT MS_prov_get_local_public_key +( + /* OUT */ UCHAR* public_key +); + +#ifdef __cplusplus +}; +#endif + +/** \} */ + +/** \} */ + +#endif /* _H_MS_PROV_API_ */ + diff --git a/src/components/ethermind/mesh/export/include/MS_scene_api.h b/src/components/ethermind/mesh/export/include/MS_scene_api.h new file mode 100644 index 0000000..d2211e6 --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_scene_api.h @@ -0,0 +1,480 @@ +/** + \file MS_scene_api.h + + \brief This file defines the Mesh Scene Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_SCENE_API_ +#define _H_MS_SCENE_API_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_access_api.h" + + +/* --------------------------------------------- Global Definitions */ +/** + \defgroup scene_module SCENE (Mesh Scene Model) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Scene Model (SCENE) module to the Application. +*/ + +/** Scene Event Types */ +/** Scene Event - Store */ +#define MS_SCENE_EVENT_STORE 0x01 + +/** Scene Event - Delete */ +#define MS_SCENE_EVENT_DELETE 0x02 + +/** Scene Event - Recall Start */ +#define MS_SCENE_EVENT_RECALL_START 0x03 + +/** Scene Event - Recall Complete */ +#define MS_SCENE_EVENT_RECALL_COMPLETE 0x04 + +/** Scene Event - Recall Immediate */ +#define MS_SCENE_EVENT_RECALL_IMMEDIATE 0x05 + +/* --------------------------------------------- Data Types/ Structures */ +/** + \defgroup scene_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ + +/** + Scene Server application Asynchronous Notification Callback. + + Scene Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. + + TODO: Update +*/ +typedef void* (* MS_SCENE_SERVER_CB) +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT8 event_type, + void* event_param, + UINT16 event_length, + void* context +) DECL_REENTRANT; + +/** + Scene Client application Asynchronous Notification Callback. + + Scene Client calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param opcode Opcode. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef API_RESULT (* MS_SCENE_CLIENT_CB) +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT32 opcode, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; +/** \} */ + +/** + \defgroup scene_structures Structures + \{ +*/ + +/** + Scene Recall message parameters. +*/ +typedef struct MS_scene_recall_struct +{ + /** The number of the scene to be recalled. */ + UINT16 scene_number; + + /** Transaction Identifier */ + UCHAR tid; + + /** + Transition Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR transition_time; + + /** Message execution delay in 5 milliseconds steps */ + UCHAR delay; + + /** Flag: To represent if optional Transaction time and Delay fields are valid */ + UCHAR optional_fields_present; + +} MS_SCENE_RECALL_STRUCT; + +/** + Scene Status message parameters. +*/ +typedef struct MS_scene_status_struct +{ + /** Status Code */ + UCHAR status_code; + + /** Scene Number of a current scene. */ + UINT16 current_scene; + + /** Scene Number of a target scene. (Optional) */ + UINT16 target_scene; + + /** + Remaining Time is a 1-octet value that consists of two fields: + - a 2-bit bit field representing the step resolution + - a 6-bit bit field representing the number of transition steps. + + Field | Size (bits) | Description + ---------------------------|-------------|---------------- + Transition Number of Steps | 6 | The number of Steps + Transition Step Resolution | 2 | The resolution of the Default Transition + | Number of Steps field + */ + UCHAR remaining_time; + + /** Flag: To represent if optional fields Target Scene and Remaining Time are valid */ + UCHAR optional_fields_present; + +} MS_SCENE_STATUS_STRUCT; + +/** + Scene Register Status message parameters. +*/ +typedef struct MS_scene_register_status_struct +{ + /** Status Code */ + UCHAR status_code; + + /** Scene Number of a current scene */ + UINT16 current_scene; + + /** A list of scenes stored within an element */ + UCHAR* scenes; + + /** Number of Scenes */ + UINT16 scenes_len; + +} MS_SCENE_REGISTER_STATUS_STRUCT; + +/** + Scene Store message parameters. +*/ +typedef struct MS_scene_struct +{ + /** The number of the scene to be stored. */ + UINT16 scene_number; + +} MS_SCENE_STRUCT; + +/** \} */ + + + +/* --------------------------------------------- Function */ +/** + \defgroup scene_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Scene Model APIs. +*/ +/** + \defgroup scene_ser_api_defs Scene Server API Definitions + \{ + This section describes the Scene Server APIs. +*/ + +/** + \brief API to initialize Scene Server model + + \par Description + This is to initialize Scene Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] scene_model_handle + Model identifier associated with the Scene model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in, out] scene_setup_model_handle + Model identifier associated with the Scene Setup model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Scene Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_scene_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* scene_model_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* scene_setup_model_handle, + /* IN */ MS_SCENE_SERVER_CB appl_cb +); + +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_scene_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +); +/** \} */ + +/** + \defgroup scene_cli_api_defs Scene Client API Definitions + \{ + This section describes the Scene Client APIs. +*/ + +/** + \brief API to initialize Scene Client model + + \par Description + This is to initialize Scene Client model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] appl_cb Application Callback to be used by the Scene Client. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_scene_client_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_SCENE_CLIENT_CB appl_cb +); + +/** + \brief API to get Scene client model handle + + \par Description + This is to get the handle of Scene client model. + + \param [out] model_handle Address of model handle to be filled/returned. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_scene_client_get_model_handle +( + /* OUT */ MS_ACCESS_MODEL_HANDLE* model_handle +); + +/** + \brief API to send acknowledged commands + + \par Description + This is to initialize sending acknowledged commands. + + \param [in] req_opcode Request Opcode. + \param [in] param Parameter associated with Request Opcode. + \param [in] rsp_opcode Response Opcode. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_scene_client_send_reliable_pdu +( + /* IN */ UINT32 req_opcode, + /* IN */ void* param, + /* IN */ UINT32 rsp_opcode +); + +/** + \brief API to get the current status of a currently active scene of an element. + + \par Description + Scene Get is an acknowledged message used to get the current status of a currently active scene of an element. + The response to the Scene Get message is a Scene Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_scene_get() \ + MS_scene_client_send_reliable_pdu \ + (\ + MS_ACCESS_SCENE_GET_OPCODE,\ + NULL,\ + MS_ACCESS_SCENE_STATUS_OPCODE\ + ) + +/** + \brief API to ecall the current state of an element. + + \par Description + Scene Recall is an acknowledged message that is used to recall the current state of an element from a previously stored scene. + The response to the Scene Recall message is a Scene Status message. + + \param [in] param Scene Recall message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_scene_recall(param) \ + MS_scene_client_send_reliable_pdu \ + (\ + MS_ACCESS_SCENE_RECALL_OPCODE,\ + param,\ + MS_ACCESS_SCENE_STATUS_OPCODE\ + ) + +/** + \brief API to ecall the current state of an element. + + \par Description + Scene Recall Unacknowledged is an unacknowledged message used to recall the current state of an element from a previously stored Scene. + + \param [in] param Scene Recall message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_scene_recall_unacknowledged(param) \ + MS_scene_client_send_reliable_pdu \ + (\ + MS_ACCESS_SCENE_RECALL_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to get the current status of the Scene Register of an element. + + \par Description + Scene Register Get is an acknowledged message used to get the current status of the Scene Register of an element. + The response to the Scene Register Get message is a Scene Register Status message. + There are no parameters for this message. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_scene_register_get() \ + MS_scene_client_send_reliable_pdu \ + (\ + MS_ACCESS_SCENE_REGISTER_GET_OPCODE,\ + NULL,\ + MS_ACCESS_SCENE_REGISTER_STATUS_OPCODE\ + ) + +/** + \brief API to store the current state of an element as a Scene. + + \par Description + Scene Store is an acknowledged message used to store the current state of an element as a Scene, which can be recalled later. + The response to the Scene Store message is a Scene Register Status message. + + \param [in] param Scene Store message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_scene_store(param) \ + MS_scene_client_send_reliable_pdu \ + (\ + MS_ACCESS_SCENE_STORE_OPCODE,\ + param,\ + MS_ACCESS_SCENE_REGISTER_STATUS_OPCODE\ + ) + +/** + \brief API to store the current state of an element as a Scene. + + \par Description + Scene Store Unacknowledged is an unacknowledged message used to store the current state of an element as a Scene, which can be recalled later. + + \param [in] param Scene Store message + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_scene_store_unacknowledged(param) \ + MS_scene_client_send_reliable_pdu \ + (\ + MS_ACCESS_SCENE_STORE_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) + +/** + \brief API to delete a Scene from the Scene Register state of an element. + + \par Description + Scene Delete is an acknowledged message used to delete a Scene from the Scene Register state of an element. + The response to the Scene Delete message is a Scene Register Status message. + + \param [in] param Scene Delete parameter + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_scene_delete(param) \ + MS_scene_client_send_reliable_pdu \ + (\ + MS_ACCESS_SCENE_DELETE_OPCODE,\ + param,\ + MS_ACCESS_SCENE_REGISTER_STATUS_OPCODE\ + ) + +/** + \brief API to delete a Scene from the Scene Register state of an element. + + \par Description + Scene Delete Unacknowledged is an unacknowledged message used to delete a scene from the Scene Register state of an element. + + \param [in] param Scene Delete parameter + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_scene_delete_unacknowledged(param) \ + MS_scene_client_send_reliable_pdu \ + (\ + MS_ACCESS_SCENE_DELETE_UNACKNOWLEDGED_OPCODE,\ + param,\ + 0xFFFFFFFF\ + ) +/** \} */ +/** \} */ +/** \} */ + +#endif /*_H_MS_SCENE_API_ */ diff --git a/src/components/ethermind/mesh/export/include/MS_trn_api.h b/src/components/ethermind/mesh/export/include/MS_trn_api.h new file mode 100644 index 0000000..9437447 --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_trn_api.h @@ -0,0 +1,1031 @@ + +/** + \file MS_trn_api.h + + \brief This file defines the Mesh Transport Application Interface - includes + Data Structures and Methods. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_TRN_API_ +#define _H_MS_TRN_API_ + +/* --------------------------------------------- Header File Inclusion */ +/* Lower Transport Layer */ +#include "MS_ltrn_api.h" + +extern void blebrr_scan_pl (UCHAR enable); + + + +/* --------------------------------------------- Global Definitions */ + +/** + \defgroup trn_module TRANSPORT (Mesh Transport Layer) + \{ + This section describes the interfaces & APIs offered by the EtherMind + Mesh Transport (TRANSPORT) module to the Application and other upper + layers of the stack. +*/ + +/** + \defgroup trn_defines Defines + \{ + Describes defines for the module. +*/ + +/** + \defgroup trn_constants Constants + \{ + Describes Constants defined by the module. +*/ + +/** + Tranport Layer Control Packet Opcodes + + RFU: 0x02 - 0x0F +*/ + +/** + Sent by a Low Power node to its Friend node to request any messages + that it has cached for the Low Power node +*/ +#define MS_TRN_CTRL_OPCODE_FRND_POLL 0x01 + +/** + Sent by a Friend node to a Low Power node to inform it about cache + and/or security updates +*/ +#define MS_TRN_CTRL_OPCODE_FRND_UPDATE 0x02 + +/** Broadcast by a Low Power node to start to find a friend */ +#define MS_TRN_CTRL_OPCODE_FRND_REQ 0x03 + +/** Sent by a Friend node to a Low Power node to offer to become its friend */ +#define MS_TRN_CTRL_OPCODE_FRND_OFFER 0x04 + +/** + Sent to a Friend node to inform a previous friend of a Low Power node + about the removal of a friendship +*/ +#define MS_TRN_CTRL_OPCODE_FRND_CLEAR 0x05 + +/** + Sent from a previous friend to Friend node to confirm that a prior friend + relationship has been removed +*/ +#define MS_TRN_CTRL_OPCODE_FRND_CLEAR_CNF 0x06 + +/** + Sent to a Friend node to add one or more addresses + to the Friend Subscription List +*/ +#define MS_TRN_CTRL_OPCODE_FRND_SUBSCRN_LIST_ADD 0x07 + +/** + Sent to a Friend node to remove one or more addresses + from the Friend Subscription List +*/ +#define MS_TRN_CTRL_OPCODE_FRND_SUBSCRN_LIST_REMOVE 0x08 + +/** Sent by a Friend node to confirm Friend Subscription List updates */ +#define MS_TRN_CTRL_OPCODE_FRND_SUBSCRN_LIST_CNF 0x09 + +/** Sent by a node to let other nodes determine topology of a Subnet */ +#define MS_TRN_CTRL_OPCODE_HEARTBEAT 0x0A + +/** + Parameter defines for Friendship Opcodes +*/ +/** + Friend Update Flags + + Bit 0: Key Refresh Flag + 0: Not-In-Phase2 + 1: In-Phase2 + + Bit 1: IV Update Flag + 0: Normal operation + 1: IV Update active +*/ +#define MS_FRNDUPD_FLAG_KEYREF_BIT 0 +#define MS_FRNDUPD_FLAG_KEYREF_NOTINPHASE_2 0x00 +#define MS_FRNDUPD_FLAG_KEYREF_INPHASE_2 0x01 + +#define MS_FRNDUPD_FLAG_IVUPDATE_BIT 1 +#define MS_FRNDUPD_FLAG_IVUPDATE_NORMAL 0x00 +#define MS_FRNDUPD_FLAG_IVUPDATE_ACTIVE 0x01 + +/** + Friend Update More Data +*/ +#define MS_FRNDUPD_MD_QUEUE_EMPTY 0x00 +#define MS_FRNDUPD_MD_QUEUE_NOTEMPTY 0x01 + +/** + Friend Request Criteria +*/ +#define MS_FRNDREQ_RSSIFACTOR_OFFSET 5 +#define MS_FRNDREQ_RSSIFACTOR_MASK 0x60 +#define MS_FRNDREQ_RSSIFACTOR_1 0x00 +#define MS_FRNDREQ_RSSIFACTOR_1_5 0x01 +#define MS_FRNDREQ_RSSIFACTOR_2 0x02 +#define MS_FRNDREQ_RSSIFACTOR_2_5 0x03 + +#define MS_FRNDREQ_RCVWINFACTOR_OFFSET 3 +#define MS_FRNDREQ_RCVWINFACTOR_MASK 0x18 +#define MS_FRNDREQ_RCVWINFACTOR_1 0x00 +#define MS_FRNDREQ_RCVWINFACTOR_1_5 0x01 +#define MS_FRNDREQ_RCVWINFACTOR_2 0x02 +#define MS_FRNDREQ_RCVWINFACTOR_2_5 0x03 + +#define MS_FRNDREQ_MINQSIZELOG_OFFSET 0 +#define MS_FRNDREQ_MINQSIZELOG_MASK 0x07 +#define MS_FRNDREQ_MINQSIZE_INVALID 0x00 +#define MS_FRNDREQ_MINQSIZE_2 0x01 +#define MS_FRNDREQ_MINQSIZE_4 0x02 +#define MS_FRNDREQ_MINQSIZE_8 0x03 +#define MS_FRNDREQ_MINQSIZE_16 0x04 +#define MS_FRNDREQ_MINQSIZE_32 0x05 +#define MS_FRNDREQ_MINQSIZE_64 0x06 +#define MS_FRNDREQ_MINQSIZE_128 0x07 + +/** + Heartbeat features +*/ +#define MS_HEARTBEAT_FEATURE_RELAY (1 << 0) +#define MS_HEARTBEAT_FEATURE_PROXY (1 << 1) +#define MS_HEARTBEAT_FEATURE_FRIEND (1 << 2) +#define MS_HEARTBEAT_FEATURE_LOWPOWER (1 << 3) + +/** Friendship constants as defined in the specification */ +#define MS_MIN_FRNDOFFER_DELAY 100 /* ms */ +#define MS_TRN_INITIAL_FRNDPOLL_TIMEOUT 1000 /* ms */ + +/** \} */ + +/** + \defgroup trn_events Events + \{ + This section lists the Asynchronous Events notified to Application by the + Module. +*/ +#define MS_TRN_FRIEND_SETUP_CNF 0x00 +#define MS_TRN_FRIEND_SUBSCRNLIST_CNF 0x01 +#define MS_TRN_FRIEND_CLEAR_CNF 0x02 +#define MS_TRN_FRIEND_TERMINATE_IND 0x03 + +/** \} */ +/** \} */ + +/** + \defgroup trn_marcos Utility Macros + \{ + Initialization and other Utility Macros offered by the module. +*/ + +/** \} */ + +/* --------------------------------------------- Data Types/ Structures */ + +/** + \addtogroup trn_defines Defines + \{ +*/ + +/** + \addtogroup trn_structures Structures + \{ +*/ + +/** \} */ + +/** \} */ + +typedef API_RESULT (*TRN_HEARTBEAT_RCV_CB) +( + MS_NET_ADDR addr, + MS_SUBNET_HANDLE subnet_handle, + UINT8 countlog +) DECL_REENTRANT; + +typedef API_RESULT (*TRN_HEARTBEAT_RCV_TIMEOUT_CB) +( + void +) DECL_REENTRANT; + + + +/** + \defgroup trn_cb Application Callback + \{ + This Section Describes the module Notification Callback interface offered + to the application +*/ +/** + TRANSPORT Application Asynchronous Notification Callback. + + TRANSPORT calls the registered callback to indicate events occurred to the + application. + + \param brr_type Bearer Type. + \param net_hdr Network Header. + \param subnet_handle Associated Subnet Handle. + \param appkey_handle Associated AppKey Handle. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +typedef void (*TRN_NTF_CB) +( + MS_NET_HEADER* net_hdr, + MS_SUBNET_HANDLE subnet_handle, + MS_APPKEY_HANDLE appkey_handle, + UCHAR* data_param, + UINT16 data_len +) DECL_REENTRANT; + +/** + TRANSPORT Application Friendship Asynchronous Notification Callback. + + TRANSPORT calls the registered callback to indicate the status of froednship + setup procedure to the application + + \param subnet_handle Associated Subnet Handle. + \param event_type Friendship event. \ref trn_events + \param status Result of the procedure. +*/ +typedef void (*TRN_FRND_CB) +( + MS_SUBNET_HANDLE subnet_handle, + UCHAR event_type, + UINT16 status +) DECL_REENTRANT; + +/** \} */ + +/** + \addtogroup trn_defines Defines + \{ +*/ + +/** + \addtogroup trn_structures Structures + \{ +*/ +/** Transport Control Packet Opcode Type */ +typedef UCHAR MS_TRN_CTRL_PKT_OPCODE; + +/** Friend Data Structure */ +typedef struct _MS_TRN_FRIEND_ENTRY +{ + /** Friend Seqnece Number - 7 bit value */ + UINT8 fsn; + + /** Low Power Node Address */ + MS_NET_ADDR addr; + + /** Number of Elements in LPN */ + UINT8 num_elements; + + /** Previous Friend Address */ + MS_NET_ADDR prev_faddr; + + /** Friend Queue */ + /* UINT32 q; */ + + /** Subscription List of LPN */ + /* UINT32 subscription_list; */ + +} MS_TRN_FRIEND_ENTRY; + +/** Transport Friend Poll Message */ +typedef struct _MS_TRN_FRND_POLL_PARAM +{ + /** + Friend Sequence Number used to acknowledge receipt of + previous messages from the Friend node to the Low Power node. + */ + UINT8 fsn; + +} MS_TRN_FRND_POLL_PARAM; + +/** Transport Friend Update Message */ +typedef struct _MS_TRN_FRND_UPDATE_PARAM +{ + /** Contains the IV Update Flag and the Key Refresh Flag */ + UINT8 flags; + + /** The current IV Index value known by the Friend node */ + UINT32 ivi; + + /** + Availability of data in friend queue + + Value | Description + ------|------------ + 0 | Friend Queue is empty + 1 | Friend Queue is not empty + */ + UCHAR md; + +} MS_TRN_FRND_UPDATE_PARAM; + +/** Transport Friend Request Message */ +typedef struct _MS_TRN_FRND_REQ_PARAM +{ + /** + The criteria that a Friend node should support + in order to participate in friendship negotiation + */ + UCHAR criteria; + + /** Receive delay requested by the Low Power node */ + UCHAR rx_delay; + + /** Poll timeout requested by the Low Power node */ + UINT32 poll_to; + + /** Previous Friend's unicast address */ + UINT16 prev_addr; + + /** Number of Elements in the Low Power node */ + UCHAR num_elem; + + /** Number of Friend Request messages that the Low Power node has sent */ + UINT16 lpn_counter; + +} MS_TRN_FRND_REQ_PARAM; + +/** Transport Friend Offer Message */ +typedef struct _MS_TRN_FRND_OFFER_PARAM +{ + /** Receive Window value supported by the Friend node */ + UINT8 rx_window; + + /** Queue Size available on the Friend node */ + UINT8 queue_size; + + /** + Size of the Subscription List that can be supported + by a Friend node for a Low Power node + */ + UINT8 sublist_size; + + /** RSSI measured by the Friend node */ + UINT8 rssi; + + /** Number of Friend Offer messages that the Friend node has sent */ + UINT16 frnd_counter; + +} MS_TRN_FRND_OFFER_PARAM; + +/** Transport Friend Clear Message */ +typedef struct _MS_TRN_FRND_CLEAR_PARAM +{ + /** The unicast address of the Low Power node being removed */ + UINT16 lpn_addr; + + /** Value of the LPNCounter of new relationship */ + UINT16 lpn_counter; + +} MS_TRN_FRND_CLEAR_PARAM; + +/** Transport Friend Clear Confirm Message */ +typedef struct _MS_TRN_FRND_CLEAR_CNF_PARAM +{ + /** The unicast address of the Low Power node being removed */ + UINT16 lpn_addr; + + /** Value of the LPNCounter of corresponding Friend Clear message */ + UINT16 lpn_counter; + +} MS_TRN_FRND_CLEAR_CNF_PARAM; + +/** Transport Friend Subscription List Add/Remove Message */ +typedef struct _MS_TRN_FRND_MANAGE_PARAM +{ + /** The number for identifying a transaction */ + UINT8 txn_num; + + /** + List of group addresses and virtual addresses where N is + the number of group addresses and virtual addresses in this message. + + Address octet stream packed in big-endian format. + */ + void* addr_list; + + /** + Number of Addresses in the list + + Note: Number of addresses is half of the octets in the addr_list field. + */ + UINT16 num_addr; + + /** Opcode - Add/Delete */ + UINT8 opcode; + +} MS_TRN_FRND_MANAGE_PARAM; + +/** Transport Friend Subscription List Confirm Message */ +typedef struct _MS_TRN_FRND_SUBSCRN_LIST_CNF_PARAM +{ + /** The number for identifying a transaction */ + UINT8 txn_num; + +} MS_TRN_FRND_SUBSCRN_LIST_CNF_PARAM; + +/** Transport Heartbeat Message */ +typedef struct _MS_TRN_HEARTBEAT_PARAM +{ + /** Initial TTL used when sending the message */ + UINT8 init_ttl; + + /** Bit field of currently active features of the node */ + UINT16 features; + +} MS_TRN_HEARTBEAT_PARAM; + +/** Low Power Node element information */ +typedef struct _MS_TRN_FRNDSHIP_INFO +{ + /* Main subnet handle of the element */ + MS_SUBNET_HANDLE subnet_handle; + + /* Peer LPN/Friend Address */ + MS_NET_ADDR addr; + + /* Low Power Node Counter */ + UINT16 lpn_counter; + + /* Friend Counter - TODO: Should be a global index? */ + UINT16 frnd_counter; + +} MS_TRN_FRNDSHIP_INFO; + +/* Invalid LPN Handle */ +#define LPN_HANDLE_INVALID MS_CONFIG_LIMITS(MS_MAX_LPNS) + +/** Hearbeat Publication state */ +typedef struct _MS_TRN_HEARTBEAT_PUBLICATION_INFO +{ + /** + Destination address for Heartbeat messages + */ + MS_NET_ADDR daddr; + + /** + Count to control the number of periodic heartbeat + transport messages to be sent + */ + UINT8 count_log; + + /** + Period to control the cadence of periodic heartbeat + transport messages + */ + UINT8 period_log; + + /** + TTL value to be used when sending Heartbeat messages + */ + UINT8 ttl; + + /** + Features that trigger sending Heartbeat messages when changed + */ + UINT16 features; + + /** + Global NetKey index of the NetKey to be used to send Heartbeat messges + */ + UINT16 netkey_index; + +} MS_TRN_HEARTBEAT_PUBLICATION_INFO; + +/** Hearbeat Subscription state */ +typedef struct _MS_TRN_HEARTBEAT_SUBSCRIPTION_INFO +{ + /** + Source address for Heartbeat messages that a node shall process + */ + MS_NET_ADDR saddr; + + /** + Destination address for Heartbeat messages + */ + MS_NET_ADDR daddr; + + /** + Counter that tracks the number of periodic heartbeat transport message + received since receiving the most recent Config Heartbeat Subscription + Set message + */ + UINT8 count_log; + + /** + Period that controls the period for processing periodical Heartbeat + transport control messages + */ + UINT8 period_log; + + /** + Minimum hops value registered when receiving heartbeat messages since + receiving the most recent Config Heartbeat Subscription Set message + */ + UINT16 min_hops; + + /** + Maximum hops value registered when receiving heartbeat messages since + receiving the most recent Config Heartbeat Subscription Set message + */ + UINT16 max_hops; + +} MS_TRN_HEARTBEAT_SUBSCRIPTION_INFO; + +/** \} */ + +/** \} */ + +/** TCF (Transport Control Field) - Transport Field Value */ + + +/* --------------------------------------------- Function */ + +/** + \defgroup trn_api_defs API Definitions + \{ + This section describes the EtherMind Mesh Transport Layer APIs. +*/ +#ifdef __cplusplus +extern "C" { +#endif + +/** + \brief Register Inerface with Transport Layer + + \par Description + This routine registers interface with the Transport Layer. + Transport Layer supports single Application, hence this rouine shall be called once. + + \param [in] trn_cb + Upper Layer Notification Callback for specific message type + + \param [in] msg_type + Message type (Control or Access) for which the callback to be called. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_trn_register +( + /* IN */ TRN_NTF_CB trn_cb, + /* IN */ MS_TRN_MSG_TYPE msg_type +); + +API_RESULT MS_trn_heartbeat_register +( + /* IN */ TRN_HEARTBEAT_RCV_CB rcv_cb, + /* IN */ TRN_HEARTBEAT_RCV_TIMEOUT_CB rcv_to_cb +); + + + +/** + \brief API to send Access Layer PDUs + + \par Description + This routine sends Access Layer PDUs to peer device. + + \param [in] src_addr + Source Address + + \param [in] dst_addr + Destination Address + + \param [in] label + Lable UUID, represending Virtual Address of Destination + + \param [in] subnet_handle + Handle identifying the Subnet + + \param [in] appkey_handle + Handle identifying the AppKey to be used for Transport Layer encryption. + + \param [in] ttl + Time to Live + + \param [in] param + Transport parameter, based on the type and header + + \param [in] reliable + If requires lower transport Ack, set reliable as TRUE + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_trn_send_access_pdu +( + /* IN */ MS_NET_ADDR src_addr, + /* IN */ MS_NET_ADDR dst_addr, + /* IN */ UINT8* label, + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ MS_APPKEY_HANDLE appkey_handle, + /* IN */ UINT8 ttl, + /* IN */ void* param, + /* IN */ UINT8 reliable +); + +/** + \brief API to send transport Control PDUs + + \par Description + This routine sends transport Control PDUs to peer device. + + \param [in] src_addr + Source Address + + \param [in] dst_addr + Destination Address + + \param [in] subnet_handle + Handle identifying the Subnet + + \param [in] ttl + Time to Live + + \param [in] ctrl_opcode + Control Packet Opcode. + + \param [in] param + Transport parameter, based on the type and header + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_trn_send_control_pdu +( + /* IN */ MS_NET_ADDR src_addr, + /* IN */ MS_NET_ADDR dst_addr, + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ UINT8 ttl, + /* IN */ MS_TRN_CTRL_PKT_OPCODE ctrl_opcode, + /* IN */ void* param +); + + +/** + \brief API to setup Friendship. + + \par Description + This routine is used by the device acting as a low power node + to setup a friendship procedure to any available friend nodes. + + \param [in] subnet_handle + The subnet to initiate the friendship procedure. + + \param [in] criteria + Friend criteria that is required. RSSI, Receive Window, + MessageQueue size requirements can be established. + + \param [in] rx_delay + Receive delay in milliseconds that the LPN will wait before + listening to response for any request. + + \param [in] poll_timeout + Timeout in milliseconds after which the LPN will send Poll PDU + to check for data from the friend. + + \param [in] setup_timeout + Timeout in milliseconds for which the Friend Establishment + procedure is to be tried. + + \param [in] cb + Application Callback to notify the result of friendship procedures. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_trn_lpn_setup_friendship +( + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ UCHAR criteria, + /* IN */ UCHAR rx_delay, + /* IN */ UINT32 poll_timeout, + /* IN */ UINT32 setup_timeout, + /* IN */ TRN_FRND_CB cb +); + + +/** + \brief API to terminate friendship. + + \par Description + This routine is used by the device acting as a low power node + terminate friendship with an active Friend node. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_trn_lpn_clear_friendship(void); + + +/** + \brief API to manage friend subscription list. + + \par Description + This routine is used by the device acting as a low power node + add/remove addresses to/from the friends subscription list. + + \param [in] action + Will be one of MS_TRN_CTRL_OPCODE_FRND_SUBSCRN_LIST_ADD or + MS_TRN_CTRL_OPCODE_FRND_SUBSCRN_LIST_REMOVE + + \param [in] addr_list + Pointer to the packed list of addresses to be managed. + + \param [in] count + Number of addresses given. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_trn_lpn_manage_subscription +( + UCHAR action, + UINT16* addr_list, + UINT16 count +); + + +/** + \brief API to add to friend subscription list. + + \par Description + This routine is used by the device acting as a low power node + add addresses to the friends subscription list. + + \param [in] addr_list + Pointer to the list of addresses to be managed. + + \param [in] count + Number of addresses given. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_trn_lpn_subscrn_list_add(addr_list, count)\ + MS_trn_lpn_manage_subscription\ + (\ + MS_TRN_CTRL_OPCODE_FRND_SUBSCRN_LIST_ADD,\ + (addr_list),\ + (count)\ + ); + + +/** + \brief API to remove from friend subscription list. + + \par Description + This routine is used by the device acting as a low power node + remove addresses from the friends subscription list. + + \param [in] addr_list + Pointer to the list of addresses to be managed. + + \param [in] count + Number of addresses given. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +#define MS_trn_lpn_subscrn_list_remove(addr_list, count)\ + MS_trn_lpn_manage_subscription\ + (\ + MS_TRN_CTRL_OPCODE_FRND_SUBSCRN_LIST_REMOVE,\ + (addr_list),\ + (count)\ + ); + +/** + \brief To check if address matches with any of the LPN + + \par Description + This routine checks if destination address in a received packet matches + with any of the known element address of LPN. + + \param [in] addr Unicast Address to search + \param [out] lpn_handle LPN Handle on match + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_trn_is_valid_lpn_element_address +( + /* IN */ MS_NET_ADDR addr, + /* OUT */ LPN_HANDLE* lpn_handle +); + +/** + \brief To check if valid subscription address of an LPN to receive a packet + + \par Description + This routine checks if destination address in a received packet matches + with any of the known subscription address of an LPN. + + \param [in] addr Address to search + \param [out] lpn_handle Pointer to an LPN Handle, which will be filled + if match found + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_trn_is_valid_lpn_subscription_address +( + /* IN */ MS_NET_ADDR addr, + /* OUT */ LPN_HANDLE* lpn_handle +); + +/** + \brief To check if valid uicast address of an LPN to receive a packet + + \par Description + This routine checks if destination address in a received packet matches + with any of the known subscription address of an LPN. + + \param [in] addr Address to search + \param [in] lpn_handle An LPN Handle, which will be filled + if match found + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_trn_is_valid_lpn_uincast_address +( + /* IN */ MS_NET_ADDR addr, + /* IN */ LPN_HANDLE lpn_handle +); + +/** + \brief To get Poll Timeout of an LPN + + \par Description + This routine checks if LPN address is valid and then returns + Poll Timeout configured for the LPN. + + \param [in] lpn_addr LPN Address to search + \param [out] poll_timeout Memory where poll timeout of the LPN to be filled + (if match found) + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_trn_get_lpn_polltimeout +( + /* IN */ MS_NET_ADDR lpn_addr, + /* OUT */ UINT32* poll_timeout +); + +/** + \brief To get the LPN node information + + \par Description + This routine fetches the node information of the LPN element at the + given index + + \param [in] role Local friendship role + \param [in] lpn_index Index of the LPN element + \param [out] node Pointer to copy the information + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_trn_get_frndship_info +( + UINT8 role, + UINT16 lpn_index, + MS_TRN_FRNDSHIP_INFO* node +); + +/** + \brief To add the security update information + + \par Description + This routine updates the security state of the network to all the active + LPN elements. This will be forwarded to the elements when it polls for the + next packet available. + + \param [in] subnet_handle Handle to identitfy the network. + \param [in] flag Flag indicating the Key Refresh and IV Update state. + \param [in] ivindex Current IV Index of teh network. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_trn_lpn_register_security_update +( + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ UCHAR flag, + /* IN */ UINT32 ivindex +); + +/** + \brief To clear information related to all LPNs + + \par Description + This routine clears information related to all LPNs. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_trn_clear_all_lpn +( + void +); + +/** + \brief To set the Heartbeat publication data + + \par Description + This routine configures the Heartbeat publication information + + \param [out] info Heartbeat Publication information data as + in \ref MS_TRN_HEARTBEAT_PUBLICATION_INFO + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_trn_set_heartbeat_publication +( + /* INOUT */ MS_TRN_HEARTBEAT_PUBLICATION_INFO* info +); + +/** + \brief To get the Heartbeat publication data + + \par Description + This routine retrieves the Heartbeat publication information + + \param [out] info Heartbeat Publication information data as + in \ref MS_TRN_HEARTBEAT_PUBLICATION_INFO + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_trn_get_heartbeat_publication +( + /* OUT */ MS_TRN_HEARTBEAT_PUBLICATION_INFO* info +); + + +/** + \brief To set the Heartbeat subscription data + + \par Description + This routine configures the Heartbeat subscription information + + \param [in, out] info Heartbeat Subscription information data as + in \ref MS_TRN_HEARTBEAT_SUBSCRIPTION_INFO + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_trn_set_heartbeat_subscription +( + /* INOUT */ MS_TRN_HEARTBEAT_SUBSCRIPTION_INFO* info +); + +/** + \brief To get the Heartbeat subscription data + + \par Description + This routine retrieves the Heartbeat subscription information + + \param [out] info Heartbeat Subscription information data as + in \ref MS_TRN_HEARTBEAT_SUBSCRIPTION_INFO + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_trn_get_heartbeat_subscription +( + /* OUT */ MS_TRN_HEARTBEAT_SUBSCRIPTION_INFO* info +); + +/** + \brief To trigger Heartbeat send on change in feature + + \par Description + This routine triggers the Heartbeat send on change in state of supported + features. + + \param [in] change_in_feature_bit Bit mask of the changed feature field + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_trn_trigger_heartbeat (/* IN */ UINT8 change_in_feature_bit); + +void trn_stop_heartbeat_pub_timer(void); + +void trn_start_heartbeat_sub_timer(/* IN */ UINT32 timeout); + +void trn_stop_heartbeat_sub_timer(void); + +void trn_heartbeat_timer_restart(void); + + +#ifdef __cplusplus +}; +#endif + +/** \} */ + +/** \} */ + +#endif /* _H_MS_TRN_API_ */ + diff --git a/src/components/ethermind/mesh/export/include/MS_version.h b/src/components/ethermind/mesh/export/include/MS_version.h new file mode 100644 index 0000000..68ba1e7 --- /dev/null +++ b/src/components/ethermind/mesh/export/include/MS_version.h @@ -0,0 +1,112 @@ + +/** + \file MS_version.h + + This EtherMind Header File containing version number of the stack. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_VERSION_ +#define _H_MS_VERSION_ + +/* -------------------------------------------- Header File Inclusion */ +#include "MS_common.h" + +/* -------------------------------------------- Global Definitions */ + +/** + An increment in the major number of the stack implies a large update to + the stack. Such an update could occur due to multiple factors, including + changes to stack to adhere to new version of the specification or + support for new device specializations or in extreme cases a design + overhaul to address future needs. + + An update in the major number would signify an update to the application + interface offered by the stack. Update need not necessarily imply a + change in existing interface, it could be additional APIs or events. + When an increment in major number occurs, minor & sub-minor numbers + are reset to zero. In event of minor number reaching 255, the max + permissible number, a change resulting in increment in minor version + number will result in increment in major number. +*/ +#define MS_MAJOR_VERSION_NUMBER 1 + +/** + An increment in the minor number of the stack implies an update to fix + an observed defect or changes resulting from optimzations performed on the + stack or enhancement to accommodate addendums to specifications. Minor + utility functions added may also result in increase in this number, however + none of these changes are categorized as causing an increment in minor + number, cause any change in existing interface. It is possible that an + existing functionality is required to be conditionally included; hence + feature flag may be introduced to enable or disable inclusion of the + functionality. Such a change would be categorized under a change resulting + in increment in minor number. + When an increment in minor number occurs, sub-minor number is reset + to zero. In event of sub-minor number reaching 255, the max permissible + number, a change resulting in increment in sub-minor number will result in + increment in minor number. +*/ +#define MS_MINOR_VERSION_NUMBER 2 + +/** + An increment in this number implies a trivial change, changes such as + update in debug log, updating comments, macros, conditions renaming, + internal function/variable names etc are viewed as changes that result in + increment in this number. +*/ +#define MS_SUB_MINOR_VERSION_NUMBER 0 + +/* -------------------------------------------- Macros */ + +/* -------------------------------------------- Structures/Data Types */ + +/** Version Number Structure */ +typedef struct _MS_VERSION_NUMBER +{ + /** Major Version Number */ + UCHAR major; + + /** Minor Version Number */ + UCHAR minor; + + /** Sub-minor Version Number */ + UCHAR subminor; + +} MS_VERSION_NUMBER; + +/* -------------------------------------------- Function/API Declarations */ +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef MS_SUPPORT_STACK_VERSION_INFO +/** + \brief Routine to get Stack Version Number + + \par Description + Routine to get the version number of the stack as return value. + The version number consists of 3 fields: + Major Number + Minor Number + Sub-minor Number + + \param [out] version_number + Pointer to \ref MS_VERSION_NUMBER structure to be filled. +*/ +void MS_get_version_number +( + /* OUT */ MS_VERSION_NUMBER* version_number +); +#endif /* MS_SUPPORT_STACK_VERSION_INFO */ + +#ifdef __cplusplus +}; +#endif + +#endif /* _H_MS_VERSION_ */ + diff --git a/src/components/ethermind/mesh/export/include/access_extern.h b/src/components/ethermind/mesh/export/include/access_extern.h new file mode 100644 index 0000000..77e0b8b --- /dev/null +++ b/src/components/ethermind/mesh/export/include/access_extern.h @@ -0,0 +1,108 @@ + +/** + \file access_extern.h + +*/ + +/* + Copyright (C) 2016. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_ACCESS_EXTERN_ +#define _H_ACCESS_EXTERN_ + +#include "MS_access_api.h" + +/* --------------------------------------------- Data Types/ Structures */ + +/** Current IV Index and Update State */ +typedef struct _MS_ACCESS_IV_INDEX +{ + /** Current IV Index */ + UINT32 iv_index; + + /** Current IV Update State */ + UINT8 iv_update_state; + + /** IV Update time expire */ + UINT32 iv_expire_time; + +} MS_ACCESS_IV_INDEX; + + +/* --------------------------------------------- Global Definitions */ +#define NVS_FLASH_BASE1 0x39000 +#define NVS_FLASH_BASE2 0x3a000 + +/* --------------------------------------------- External Global Definitions */ +/** + Current IV Index and associated update state +*/ +extern MS_ACCESS_IV_INDEX ms_iv_index; + +extern UINT8 access_default_ttl; + +/** Start unicast Address */ +extern MS_NET_ADDR ms_start_unicast_addr; + +/** Stop unicast Address */ +extern MS_NET_ADDR ms_stop_unicast_addr; + + +extern UINT8 ms_ps_store_disable_flag; +extern MS_NET_ADDR ms_provisioner_addr; + +extern UINT8 rx_test_ttl; +extern UINT8 vendor_tid; + + + + +/* Macro to get default TTL primary unicast address */ +#define ACCESS_CM_GET_DEFAULT_TTL(ttl) \ + (ttl) = access_default_ttl + +/* Macro to get rx TTL primary unicast address */ +#define ACCESS_CM_GET_RX_TTL(ttl) \ + (ttl) = rx_test_ttl + + +API_RESULT MS_access_raw_data +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ MS_NET_ADDR dst_addr, + /* IN */ MS_APPKEY_HANDLE appKeyHandle, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len, + /* IN */ UINT8 reliable +); + +/** Get Publish Address */ +API_RESULT MS_access_get_publish_addr +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ MS_NET_ADDR* publish_addr +); + + +/** Publish */ +API_RESULT MS_access_publish_ex +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ UINT32 opcode, + /* IN */ MS_NET_ADDR dst_addr, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len, + /* IN */ UINT8 reliable +); + +/** Store all record */ +void MS_access_ps_store_all_record(void); + +API_RESULT MS_access_ps_store_disable(UINT8 enable); + +API_RESULT MS_access_ps_crc_check(void); +#endif /* _H_ACCESS_EXTERN_ */ + diff --git a/src/components/ethermind/mesh/export/include/fsm_defines.h b/src/components/ethermind/mesh/export/include/fsm_defines.h new file mode 100644 index 0000000..110a4b6 --- /dev/null +++ b/src/components/ethermind/mesh/export/include/fsm_defines.h @@ -0,0 +1,107 @@ + +/** + \file fsm_defines.h + + This file defines state and events related to FSM. +*/ + +/* + Copyright (C) 2013. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_FSM_DEFINES_ +#define _H_FSM_DEFINES_ + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_common.h" + +/* --------------------------------------------- Global Definitions */ +#define FSM_MAX_MODULES 2 + +/* --------------------------------------------- Structures/Data Types */ + +typedef UINT32 STATE_T; + +typedef UCHAR EVENT_T; + +typedef API_RESULT (*SE_HNDLR_T)(void*); + +typedef API_RESULT RETVAL_T; + +typedef struct +{ + STATE_T set_bits; +} FSM_STATE_MASK; + +typedef struct +{ + RETVAL_T handler_retval; + FSM_STATE_MASK next_state; + +} RETVAL_TABLE_T; + +/* + Event Handler Table. + Current State, handler(if any), num_of_retval, retval_table_start_index, + num_of_substates handles this event, + start_index_of_those_handler_in_this_same_table +*/ + +typedef struct +{ + STATE_T current_state; + SE_HNDLR_T handler; + +} EVENT_HANDLER_TABLE_T; + +#define EVENT_HANDLER_TABLE EVENT_HANDLER_TABLE_T + +/* State-Event Table. + Event, Default Handler, num_of_retval, retval_table_start_index, + num_of_substates handles this event, + start_index_of_those_handler_in_this_same_table +*/ +typedef struct +{ + EVENT_T event; + UINT32 event_handler_table_end_index; + UINT32 event_handler_table_start_index; + +} STATE_EVENT_TABLE_T; + +#define STATE_EVENT_TABLE STATE_EVENT_TABLE_T + +/* State identifier */ +typedef struct +{ + STATE_T state; +} STATE_TABLE_T; + +typedef void (*FSM_STATE_CHANGE_HANDLER)(void* param, STATE_T state) DECL_REENTRANT; + +typedef API_RESULT (*FSM_STATE_ACCESS_HANDLER)(void* param, STATE_T* state) DECL_REENTRANT; + +typedef UCHAR FSM_STATE_SIZE_T; + +typedef struct fsm_module_t +{ + /* Function to Access State of Module */ + FSM_STATE_ACCESS_HANDLER state_access_handler; + + /* State Change Function Registered with FSM */ + FSM_STATE_CHANGE_HANDLER state_change_handler; + + /* Event Handler Table */ + DECL_CONST EVENT_HANDLER_TABLE* event_table; + + /* State Event Table */ + DECL_CONST STATE_EVENT_TABLE* state_event_table; + + /* State Event Table Size */ + FSM_STATE_SIZE_T state_event_table_size; + +} FSM_MODULE_TABLE_T; + +#endif /* _H_FSM_DEFINES_ */ + diff --git a/src/components/ethermind/mesh/export/include/fsm_engine.h b/src/components/ethermind/mesh/export/include/fsm_engine.h new file mode 100644 index 0000000..d986cc7 --- /dev/null +++ b/src/components/ethermind/mesh/export/include/fsm_engine.h @@ -0,0 +1,72 @@ + +/** + \file fsm_engine.h + + This file defines interface offered by the FSM module. +*/ + +/* + Copyright (C) 2013. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_FSM_ENGINE_ +#define _H_FSM_ENGINE_ + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_common.h" +#include "fsm_defines.h" + + +#ifndef FSM_NO_DEBUG + #ifdef VAR_ARG_IN_MACRO_NOT_SUPPORTED + #define FSM_ERR + #else + #define FSM_ERR(...) EM_debug_error(MS_MODULE_ID_FSM,__VA_ARGS__) + #endif /* VAR_ARG_IN_MACRO_NOT_SUPPORTED */ +#else /* FSM_NO_DEBUG */ + #define FSM_ERR EM_debug_null +#endif /* FSM_NO_DEBUG */ + +#ifdef FSM_DEBUG + + #define FSM_TRC(...) EM_debug_trace(BT_MODULE_ID_FSM,__VA_ARGS__) + #define FSM_INF(...) EM_debug_info(BT_MODULE_ID_FSM,__VA_ARGS__) + +#else /* FSM_DEBUG */ + #ifdef VAR_ARG_IN_MACRO_NOT_SUPPORTED + #define FSM_TRC + #define FSM_INF + #else + #define FSM_TRC EM_debug_null + #define FSM_INF EM_debug_null + #endif /* VAR_ARG_IN_MACRO_NOT_SUPPORTED */ + +#endif /* FSM_DEBUG */ + +/* --------------------------------------------- Functions */ +#ifdef __cplusplus +extern "C" { +#endif + +void ms_fsm_init (void); + +API_RESULT ms_fsm_register_module +( + /* IN */ DECL_CONST FSM_MODULE_TABLE_T* module_fsm, + /* OUT */ UCHAR* fsm_id +); + +API_RESULT ms_fsm_post_event +( + UCHAR fsm_id, + EVENT_T fsm_event, + void* param +); + +#ifdef __cplusplus +}; +#endif + +#endif /* _H_FSM_ENGINE_ */ + diff --git a/src/components/ethermind/mesh/export/include/ltrn_extern.h b/src/components/ethermind/mesh/export/include/ltrn_extern.h new file mode 100644 index 0000000..f8d1515 --- /dev/null +++ b/src/components/ethermind/mesh/export/include/ltrn_extern.h @@ -0,0 +1,37 @@ + +/** + \file ltrn_extern.h + +*/ + +/* + Copyright (C) 2016. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_LTRN_EXTERN_ +#define _H_LTRN_EXTERN_ + +/* --------------------------------------------- External Global Definitions */ +/* Module Mutex */ +MS_DEFINE_MUTEX_TYPE(extern, ltrn_mutex) + +/* Module callback pointer */ +extern LTRN_NTF_CB ltrn_callback; + + + +API_RESULT ltrn_delete_from_reassembled_cache +( + /* IN */ MS_NET_ADDR addr +); + +API_RESULT ltrn_delete_from_replay_cache +( + /* IN */ MS_NET_ADDR addr +); + + + +#endif /* _H_LTRN_EXTERN_ */ + diff --git a/src/components/ethermind/mesh/export/include/net_extern.h b/src/components/ethermind/mesh/export/include/net_extern.h new file mode 100644 index 0000000..605f5e8 --- /dev/null +++ b/src/components/ethermind/mesh/export/include/net_extern.h @@ -0,0 +1,49 @@ + +/** + \file net_extern.h + +*/ + +/* + Copyright (C) 2016. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_NET_EXTERN_ +#define _H_NET_EXTERN_ + +#include "MS_net_api.h" + + +/* --------------------------------------------- External Global Definitions */ +/* Module Mutex */ +MS_DEFINE_MUTEX_TYPE(extern, net_mutex) + +/* Module callback pointer */ +extern NET_NTF_CB net_callback; + +/* Network Sequence Number */ +extern NET_SEQ_NUMBER_STATE net_seq_number_state; + +extern UINT8 seq_num_init_flag; +extern UINT32 g_iv_update_index; +extern UINT8 g_iv_update_state; +extern UINT8 g_iv_update_start_timer; +extern UINT8 MS_key_refresh_active; + +extern UINT16 ms_proxy_filter_addr[5]; + +/* Network Cache */ +//MS_DECLARE_GLOBAL_ARRAY(NET_CACHE_ELEMENT, net_cache, MS_CONFIG_LIMITS(MS_NET_CACHE_SIZE)); + +//extern UINT16 net_cache_start; +//extern UINT16 net_cache_size; + +API_RESULT net_delete_from_cache +( + /* IN */ MS_NET_ADDR addr +); + + +#endif /* _H_NET_EXTERN_ */ + diff --git a/src/components/ethermind/mesh/export/include/net_internal.h b/src/components/ethermind/mesh/export/include/net_internal.h new file mode 100644 index 0000000..8fac33b --- /dev/null +++ b/src/components/ethermind/mesh/export/include/net_internal.h @@ -0,0 +1,568 @@ + +/** + \file net_internal.h + + Module Internal Header File contains structure definitions including tables + maintained by the module +*/ + +/* + Copyright (C) 2016. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_NET_INTERNAL_ +#define _H_NET_INTERNAL_ + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_common.h" +#include "MS_net_api.h" +#include "MS_brr_api.h" + +/* --------------------------------------------- Global Definitions */ + +#ifdef NET_NO_DEBUG + #define NET_ERR EM_debug_null +#else /* NET_NO_DEBUG */ + #ifdef VAR_ARG_IN_MACRO_NOT_SUPPORTED + #define NET_ERR + #else + #define NET_ERR(...) EM_debug_error(MS_MODULE_ID_NET, __VA_ARGS__) + #endif /* VAR_ARG_IN_MACRO_NOT_SUPPORTED */ +#endif /* NET_NO_DEBUG */ + +#ifdef NET_DEBUG + #ifdef VAR_ARG_IN_MACRO_NOT_SUPPORTED + #define NET_TRC + #define NET_INF + + #define NET_debug_dump_bytes(data, datalen) + + #else + #define NET_TRC(...) EM_debug_trace(MS_MODULE_ID_NET,__VA_ARGS__) + #define NET_INF(...) EM_debug_info(MS_MODULE_ID_NET,__VA_ARGS__) + + #define NET_debug_dump_bytes(data, datalen) EM_debug_dump_bytes(MS_MODULE_ID_NET, (data), (datalen)) + + #endif /* VAR_ARG_IN_MACRO_NOT_SUPPORTED */ +#else /* NET_DEBUG */ + #define NET_TRC EM_debug_null + #define NET_INF EM_debug_null + + #define NET_debug_dump_bytes(data, datalen) + +#endif /* NET_DEBUG */ + +/** + Locks the NET Mutex which prevents any global variable being + overwritten by any function. It returns an error if mutex lock fails. +*/ +#define NET_LOCK()\ + MS_MUTEX_LOCK(net_mutex, NET) + +/** + Locks the NET_mutex which prevents any global variable being + overwritten by any function. To be used in void function as it + returns no error. +*/ +#define NET_LOCK_VOID()\ + MS_MUTEX_LOCK_VOID(net_mutex, NET) + +/** + Unlocks the NET_mutex which realeses the global variables + to be written into. It returns an error if mutex unlock fails. +*/ +#define NET_UNLOCK()\ + MS_MUTEX_UNLOCK(net_mutex, NET) + +/** + Unlocks the NET_mutex which realeses the global variables + to be written into. To be used in void functions as it returns + no error. +*/ +#define NET_UNLOCK_VOID()\ + MS_MUTEX_UNLOCK_VOID(net_mutex, NET) + + +#define net_alloc_mem(size)\ + EM_alloc_mem(size) + +#define net_free_mem(ptr)\ + EM_free_mem(ptr) + +#ifndef NET_NO_NULL_PARAM_CHECK +/** Null Check of Network API Parameters */ +#define NET_NULL_CHECK(x) \ + if (NULL == (x)) \ + { \ + NET_ERR( \ + "[NET] NULL Pointer detected. Referrence Impossible\n"); \ + return NET_NULL_PARAMETER_NOT_ALLOWED; \ + } +#else +#define NET_NULL_CHECK(x) +#endif /* NET_NO_NULL_PARAM_CHECK */ + +#ifndef MS_NET_NO_RANGE_CHECK +/** Range Check for Network API Parameters */ +#define NET_RANGE_CHECK_START(param, start) \ + if ( ! ((param) >= (start)) ) \ + { \ + NET_ERR( \ + "[NET] NET Range Check FAILED\n"); \ + return NET_PARAMETER_OUTSIDE_RANGE; \ + } + +#define NET_RANGE_CHECK_END(param, end) \ + if ( ! ((param) <= (end)) ) \ + { \ + NET_ERR( \ + "[NET] NET Range Check FAILED\n"); \ + return NET_PARAMETER_OUTSIDE_RANGE; \ + } + +#define NET_RANGE_CHECK(param, start, end) \ + if ( ! ( ((param) >= (start)) && ((param) <= (end)) ) ) \ + { \ + NET_ERR( \ + "[NET] NET Range Check FAILED\n"); \ + return NET_PARAMETER_OUTSIDE_RANGE; \ + } + +#else +#define NET_RANGE_CHECK_START(param, start) +#define NET_RANGE_CHECK_END(param, end) +#define NET_RANGE_CHECK(param, start, end) +#endif /* NET_NO_RANGE_CHECK */ + +/** Network Header Size */ +#define NET_HDR_SIZE 9 + +/** Maximum Network Payload Size - TransportPDU can be 8 to 128 bits */ +#define NET_MAX_PAYLOAD_SIZE 16 + +/** Network MIC Size - 32 or 64 bits. */ +#define NET_MIN_MIC_SIZE 4 +#define NET_MAX_MIC_SIZE 8 + +/** Sequence Number related macro defines */ +#define NET_INIT_SEQ_NUM_STATE() \ + net_seq_number_state.seq_num = 0; \ + net_seq_number_state.block_seq_num_max = 0 + +/** + (all-nodes address) OR + ((all-relays address) AND (Relay funcationality is enabled)) + ((all-friends address) AND (Friend funcationality is enabled)) + ((all-proxies address) AND (Proxy funcationality is enabled)) +*/ +#define NET_ADDR_FROM_FIXED_GROUP(addr) \ + (((MS_NET_ADDR_ALL_NODES == (addr)) ||\ + (MS_NET_ADDR_ALL_RELAYS == (addr)) ||\ + (MS_NET_ADDR_ALL_FRIENDS == (addr)) ||\ + (MS_NET_ADDR_ALL_PROXIES == (addr))) ? MS_TRUE: MS_FALSE) + +/** + RFU: 0xFF00 - 0xFFFB +*/ +#define NET_ADDR_FROM_RFU(addr) \ + (((0xFF00 <= (addr)) && (0xFFFB >= (addr))) ? MS_TRUE : MS_FALSE) + +/** + Network Proxy Filter List Count is ONE less that configured network interface. + First (0-th) network interface is used for Advertising Channel. +*/ +#define PROXY_FILTER_LIST_COUNT (MS_CONFIG_LIMITS(MS_NUM_NETWORK_INTERFACES) - 1) + + +/* --------------------------------------------- Data Types/ Structures */ +/** Network Cache Data Structure */ +typedef struct _NET_CACHE_ELEMENT +{ + /** Least significant bit of IV Index - 1 bit */ + UINT8 ivi; + + /** + Value derived from the NetKey used to identify + the Encrytion Key and Privacy Key used to secure + this PDU - 7 bits + */ + UINT8 nid; + + /** 16 Bit Source Address */ + MS_NET_ADDR saddr; + + /** 24 bit sequence number */ + UINT32 seq_num; + +} NET_CACHE_ELEMENT; + +/** Network Interface Packet Type - Network Packet or Proxy Packet */ +typedef UINT8 NETIF_PKT_T; + +/** + NOTE: The below define values of NETIF_PKT_T_NETWORK and NETIF_PKT_T_RELAY + 'SHALL' not be modified. The Network logic is dependent on these + values. +*/ +#define NETIF_PKT_T_NETWORK 0x00 +#define NETIF_PKT_T_RELAY 0x01 +#define NETIF_PKT_T_PROXY 0x02 + +#define NETIF_PKT_T_RELAY_MASK NETIF_PKT_T_RELAY + +#if ((NETIF_PKT_T_NETWORK != 0x00) || (NETIF_PKT_T_RELAY != 0x01) || (NETIF_PKT_T_RELAY_MASK != NETIF_PKT_T_RELAY)) + #error "NETIF_PKT_T defines modified !!" +#endif /* ((NETIF_PKT_T_NETWORK != 0x00) || (NETIF_PKT_T_RELAY != 0x01) || (NETIF_PKT_T_RELAY_MASK != NETIF_PKT_T_RELAY)) */ + +/** Network Tx Queue */ +typedef struct _NET_TX_Q_ELEMENT +{ + /* "Allocated" Data Pointer */ + UINT8* allocated_data; + + /* + Data Length. If data length is zero, the element is considered + invalid. + If data_length is 0, element is not valid. + */ + UINT16 data_length; + + /* Transmission Count */ + UINT8 tx_count; + + /* Transmission Interval */ + UINT8 tx_interval; + + /* Type of the Packet */ + NETIF_PKT_T type; + + /* Destination Address */ + MS_NET_ADDR d_addr; + + /* Check Transmission Type(seg)*/ + UINT8 unsegment; + + /* Transmission Flag*/ + UINT8 tx_flag; + +} NET_TX_Q_ELEMENT; + +/** Proxy Filter List */ +typedef struct _PROXY_FILTER_LIST +{ + /* Proxy Address List */ + MS_DEFINE_GLOBAL_ARRAY(PROXY_ADDR, p_addr, MS_CONFIG_LIMITS(MS_PROXY_FILTER_LIST_SIZE)); + MS_DEFINE_GLOBAL_ARRAY(PROXY_ADDR, v_addr, MS_CONFIG_LIMITS(MS_PROXY_FILTER_LIST_SIZE)); + + /* Proxy Address List Active Count */ + UINT16 p_count; + + /* Proxy Address List Active Count */ + UINT16 v_count; + + /* Proxy List Filter Type */ + PROXY_FILTER_TYPE type; + + /* Proxy Server/Client Role */ + UCHAR role; + +} PROXY_FILTER_LIST; + +//DECL_STATIC MS_DEFINE_GLOBAL_ARRAY(PROXY_FILTER_LIST, net_proxy_list, PROXY_FILTER_LIST_COUNT); + + +//UINT16 proxy_filter_table[MS_PROXY_FILTER_LIST_SIZE]; + + +/* TODO: Move to Limits.h */ +/* NET TX Q */ +//#define NET_TX_QUEUE_SIZE 30 //20 ->30 by ZQ +#define NET_TX_QUEUE_SIZE 40 //30 ->40 by HQ + + +/* TODO: To be dynamically adjusted based on the type of packet and corresponding configuration redefine by hq*/ +#define NET_TX_TIMEOUT (EM_TIMEOUT_MILLISEC | 15) /* Millisecond */ + +MS_DECLARE_GLOBAL_ARRAY(NET_CACHE_ELEMENT, net_cache, MS_CONFIG_LIMITS(MS_NET_CACHE_SIZE)); + + +extern UINT16 net_cache_start; +extern UINT16 net_cache_size; + + + +/* --------------------------------------------- Functions */ +/** + \par Description + This function handles the incoming data received over a network interface. + + \param [in] type + Network Inteface Packet Type + \param [in] handle + Network Interface Handle + \param [in] pdata + The incoming Data Packet + \param [in] pdatalen + Size of the incoming Data Packet +*/ +void net_pkt_in +( + /* IN */ NETIF_PKT_T type, + /* IN */ NETIF_HANDLE* handle, + /* IN */ UCHAR* pdata, + /* IN */ UINT16 pdatalen +); + +API_RESULT netif_adv_recv_cb (BRR_HANDLE* handle, UCHAR pevent, UCHAR* pdata, UINT16 pdatalen); +API_RESULT netif_gatt_recv_cb (BRR_HANDLE* handle, UCHAR pevent, UCHAR* pdata, UINT16 pdatalen); + +/* Initialize network cache */ +void net_init_cache (void); + +/* Is already in cache? */ +API_RESULT net_is_in_cache +( + /* IN */ MS_NET_HEADER* hdr +); + +/* Add to cache */ +API_RESULT net_add_to_cache +( + /* IN */ MS_NET_HEADER* hdr +); + +/** + Routine to decode a received Network PDU, + based on a specific network Key from the store. + This function returns status of the decode operation. + If success, return the decoded network header and PDU. +*/ +API_RESULT net_decode_frame +( + /* IN */ NETIF_PKT_T type, + /* IN */ UCHAR* pdata, + /* IN */ UINT16 pdatalen, + /* OUT */ MS_SUBNET_HANDLE* subnet_handle, + /* OUT */ MS_NET_HEADER* net_hdr, + /* OUT */ UCHAR* trn_pdu, + /* OUT */ UINT16* trn_pdu_len +); + +/** + \par Description + This function obfuscates or de-obfuscates a network header. + + \param [in] network_pkt + Network Packet + \param [in] privacy_key + Privacy Key + \param [in] pecb_input + PECB Input + \param [out] pecb_output + PECB Output. Can not be same pointer as PECB Input. +*/ +void net_obfuscate +( + /* IN */ UINT8* network_pkt, + /* IN */ UINT8* privacy_key, + /* IN */ UINT8* pecb_input, + /* OUT */ UINT8* pecb_output +); + +/** + \par Description + This macro de-obfuscates a network header. + + \param [in] network_pkt + Network Packet + \param [in] privacy_key + Privacy Key + \param [in] pecb_input + PECB Input + \param [out] pecb_output + PECB Output. Can not be same pointer as PECB Input. +*/ +#define net_de_obfuscate(network_pkt, privacy_key, pecb_input, pecb_output) \ + net_obfuscate((network_pkt), (privacy_key), (pecb_input), (pecb_output)) + +/** + \par Description + This function creaets input bytes to be used for PECB. + + \param [in] iv_index + Network IV Index + \param [in] network_pkt + Network Packet + \param [out] pecb_input + Buffer where PECB input bytes to be prepared +*/ +void net_create_pecb_input +( + /* IN */ UINT32 iv_index, + /* IN */ UINT8* network_pkt, + /* OUT */ UINT8* pecb_input +); + +/** + \par Description + This function sends data over a network interface. + + \param [in] hdr + Network Header for the transmit packet + \param [in] subnet_handle + Handle identifying associated subnet on which the packet to be transmitted + \param [in] buffer + Outgoing Data Packet + \param [in] is_relay + Flag + \ref MS_TRUE : If the packet to be tagged as relay + \ref MS_FALSE: Otherwise +*/ +API_RESULT net_pkt_send +( + /* IN */ MS_NET_HEADER* hdr, + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ MS_BUFFER* buffer, + /* IN */ UINT8 is_relay, + /* IN */ UINT8 is_seg +); + +/* netif interfaces */ +API_RESULT netif_init (void); +API_RESULT netif_deinit (void); +API_RESULT netif_send (NETIF_PKT_T type, MS_NET_ADDR d_addr, UCHAR* pdata, UINT16 pdatalen,UINT8 unsegment_flag,UINT8 tx_flag); + +/* Network Tx Queue routines */ +void net_tx_queue_init(void); +API_RESULT net_tx_enqueue +( + /* IN */ NETIF_PKT_T type, + /* IN */ MS_NET_ADDR d_addr, + /* IN */ UINT8* buffer, + /* IN */ UINT16 buffer_len, + /* IN */ UINT8 is_seg +); +API_RESULT net_trigger_tx(void); +void net_tx_timeout_handler(void* args, UINT16 size); + +#ifdef MS_PROXY_SERVER +/* GATT Proxy Server Related defines */ +#define net_proxy_server_add_to_list(h,a,c,f) \ + net_proxy_server_filter_op \ + ( \ + (h), \ + MS_PROXY_ADD_TO_FILTER_OPCODE, \ + (a), \ + (c), \ + (f) \ + ); + +#define net_proxy_server_del_from_list(h,a,c,f) \ + net_proxy_server_filter_op \ + ( \ + (h), \ + MS_PROXY_REM_FROM_FILTER_OPCODE, \ + (a), \ + (c), \ + (f) \ + ); +#endif /* MS_PROXY_SERVER */ + +/* TODO: Protect by Proxy Feature */ +/* Init functons */ +API_RESULT net_proxy_init(void); + +void net_proxy_iface_up (NETIF_HANDLE* handle, UCHAR role); +void net_proxy_iface_down(NETIF_HANDLE* handle); + +/** + Interface for Network layer to inform Proxy of the received + Packets which are intended for the Proxy[Configuration Messages]. + + \param net_hdr Network Header. + \param netif_handle Network Interface Handle. + \param subnet_handle Associated Subnet Handle. + \param data_param Data associated with the event if any or NULL. + \param data_len Size of the event data. 0 if event data is NULL. +*/ +void net_proxy_recv +( + MS_NET_HEADER* net_hdr, + NETIF_HANDLE* handle, + MS_SUBNET_HANDLE subnet_handle, + UCHAR* data_param, + UINT16 data_len +); + +/** + \brief Send a Proxy PDU + + \par Description + This routine sends a PDU from the Mesh stack to over the Proxy + indicated by the Proxy Type. + + \param [in] subnet_handle + subnet_handle on which PDU is to be sent. + + \param [in] pdu + PDU data to be sent. + + \param [in] pdu_len + length of PDU data to be sent. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT net_proxy_send +( + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ UCHAR* pdu, + /* IN */ UINT16 pdu_len +); + +#ifdef MS_PROXY_SERVER +/* Interface to set, and get current proxy filter types */ +API_RESULT net_proxy_server_set_filter +( + /* IN */ NETIF_HANDLE* handle, + /* IN */ PROXY_FILTER_TYPE type +); + +/* Interface to ADD, Remove to Filter List */ +API_RESULT net_proxy_server_filter_op +( + /* IN */ NETIF_HANDLE* handle, + /* IN */ UCHAR opcode, + /* IN */ UCHAR* pdu, + /* IN */ UINT16 pdu_len, + /* IN */ UCHAR proxy_fitlter_flg +); + +/* Interface to send List Filter Status */ +void net_proxy_send_filter_status +( + NETIF_HANDLE* handle, + MS_SUBNET_HANDLE subnet_handle +); + +API_RESULT net_proxy_process_first_pkt +( + /* IN */ NETIF_HANDLE* handle, + /* IN */ PROXY_ADDR src_addr +); +#endif /* MS_PROXY_SERVER */ + +API_RESULT net_proxy_filter_check_forwarding +( + NETIF_HANDLE* handle, + NETIF_PKT_T pkt_sub_type, + PROXY_ADDR d_addr +); + +void net_handle_secure_beacon(UCHAR* pdata, UINT16 pdatalen); +API_RESULT net_proxy_nodeid_adv(MS_SUBNET_HANDLE handle); +void net_proxy_netid_timeout_handler(void* args, UINT16 size); +void net_proxy_nodeid_timeout_handler(void* args, UINT16 size); + +#endif /* _H_NET_INTERNAL_ */ + diff --git a/src/components/ethermind/mesh/export/platforms/ext/MS_common_pl.c b/src/components/ethermind/mesh/export/platforms/ext/MS_common_pl.c new file mode 100644 index 0000000..3816d6e --- /dev/null +++ b/src/components/ethermind/mesh/export/platforms/ext/MS_common_pl.c @@ -0,0 +1,68 @@ + +/** + \file MS_common_pl.c + + Common routines and start-up initialization & shutdown handlers + (Platform: Windows User Mode) +*/ + +/* + Copyright (C) 2016. Mindtree Ltd. + All rights reserved. +*/ + +/* ------------------------------------------- Header File Inclusion */ +#include "MS_common.h" +#include "MS_access_api.h" +#include "blebrr.h" + +/* ------------------------------------------- External Global Variables */ + + +/* ------------------------------------------- External Global Variables */ + + +/* ------------------------------------------- External Global Variables */ + + +/* ------------------------------------------- Functions */ +/* EtherMind-Init: Platform Handler */ +void ms_init_pl (void) +{ +} + +__ATTR_SECTION_XIP__ UINT8 MS_common_reset(void) +{ + UINT8 retval; + UINT8 proxy_state,proxy; + retval = MS_TRUE; + MS_access_cm_get_features_field(&proxy, MS_FEATURE_PROXY); + MS_proxy_fetch_state(&proxy_state); + + if((MS_TRUE == proxy) && (proxy_state == MS_PROXY_CONNECTED)) + { + blebrr_disconnect_pl(); + retval = MS_FALSE; + } + + #if(BLEMESH_ROLE == PROV_ROLE_PROVISIONER) + MS_access_cm_reset(PROV_ROLE_PROVISIONER); + #else + nvs_reset(NVS_BANK_PERSISTENT); + MS_access_cm_reset(PROV_ROLE_DEVICE); + #endif + return retval; +} + + + +#ifndef MS_NO_SHUTDOWN + +/* Mesh Shutdown: Platform Handler */ +void ms_shutdown_pl (void) +{ +} + +#endif /* MS_NO_SHUTDOWN */ + + diff --git a/src/components/ethermind/mesh/export/platforms/ext/MS_common_pl.h b/src/components/ethermind/mesh/export/platforms/ext/MS_common_pl.h new file mode 100644 index 0000000..a4f25b4 --- /dev/null +++ b/src/components/ethermind/mesh/export/platforms/ext/MS_common_pl.h @@ -0,0 +1,54 @@ + +/** + \file MS_common_pl.h + + This file contains the Function Declaration, and Constant Definitions + for the EtherMind Mesh Stack in Windows User Mode. +*/ + +/* + Copyright (C) 2016. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_COMMON_PL_ +#define _H_MS_COMMON_PL_ + +/* ------------------------------------------- Header File Inclusion */ + +/* ------------------------------------------- Common PL Debug */ +#define PL_ERR(...) MS_debug_error(ms_debug_fd, __VA_ARGS__) + +#ifdef PL_DEBUG + + #define PL_TRC(...) MS_debug_trace(ms_debug_fd, __VA_ARGS__) + #define PL_INF(...) MS_debug_info(ms_debug_fd, __VA_ARGS__) + +#else /* PL_DEBUG */ + + #define PL_TRC MS_debug_null + #define PL_INF MS_debug_null + +#endif /* PL_DEBUG */ + + +/* ------------------------------------------- Global Definitions/Macros */ +/* EtherMind Configuration File */ +#define MS_CONFIG_FILE "ethermind.conf" + + +/* ------------------------------------------- Data Structures */ + + +/* ------------------------------------------- Function Declarations */ +/* EtherMind-Init: Platform Handler */ +void ms_init_pl(void); + +__ATTR_SECTION_XIP__ UINT8 MS_common_reset(void); + + +/* Mesh Shutdown: Platform Handler */ +void ms_shutdown_pl(void); + +#endif /* _H_MS_COMMON_PL_ */ + diff --git a/src/components/ethermind/mesh/export/platforms/ext/prov_pl.c b/src/components/ethermind/mesh/export/platforms/ext/prov_pl.c new file mode 100644 index 0000000..1bc6a3b --- /dev/null +++ b/src/components/ethermind/mesh/export/platforms/ext/prov_pl.c @@ -0,0 +1,48 @@ + +/** + \file prov_pl.c + + +*/ + +/* + Copyright (C) 2013. Mindtree Limited. + All rights reserved. +*/ + +/* --------------------------------------------- Header File Inclusion */ +#include "prov_pl.h" + +/* --------------------------------------------- External Global Variables */ + +/* --------------------------------------------- Exported Global Variables */ + +/* --------------------------------------------- Static Global Variables */ +/** Out of Band Public Key information */ +DECL_STATIC UCHAR prov_dev_oob_pubkey[PROV_PUBKEY_SIZE_PL]; + +/** Static Out of Band Authentication information */ +DECL_STATIC UCHAR prov_static_oob_auth[PROV_AUTHVAL_SIZE_PL]; + +/* --------------------------------------------- Functions */ + +void prov_set_device_oob_pubkey_pl(UCHAR* key, UINT16 size) +{ + EM_mem_copy(prov_dev_oob_pubkey, key, size); +} + +void prov_read_device_oob_pubkey_pl (UCHAR* key, UINT16 size) +{ + EM_mem_copy(key, prov_dev_oob_pubkey, size); +} + +void prov_set_static_oob_auth_pl(UCHAR* key, UINT16 size) +{ + EM_mem_copy(prov_static_oob_auth, key, size); +} + +void prov_read_static_oob_auth_pl(UCHAR* key, UINT16 size) +{ + EM_mem_copy(key, prov_static_oob_auth, size); +} + diff --git a/src/components/ethermind/mesh/export/platforms/ext/prov_pl.h b/src/components/ethermind/mesh/export/platforms/ext/prov_pl.h new file mode 100644 index 0000000..ce17d3f --- /dev/null +++ b/src/components/ethermind/mesh/export/platforms/ext/prov_pl.h @@ -0,0 +1,36 @@ + +/** + \file prov_pl.h + + +*/ + +/* + Copyright (C) 2013. Mindtree Limited. + All rights reserved. +*/ + +#ifndef _H_PROV_PL_ +#define _H_PROV_PL_ + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_common.h" + +/* --------------------------------------------- Global Definitions */ +#define PROV_PUBKEY_SIZE_PL 64 +#define PROV_AUTHVAL_SIZE_PL 16 + +/* --------------------------------------------- Structures/Data Types */ + +/* --------------------------------------------- Macros */ + +/* --------------------------------------------- Internal Functions */ + +/* --------------------------------------------- API Declarations */ +void prov_set_device_oob_pubkey_pl(UCHAR* key, UINT16 size); +void prov_set_static_oob_auth_pl(UCHAR* key, UINT16 size); +void prov_read_device_oob_pubkey_pl (UCHAR* key, UINT16 size); +void prov_read_static_oob_auth_pl(UCHAR* key, UINT16 size); + +#endif /* _H_PROV_PL_ */ + diff --git a/src/components/ethermind/mesh/export/sample/appl_sample_example_1.c b/src/components/ethermind/mesh/export/sample/appl_sample_example_1.c new file mode 100644 index 0000000..08e6469 --- /dev/null +++ b/src/components/ethermind/mesh/export/sample/appl_sample_example_1.c @@ -0,0 +1,665 @@ + +/** + \file appl_sample_example_1.c + + Source File for Generic OnOff Server Standalone application without CLI or + menu based console input interface. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#if (MESH_STANDALONE == 1) + +/* ----------------------------------------- Header File Inclusion */ +#include "MS_common.h" +#include "MS_access_api.h" +#include "MS_config_api.h" +#include "MS_health_server_api.h" +#include "MS_generic_onoff_api.h" +#include "blebrr.h" +#include "nvsto.h" +#include "model_state_handler_pl.h" + +/* Console Input/Output */ +#define CONSOLE_OUT(...) printf(__VA_ARGS__) +#define CONSOLE_IN(...) scanf(__VA_ARGS__) + +void appl_dump_bytes(UCHAR* buffer, UINT16 length); +void appl_mesh_sample (void); + +/* ----------------------------------------- External Global Variables */ + + +/* ----------------------------------------- Exported Global Variables */ + + +/* ----------------------------------------- Static Global Variables */ + + +/* ----------------------------------------- Functions */ +/* Model Server - Foundation Models */ + +/* Health Server - Test Routines */ +static void UI_health_self_test_00(UINT8 test_id, UINT16 company_id) +{ +} + +static void UI_health_self_test_01(UINT8 test_id, UINT16 company_id) +{ +} + +static void UI_health_self_test_FF(UINT8 test_id, UINT16 company_id) +{ +} + +/* List of Self Tests */ +static MS_HEALTH_SERVER_SELF_TEST UI_health_server_self_tests[] = +{ + { + 0x00, /* Test ID: 0x00 */ + UI_health_self_test_00 + }, + { + 0x01, /* Test ID: 0x01 */ + UI_health_self_test_01 + }, + { + 0xFF, /* Test ID: 0xFF */ + UI_health_self_test_FF + } +}; + +/** + \brief Health Server application Asynchronous Notification Callback. + + \par Description + Health Server calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param event_type Health Server Event type. + \param event_param Parameter associated with the event if any or NULL. + \param param_len Size of the event parameter data. 0 if event param is NULL. +*/ +static API_RESULT UI_health_server_cb +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT8 event_type, + UINT8* event_param, + UINT16 param_len +) +{ + CONSOLE_OUT( + "Health Server Callback. Not handled. Returning\n"); + return API_SUCCESS; +} + +static API_RESULT UI_register_foundation_model_servers +( + MS_ACCESS_ELEMENT_HANDLE element_handle +) +{ + /* Configuration Server */ + MS_ACCESS_MODEL_HANDLE UI_config_server_model_handle; + MS_ACCESS_MODEL_HANDLE UI_health_server_model_handle; + API_RESULT retval; + /* Health Server */ + UINT16 company_id; + MS_HEALTH_SERVER_SELF_TEST* self_tests; + UINT32 num_self_tests; + CONSOLE_OUT("In Model Server - Foundation Models\n"); + retval = MS_config_server_init(element_handle, &UI_config_server_model_handle); + CONSOLE_OUT("Config Model Server Registration Status: 0x%04X\n", retval); + /* Health Server */ + company_id = MS_DEFAULT_COMPANY_ID; + self_tests = &UI_health_server_self_tests[0]; + num_self_tests = sizeof(UI_health_server_self_tests)/sizeof(MS_HEALTH_SERVER_SELF_TEST); + retval = MS_health_server_init + ( + element_handle, + &UI_health_server_model_handle, + company_id, + self_tests, + num_self_tests, + UI_health_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Health Server Initialized. Model Handle: 0x%04X\n", + UI_health_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Sensor Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + return retval; +} + + +/* ---- Generic OnOff States and Get/Set Handlers */ +static MS_STATE_GENERIC_ONOFF_STRUCT UI_generic_onoff; + +/* Generic OnOff Model state Initialization */ +static void UI_generic_onoff_model_states_initialization(void) +{ + EM_mem_set(&UI_generic_onoff, 0, sizeof(UI_generic_onoff)); +} + +/* Generic OnOff Model Get Handler */ +static API_RESULT UI_generic_onoff_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = UI_generic_onoff; + } + break; + + default: + break; + } + + return retval; +} + +/* Generic OnOff Model Set Handler */ +static API_RESULT UI_generic_onoff_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + /* Instantaneous Change */ + UI_generic_onoff.onoff = param_p->onoff; + *param_p = UI_generic_onoff; + CONSOLE_OUT("[state] current: 0x%02X\n", UI_generic_onoff.onoff); + CONSOLE_OUT("[state] target: 0x%02X\n", UI_generic_onoff.target_onoff); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", UI_generic_onoff.transition_time); + generic_onoff_set_pl(param_p->onoff); + /* Ignoring Instance and direction right now */ + } + break; + + default: + break; + } + + return retval; +} + +/* Model state Initialization */ +static void UI_model_states_initialization(void) +{ + /* Generic OnOff States */ + UI_generic_onoff_model_states_initialization(); +} + +/* Generic OnOff Model Server */ +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +static API_RESULT UI_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONOFF_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] GET Request.\n"); + UI_generic_onoff_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + /* Using same as target state and remaining time as 0 */ + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] SET Request.\n"); + retval = UI_generic_onoff_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT("[GENERIC_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +static API_RESULT UI_register_generic_onoff_model_server +( + MS_ACCESS_ELEMENT_HANDLE element_handle +) +{ + /* Generic OnOff Server */ + MS_ACCESS_MODEL_HANDLE UI_generic_onoff_server_model_handle; + API_RESULT retval; + CONSOLE_OUT("In Generic OnOff Model Server\n"); + retval = MS_generic_onoff_server_init + ( + element_handle, + &UI_generic_onoff_server_model_handle, + UI_generic_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Onoff Server Initialized. Model Handle: 0x%04X\n", + UI_generic_onoff_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Onoff Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + return retval; +} + +/* Provisionee */ +#define UI_PROV_OUTPUT_OOB_ACTIONS \ + (PROV_MASK_OOOB_ACTION_BLINK | PROV_MASK_OOOB_ACTION_BEEP | \ + PROV_MASK_OOOB_ACTION_VIBRATE | PROV_MASK_OOOB_ACTION_NUMERIC | \ + PROV_MASK_OOOB_ACTION_ALPHANUMERIC) + +/** Output OOB Maximum size supported */ +#define UI_PROV_OUTPUT_OOB_SIZE 0x08 + +/** Input OOB Actions supported */ +#define UI_PROV_INPUT_OOB_ACTIONS \ + (PROV_MASK_IOOB_ACTION_PUSH | PROV_MASK_IOOB_ACTION_TWIST | \ + PROV_MASK_IOOB_ACTION_NUMERIC | PROV_MASK_IOOB_ACTION_ALPHANUMERIC) + +/** Input OOB Maximum size supported */ +#define UI_PROV_INPUT_OOB_SIZE 0x08 + +/** Beacon setup timeout in seconds */ +#define UI_PROV_SETUP_TIMEOUT_SECS 30 + +/** Attention timeout for device in seconds */ +#define UI_PROV_DEVICE_ATTENTION_TIMEOUT 30 + +#define PROV_AUTHVAL_SIZE_PL 16 + +/** Authentication values for OOB Display - To be made random */ +#define UI_DISPLAY_AUTH_DIGIT 3 +#define UI_DISPLAY_AUTH_NUMERIC 35007 +#define UI_DISPLAY_AUTH_STRING "f00l" + +/** Provisioning capabilities of local device */ +DECL_STATIC PROV_CAPABILITIES_S UI_prov_capab = +{ + /** Number of Elements */ + 0x01, + + /** Supported algorithms */ + PROV_MASK_ALGO_EC_FIPS_P256, + + /** Public key type */ + PROV_MASK_PUBKEY_OOBINFO, + + /** Static OOB type */ + PROV_MASK_STATIC_OOBINFO, + + /** Output OOB information */ + { UI_PROV_OUTPUT_OOB_ACTIONS, UI_PROV_OUTPUT_OOB_SIZE }, + + /** Input OOB information */ + { UI_PROV_INPUT_OOB_ACTIONS, UI_PROV_INPUT_OOB_SIZE }, +}; + +/** Unprovisioned device identifier */ +PROV_DEVICE_S UI_lprov_device = +{ + /** UUID */ + {0xa8, 0x01, 0xb1, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0x00, 0x00, 0x00}, + + /** OOB Flag */ + 0x00, + + /** + Encoded URI Information + For example, to give a web address, "https://www.abc.com" + the URI encoded data would be - + 0x17 0x2F 0x2F 0x77 0x77 0x77 0x2E 0x61 0x62 0x63 0x2E 0x63 0x6F 0x6D + where 0x17 is the URI encoding for https: + */ + NULL +}; + +/** Current role of application - Provisioner/Device */ +DECL_STATIC UCHAR UI_prov_role; + +/** Provisioning Handle */ +DECL_STATIC PROV_HANDLE UI_prov_handle; + +static API_RESULT UI_prov_callback +( + PROV_HANDLE* phandle, + UCHAR event_type, + API_RESULT event_result, + void* event_data, + UINT16 event_datalen +) +{ + PROV_DEVICE_S* rdev; + PROV_CAPABILITIES_S* rcap; + PROV_DATA_S* rdata; + PROV_OOB_TYPE_S* oob_info; + API_RESULT retval; + UCHAR i; + UCHAR authstr[PROV_AUTHVAL_SIZE_PL << 1]; + UINT32 authnum; + UCHAR authtype; + UCHAR* pauth; + UINT16 authsize; + UCHAR pdata[(MS_DEVICE_UUID_SIZE * 2) + 1]; + UCHAR* t_data; + + switch (event_type) + { + case PROV_EVT_PROVISIONING_SETUP: + CONSOLE_OUT("Recvd PROV_EVT_PROVISIONING_SETUP\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Display the attention timeout */ + CONSOLE_OUT("Attention TImeout - %d\n", *((UCHAR*)event_data)); + break; + + case PROV_EVT_OOB_DISPLAY: + CONSOLE_OUT("Recvd PROV_EVT_OOB_DISPLAY\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Authenticatio Type information */ + oob_info = (PROV_OOB_TYPE_S*)event_data; + CONSOLE_OUT("Authenticaion Action - 0x%02X\n", oob_info->action); + CONSOLE_OUT("Authenticaion Size - 0x%02X\n", oob_info->size); + + /* If role is Device, the action is of Output OOB, else Input OOB */ + if (PROV_ROLE_DEVICE == UI_prov_role) + { + if (PROV_OOOB_ACTION_ALPHANUMERIC == oob_info->action) + { + authtype = 1; + } + else if (PROV_OOOB_ACTION_NUMERIC == oob_info->action) + { + authtype = 2; + } + else + { + authtype = 0; + } + } + else + { + if (PROV_IOOB_ACTION_ALPHANUMERIC == oob_info->action) + { + authtype = 1; + } + else if (PROV_IOOB_ACTION_NUMERIC == oob_info->action) + { + authtype = 2; + } + else + { + authtype = 0; + } + } + + if (1 == authtype) + { + EM_str_copy (authstr, UI_DISPLAY_AUTH_STRING); + CONSOLE_OUT("\n\n>>> AuthVal - %s <<<\n\n", authstr); + pauth = authstr; + authsize = EM_str_len(authstr); + } + else if (2 == authtype) + { + authnum = (UINT32)UI_DISPLAY_AUTH_NUMERIC; + CONSOLE_OUT("\n\n>>> AuthVal - %d <<<\n\n", authnum); + pauth = (UCHAR*)&authnum; + authsize = sizeof(UINT32); + } + else + { + authnum = (UINT32)UI_DISPLAY_AUTH_DIGIT; + CONSOLE_OUT("\n\n>>> AuthVal - %d <<<\n\n", authnum); + pauth = (UCHAR*)&authnum; + authsize = sizeof(UINT32); + } + + /* Call to input the oob */ + CONSOLE_OUT("Setting the Authval...\n"); + retval = MS_prov_set_authval(&UI_prov_handle, pauth, authsize); + CONSOLE_OUT("Retval - 0x%04X\n", retval); + break; + + case PROV_EVT_OOB_ENTRY: + CONSOLE_OUT("Recvd PROV_EVT_OOB_ENTRY\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Authenticatio Type information */ + oob_info = (PROV_OOB_TYPE_S*)event_data; + CONSOLE_OUT("Authenticaion Action - 0x%02X\n", oob_info->action); + CONSOLE_OUT("Authenticaion Size - 0x%02X\n", oob_info->size); + break; + + case PROV_EVT_DEVINPUT_COMPLETE: + CONSOLE_OUT("Recvd PROV_EVT_DEVINPUT_COMPLETE\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + break; + + case PROV_EVT_PROVDATA_INFO: + CONSOLE_OUT("Recvd PROV_EVT_PROVDATA_INFO\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Provisioning Data */ + rdata = (PROV_DATA_S*)event_data; + CONSOLE_OUT("NetKey : "); + appl_dump_bytes(rdata->netkey, PROV_KEY_NETKEY_SIZE); + CONSOLE_OUT("Key ID : 0x%04X\n", rdata->keyid); + CONSOLE_OUT("Flags : 0x%02X\n", rdata->flags); + CONSOLE_OUT("IVIndex : 0x%08X\n", rdata->ivindex); + CONSOLE_OUT("UAddr : 0x%04X\n", rdata->uaddr); + blebrr_scan_pl(FALSE); // HZF + /* Provide Provisioning Data to Access Layer */ + MS_access_cm_set_prov_data + ( + rdata + ); + break; + + case PROV_EVT_PROVISIONING_COMPLETE: + CONSOLE_OUT("Recvd PROV_EVT_PROVISIONING_COMPLETE\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + + if (API_SUCCESS == event_result) + { + /* Already Set while handling PROV_EVT_PROVDATA_INFO */ + /* LED ON/OFF for Provisioning Indication Abstraction Call */ + mesh_model_device_provisioned_ind_pl(); + } + + break; + + default: + CONSOLE_OUT("Unknown Event - 0x%02X\n", event_type); + } + + return API_SUCCESS; +} + +static void UI_register_prov(void) +{ + API_RESULT retval; + CONSOLE_OUT("Registering with Provisioning layer...\n"); + retval = MS_prov_register(&UI_prov_capab, UI_prov_callback); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +static void UI_setup_prov(UCHAR role, UCHAR brr) +{ + API_RESULT retval; + + if (PROV_ROLE_PROVISIONER != role) + { + CONSOLE_OUT("Setting up Device for Provisioning ...\n"); + retval = MS_prov_setup + ( + brr, + role, + &UI_lprov_device, + UI_PROV_SETUP_TIMEOUT_SECS + ); + UI_prov_role = PROV_ROLE_DEVICE; + } + else + { + CONSOLE_OUT("Setting up Provisioner for Provisioning ...\n"); + retval = MS_prov_setup + ( + brr, + role, + NULL, + UI_PROV_SETUP_TIMEOUT_SECS + ); + UI_prov_role = PROV_ROLE_PROVISIONER; + } + + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +static void UI_prov_bind(UCHAR brr, UCHAR index) +{ + API_RESULT retval; + /* Call to bind with the selected device */ + CONSOLE_OUT("Binding with the selected device...\n"); + retval = MS_prov_bind(brr, &UI_lprov_device, UI_PROV_DEVICE_ATTENTION_TIMEOUT, &UI_prov_handle); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void appl_mesh_sample (void) +{ + MS_ACCESS_NODE_ID node_id; + MS_ACCESS_ELEMENT_DESC element; + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + UCHAR role, brr; + MS_CONFIG* config_ptr; + #ifdef MS_HAVE_DYNAMIC_CONFIG + MS_CONFIG config; + /* Initialize dynamic configuration */ + MS_INIT_CONFIG(config); + config_ptr = &config; + #else + config_ptr = NULL; + #endif /* MS_HAVE_DYNAMIC_CONFIG */ + /* Initialize OSAL */ + EM_os_init(); + /* Initialize Debug Module */ + EM_debug_init(); + /* Initialize Timer Module */ + EM_timer_init(); + timer_em_init(); + /* Initialize utilities */ + nvsto_init(); + /* Initialize Mesh Stack */ + MS_init(config_ptr); + /* Register with underlying BLE stack */ + blebrr_register(); + /* Enable LED Port */ + /* Platform Abstraction Initializations of GPIOs/LEDs etc. */ + mesh_model_platform_init_pl(); + /* LED ON */ + /* LED ON/OFF for BOOT UP Indication Abstraction Call */ + mesh_model_device_bootup_ind_pl(); + /* Create Node */ + retval = MS_access_create_node(&node_id); + /* Register Element */ + /** + TBD: Define GATT Namespace Descriptions from + https://www.bluetooth.com/specifications/assigned-numbers/gatt-namespace-descriptors + + Using 'main' (0x0106) as Location temporarily. + */ + element.loc = 0x0106; + retval = MS_access_register_element + ( + node_id, + &element, + &element_handle + ); + + if (API_SUCCESS == retval) + { + /* Register foundation model servers */ + retval = UI_register_foundation_model_servers(element_handle); + } + + if (API_SUCCESS == retval) + { + /* Register Generic OnOff model server */ + retval = UI_register_generic_onoff_model_server(element_handle); + } + + if (API_SUCCESS == retval) + { + /* Initialize model states */ + UI_model_states_initialization(); + } + + /* Configure as provisionee/device */ + UI_register_prov(); + /** + setup onoff; + *param_p = UI_generic_onoff; + CONSOLE_OUT("[state] current: 0x%02X\n", UI_generic_onoff.onoff); + CONSOLE_OUT("[state] target: 0x%02X\n", UI_generic_onoff.target_onoff); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", UI_generic_onoff.transition_time); + generic_onoff_set_pl(param_p->onoff); + /* Ignoring Instance and direction right now */ + } + break; + + default: + break; + } + + return retval; +} + +/* Model state Initialization */ +void UI_model_states_initialization(void) +{ + /* Generic OnOff States */ + UI_generic_onoff_model_states_initialization(); +} + +/* Generic OnOff Model Server */ +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT UI_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONOFF_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] GET Request.\n"); + UI_generic_onoff_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + /* Using same as target state and remaining time as 0 */ + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] SET Request.\n"); + retval = UI_generic_onoff_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT("[GENERIC_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +API_RESULT UI_register_generic_onoff_model_server +( + MS_ACCESS_ELEMENT_HANDLE element_handle +) +{ + /* Generic OnOff Server */ + MS_ACCESS_MODEL_HANDLE UI_generic_onoff_server_model_handle; + API_RESULT retval; + CONSOLE_OUT("In Generic OnOff Model Server\n"); + retval = MS_generic_onoff_server_init + ( + element_handle, + &UI_generic_onoff_server_model_handle, + UI_generic_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Onoff Server Initialized. Model Handle: 0x%04X\n", + UI_generic_onoff_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Onoff Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + return retval; +} + +void UI_lpn_seek_friend(void); +void UI_frndsetup_cb(MS_SUBNET_HANDLE subnet, UCHAR event_type, UINT16 status) +{ + API_RESULT retval; + UINT16 num_subaddr; + UINT16 subaddr[5]; + CONSOLE_OUT("\nFriendship Event 0x%02X on Subnet 0x%04X - 0x%04X\n", + event_type, subnet, status); + + switch (event_type) + { + case MS_TRN_FRIEND_SETUP_CNF: + CONSOLE_OUT("Recvd MS_TRN_FRIEND_SETUP_CNF - 0x%04X\n", status); + + if (API_SUCCESS == status) + { + /* Get the subscription list */ + num_subaddr = sizeof(subaddr) / sizeof(UINT16); + MS_access_cm_get_all_model_subscription_list(&num_subaddr, subaddr); + + if (0 < num_subaddr) + { + CONSOLE_OUT("Initiating FriendSubscriptionListAdd - %d addr\n", num_subaddr); + retval = MS_trn_lpn_subscrn_list_add(subaddr, num_subaddr); + CONSOLE_OUT("Retval - 0x%04X\n", retval); + } + } + else + { + CONSOLE_OUT("Friendship Setup Failure%04X\n", status); + UI_lpn_seek_friend(); + } + + break; + + case MS_TRN_FRIEND_SUBSCRNLIST_CNF: + CONSOLE_OUT("Recvd MS_TRN_FRIEND_SUBSCRNLIST_CNF - 0x%04X\n", status); + break; + + case MS_TRN_FRIEND_CLEAR_CNF: + CONSOLE_OUT("Recvd MS_TRN_FRIEND_CLEAR_CNF - 0x%04X\n", status); + break; + + case MS_TRN_FRIEND_TERMINATE_IND: + CONSOLE_OUT("Recvd MS_TRN_FRIEND_TERMINATE_IND - 0x%04X\n", status); + /* Enable Friend feature */ + MS_ENABLE_FRIEND_FEATURE(); + break; + + default: + break; + } +} + +void UI_lpn_seek_friend (void) +{ + API_RESULT retval; + /* Disable Friend feature */ + MS_DISABLE_FRIEND_FEATURE(); + /* Enable LPN feature */ + MS_ENABLE_LPN_FEATURE(); + CONSOLE_OUT ("Requesting for friendship...\n"); + retval = MS_trn_lpn_setup_friendship + ( + 0x00, + UI_FRND_CRITERIA, + UI_FRND_RECEIVE_DELAY_MS, + UI_FRND_POLLTIMEOUT_100MS, + UI_FRND_SETUPTIMEOUT, + UI_frndsetup_cb + ); + CONSOLE_OUT ("Retval - 0x%04X\n", retval); + return; +} + + +/* Provisionee */ +#define UI_PROV_OUTPUT_OOB_ACTIONS \ + (PROV_MASK_OOOB_ACTION_BLINK | PROV_MASK_OOOB_ACTION_BEEP | \ + PROV_MASK_OOOB_ACTION_VIBRATE | PROV_MASK_OOOB_ACTION_NUMERIC | \ + PROV_MASK_OOOB_ACTION_ALPHANUMERIC) + +/** Output OOB Maximum size supported */ +#define UI_PROV_OUTPUT_OOB_SIZE 0x08 + +/** Input OOB Actions supported */ +#define UI_PROV_INPUT_OOB_ACTIONS \ + (PROV_MASK_IOOB_ACTION_PUSH | PROV_MASK_IOOB_ACTION_TWIST | \ + PROV_MASK_IOOB_ACTION_NUMERIC | PROV_MASK_IOOB_ACTION_ALPHANUMERIC) + +/** Input OOB Maximum size supported */ +#define UI_PROV_INPUT_OOB_SIZE 0x08 + +/** Beacon setup timeout in seconds */ +#define UI_PROV_SETUP_TIMEOUT_SECS 30 + +/** Attention timeout for device in seconds */ +#define UI_PROV_DEVICE_ATTENTION_TIMEOUT 30 + +#define PROV_AUTHVAL_SIZE_PL 16 + +/** Authentication values for OOB Display - To be made random */ +#define UI_DISPLAY_AUTH_DIGIT 3 +#define UI_DISPLAY_AUTH_NUMERIC 35007 +#define UI_DISPLAY_AUTH_STRING "f00l" + +/** Provisioning capabilities of local device */ +DECL_STATIC PROV_CAPABILITIES_S UI_prov_capab = +{ + /** Number of Elements */ + 0x01, + + /** Supported algorithms */ + PROV_MASK_ALGO_EC_FIPS_P256, + + /** Public key type */ + PROV_MASK_PUBKEY_OOBINFO, + + /** Static OOB type */ + PROV_MASK_STATIC_OOBINFO, + + /** Output OOB information */ + { UI_PROV_OUTPUT_OOB_ACTIONS, UI_PROV_OUTPUT_OOB_SIZE }, + + /** Input OOB information */ + { UI_PROV_INPUT_OOB_ACTIONS, UI_PROV_INPUT_OOB_SIZE }, +}; + +/** Unprovisioned device identifier */ +PROV_DEVICE_S UI_lprov_device = +{ + /** UUID */ + {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}, + + /** OOB Flag */ + 0x00, + + /** + Encoded URI Information + For example, to give a web address, "https://www.abc.com" + the URI encoded data would be - + 0x17 0x2F 0x2F 0x77 0x77 0x77 0x2E 0x61 0x62 0x63 0x2E 0x63 0x6F 0x6D + where 0x17 is the URI encoding for https: + */ + NULL +}; + +/** Data exchanged during Provisiong procedure */ +DECL_STATIC PROV_DATA_S UI_prov_data = +{ + /** NetKey */ + { 0x45, 0x74, 0x68, 0x65, 0x72, 0x4d, 0x69, 0x6e, 0x64, 0x4e, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x00 }, + + /** Index of the NetKey */ + 0x0000, + + /** Flags bitmask */ + 0x00, + + /** Current value of the IV index */ + 0x00000001, + + /** Unicast address of the primary element */ + 0x0002 +}; + + +/** Current role of application - Provisioner/Device */ +DECL_STATIC UCHAR UI_prov_role; + +/** Provisioning Handle */ +DECL_STATIC PROV_HANDLE UI_prov_handle; + +API_RESULT UI_prov_callback +( + PROV_HANDLE* phandle, + UCHAR event_type, + API_RESULT event_result, + void* event_data, + UINT16 event_datalen +) +{ + PROV_DEVICE_S* rdev; + PROV_CAPABILITIES_S* rcap; + PROV_DATA_S* rdata; + PROV_OOB_TYPE_S* oob_info; + API_RESULT retval; + UCHAR i; + UCHAR authstr[PROV_AUTHVAL_SIZE_PL << 1]; + UINT32 authnum; + UCHAR authtype; + UCHAR* pauth; + UINT16 authsize; + UCHAR pdata[(MS_DEVICE_UUID_SIZE * 2) + 1]; + UCHAR* t_data; + + switch (event_type) + { + case PROV_EVT_PROVISIONING_SETUP: + CONSOLE_OUT("Recvd PROV_EVT_PROVISIONING_SETUP\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Display the attention timeout */ + CONSOLE_OUT("Attention TImeout - %d\n", *((UCHAR*)event_data)); + break; + + case PROV_EVT_OOB_DISPLAY: + CONSOLE_OUT("Recvd PROV_EVT_OOB_DISPLAY\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Authenticatio Type information */ + oob_info = (PROV_OOB_TYPE_S*)event_data; + CONSOLE_OUT("Authenticaion Action - 0x%02X\n", oob_info->action); + CONSOLE_OUT("Authenticaion Size - 0x%02X\n", oob_info->size); + + /* If role is Device, the action is of Output OOB, else Input OOB */ + if (PROV_ROLE_DEVICE == UI_prov_role) + { + if (PROV_OOOB_ACTION_ALPHANUMERIC == oob_info->action) + { + authtype = 1; + } + else if (PROV_OOOB_ACTION_NUMERIC == oob_info->action) + { + authtype = 2; + } + else + { + authtype = 0; + } + } + else + { + if (PROV_IOOB_ACTION_ALPHANUMERIC == oob_info->action) + { + authtype = 1; + } + else if (PROV_IOOB_ACTION_NUMERIC == oob_info->action) + { + authtype = 2; + } + else + { + authtype = 0; + } + } + + if (1 == authtype) + { + EM_str_copy (authstr, UI_DISPLAY_AUTH_STRING); + CONSOLE_OUT("\n\n>>> AuthVal - %s <<<\n\n", authstr); + pauth = authstr; + authsize = EM_str_len(authstr); + } + else if (2 == authtype) + { + authnum = (UINT32)UI_DISPLAY_AUTH_NUMERIC; + CONSOLE_OUT("\n\n>>> AuthVal - %d <<<\n\n", authnum); + pauth = (UCHAR*)&authnum; + authsize = sizeof(UINT32); + } + else + { + authnum = (UINT32)UI_DISPLAY_AUTH_DIGIT; + CONSOLE_OUT("\n\n>>> AuthVal - %d <<<\n\n", authnum); + pauth = (UCHAR*)&authnum; + authsize = sizeof(UINT32); + } + + /* Call to input the oob */ + CONSOLE_OUT("Setting the Authval...\n"); + retval = MS_prov_set_authval(&UI_prov_handle, pauth, authsize); + CONSOLE_OUT("Retval - 0x%04X\n", retval); + break; + + case PROV_EVT_OOB_ENTRY: + CONSOLE_OUT("Recvd PROV_EVT_OOB_ENTRY\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Authenticatio Type information */ + oob_info = (PROV_OOB_TYPE_S*)event_data; + CONSOLE_OUT("Authenticaion Action - 0x%02X\n", oob_info->action); + CONSOLE_OUT("Authenticaion Size - 0x%02X\n", oob_info->size); + break; + + case PROV_EVT_DEVINPUT_COMPLETE: + CONSOLE_OUT("Recvd PROV_EVT_DEVINPUT_COMPLETE\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + break; + + case PROV_EVT_PROVDATA_INFO: + CONSOLE_OUT("Recvd PROV_EVT_PROVDATA_INFO\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Provisioning Data */ + rdata = (PROV_DATA_S*)event_data; + CONSOLE_OUT("NetKey : "); + appl_dump_bytes(rdata->netkey, PROV_KEY_NETKEY_SIZE); + CONSOLE_OUT("Key ID : 0x%04X\n", rdata->keyid); + CONSOLE_OUT("Flags : 0x%02X\n", rdata->flags); + CONSOLE_OUT("IVIndex : 0x%08X\n", rdata->ivindex); + CONSOLE_OUT("UAddr : 0x%04X\n", rdata->uaddr); + /* Provide Provisioning Data to Access Layer */ + MS_access_cm_set_prov_data + ( + rdata + ); + break; + + case PROV_EVT_PROVISIONING_COMPLETE: + CONSOLE_OUT("Recvd PROV_EVT_PROVISIONING_COMPLETE\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + + if (API_SUCCESS == event_result) + { + /* Already Set while handling PROV_EVT_PROVDATA_INFO */ + } + + break; + + default: + CONSOLE_OUT("Unknown Event - 0x%02X\n", event_type); + } + + return API_SUCCESS; +} + +void UI_register_prov(void) +{ + API_RESULT retval; + CONSOLE_OUT("Registering with Provisioning layer...\n"); + retval = MS_prov_register(&UI_prov_capab, UI_prov_callback); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void UI_setup_prov(UCHAR role, UCHAR brr) +{ + API_RESULT retval; + + if (PROV_ROLE_PROVISIONER != role) + { + CONSOLE_OUT("Setting up Device for Provisioning ...\n"); + retval = MS_prov_setup + ( + brr, + role, + &UI_lprov_device, + UI_PROV_SETUP_TIMEOUT_SECS + ); + UI_prov_role = PROV_ROLE_DEVICE; + } + else + { + CONSOLE_OUT("Setting up Provisioner for Provisioning ...\n"); + retval = MS_prov_setup + ( + brr, + role, + NULL, + UI_PROV_SETUP_TIMEOUT_SECS + ); + UI_prov_role = PROV_ROLE_PROVISIONER; + } + + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void UI_prov_bind(UCHAR brr, UCHAR index) +{ + API_RESULT retval; + /* Call to bind with the selected device */ + CONSOLE_OUT("Binding with the selected device...\n"); + retval = MS_prov_bind(brr, &UI_lprov_device, UI_PROV_DEVICE_ATTENTION_TIMEOUT, &UI_prov_handle); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void appl_mesh_sample (void) +{ + MS_ACCESS_NODE_ID node_id; + MS_ACCESS_ELEMENT_DESC element; + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + UCHAR role, brr; + MS_CONFIG* config_ptr; + #ifdef MS_HAVE_DYNAMIC_CONFIG + MS_CONFIG config; + /* Initialize dynamic configuration */ + MS_INIT_CONFIG(config); + config_ptr = &config; + #else + config_ptr = NULL; + #endif /* MS_HAVE_DYNAMIC_CONFIG */ + /* Initialize OSAL */ + EM_os_init(); + /* Initialize Debug Module */ + EM_debug_init(); + /* Initialize Timer Module */ + EM_timer_init(); + timer_em_init(); + /* Initialize utilities */ + nvsto_init(); + /* Initialize Mesh Stack */ + MS_init(config_ptr); + /* Register with underlying BLE stack */ + blebrr_register(); + /* Create Node */ + retval = MS_access_create_node(&node_id); + /* Register Element */ + /** + TBD: Define GATT Namespace Descriptions from + https://www.bluetooth.com/specifications/assigned-numbers/gatt-namespace-descriptors + + Using 'main' (0x0106) as Location temporarily. + */ + element.loc = 0x0106; + retval = MS_access_register_element + ( + node_id, + &element, + &element_handle + ); + + if (API_SUCCESS == retval) + { + /* Register foundation model servers */ + retval = UI_register_foundation_model_servers(element_handle); + } + + if (API_SUCCESS == retval) + { + /* Register Generic OnOff model server */ + retval = UI_register_generic_onoff_model_server(element_handle); + } + + if (API_SUCCESS == retval) + { + /* Initialize model states */ + UI_model_states_initialization(); + } + + /* Configure as provisionee/device */ + UI_register_prov(); + /** + setup onoff; + *param_p = UI_generic_onoff; + CONSOLE_OUT("[state] current: 0x%02X\n", UI_generic_onoff.onoff); + CONSOLE_OUT("[state] target: 0x%02X\n", UI_generic_onoff.target_onoff); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", UI_generic_onoff.transition_time); + /* Ignoring Instance and direction right now */ + /* LED ON/OFF for GENERIC ONOFF Abstraction Call */ + generic_onoff_set_pl (param_p->onoff); + } + break; + + default: + break; + } + + return retval; +} + +/* Model state Initialization */ +void UI_model_states_initialization(void) +{ + /* Generic OnOff States */ + UI_generic_onoff_model_states_initialization(); +} + +/* Generic OnOff Model Server */ +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT UI_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONOFF_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] GET Request.\n"); + UI_generic_onoff_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + /* Using same as target state and remaining time as 0 */ + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] SET Request.\n"); + retval = UI_generic_onoff_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT("[GENERIC_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +API_RESULT UI_register_generic_onoff_model_server +( + MS_ACCESS_ELEMENT_HANDLE element_handle +) +{ + /* Generic OnOff Server */ + MS_ACCESS_MODEL_HANDLE UI_generic_onoff_server_model_handle; + API_RESULT retval; + CONSOLE_OUT("In Generic OnOff Model Server\n"); + retval = MS_generic_onoff_server_init + ( + element_handle, + &UI_generic_onoff_server_model_handle, + UI_generic_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Onoff Server Initialized. Model Handle: 0x%04X\n", + UI_generic_onoff_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Onoff Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + return retval; +} + +void UI_lpn_seek_friend(void); +void UI_frndsetup_cb(MS_SUBNET_HANDLE subnet, UCHAR event_type, UINT16 status) +{ + API_RESULT retval; + UINT16 num_subaddr; + UINT16 subaddr[5]; + CONSOLE_OUT("\nFriendship Event 0x%02X on Subnet 0x%04X - 0x%04X\n", + event_type, subnet, status); + + switch (event_type) + { + case MS_TRN_FRIEND_SETUP_CNF: + CONSOLE_OUT("Recvd MS_TRN_FRIEND_SETUP_CNF - 0x%04X\n", status); + + if (API_SUCCESS == status) + { + /* Get the subscription list */ + num_subaddr = sizeof(subaddr) / sizeof(UINT16); + MS_access_cm_get_all_model_subscription_list(&num_subaddr, subaddr); + + if (0 < num_subaddr) + { + CONSOLE_OUT("Initiating FriendSubscriptionListAdd - %d addr\n", num_subaddr); + retval = MS_trn_lpn_subscrn_list_add(subaddr, num_subaddr); + CONSOLE_OUT("Retval - 0x%04X\n", retval); + } + } + else + { + CONSOLE_OUT("Friendship Setup Failure%04X\n", status); + UI_lpn_seek_friend(); // HZF: why seek again? + } + + break; + + case MS_TRN_FRIEND_SUBSCRNLIST_CNF: + CONSOLE_OUT("Recvd MS_TRN_FRIEND_SUBSCRNLIST_CNF - 0x%04X\n", status); + break; + + case MS_TRN_FRIEND_CLEAR_CNF: + CONSOLE_OUT("Recvd MS_TRN_FRIEND_CLEAR_CNF - 0x%04X\n", status); + break; + + case MS_TRN_FRIEND_TERMINATE_IND: + CONSOLE_OUT("Recvd MS_TRN_FRIEND_TERMINATE_IND - 0x%04X\n", status); + /* Enable Friend feature */ + MS_ENABLE_FRIEND_FEATURE(); + break; + + default: + break; + } +} + +void UI_lpn_seek_friend (void) +{ + API_RESULT retval; + blebrr_scan_pl(FALSE); // HZF + /* Disable Friend feature */ + MS_DISABLE_FRIEND_FEATURE(); + /* Enable LPN feature */ + MS_ENABLE_LPN_FEATURE(); + CONSOLE_OUT ("Requesting for friendship...\n"); + retval = MS_trn_lpn_setup_friendship + ( + 0x00, + UI_FRND_CRITERIA, + UI_FRND_RECEIVE_DELAY_MS, + UI_FRND_POLLTIMEOUT_100MS, + UI_FRND_SETUPTIMEOUT, + UI_frndsetup_cb + ); + CONSOLE_OUT ("Retval - 0x%04X\n", retval); + return; +} + + +/* Provisionee */ +/** Public Key OOB Flag */ +#define UI_PROV_PUBKEY_OOBINFO 0x00 + +/** Static OOB Flag */ +#define UI_PROV_STATIC_OOBINFO 0x00 + +/** Output OOB Actions Supported */ +#ifdef MESH_SAMPLE_HAVE_OUTPUT_OOB_DISPLAY + /** Currently Selecting the Output OOB Actions as Alphanumeric OOB Action */ + #define UI_PROV_OUTPUT_OOB_ACTIONS PROV_MASK_OOOB_ACTION_ALPHANUMERIC + + /** Output OOB Maximum size supported */ + #define UI_PROV_OUTPUT_OOB_SIZE 0x04 +#else /* MESH_SAMPLE_HAVE_OUTPUT_OOB_DISPLAY */ + /** Currently Selecting the Output OOB Actions as Alphanumeric OOB Action */ + #define UI_PROV_OUTPUT_OOB_ACTIONS 0x00 + + /** Output OOB Maximum size supported */ + #define UI_PROV_OUTPUT_OOB_SIZE 0x00 +#endif /* MESH_SAMPLE_HAVE_OUTPUT_OOB_DISPLAY */ + +/** Input OOB Actions supported */ +#define UI_PROV_INPUT_OOB_ACTIONS 0x00 + +/** Input OOB Maximum size supported */ +#define UI_PROV_INPUT_OOB_SIZE 0x00 + +/** Beacon setup timeout in seconds */ +#define UI_PROV_SETUP_TIMEOUT_SECS 30 + +/** Attention timeout for device in seconds */ +#define UI_PROV_DEVICE_ATTENTION_TIMEOUT 30 + +#define PROV_AUTHVAL_SIZE_PL 16 + +/** Authentication values for OOB Display - To be made random */ +#define UI_DISPLAY_AUTH_DIGIT 3 +#define UI_DISPLAY_AUTH_NUMERIC 35007 +#define UI_DISPLAY_AUTH_STRING "F00L" + +/** Provisioning capabilities of local device */ +DECL_STATIC PROV_CAPABILITIES_S UI_prov_capab = +{ + /** Number of Elements */ + 0x01, + + /** Supported algorithms */ + PROV_MASK_ALGO_EC_FIPS_P256, + + /** Public key type */ + UI_PROV_PUBKEY_OOBINFO, + + /** Static OOB type */ + UI_PROV_STATIC_OOBINFO, + + /** Output OOB information */ + { UI_PROV_OUTPUT_OOB_ACTIONS, UI_PROV_OUTPUT_OOB_SIZE }, + + /** Input OOB information */ + { UI_PROV_INPUT_OOB_ACTIONS, UI_PROV_INPUT_OOB_SIZE }, +}; + +/** Unprovisioned device identifier */ +PROV_DEVICE_S UI_lprov_device = +{ + /** UUID */ + {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}, + + /** OOB Flag */ + 0x00, + + /** + Encoded URI Information + For example, to give a web address, "https://www.abc.com" + the URI encoded data would be - + 0x17 0x2F 0x2F 0x77 0x77 0x77 0x2E 0x61 0x62 0x63 0x2E 0x63 0x6F 0x6D + where 0x17 is the URI encoding for https: + */ + NULL +}; + +/** Current role of application - Provisioner/Device */ +DECL_STATIC UCHAR UI_prov_role; + +/** Provisioning Handle */ +DECL_STATIC PROV_HANDLE UI_prov_handle; + +API_RESULT UI_prov_callback +( + PROV_HANDLE* phandle, + UCHAR event_type, + API_RESULT event_result, + void* event_data, + UINT16 event_datalen +) +{ + PROV_DATA_S* rdata; + PROV_OOB_TYPE_S* oob_info; + API_RESULT retval; + UCHAR authstr[PROV_AUTHVAL_SIZE_PL << 1]; + UINT32 authnum; + UCHAR authtype; + UCHAR* pauth; + UINT16 authsize; + + switch (event_type) + { + case PROV_EVT_PROVISIONING_SETUP: + CONSOLE_OUT("Recvd PROV_EVT_PROVISIONING_SETUP\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Display the attention timeout */ + CONSOLE_OUT("Attention TImeout - %d\n", *((UCHAR*)event_data)); + break; + + case PROV_EVT_OOB_DISPLAY: + CONSOLE_OUT("Recvd PROV_EVT_OOB_DISPLAY\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Authenticatio Type information */ + oob_info = (PROV_OOB_TYPE_S*)event_data; + CONSOLE_OUT("Authenticaion Action - 0x%02X\n", oob_info->action); + CONSOLE_OUT("Authenticaion Size - 0x%02X\n", oob_info->size); + + /* If role is Device, the action is of Output OOB, else Input OOB */ + if (PROV_ROLE_DEVICE == UI_prov_role) + { + if (PROV_OOOB_ACTION_ALPHANUMERIC == oob_info->action) + { + authtype = 1; + } + else if (PROV_OOOB_ACTION_NUMERIC == oob_info->action) + { + authtype = 2; + } + else + { + authtype = 0; + } + } + else + { + if (PROV_IOOB_ACTION_ALPHANUMERIC == oob_info->action) + { + authtype = 1; + } + else if (PROV_IOOB_ACTION_NUMERIC == oob_info->action) + { + authtype = 2; + } + else + { + authtype = 0; + } + } + + if (1 == authtype) + { + EM_str_copy (authstr, UI_DISPLAY_AUTH_STRING); + CONSOLE_OUT("\n\n>>> AuthVal - %s <<<\n\n", authstr); + pauth = authstr; + authsize = (UINT16)EM_str_len(authstr); + } + else if (2 == authtype) + { + authnum = (UINT32)UI_DISPLAY_AUTH_NUMERIC; + CONSOLE_OUT("\n\n>>> AuthVal - %d <<<\n\n", authnum); + pauth = (UCHAR*)&authnum; + authsize = sizeof(UINT32); + } + else + { + authnum = (UINT32)UI_DISPLAY_AUTH_DIGIT; + CONSOLE_OUT("\n\n>>> AuthVal - %d <<<\n\n", authnum); + pauth = (UCHAR*)&authnum; + authsize = sizeof(UINT32); + } + + /* Call to input the oob */ + CONSOLE_OUT("Setting the Authval...\n"); + retval = MS_prov_set_authval(&UI_prov_handle, pauth, authsize); + CONSOLE_OUT("Retval - 0x%04X\n", retval); + break; + + case PROV_EVT_OOB_ENTRY: + CONSOLE_OUT("Recvd PROV_EVT_OOB_ENTRY\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Authenticatio Type information */ + oob_info = (PROV_OOB_TYPE_S*)event_data; + CONSOLE_OUT("Authenticaion Action - 0x%02X\n", oob_info->action); + CONSOLE_OUT("Authenticaion Size - 0x%02X\n", oob_info->size); + break; + + case PROV_EVT_DEVINPUT_COMPLETE: + CONSOLE_OUT("Recvd PROV_EVT_DEVINPUT_COMPLETE\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + break; + + case PROV_EVT_PROVDATA_INFO: + CONSOLE_OUT("Recvd PROV_EVT_PROVDATA_INFO\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Provisioning Data */ + rdata = (PROV_DATA_S*)event_data; + CONSOLE_OUT("NetKey : "); + appl_dump_bytes(rdata->netkey, PROV_KEY_NETKEY_SIZE); + CONSOLE_OUT("Key ID : 0x%04X\n", rdata->keyid); + CONSOLE_OUT("Flags : 0x%02X\n", rdata->flags); + CONSOLE_OUT("IVIndex : 0x%08X\n", rdata->ivindex); + CONSOLE_OUT("UAddr : 0x%04X\n", rdata->uaddr); + /* Provide Provisioning Data to Access Layer */ + MS_access_cm_set_prov_data + ( + rdata + ); + break; + + case PROV_EVT_PROVISIONING_COMPLETE: + CONSOLE_OUT("Recvd PROV_EVT_PROVISIONING_COMPLETE\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + + if (API_SUCCESS == event_result) + { + /* Already Set while handling PROV_EVT_PROVDATA_INFO */ + /* LED ON/OFF for Provisioning Indication Abstraction Call */ + mesh_model_device_provisioned_ind_pl(); + } + + break; + + default: + CONSOLE_OUT("Unknown Event - 0x%02X\n", event_type); + } + + return API_SUCCESS; +} + +void UI_register_prov(void) +{ + API_RESULT retval; + CONSOLE_OUT("Registering with Provisioning layer...\n"); + retval = MS_prov_register(&UI_prov_capab, UI_prov_callback); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void UI_setup_prov(UCHAR role, UCHAR brr) +{ + API_RESULT retval; + + if (PROV_BRR_GATT == brr) + { + blebrr_gatt_mode_set(BLEBRR_GATT_PROV_MODE); + } + + if (PROV_ROLE_PROVISIONER != role) + { + CONSOLE_OUT("Setting up Device for Provisioning ...\n"); + retval = MS_prov_setup + ( + brr, + role, + &UI_lprov_device, + UI_PROV_SETUP_TIMEOUT_SECS + ); + UI_prov_role = PROV_ROLE_DEVICE; + } + else + { + CONSOLE_OUT("Setting up Provisioner for Provisioning ...\n"); + retval = MS_prov_setup + ( + brr, + role, + NULL, + UI_PROV_SETUP_TIMEOUT_SECS + ); + UI_prov_role = PROV_ROLE_PROVISIONER; + } + + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void UI_prov_bind(UCHAR brr, UCHAR index) +{ + API_RESULT retval; + /* Call to bind with the selected device */ + CONSOLE_OUT("Binding with the selected device...\n"); + retval = MS_prov_bind(brr, &UI_lprov_device, UI_PROV_DEVICE_ATTENTION_TIMEOUT, &UI_prov_handle); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void UI_proxy_start_adv(MS_SUBNET_HANDLE subnet_handle, UCHAR proxy_adv_mode) +{ + #ifdef MS_PROXY_SERVER + API_RESULT retval; + DECL_STATIC UINT8 first_time = 0; + + if (0 == first_time) + { + /** + Register with Proxy Module as Device is going to be a Proxy. + This is typically a one-time-event, and hence registering the + PROXY when Proxy ADV is being initiated! + */ + UI_register_proxy(); + first_time = 1; + } + + /* Set the role to Proxy with bearer */ + blebrr_gatt_mode_set(BLEBRR_GATT_PROXY_MODE); + CONSOLE_OUT("Start Proxy Advertisements with %s for Subnet 0x%04X\n", + (proxy_adv_mode == MS_PROXY_NET_ID_ADV_MODE) ? "Network ID" : "Node Identity", + subnet_handle); + retval = MS_proxy_server_adv_start + ( + subnet_handle, + proxy_adv_mode + ); + CONSOLE_OUT("Retval - 0x%04X\n", retval); + #else /* MS_PROXY_SERVER */ + CONSOLE_OUT("\n [** ERR **] MS_PROXY_SERVER feature is DISABLED!\n"); + return; + #endif /* MS_PROXY_SERVER */ +} + +void UI_proxy_callback +( + NETIF_HANDLE* handle, + UCHAR p_evt, + UCHAR* data_param, + UINT16 data_len +) +{ + UCHAR role; + MS_IGNORE_UNUSED_PARAM(data_len); + + switch(p_evt) + { + case MS_PROXY_UP_EVENT: + CONSOLE_OUT( + "\n\n[PROXY APPL]: MS_PROXY_UP_EVENT Received for NETIF Handle 0x%02X\n\n", *handle); + + if (NULL != data_param) + { + /* Catch the current role into a local */ + role = data_param[0]; + + if (BRR_SERVER_ROLE == role) + { + /* Send Secure Network Beacons */ + /* MS_net_broadcast_secure_beacon(0x0000); */ + } + } + + break; + + case MS_PROXY_DOWN_EVENT: + CONSOLE_OUT( + "\n\n[PROXY APPL]: MS_PROXY_DOWN_EVENT Received for NETIF Handle 0x%02X\n\n", *handle); + break; + + default: + CONSOLE_OUT( + "\n\n[PROXY APPL ERR]: Unknown Event Received for NETIF Handle 0x%02X!!\n\n", *handle); + break; + } +} + +void UI_register_proxy(void) +{ + API_RESULT retval; + CONSOLE_OUT("Registering with Proxy layer...\n"); + retval = MS_proxy_register(UI_proxy_callback); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +API_RESULT UI_set_brr_scan_rsp_data (void) +{ + /** + Currently setting MT-MESH-SAMPLE-10a as Complete Device Name! + This can be updated to each individual devices as per requirement. + */ + UCHAR UI_brr_scanrsp_data[] = + { + /** + Shortened Device Name: MT-MESH-SAMPLE-10a + */ + 0x11, 0x09, 'M', 'T', '-', 'M', 'E', 'S', 'H', '-', 'S', 'A', 'M', 'P', 'L', 'E', '-', '1', '0', 'a' + }; + CONSOLE_OUT("\n Setting MT-MESH-SAMPLE-8 as Complete Device Name!\n"); + /* Set the Scan Response Data at the Bearer Layer */ + blebrr_set_adv_scanrsp_data_pl + ( + UI_brr_scanrsp_data, + sizeof(UI_brr_scanrsp_data) + ); + return API_SUCCESS; +} + +EM_timer_handle thandle; +void timeout_cb (void* args, UINT16 size) +{ + thandle = EM_TIMER_HANDLE_INIT_VAL; + UI_sample_reinit(); +} + +void UI_gatt_iface_event_pl_cb +( + UCHAR ev_name, + UCHAR ev_param +) +{ + switch(ev_name) + { + /* GATT Bearer BLE Link Layer Disconnected */ + case BLEBRR_GATT_IFACE_DOWN: + CONSOLE_OUT("\r\n >> GATT Bearer BLE Link Layer Disconnection Event Received!\r\n"); + //UI_sample_reinit(); + EM_start_timer (&thandle, 3, timeout_cb, NULL, 0); + break; + + /* GATT Bearer BLE Link Layer Connected */ + case BLEBRR_GATT_IFACE_UP: + CONSOLE_OUT("\r\n >> GATT Bearer BLE Link Layer Connection Event Received!\r\n"); + + /* Do Nothing! */ + if (BLEBRR_GATT_PROV_MODE == blebrr_gatt_mode_get()) + { + MS_brr_bcast_end(BRR_BCON_TYPE_UNPROV_DEVICE, BRR_BCON_ACTIVE); + } + else if (BLEBRR_GATT_PROXY_MODE == blebrr_gatt_mode_get()) + { + MS_proxy_server_adv_stop(); + } + + break; + + case BLEBRR_GATT_IFACE_ENABLE: + CONSOLE_OUT("\r\n >> GATT Bearer Active Event Received!\r\n"); + { + if (BLEBRR_GATT_PROV_MODE == ev_param) + { + /* Call to bind with the selected device */ + UI_prov_bind(PROV_BRR_GATT, 0); + } + } + break; + + case BLEBRR_GATT_IFACE_DISABLE: + CONSOLE_OUT("\r\n >> GATT Bearer Inactive Event Received!\r\n"); + break; + + /* Unknown Event! */ + default: + CONSOLE_OUT("\r\n >> GATT Bearer BLE Link Layer Unknown Event 0x%02X Received!\r\n", ev_name); + /* Do Nothing! */ + break; + } +} + +void appl_mesh_sample (void) +{ + MS_ACCESS_NODE_ID node_id; + MS_ACCESS_ELEMENT_DESC element; + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + MS_CONFIG* config_ptr; + #ifdef MS_HAVE_DYNAMIC_CONFIG + MS_CONFIG config; + /* Initialize dynamic configuration */ + MS_INIT_CONFIG(config); + config_ptr = &config; + #else + config_ptr = NULL; + #endif /* MS_HAVE_DYNAMIC_CONFIG */ + /* Initialize OSAL */ + EM_os_init(); + /* Initialize Debug Module */ + EM_debug_init(); + /* Initialize Timer Module */ + EM_timer_init(); + timer_em_init(); + /* Initialize utilities */ + nvsto_init(); + /* Initialize Mesh Stack */ + MS_init(config_ptr); + /* Register with underlying BLE stack */ + blebrr_register(); + /* Register GATT Bearer Connection/Disconnection Event Hook */ + blebrr_register_gatt_iface_event_pl(UI_gatt_iface_event_pl_cb); + /* Enable LED Port */ + /* Platform Abstraction Initializations of GPIOs/LEDs etc. */ + mesh_model_platform_init_pl(); + /* LED ON */ + /* LED ON/OFF for BOOT UP Indication Abstraction Call */ + mesh_model_device_bootup_ind_pl(); + /* Create Node */ + retval = MS_access_create_node(&node_id); + /* Register Element */ + /** + TBD: Define GATT Namespace Descriptions from + https://www.bluetooth.com/specifications/assigned-numbers/gatt-namespace-descriptors + + Using 'main' (0x0106) as Location temporarily. + */ + element.loc = 0x0106; + retval = MS_access_register_element + ( + node_id, + &element, + &element_handle + ); + + if (API_SUCCESS == retval) + { + /* Register foundation model servers */ + retval = UI_register_foundation_model_servers(element_handle); + } + + if (API_SUCCESS == retval) + { + /* Register Generic OnOff model server */ + retval = UI_register_generic_onoff_model_server(element_handle); + } + + if (API_SUCCESS == retval) + { + /* Initialize model states */ + UI_model_states_initialization(); + } + + /* Configure as provisionee/device */ + UI_register_prov(); + /** + Set Scan Response Data Before Starting Provisioning. + This is optional/additional set of Data that the device can + set to enhance the User Experience. + For Example, set a specific device name or URL as part of the + Scan Response Data when awaiting connections over GATT bearer. + */ + UI_set_brr_scan_rsp_data(); + /* Enable Friend feature */ + MS_ENABLE_FRIEND_FEATURE(); + //UI_sample_reinit(); + EM_start_timer (&thandle, 5, timeout_cb, NULL, 0); + return; +} + +API_RESULT UI_sample_check_app_key(void) +{ + MS_APPKEY_HANDLE handle; + UINT8* key; + UINT8 aid; + UINT32 i; + DECL_CONST UINT8 t_key[16] = {0}; + API_RESULT retval; + CONSOLE_OUT("Fetching App Key for Handle 0x0000\n"); + handle = 0x0000; + retval = MS_access_cm_get_app_key + ( + handle, + &key, + &aid + ); + + /* Check Retval. Print App Key */ + if (API_SUCCESS == retval) + { + CONSOLE_OUT("App Key[0x%02X]: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\r\n", + handle, key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7], + key[8], key[9], key[10], key[11], key[12], key[13], key[14], key[15]); + + if (0 == EM_mem_cmp(key, t_key, 16)) + { + /* NO AppKey Bound */ + retval = API_FAILURE; + } + else + { + /* Found a Valid App Key */ + /* Keeping the retval as API_SUCCESS */ + } + } + + return retval; +} + +/** + On GATT Bearer Disconnection or on Startup: + 1. If device not provisioned, start unprovisioned beacons over GATT bearer + 2. If device is provisioned and App Key is bound i.e. Device is Configured + - Check if Proxy Feature is enabled then Start ADV as Proxy, + Else, + Do nothing! + Else, + If device is provisioned and App Key is not bound i.e. Device is not Configured + Start ADV as Proxy. +*/ +void UI_sample_reinit(void) +{ + API_RESULT retval; + MS_NET_ADDR addr; + UCHAR is_prov_req; + UCHAR role, brr; + UCHAR state; + retval = API_SUCCESS; + is_prov_req = MS_TRUE; + retval = MS_access_cm_get_primary_unicast_address(&addr); + + if (API_SUCCESS == retval) + { + if (MS_NET_ADDR_UNASSIGNED != addr) + { + /* Set Provisioning is not Required */ + is_prov_req = MS_FALSE; + } + } + + if (MS_TRUE == is_prov_req) + { + /* Start Provisioning over GATT here */ + /** + setup onoff; + *param_p = UI_generic_onoff; + CONSOLE_OUT("[state] current: 0x%02X\n", UI_generic_onoff.onoff); + CONSOLE_OUT("[state] target: 0x%02X\n", UI_generic_onoff.target_onoff); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", UI_generic_onoff.transition_time); + /* Ignoring Instance and direction right now */ + /* LED ON/OFF for GENERIC ONOFF Abstraction Call */ + generic_onoff_set_pl (param_p->onoff); + } + break; + + default: + break; + } + + return retval; +} + +/* Model state Initialization */ +void UI_model_states_initialization(void) +{ + /* Generic OnOff States */ + UI_generic_onoff_model_states_initialization(); +} + +/* Generic OnOff Model Server */ +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT UI_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONOFF_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] GET Request.\n"); + UI_generic_onoff_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + /* Using same as target state and remaining time as 0 */ + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] SET Request.\n"); + retval = UI_generic_onoff_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT("[GENERIC_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +API_RESULT UI_register_generic_onoff_model_server +( + MS_ACCESS_ELEMENT_HANDLE element_handle +) +{ + /* Generic OnOff Server */ + MS_ACCESS_MODEL_HANDLE UI_generic_onoff_server_model_handle; + API_RESULT retval; + CONSOLE_OUT("In Generic OnOff Model Server\n"); + retval = MS_generic_onoff_server_init + ( + element_handle, + &UI_generic_onoff_server_model_handle, + UI_generic_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Onoff Server Initialized. Model Handle: 0x%04X\n", + UI_generic_onoff_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Onoff Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + return retval; +} + +void UI_lpn_seek_friend(void); +void UI_frndsetup_cb(MS_SUBNET_HANDLE subnet, UCHAR event_type, UINT16 status) +{ + API_RESULT retval; + UINT16 num_subaddr; + UINT16 subaddr[5]; + CONSOLE_OUT("\nFriendship Event 0x%02X on Subnet 0x%04X - 0x%04X\n", + event_type, subnet, status); + + switch (event_type) + { + case MS_TRN_FRIEND_SETUP_CNF: + CONSOLE_OUT("Recvd MS_TRN_FRIEND_SETUP_CNF - 0x%04X\n", status); + + if (API_SUCCESS == status) + { + /* Get the subscription list */ + num_subaddr = sizeof(subaddr) / sizeof(UINT16); + MS_access_cm_get_all_model_subscription_list(&num_subaddr, subaddr); + + if (0 < num_subaddr) + { + CONSOLE_OUT("Initiating FriendSubscriptionListAdd - %d addr\n", num_subaddr); + retval = MS_trn_lpn_subscrn_list_add(subaddr, num_subaddr); + CONSOLE_OUT("Retval - 0x%04X\n", retval); + } + } + else + { + CONSOLE_OUT("Friendship Setup Failure%04X\n", status); + UI_lpn_seek_friend(); + } + + break; + + case MS_TRN_FRIEND_SUBSCRNLIST_CNF: + CONSOLE_OUT("Recvd MS_TRN_FRIEND_SUBSCRNLIST_CNF - 0x%04X\n", status); + break; + + case MS_TRN_FRIEND_CLEAR_CNF: + CONSOLE_OUT("Recvd MS_TRN_FRIEND_CLEAR_CNF - 0x%04X\n", status); + break; + + case MS_TRN_FRIEND_TERMINATE_IND: + CONSOLE_OUT("Recvd MS_TRN_FRIEND_TERMINATE_IND - 0x%04X\n", status); + /* Enable Friend feature */ + MS_ENABLE_FRIEND_FEATURE(); + break; + + default: + break; + } +} + +void UI_lpn_seek_friend (void) +{ + API_RESULT retval; + /* Disable Friend feature */ + MS_DISABLE_FRIEND_FEATURE(); + /* Enable LPN feature */ + MS_ENABLE_LPN_FEATURE(); + CONSOLE_OUT ("Requesting for friendship...\n"); + retval = MS_trn_lpn_setup_friendship + ( + 0x00, + UI_FRND_CRITERIA, + UI_FRND_RECEIVE_DELAY_MS, + UI_FRND_POLLTIMEOUT_100MS, + UI_FRND_SETUPTIMEOUT, + UI_frndsetup_cb + ); + CONSOLE_OUT ("Retval - 0x%04X\n", retval); + return; +} + + +/* Provisionee */ +/** Public Key OOB Flag */ +#define UI_PROV_PUBKEY_OOBINFO 0x00 + +/** Static OOB Flag */ +#define UI_PROV_STATIC_OOBINFO 0x00 + +/** Output OOB Actions Supported */ +#ifdef MESH_SAMPLE_HAVE_OUTPUT_OOB_DISPLAY + /** Currently Selecting the Output OOB Actions as Alphanumeric OOB Action */ + #define UI_PROV_OUTPUT_OOB_ACTIONS PROV_MASK_OOOB_ACTION_ALPHANUMERIC + + /** Output OOB Maximum size supported */ + #define UI_PROV_OUTPUT_OOB_SIZE 0x04 +#else /* MESH_SAMPLE_HAVE_OUTPUT_OOB_DISPLAY */ + /** Currently Selecting the Output OOB Actions as Alphanumeric OOB Action */ + #define UI_PROV_OUTPUT_OOB_ACTIONS 0x00 + + /** Output OOB Maximum size supported */ + #define UI_PROV_OUTPUT_OOB_SIZE 0x00 +#endif /* MESH_SAMPLE_HAVE_OUTPUT_OOB_DISPLAY */ + +/** Input OOB Actions supported */ +#define UI_PROV_INPUT_OOB_ACTIONS 0x00 + +/** Input OOB Maximum size supported */ +#define UI_PROV_INPUT_OOB_SIZE 0x00 + +/** Beacon setup timeout in seconds */ +#define UI_PROV_SETUP_TIMEOUT_SECS 30 + +/** Attention timeout for device in seconds */ +#define UI_PROV_DEVICE_ATTENTION_TIMEOUT 30 + +#define PROV_AUTHVAL_SIZE_PL 16 + +/** Authentication values for OOB Display - To be made random */ +#define UI_DISPLAY_AUTH_DIGIT 3 +#define UI_DISPLAY_AUTH_NUMERIC 35007 +#define UI_DISPLAY_AUTH_STRING "F00L" + +/** Provisioning capabilities of local device */ +DECL_STATIC PROV_CAPABILITIES_S UI_prov_capab = +{ + /** Number of Elements */ + 0x01, + + /** Supported algorithms */ + PROV_MASK_ALGO_EC_FIPS_P256, + + /** Public key type */ + UI_PROV_PUBKEY_OOBINFO, + + /** Static OOB type */ + UI_PROV_STATIC_OOBINFO, + + /** Output OOB information */ + { UI_PROV_OUTPUT_OOB_ACTIONS, UI_PROV_OUTPUT_OOB_SIZE }, + + /** Input OOB information */ + { UI_PROV_INPUT_OOB_ACTIONS, UI_PROV_INPUT_OOB_SIZE }, +}; + +/** Unprovisioned device identifier */ +PROV_DEVICE_S UI_lprov_device = +{ + /** UUID */ + {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}, + + /** OOB Flag */ + 0x00, + + /** + Encoded URI Information + For example, to give a web address, "https://www.abc.com" + the URI encoded data would be - + 0x17 0x2F 0x2F 0x77 0x77 0x77 0x2E 0x61 0x62 0x63 0x2E 0x63 0x6F 0x6D + where 0x17 is the URI encoding for https: + */ + NULL +}; + +/** Current role of application - Provisioner/Device */ +DECL_STATIC UCHAR UI_prov_role; + +/** Provisioning Handle */ +DECL_STATIC PROV_HANDLE UI_prov_handle; + +API_RESULT UI_prov_callback +( + PROV_HANDLE* phandle, + UCHAR event_type, + API_RESULT event_result, + void* event_data, + UINT16 event_datalen +) +{ + PROV_DATA_S* rdata; + PROV_OOB_TYPE_S* oob_info; + API_RESULT retval; + UCHAR authstr[PROV_AUTHVAL_SIZE_PL << 1]; + UINT32 authnum; + UCHAR authtype; + UCHAR* pauth; + UINT16 authsize; + + switch (event_type) + { + case PROV_EVT_PROVISIONING_SETUP: + CONSOLE_OUT("Recvd PROV_EVT_PROVISIONING_SETUP\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Display the attention timeout */ + CONSOLE_OUT("Attention TImeout - %d\n", *((UCHAR*)event_data)); + break; + + case PROV_EVT_OOB_DISPLAY: + CONSOLE_OUT("Recvd PROV_EVT_OOB_DISPLAY\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Authenticatio Type information */ + oob_info = (PROV_OOB_TYPE_S*)event_data; + CONSOLE_OUT("Authenticaion Action - 0x%02X\n", oob_info->action); + CONSOLE_OUT("Authenticaion Size - 0x%02X\n", oob_info->size); + + /* If role is Device, the action is of Output OOB, else Input OOB */ + if (PROV_ROLE_DEVICE == UI_prov_role) + { + if (PROV_OOOB_ACTION_ALPHANUMERIC == oob_info->action) + { + authtype = 1; + } + else if (PROV_OOOB_ACTION_NUMERIC == oob_info->action) + { + authtype = 2; + } + else + { + authtype = 0; + } + } + else + { + if (PROV_IOOB_ACTION_ALPHANUMERIC == oob_info->action) + { + authtype = 1; + } + else if (PROV_IOOB_ACTION_NUMERIC == oob_info->action) + { + authtype = 2; + } + else + { + authtype = 0; + } + } + + if (1 == authtype) + { + EM_str_copy (authstr, UI_DISPLAY_AUTH_STRING); + CONSOLE_OUT("\n\n>>> AuthVal - %s <<<\n\n", authstr); + pauth = authstr; + authsize = (UINT16)EM_str_len(authstr); + } + else if (2 == authtype) + { + authnum = (UINT32)UI_DISPLAY_AUTH_NUMERIC; + CONSOLE_OUT("\n\n>>> AuthVal - %d <<<\n\n", authnum); + pauth = (UCHAR*)&authnum; + authsize = sizeof(UINT32); + } + else + { + authnum = (UINT32)UI_DISPLAY_AUTH_DIGIT; + CONSOLE_OUT("\n\n>>> AuthVal - %d <<<\n\n", authnum); + pauth = (UCHAR*)&authnum; + authsize = sizeof(UINT32); + } + + /* Call to input the oob */ + CONSOLE_OUT("Setting the Authval...\n"); + retval = MS_prov_set_authval(&UI_prov_handle, pauth, authsize); + CONSOLE_OUT("Retval - 0x%04X\n", retval); + break; + + case PROV_EVT_OOB_ENTRY: + CONSOLE_OUT("Recvd PROV_EVT_OOB_ENTRY\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Authenticatio Type information */ + oob_info = (PROV_OOB_TYPE_S*)event_data; + CONSOLE_OUT("Authenticaion Action - 0x%02X\n", oob_info->action); + CONSOLE_OUT("Authenticaion Size - 0x%02X\n", oob_info->size); + break; + + case PROV_EVT_DEVINPUT_COMPLETE: + CONSOLE_OUT("Recvd PROV_EVT_DEVINPUT_COMPLETE\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + break; + + case PROV_EVT_PROVDATA_INFO: + CONSOLE_OUT("Recvd PROV_EVT_PROVDATA_INFO\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Provisioning Data */ + rdata = (PROV_DATA_S*)event_data; + CONSOLE_OUT("NetKey : "); + appl_dump_bytes(rdata->netkey, PROV_KEY_NETKEY_SIZE); + CONSOLE_OUT("Key ID : 0x%04X\n", rdata->keyid); + CONSOLE_OUT("Flags : 0x%02X\n", rdata->flags); + CONSOLE_OUT("IVIndex : 0x%08X\n", rdata->ivindex); + CONSOLE_OUT("UAddr : 0x%04X\n", rdata->uaddr); + /* Provide Provisioning Data to Access Layer */ + MS_access_cm_set_prov_data + ( + rdata + ); + break; + + case PROV_EVT_PROVISIONING_COMPLETE: + CONSOLE_OUT("Recvd PROV_EVT_PROVISIONING_COMPLETE\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + + if (API_SUCCESS == event_result) + { + /* Already Set while handling PROV_EVT_PROVDATA_INFO */ + /* LED ON/OFF for Provisioning Indication Abstraction Call */ + mesh_model_device_provisioned_ind_pl(); + } + + break; + + default: + CONSOLE_OUT("Unknown Event - 0x%02X\n", event_type); + } + + return API_SUCCESS; +} + +void UI_register_prov(void) +{ + API_RESULT retval; + CONSOLE_OUT("Registering with Provisioning layer...\n"); + retval = MS_prov_register(&UI_prov_capab, UI_prov_callback); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void UI_setup_prov(UCHAR role, UCHAR brr) +{ + API_RESULT retval; + + if (PROV_BRR_GATT == brr) + { + blebrr_gatt_mode_set(BLEBRR_GATT_PROV_MODE); + } + + if (PROV_ROLE_PROVISIONER != role) + { + CONSOLE_OUT("Setting up Device for Provisioning ...\n"); + retval = MS_prov_setup + ( + brr, + role, + &UI_lprov_device, + UI_PROV_SETUP_TIMEOUT_SECS + ); + UI_prov_role = PROV_ROLE_DEVICE; + } + else + { + CONSOLE_OUT("Setting up Provisioner for Provisioning ...\n"); + retval = MS_prov_setup + ( + brr, + role, + NULL, + UI_PROV_SETUP_TIMEOUT_SECS + ); + UI_prov_role = PROV_ROLE_PROVISIONER; + } + + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void UI_prov_bind(UCHAR brr, UCHAR index) +{ + API_RESULT retval; + /* Call to bind with the selected device */ + CONSOLE_OUT("Binding with the selected device...\n"); + retval = MS_prov_bind(brr, &UI_lprov_device, UI_PROV_DEVICE_ATTENTION_TIMEOUT, &UI_prov_handle); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void UI_proxy_start_adv(MS_SUBNET_HANDLE subnet_handle, UCHAR proxy_adv_mode) +{ + #ifdef MS_PROXY_SERVER + API_RESULT retval; + DECL_STATIC UINT8 first_time = 0; + + if (0 == first_time) + { + /** + Register with Proxy Module as Device is going to be a Proxy. + This is typically a one-time-event, and hence registering the + PROXY when Proxy ADV is being initiated! + */ + UI_register_proxy(); + first_time = 1; + } + + /* Set the role to Proxy with bearer */ + blebrr_gatt_mode_set(BLEBRR_GATT_PROXY_MODE); + CONSOLE_OUT("Start Proxy Advertisements with %s for Subnet 0x%04X\n", + (proxy_adv_mode == MS_PROXY_NET_ID_ADV_MODE) ? "Network ID" : "Node Identity", + subnet_handle); + retval = MS_proxy_server_adv_start + ( + subnet_handle, + proxy_adv_mode + ); + CONSOLE_OUT("Retval - 0x%04X\n", retval); + #else /* MS_PROXY_SERVER */ + CONSOLE_OUT("\n [** ERR **] MS_PROXY_SERVER feature is DISABLED!\n"); + return; + #endif /* MS_PROXY_SERVER */ +} + +void UI_proxy_callback +( + NETIF_HANDLE* handle, + UCHAR p_evt, + UCHAR* data_param, + UINT16 data_len +) +{ + UCHAR role; + MS_IGNORE_UNUSED_PARAM(data_len); + + switch(p_evt) + { + case MS_PROXY_UP_EVENT: + CONSOLE_OUT( + "\n\n[PROXY APPL]: MS_PROXY_UP_EVENT Received for NETIF Handle 0x%02X\n\n", *handle); + + if (NULL != data_param) + { + /* Catch the current role into a local */ + role = data_param[0]; + + if (BRR_SERVER_ROLE == role) + { + /* Send Secure Network Beacons */ + /* MS_net_broadcast_secure_beacon(0x0000); */ + } + } + + break; + + case MS_PROXY_DOWN_EVENT: + CONSOLE_OUT( + "\n\n[PROXY APPL]: MS_PROXY_DOWN_EVENT Received for NETIF Handle 0x%02X\n\n", *handle); + break; + + default: + CONSOLE_OUT( + "\n\n[PROXY APPL ERR]: Unknown Event Received for NETIF Handle 0x%02X!!\n\n", *handle); + break; + } +} + +void UI_register_proxy(void) +{ + API_RESULT retval; + CONSOLE_OUT("Registering with Proxy layer...\n"); + retval = MS_proxy_register(UI_proxy_callback); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +API_RESULT UI_set_brr_scan_rsp_data (void) +{ + /** + Currently setting MT-MESH-SAMPLE-10a as Complete Device Name! + This can be updated to each individual devices as per requirement. + */ + UCHAR UI_brr_scanrsp_data[] = + { + /** + Shortened Device Name: MT-MESH-SAMPLE-11 + */ + 0x12, 0x09, 'M', 'T', '-', 'M', 'E', 'S', 'H', '-', 'S', 'A', 'M', 'P', 'L', 'E', '-', '1', '1' + }; + CONSOLE_OUT("\n Setting MT-MESH-SAMPLE-11 as Complete Device Name!\n"); + /* Set the Scan Response Data at the Bearer Layer */ + blebrr_set_adv_scanrsp_data_pl + ( + UI_brr_scanrsp_data, + sizeof(UI_brr_scanrsp_data) + ); + return API_SUCCESS; +} + +EM_timer_handle thandle; +void timeout_cb (void* args, UINT16 size) +{ + thandle = EM_TIMER_HANDLE_INIT_VAL; + UI_sample_reinit(); +} + +void UI_gatt_iface_event_pl_cb +( + UCHAR ev_name, + UCHAR ev_param +) +{ + switch(ev_name) + { + /* GATT Bearer BLE Link Layer Disconnected */ + case BLEBRR_GATT_IFACE_DOWN: + CONSOLE_OUT("\r\n >> GATT Bearer BLE Link Layer Disconnection Event Received!\r\n"); + //UI_sample_reinit(); + EM_start_timer (&thandle, 3, timeout_cb, NULL, 0); + break; + + /* GATT Bearer BLE Link Layer Connected */ + case BLEBRR_GATT_IFACE_UP: + CONSOLE_OUT("\r\n >> GATT Bearer BLE Link Layer Connection Event Received!\r\n"); + + /* Do Nothing! */ + if (BLEBRR_GATT_PROV_MODE == blebrr_gatt_mode_get()) + { + MS_brr_bcast_end(BRR_BCON_TYPE_UNPROV_DEVICE, BRR_BCON_ACTIVE); + } + else if (BLEBRR_GATT_PROXY_MODE == blebrr_gatt_mode_get()) + { + MS_proxy_server_adv_stop(); + } + + break; + + case BLEBRR_GATT_IFACE_ENABLE: + CONSOLE_OUT("\r\n >> GATT Bearer Active Event Received!\r\n"); + { + if (BLEBRR_GATT_PROV_MODE == ev_param) + { + /* Call to bind with the selected device */ + UI_prov_bind(PROV_BRR_GATT, 0); + } + } + break; + + case BLEBRR_GATT_IFACE_DISABLE: + CONSOLE_OUT("\r\n >> GATT Bearer Inactive Event Received!\r\n"); + break; + + /* Unknown Event! */ + default: + CONSOLE_OUT("\r\n >> GATT Bearer BLE Link Layer Unknown Event 0x%02X Received!\r\n", ev_name); + /* Do Nothing! */ + break; + } +} + +void appl_mesh_sample (void) +{ + MS_ACCESS_NODE_ID node_id; + MS_ACCESS_ELEMENT_DESC element; + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + MS_CONFIG* config_ptr; + #ifdef MS_HAVE_DYNAMIC_CONFIG + MS_CONFIG config; + /* Initialize dynamic configuration */ + MS_INIT_CONFIG(config); + config_ptr = &config; + #else + config_ptr = NULL; + #endif /* MS_HAVE_DYNAMIC_CONFIG */ + /* Initialize OSAL */ + EM_os_init(); + /* Initialize Debug Module */ + EM_debug_init(); + /* Initialize Timer Module */ + EM_timer_init(); + timer_em_init(); + /* Initialize utilities */ + nvsto_init(); + /* Initialize Mesh Stack */ + MS_init(config_ptr); + /* Register with underlying BLE stack */ + blebrr_register(); + /* Register GATT Bearer Connection/Disconnection Event Hook */ + blebrr_register_gatt_iface_event_pl(UI_gatt_iface_event_pl_cb); + /* Enable LED Port */ + /* Platform Abstraction Initializations of GPIOs/LEDs etc. */ + mesh_model_platform_init_pl(); + /* LED ON */ + /* LED ON/OFF for BOOT UP Indication Abstraction Call */ + mesh_model_device_bootup_ind_pl(); + /* Create Node */ + retval = MS_access_create_node(&node_id); + /* Register Element */ + /** + TBD: Define GATT Namespace Descriptions from + https://www.bluetooth.com/specifications/assigned-numbers/gatt-namespace-descriptors + + Using 'main' (0x0106) as Location temporarily. + */ + element.loc = 0x0106; + retval = MS_access_register_element + ( + node_id, + &element, + &element_handle + ); + + if (API_SUCCESS == retval) + { + /* Register foundation model servers */ + retval = UI_register_foundation_model_servers(element_handle); + } + + if (API_SUCCESS == retval) + { + /* Register Generic OnOff model server */ + retval = UI_register_generic_onoff_model_server(element_handle); + } + + if (API_SUCCESS == retval) + { + /* Initialize model states */ + UI_model_states_initialization(); + } + + /* Configure as provisionee/device */ + UI_register_prov(); + /** + Set Scan Response Data Before Starting Provisioning. + This is optional/additional set of Data that the device can + set to enhance the User Experience. + For Example, set a specific device name or URL as part of the + Scan Response Data when awaiting connections over GATT bearer. + */ + UI_set_brr_scan_rsp_data(); + /* Enable Friend feature */ + MS_ENABLE_FRIEND_FEATURE(); + //UI_sample_reinit(); + EM_start_timer (&thandle, 5, timeout_cb, NULL, 0); + return; +} + +API_RESULT UI_sample_check_app_key(void) +{ + MS_APPKEY_HANDLE handle; + UINT8* key; + UINT8 aid; + DECL_CONST UINT8 t_key[16] = {0}; + API_RESULT retval; + CONSOLE_OUT("Fetching App Key for Handle 0x0000\n"); + handle = 0x0000; + retval = MS_access_cm_get_app_key + ( + handle, + &key, + &aid + ); + + /* Check Retval. Print App Key */ + if (API_SUCCESS == retval) + { + CONSOLE_OUT("App Key[0x%02X]: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\r\n", + handle, key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7], + key[8], key[9], key[10], key[11], key[12], key[13], key[14], key[15]); + + if (0 == EM_mem_cmp(key, t_key, 16)) + { + /* NO AppKey Bound */ + retval = API_FAILURE; + } + else + { + /* Found a Valid App Key */ + /* Keeping the retval as API_SUCCESS */ + } + } + + return retval; +} + +/** + On GATT Bearer Disconnection or on Startup: + 1. If device not provisioned, start unprovisioned beacons over GATT bearer + 2. If device is provisioned and App Key is bound i.e. Device is Configured + - Check if Proxy Feature is enabled then Start ADV as Proxy, + Else, + Do nothing! + Else, + If device is provisioned and App Key is not bound i.e. Device is not Configured + Start ADV as Proxy. +*/ +void UI_sample_reinit(void) +{ + API_RESULT retval; + MS_NET_ADDR addr; + UCHAR is_prov_req; + UCHAR role, brr; + UCHAR state; + retval = API_SUCCESS; + is_prov_req = MS_TRUE; + retval = MS_access_cm_get_primary_unicast_address(&addr); + + if (API_SUCCESS == retval) + { + if (MS_NET_ADDR_UNASSIGNED != addr) + { + /* Set Provisioning is not Required */ + is_prov_req = MS_FALSE; + } + } + + if (MS_TRUE == is_prov_req) + { + /* Start Provisioning over GATT here */ + /** + setup onoff; + *param_p = UI_generic_onoff; + CONSOLE_OUT("[state] current: 0x%02X\n", UI_generic_onoff.onoff); + CONSOLE_OUT("[state] target: 0x%02X\n", UI_generic_onoff.target_onoff); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", UI_generic_onoff.transition_time); + generic_onoff_set_pl(param_p->onoff); + /* Ignoring Instance and direction right now */ + } + break; + + default: + break; + } + + return retval; +} + +/* Light Lightness Model state Initialization */ +void UI_light_lightness_model_states_initialization(void) +{ + /* Light Lightness States */ + EM_mem_set(&UI_light_lightness, 0, sizeof(UI_light_lightness)); + UI_light_lightness.light_lightness_last.lightness_last = 0xFFFF; +} + +/* Light Lightness Model Get Handler */ +API_RESULT UI_light_lightness_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + MS_STATE_LIGHT_LIGHTNESS_STRUCT* param_p; + API_RESULT retval; + param_p = (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)param; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_default = UI_light_lightness.light_lightness_default; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_range = UI_light_lightness.light_lightness_range; + param_p->range_status = 0x00; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_linear = UI_light_lightness.light_lightness_linear; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_last = UI_light_lightness.light_lightness_last; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + { + /* Ignoring Instance and direction right now */ + param_p->light_lightness_actual = UI_light_lightness.light_lightness_actual; + } + break; + + default: + break; + } + + return retval; +} + +/* Light Lightness Model Set Handler */ +/* Todo: Remove the dependency */ +#include "math.h" + +static void UI_light_lightness_set_actual(UINT16 state_inst, UINT16 actual) +{ + UINT16 min, max; + /* Generic OnOff binding */ + min = UI_light_lightness.light_lightness_range.lightness_range_min; + max = UI_light_lightness.light_lightness_range.lightness_range_max; + + if ((0 != min) && (actual < min)) + { + actual = min; + } + else if ((0 != max) && (actual > max)) + { + actual = max; + } + + /* If Lightness Actual is non-zero, save as Lightness Last */ + if (0x0000 != actual) + { + UI_light_lightness.light_lightness_last.lightness_last = actual; + } + + UI_light_lightness.light_lightness_actual.lightness_actual = actual; + /* Light Lightness Linear = ((Actual)^2) / 65535 */ + UI_light_lightness.light_lightness_linear.lightness_linear = ((actual * actual) + 65534) / 65535; +} + +static void UI_light_lightness_set_linear(UINT16 state_inst, UINT16 linear) +{ + UINT16 actual; + UINT32 mul_val; + mul_val = linear * 65535; + actual = (UINT16)sqrt(mul_val); + /* Light Lightness actual = sqrt(Linear * 65535) */ + UI_light_lightness_set_actual(state_inst, actual); +} + +API_RESULT UI_light_lightness_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + MS_STATE_LIGHT_LIGHTNESS_STRUCT* param_p; + API_RESULT retval; + param_p = (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)param; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_LIGHT_LIGHTNESS_DEFAULT_T: + { + /* Ignoring Instance and direction right now */ + UI_light_lightness.light_lightness_default = param_p->light_lightness_default; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_RANGE_T: + { + /* Check range min and max */ + if (param_p->light_lightness_range.lightness_range_min > param_p->light_lightness_range.lightness_range_max) + { + /* TODO: add macro define */ + /** + Table 7.2: + 0x00 - Success + 0x01 - Cannot Set Range Min + 0x02 - Cannot Set Range Max + */ + param_p->range_status = 0x01; + } + else + { + /* Ignoring Instance and direction right now */ + UI_light_lightness.light_lightness_range = param_p->light_lightness_range; + param_p->range_status = 0x00; + } + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LINEAR_T: + { + /* Instantaneous Change */ + UI_light_lightness_set_linear(0, param_p->light_lightness_linear.lightness_linear); + *param_p = UI_light_lightness; + CONSOLE_OUT("[state] current: 0x%02X\n", param_p->light_lightness_linear.lightness_linear); + CONSOLE_OUT("[state] target: 0x%02X\n", param_p->light_lightness_linear.lightness_target); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", param_p->light_lightness_linear.transition_time); + /* Ignoring Instance and direction right now */ + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_LAST_T: + { + /* Ignoring Instance and direction right now */ + UI_light_lightness.light_lightness_last = param_p->light_lightness_last; + } + break; + + case MS_STATE_LIGHT_LIGHTNESS_ACTUAL_T: + { + /* Instantaneous Change */ + UI_light_lightness_set_actual(0, param_p->light_lightness_actual.lightness_actual); + *param_p = UI_light_lightness; + CONSOLE_OUT("[state] current: 0x%02X\n", param_p->light_lightness_actual.lightness_actual); + CONSOLE_OUT("[state] target: 0x%02X\n", param_p->light_lightness_actual.lightness_target); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", param_p->light_lightness_actual.transition_time); + } + break; + + default: + break; + } + + return retval; +} + +/* Model state Initialization */ +void UI_model_states_initialization(void) +{ + /* Generic OnOff States */ + UI_generic_onoff_model_states_initialization(); + /* Light Lightness States */ + UI_light_lightness_model_states_initialization(); +} + +/* Generic OnOff Model Server */ +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT UI_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONOFF_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] GET Request.\n"); + UI_generic_onoff_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + /* Using same as target state and remaining time as 0 */ + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] SET Request.\n"); + retval = UI_generic_onoff_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT("[GENERIC_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +API_RESULT UI_register_generic_onoff_model_server +( + MS_ACCESS_ELEMENT_HANDLE element_handle +) +{ + /* Generic OnOff Server */ + MS_ACCESS_MODEL_HANDLE UI_generic_onoff_server_model_handle; + API_RESULT retval; + CONSOLE_OUT("In Generic OnOff Model Server\n"); + retval = MS_generic_onoff_server_init + ( + element_handle, + &UI_generic_onoff_server_model_handle, + UI_generic_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Onoff Server Initialized. Model Handle: 0x%04X\n", + UI_generic_onoff_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Onoff Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + return retval; +} + +/* Light Ligthness Model Server */ +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Light_Lightness server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT UI_light_lightness_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_LIGHT_LIGHTNESS_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] GET Request.\n"); + UI_light_lightness_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] SET Request.\n"); + UI_light_lightness_model_state_set(state_params->state_type, 0, (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_LIGHT_LIGHTNESS_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[LIGHT_LIGHTNESS] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_light_lightness_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +API_RESULT UI_register_light_lightness_model_server +( + MS_ACCESS_ELEMENT_HANDLE element_handle +) +{ + /* Generic OnOff Server */ + MS_ACCESS_MODEL_HANDLE UI_light_lightness_server_model_handle; + API_RESULT retval; + retval = MS_light_lightness_server_init + ( + element_handle, + &UI_light_lightness_server_model_handle, + UI_light_lightness_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Light Lightness Server Initialized. Model Handle: 0x%04X\n", + UI_light_lightness_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Light Lightness Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + return retval; +} + +/* Provisionee */ +#define UI_PROV_OUTPUT_OOB_ACTIONS \ + (PROV_MASK_OOOB_ACTION_BLINK | PROV_MASK_OOOB_ACTION_BEEP | \ + PROV_MASK_OOOB_ACTION_VIBRATE | PROV_MASK_OOOB_ACTION_NUMERIC | \ + PROV_MASK_OOOB_ACTION_ALPHANUMERIC) + +/** Output OOB Maximum size supported */ +#define UI_PROV_OUTPUT_OOB_SIZE 0x08 + +/** Input OOB Actions supported */ +#define UI_PROV_INPUT_OOB_ACTIONS \ + (PROV_MASK_IOOB_ACTION_PUSH | PROV_MASK_IOOB_ACTION_TWIST | \ + PROV_MASK_IOOB_ACTION_NUMERIC | PROV_MASK_IOOB_ACTION_ALPHANUMERIC) + +/** Input OOB Maximum size supported */ +#define UI_PROV_INPUT_OOB_SIZE 0x08 + +/** Beacon setup timeout in seconds */ +#define UI_PROV_SETUP_TIMEOUT_SECS 30 + +/** Attention timeout for device in seconds */ +#define UI_PROV_DEVICE_ATTENTION_TIMEOUT 30 + +#define PROV_AUTHVAL_SIZE_PL 16 + +/** Authentication values for OOB Display - To be made random */ +#define UI_DISPLAY_AUTH_DIGIT 3 +#define UI_DISPLAY_AUTH_NUMERIC 35007 +#define UI_DISPLAY_AUTH_STRING "f00l" + +/** Provisioning capabilities of local device */ +DECL_STATIC PROV_CAPABILITIES_S UI_prov_capab = +{ + /** Number of Elements */ + 0x02, + + /** Supported algorithms */ + PROV_MASK_ALGO_EC_FIPS_P256, + + /** Public key type */ + PROV_MASK_PUBKEY_OOBINFO, + + /** Static OOB type */ + PROV_MASK_STATIC_OOBINFO, + + /** Output OOB information */ + { UI_PROV_OUTPUT_OOB_ACTIONS, UI_PROV_OUTPUT_OOB_SIZE }, + + /** Input OOB information */ + { UI_PROV_INPUT_OOB_ACTIONS, UI_PROV_INPUT_OOB_SIZE }, +}; + +/** Unprovisioned device identifier */ +PROV_DEVICE_S UI_lprov_device = +{ + /** UUID */ + {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}, + + /** OOB Flag */ + 0x00, + + /** + Encoded URI Information + For example, to give a web address, "https://www.abc.com" + the URI encoded data would be - + 0x17 0x2F 0x2F 0x77 0x77 0x77 0x2E 0x61 0x62 0x63 0x2E 0x63 0x6F 0x6D + where 0x17 is the URI encoding for https: + */ + NULL +}; + +/** Data exchanged during Provisiong procedure */ +DECL_STATIC PROV_DATA_S UI_prov_data = +{ + /** NetKey */ + { 0x45, 0x74, 0x68, 0x65, 0x72, 0x4d, 0x69, 0x6e, 0x64, 0x4e, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x00 }, + + /** Index of the NetKey */ + 0x0000, + + /** Flags bitmask */ + 0x00, + + /** Current value of the IV index */ + 0x00000001, + + /** Unicast address of the primary element */ + 0x0002 +}; + + +/** Current role of application - Provisioner/Device */ +DECL_STATIC UCHAR UI_prov_role; + +/** Provisioning Handle */ +DECL_STATIC PROV_HANDLE UI_prov_handle; + +API_RESULT UI_prov_callback +( + PROV_HANDLE* phandle, + UCHAR event_type, + API_RESULT event_result, + void* event_data, + UINT16 event_datalen +) +{ + PROV_DATA_S* rdata; + PROV_OOB_TYPE_S* oob_info; + API_RESULT retval; + UCHAR authstr[PROV_AUTHVAL_SIZE_PL << 1]; + UINT32 authnum; + UCHAR authtype; + UCHAR* pauth; + UINT16 authsize; + + switch (event_type) + { + case PROV_EVT_PROVISIONING_SETUP: + CONSOLE_OUT("Recvd PROV_EVT_PROVISIONING_SETUP\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Display the attention timeout */ + CONSOLE_OUT("Attention TImeout - %d\n", *((UCHAR*)event_data)); + break; + + case PROV_EVT_OOB_DISPLAY: + CONSOLE_OUT("Recvd PROV_EVT_OOB_DISPLAY\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Authenticatio Type information */ + oob_info = (PROV_OOB_TYPE_S*)event_data; + CONSOLE_OUT("Authenticaion Action - 0x%02X\n", oob_info->action); + CONSOLE_OUT("Authenticaion Size - 0x%02X\n", oob_info->size); + + /* If role is Device, the action is of Output OOB, else Input OOB */ + if (PROV_ROLE_DEVICE == UI_prov_role) + { + if (PROV_OOOB_ACTION_ALPHANUMERIC == oob_info->action) + { + authtype = 1; + } + else if (PROV_OOOB_ACTION_NUMERIC == oob_info->action) + { + authtype = 2; + } + else + { + authtype = 0; + } + } + else + { + if (PROV_IOOB_ACTION_ALPHANUMERIC == oob_info->action) + { + authtype = 1; + } + else if (PROV_IOOB_ACTION_NUMERIC == oob_info->action) + { + authtype = 2; + } + else + { + authtype = 0; + } + } + + if (1 == authtype) + { + EM_str_copy (authstr, UI_DISPLAY_AUTH_STRING); + CONSOLE_OUT("\n\n>>> AuthVal - %s <<<\n\n", authstr); + pauth = authstr; + authsize = EM_str_len(authstr); + } + else if (2 == authtype) + { + authnum = (UINT32)UI_DISPLAY_AUTH_NUMERIC; + CONSOLE_OUT("\n\n>>> AuthVal - %d <<<\n\n", authnum); + pauth = (UCHAR*)&authnum; + authsize = sizeof(UINT32); + } + else + { + authnum = (UINT32)UI_DISPLAY_AUTH_DIGIT; + CONSOLE_OUT("\n\n>>> AuthVal - %d <<<\n\n", authnum); + pauth = (UCHAR*)&authnum; + authsize = sizeof(UINT32); + } + + /* Call to input the oob */ + CONSOLE_OUT("Setting the Authval...\n"); + retval = MS_prov_set_authval(&UI_prov_handle, pauth, authsize); + CONSOLE_OUT("Retval - 0x%04X\n", retval); + break; + + case PROV_EVT_OOB_ENTRY: + CONSOLE_OUT("Recvd PROV_EVT_OOB_ENTRY\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Authenticatio Type information */ + oob_info = (PROV_OOB_TYPE_S*)event_data; + CONSOLE_OUT("Authenticaion Action - 0x%02X\n", oob_info->action); + CONSOLE_OUT("Authenticaion Size - 0x%02X\n", oob_info->size); + break; + + case PROV_EVT_DEVINPUT_COMPLETE: + CONSOLE_OUT("Recvd PROV_EVT_DEVINPUT_COMPLETE\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + break; + + case PROV_EVT_PROVDATA_INFO: + CONSOLE_OUT("Recvd PROV_EVT_PROVDATA_INFO\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Provisioning Data */ + rdata = (PROV_DATA_S*)event_data; + CONSOLE_OUT("NetKey : "); + appl_dump_bytes(rdata->netkey, PROV_KEY_NETKEY_SIZE); + CONSOLE_OUT("Key ID : 0x%04X\n", rdata->keyid); + CONSOLE_OUT("Flags : 0x%02X\n", rdata->flags); + CONSOLE_OUT("IVIndex : 0x%08X\n", rdata->ivindex); + CONSOLE_OUT("UAddr : 0x%04X\n", rdata->uaddr); + /* Provide Provisioning Data to Access Layer */ + MS_access_cm_set_prov_data + ( + rdata + ); + break; + + case PROV_EVT_PROVISIONING_COMPLETE: + CONSOLE_OUT("Recvd PROV_EVT_PROVISIONING_COMPLETE\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + + if (API_SUCCESS == event_result) + { + /* Already Set while handling PROV_EVT_PROVDATA_INFO */ + } + + break; + + default: + CONSOLE_OUT("Unknown Event - 0x%02X\n", event_type); + } + + return API_SUCCESS; +} + +void UI_register_prov(void) +{ + API_RESULT retval; + CONSOLE_OUT("Registering with Provisioning layer...\n"); + retval = MS_prov_register(&UI_prov_capab, UI_prov_callback); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void UI_setup_prov(UCHAR role, UCHAR brr) +{ + API_RESULT retval; + + if (PROV_ROLE_PROVISIONER != role) + { + CONSOLE_OUT("Setting up Device for Provisioning ...\n"); + retval = MS_prov_setup + ( + brr, + role, + &UI_lprov_device, + UI_PROV_SETUP_TIMEOUT_SECS + ); + UI_prov_role = PROV_ROLE_DEVICE; + } + else + { + CONSOLE_OUT("Setting up Provisioner for Provisioning ...\n"); + retval = MS_prov_setup + ( + brr, + role, + NULL, + UI_PROV_SETUP_TIMEOUT_SECS + ); + UI_prov_role = PROV_ROLE_PROVISIONER; + } + + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void UI_prov_bind(UCHAR brr, UCHAR index) +{ + API_RESULT retval; + /* Call to bind with the selected device */ + CONSOLE_OUT("Binding with the selected device...\n"); + retval = MS_prov_bind(brr, &UI_lprov_device, UI_PROV_DEVICE_ATTENTION_TIMEOUT, &UI_prov_handle); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void appl_mesh_sample (void) +{ + MS_ACCESS_NODE_ID node_id; + MS_ACCESS_ELEMENT_DESC element; + MS_ACCESS_ELEMENT_HANDLE element_handle; + MS_ACCESS_ELEMENT_DESC element_1; + MS_ACCESS_ELEMENT_HANDLE element_handle_1; + API_RESULT retval; + UCHAR role, brr; + MS_CONFIG* config_ptr; + #ifdef MS_HAVE_DYNAMIC_CONFIG + MS_CONFIG config; + /* Initialize dynamic configuration */ + MS_INIT_CONFIG(config); + config_ptr = &config; + #else + config_ptr = NULL; + #endif /* MS_HAVE_DYNAMIC_CONFIG */ + /* Initialize OSAL */ + EM_os_init(); + /* Initialize Debug Module */ + EM_debug_init(); + /* Initialize Timer Module */ + EM_timer_init(); + timer_em_init(); + /* Initialize utilities */ + nvsto_init(); + /* Initialize Mesh Stack */ + MS_init(config_ptr); + /* Register with underlying BLE stack */ + blebrr_register(); + /* Create Node */ + retval = MS_access_create_node(&node_id); + /* Register Element */ + /** + TBD: Define GATT Namespace Descriptions from + https://www.bluetooth.com/specifications/assigned-numbers/gatt-namespace-descriptors + + Using 'main' (0x0106) as Location temporarily. + */ + element.loc = 0x0106; + retval = MS_access_register_element + ( + node_id, + &element, + &element_handle + ); + + if (API_SUCCESS == retval) + { + /* Register foundation model servers */ + retval = UI_register_foundation_model_servers(element_handle); + } + + if (API_SUCCESS == retval) + { + /* Register Generic OnOff model server */ + retval = UI_register_generic_onoff_model_server(element_handle); + } + + /* Register another Element */ + /** + TBD: Define GATT Namespace Descriptions from + https://www.bluetooth.com/specifications/assigned-numbers/gatt-namespace-descriptors + + Using 'main' (0x0106) as Location temporarily. + */ + element_1.loc = 0x0106; + retval = MS_access_register_element + ( + node_id, + &element_1, + &element_handle_1 + ); + + if (API_SUCCESS == retval) + { + /* Register Light Lightness model server */ + retval = UI_register_light_lightness_model_server(element_handle_1); + } + + if (API_SUCCESS == retval) + { + /* Initialize model states */ + UI_model_states_initialization(); + } + + /* Configure as provisionee/device */ + UI_register_prov(); + /** + setup state_type) + { + } + + /* Publish - reliable */ + if (0 == marker) + { + pdu_ptr = NULL; + } + else + { + pdu_ptr = buffer; + } + + retval = MS_access_reply + ( + &ctx->handle, + ctx->daddr, + ctx->saddr, + ctx->subnet_handle, + ctx->appkey_handle, + ACCESS_INVALID_DEFAULT_TTL, + opcode, + pdu_ptr, + marker + ); + return retval; +} + +/* Empty Model Opcode Handler Defines */ +MODEL_OPCODE_HANDLER_EMPTY_DEF(vendor_example_set_handler) +MODEL_OPCODE_HANDLER_EMPTY_DEF(vendor_example_get_handler) +MODEL_OPCODE_HANDLER_EMPTY_DEF(vendor_example_set_unacknowledged_handler) + +/** + \brief Access Layer Application Asynchronous Notification Callback. + + \par Description + Access Layer calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] saddr 16 bit Source Address. + \param [in] daddr 16 bit Destination Address. + \param [in] appkey_handle AppKey Handle. + \param [in] subnet_handle Subnet Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +API_RESULT vendor_example_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ MS_NET_ADDR saddr, + /* IN */ MS_NET_ADDR daddr, + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ MS_APPKEY_HANDLE appkey_handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + MS_ACCESS_MODEL_REQ_MSG_CONTEXT req_context; + MS_ACCESS_MODEL_REQ_MSG_RAW req_raw; + MS_ACCESS_MODEL_REQ_MSG_T req_type; + MS_ACCESS_MODEL_EXT_PARAMS* ext_params_p; + MS_ACCESS_MODEL_STATE_PARAMS state_params; + UINT16 marker; + API_RESULT retval; + retval = API_SUCCESS; + ext_params_p = NULL; + /* Request Context */ + req_context.handle = *handle; + req_context.saddr = saddr; + req_context.daddr = daddr; + req_context.subnet_handle = subnet_handle; + req_context.appkey_handle = appkey_handle; + /* Request Raw */ + req_raw.opcode = opcode; + req_raw.data_param = data_param; + req_raw.data_len = data_len; + CONSOLE_OUT( + "[VENDOR_EXAMPLE_SERVER] Callback. Opcode 0x%04X\n", opcode); + appl_dump_bytes(data_param, data_len); + + switch(opcode) + { + case MS_ACCESS_VENDOR_EXAMPLE_GET_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_VENDOR_EXAMPLE_GET_OPCODE\n"); + MODEL_OPCODE_HANDLER_CALL(vendor_example_get_handler); + /* Get Request Type */ + req_type.type = MS_ACCESS_MODEL_REQ_MSG_T_GET; + req_type.to_be_acked = 0x01; + /* Assign reqeusted state type to the application */ + state_params.state_type = MS_STATE_VENDOR_EXAMPLE_T; + } + break; + + case MS_ACCESS_VENDOR_EXAMPLE_SET_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_VENDOR_EXAMPLE_SET_OPCODE\n"); + MODEL_OPCODE_HANDLER_CALL(vendor_example_set_handler); + /* Set Request Type */ + req_type.type = MS_ACCESS_MODEL_REQ_MSG_T_SET; + req_type.to_be_acked = 0x01; + } + break; + + case MS_ACCESS_VENDOR_EXAMPLE_SET_UNACKNOWLEDGED_OPCODE: + { + CONSOLE_OUT( + "MS_ACCESS_VENDOR_EXAMPLE_SET_UNACKNOWLEDGED_OPCODE\n"); + MODEL_OPCODE_HANDLER_CALL(vendor_example_set_unacknowledged_handler); + /* Set Request Type */ + req_type.type = MS_ACCESS_MODEL_REQ_MSG_T_SET; + req_type.to_be_acked = 0x00; + } + break; + } + + /* Application callback */ + if (NULL != vendor_example_server_UI_cb) + { + vendor_example_server_UI_cb(&req_context, &req_raw, &req_type, &state_params, ext_params_p); + } + + return retval; +} + +/** + \brief API to initialize Vendor_Example_1 Server model + + \par Description + This is to initialize Vendor_Example_1 Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] UI_cb Application Callback to be used by the Vendor_Example_1 Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_vendor_example_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_VENDOR_EXAMPLE_SERVER_CB UI_cb +) +{ + API_RESULT retval; + MS_ACCESS_NODE_ID node_id; + MS_ACCESS_MODEL model; + /* TBD: Initialize MUTEX and other data structures */ + /* Using default node ID */ + node_id = MS_ACCESS_DEFAULT_NODE_ID; + CONSOLE_OUT( + "[VENDOR_EXAMPLE] Registered Element Handle 0x%02X\n", element_handle); + /* Configure Model */ + model.model_id.id = MS_MODEL_ID_VENDOR_EXAMPLE_SERVER; + model.model_id.type = MS_ACCESS_MODEL_TYPE_VENDOR; + model.elem_handle = element_handle; + /* Register Callback */ + model.cb = vendor_example_server_cb; + /* List of Opcodes */ + model.opcodes = vendor_example_server_opcode_list; + model.num_opcodes = sizeof(vendor_example_server_opcode_list) / sizeof(UINT32); + retval = MS_access_register_model + ( + node_id, + &model, + model_handle + ); + /* Save Application Callback */ + vendor_example_server_UI_cb = UI_cb; + /* TODO: Remove */ + vendor_example_server_model_handle = *model_handle; + return retval; +} + + +/* Model Server - Foundation Models */ + +/* Health Server - Test Routines */ +static void UI_health_self_test_00(UINT8 test_id, UINT16 company_id) +{ +} + +static void UI_health_self_test_01(UINT8 test_id, UINT16 company_id) +{ +} + +static void UI_health_self_test_FF(UINT8 test_id, UINT16 company_id) +{ +} + +/* List of Self Tests */ +static MS_HEALTH_SERVER_SELF_TEST UI_health_server_self_tests[] = +{ + { + 0x00, /* Test ID: 0x00 */ + UI_health_self_test_00 + }, + { + 0x01, /* Test ID: 0x01 */ + UI_health_self_test_01 + }, + { + 0xFF, /* Test ID: 0xFF */ + UI_health_self_test_FF + } +}; + +/** + \brief Health Server application Asynchronous Notification Callback. + + \par Description + Health Server calls the registered callback to indicate events occurred to the + application. + + \param handle Model Handle. + \param event_type Health Server Event type. + \param event_param Parameter associated with the event if any or NULL. + \param param_len Size of the event parameter data. 0 if event param is NULL. +*/ +static API_RESULT UI_health_server_cb +( + MS_ACCESS_MODEL_HANDLE* handle, + UINT8 event_type, + UINT8* event_param, + UINT16 param_len +) +{ + CONSOLE_OUT( + "Health Server Callback. Not handled. Returning\n"); + return API_SUCCESS; +} + +API_RESULT UI_register_foundation_model_servers +( + MS_ACCESS_ELEMENT_HANDLE element_handle +) +{ + /* Configuration Server */ + MS_ACCESS_MODEL_HANDLE UI_config_server_model_handle; + MS_ACCESS_MODEL_HANDLE UI_health_server_model_handle; + API_RESULT retval; + /* Health Server */ + UINT16 company_id; + MS_HEALTH_SERVER_SELF_TEST* self_tests; + UINT32 num_self_tests; + CONSOLE_OUT("In Model Server - Foundation Models\n"); + retval = MS_config_server_init(element_handle, &UI_config_server_model_handle); + CONSOLE_OUT("Config Model Server Registration Status: 0x%04X\n", retval); + /* Health Server */ + company_id = 0x0000; + self_tests = &UI_health_server_self_tests[0]; + num_self_tests = sizeof(UI_health_server_self_tests)/sizeof(MS_HEALTH_SERVER_SELF_TEST); + retval = MS_health_server_init + ( + element_handle, + &UI_health_server_model_handle, + company_id, + self_tests, + num_self_tests, + UI_health_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Health Server Initialized. Model Handle: 0x%04X\n", + UI_health_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Sensor Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + return retval; +} + + +/* ---- Generic OnOff States */ +static MS_STATE_GENERIC_ONOFF_STRUCT UI_generic_onoff; + +/** -- Vendor Defined States */ +static MS_STATE_VENDOR_EXAMPLE_STRUCT UI_vendor_example; + +/* Get/Set State Handlers */ + +/* Generic OnOff Model state Initialization */ +void UI_generic_onoff_model_states_initialization(void) +{ + EM_mem_set(&UI_generic_onoff, 0, sizeof(UI_generic_onoff)); +} + +/* Generic OnOff Model Get Handler */ +API_RESULT UI_generic_onoff_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch(state_t) + { + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = UI_generic_onoff; + } + break; + + default: + break; + } + + return retval; +} + +/* Generic OnOff Model Set Handler */ +API_RESULT UI_generic_onoff_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + API_RESULT retval; + retval = API_SUCCESS; + + switch (state_t) + { + case MS_STATE_GENERIC_ONOFF_T: + { + MS_STATE_GENERIC_ONOFF_STRUCT* param_p; + param_p = (MS_STATE_GENERIC_ONOFF_STRUCT*)param; + /* Instantaneous Change */ + UI_generic_onoff.onoff = param_p->onoff; + *param_p = UI_generic_onoff; + CONSOLE_OUT("[state] current: 0x%02X\n", UI_generic_onoff.onoff); + CONSOLE_OUT("[state] target: 0x%02X\n", UI_generic_onoff.target_onoff); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", UI_generic_onoff.transition_time); + generic_onoff_set_pl(param_p->onoff); + /* Ignoring Instance and direction right now */ + } + break; + + default: + break; + } + + return retval; +} + +/* Vendor Defined Model state Initialization */ +void UI_vendor_defined_model_states_initialization(void) +{ + /* Vendor Defined States */ + EM_mem_set (&UI_vendor_example, 0, sizeof(UI_vendor_example)); +} + +/* Vendor Defined Model Get Handler */ +void UI_vendor_example_model_state_get(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + switch(state_t) + { + case MS_STATE_VENDOR_EXAMPLE_T: + { + MS_STATE_VENDOR_EXAMPLE_STRUCT* param_p; + param_p = (MS_STATE_VENDOR_EXAMPLE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + *param_p = UI_vendor_example; + } + break; + + default: + break; + } +} + +/* Vendor Defined Model Set Handler */ +void UI_vendor_example_model_state_set(UINT16 state_t, UINT16 state_inst, void* param, UINT8 direction) +{ + switch(state_t) + { + case MS_STATE_VENDOR_EXAMPLE_T: + { + MS_STATE_VENDOR_EXAMPLE_STRUCT* param_p; + param_p = (MS_STATE_VENDOR_EXAMPLE_STRUCT*)param; + /* Ignoring Instance and direction right now */ + UI_vendor_example = *param_p; + } + break; + + default: + break; + } +} + + +/* Model state Initialization */ +void UI_model_states_initialization(void) +{ + /* Generic OnOff States */ + UI_generic_onoff_model_states_initialization(); + /* Vendor Defined States */ + UI_vendor_defined_model_states_initialization(); +} + +/* Generic OnOff Model Server */ +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT UI_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONOFF_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] GET Request.\n"); + UI_generic_onoff_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + /* Using same as target state and remaining time as 0 */ + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] SET Request.\n"); + retval = UI_generic_onoff_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT("[GENERIC_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +API_RESULT UI_register_generic_onoff_model_server +( + MS_ACCESS_ELEMENT_HANDLE element_handle +) +{ + /* Generic OnOff Server */ + MS_ACCESS_MODEL_HANDLE UI_generic_onoff_server_model_handle; + API_RESULT retval; + CONSOLE_OUT("In Generic OnOff Model Server\n"); + retval = MS_generic_onoff_server_init + ( + element_handle, + &UI_generic_onoff_server_model_handle, + UI_generic_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Onoff Server Initialized. Model Handle: 0x%04X\n", + UI_generic_onoff_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Onoff Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + return retval; +} + +/* Vendor Defined Model Server */ +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Vendor_Example_1 server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT UI_vendor_example_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_VENDOR_EXAMPLE_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT( + "[VENDOR_EXAMPLE] GET Request.\n"); + UI_vendor_example_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT( + "[VENDOR_EXAMPLE] SET Request.\n"); + UI_vendor_example_model_state_set(state_params->state_type, 0, (MS_STATE_VENDOR_EXAMPLE_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_VENDOR_EXAMPLE_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT( + "[VENDOR_EXAMPLE] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_vendor_example_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +API_RESULT UI_register_vendor_defined_model_server +( + MS_ACCESS_ELEMENT_HANDLE element_handle +) +{ + /* Vendor Defined Server */ + MS_ACCESS_MODEL_HANDLE UI_vendor_defined_server_model_handle; + API_RESULT retval; + retval = MS_vendor_example_server_init + ( + element_handle, + &UI_vendor_defined_server_model_handle, + UI_vendor_example_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Vendor Defined Server Initialized. Model Handle: 0x%04X\n", + UI_vendor_defined_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Vendor Defined Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + return retval; +} + +/* Provisionee */ +#define UI_PROV_OUTPUT_OOB_ACTIONS \ + (PROV_MASK_OOOB_ACTION_BLINK | PROV_MASK_OOOB_ACTION_BEEP | \ + PROV_MASK_OOOB_ACTION_VIBRATE | PROV_MASK_OOOB_ACTION_NUMERIC | \ + PROV_MASK_OOOB_ACTION_ALPHANUMERIC) + +/** Output OOB Maximum size supported */ +#define UI_PROV_OUTPUT_OOB_SIZE 0x08 + +/** Input OOB Actions supported */ +#define UI_PROV_INPUT_OOB_ACTIONS \ + (PROV_MASK_IOOB_ACTION_PUSH | PROV_MASK_IOOB_ACTION_TWIST | \ + PROV_MASK_IOOB_ACTION_NUMERIC | PROV_MASK_IOOB_ACTION_ALPHANUMERIC) + +/** Input OOB Maximum size supported */ +#define UI_PROV_INPUT_OOB_SIZE 0x08 + +/** Beacon setup timeout in seconds */ +#define UI_PROV_SETUP_TIMEOUT_SECS 30 + +/** Attention timeout for device in seconds */ +#define UI_PROV_DEVICE_ATTENTION_TIMEOUT 30 + +#define PROV_AUTHVAL_SIZE_PL 16 + +/** Authentication values for OOB Display - To be made random */ +#define UI_DISPLAY_AUTH_DIGIT 3 +#define UI_DISPLAY_AUTH_NUMERIC 35007 +#define UI_DISPLAY_AUTH_STRING "f00l" + +/** Provisioning capabilities of local device */ +DECL_STATIC PROV_CAPABILITIES_S UI_prov_capab = +{ + /** Number of Elements */ + 0x01, + + /** Supported algorithms */ + PROV_MASK_ALGO_EC_FIPS_P256, + + /** Public key type */ + PROV_MASK_PUBKEY_OOBINFO, + + /** Static OOB type */ + PROV_MASK_STATIC_OOBINFO, + + /** Output OOB information */ + { UI_PROV_OUTPUT_OOB_ACTIONS, UI_PROV_OUTPUT_OOB_SIZE }, + + /** Input OOB information */ + { UI_PROV_INPUT_OOB_ACTIONS, UI_PROV_INPUT_OOB_SIZE }, +}; + +/** Unprovisioned device identifier */ +PROV_DEVICE_S UI_lprov_device = +{ + /** UUID */ + {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}, + + /** OOB Flag */ + 0x00, + + /** + Encoded URI Information + For example, to give a web address, "https://www.abc.com" + the URI encoded data would be - + 0x17 0x2F 0x2F 0x77 0x77 0x77 0x2E 0x61 0x62 0x63 0x2E 0x63 0x6F 0x6D + where 0x17 is the URI encoding for https: + */ + NULL +}; + +/** Data exchanged during Provisiong procedure */ +DECL_STATIC PROV_DATA_S UI_prov_data = +{ + /** NetKey */ + { 0x45, 0x74, 0x68, 0x65, 0x72, 0x4d, 0x69, 0x6e, 0x64, 0x4e, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x00 }, + + /** Index of the NetKey */ + 0x0000, + + /** Flags bitmask */ + 0x00, + + /** Current value of the IV index */ + 0x00000001, + + /** Unicast address of the primary element */ + 0x0002 +}; + + +/** Current role of application - Provisioner/Device */ +DECL_STATIC UCHAR UI_prov_role; + +/** Provisioning Handle */ +DECL_STATIC PROV_HANDLE UI_prov_handle; + +API_RESULT UI_prov_callback +( + PROV_HANDLE* phandle, + UCHAR event_type, + API_RESULT event_result, + void* event_data, + UINT16 event_datalen +) +{ + PROV_DEVICE_S* rdev; + PROV_CAPABILITIES_S* rcap; + PROV_DATA_S* rdata; + PROV_OOB_TYPE_S* oob_info; + API_RESULT retval; + UCHAR i; + UCHAR authstr[PROV_AUTHVAL_SIZE_PL << 1]; + UINT32 authnum; + UCHAR authtype; + UCHAR* pauth; + UINT16 authsize; + UCHAR pdata[(MS_DEVICE_UUID_SIZE * 2) + 1]; + UCHAR* t_data; + + switch (event_type) + { + case PROV_EVT_PROVISIONING_SETUP: + CONSOLE_OUT("Recvd PROV_EVT_PROVISIONING_SETUP\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Display the attention timeout */ + CONSOLE_OUT("Attention TImeout - %d\n", *((UCHAR*)event_data)); + break; + + case PROV_EVT_OOB_DISPLAY: + CONSOLE_OUT("Recvd PROV_EVT_OOB_DISPLAY\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Authenticatio Type information */ + oob_info = (PROV_OOB_TYPE_S*)event_data; + CONSOLE_OUT("Authenticaion Action - 0x%02X\n", oob_info->action); + CONSOLE_OUT("Authenticaion Size - 0x%02X\n", oob_info->size); + + /* If role is Device, the action is of Output OOB, else Input OOB */ + if (PROV_ROLE_DEVICE == UI_prov_role) + { + if (PROV_OOOB_ACTION_ALPHANUMERIC == oob_info->action) + { + authtype = 1; + } + else if (PROV_OOOB_ACTION_NUMERIC == oob_info->action) + { + authtype = 2; + } + else + { + authtype = 0; + } + } + else + { + if (PROV_IOOB_ACTION_ALPHANUMERIC == oob_info->action) + { + authtype = 1; + } + else if (PROV_IOOB_ACTION_NUMERIC == oob_info->action) + { + authtype = 2; + } + else + { + authtype = 0; + } + } + + if (1 == authtype) + { + EM_str_copy (authstr, UI_DISPLAY_AUTH_STRING); + CONSOLE_OUT("\n\n>>> AuthVal - %s <<<\n\n", authstr); + pauth = authstr; + authsize = EM_str_len(authstr); + } + else if (2 == authtype) + { + authnum = (UINT32)UI_DISPLAY_AUTH_NUMERIC; + CONSOLE_OUT("\n\n>>> AuthVal - %d <<<\n\n", authnum); + pauth = (UCHAR*)&authnum; + authsize = sizeof(UINT32); + } + else + { + authnum = (UINT32)UI_DISPLAY_AUTH_DIGIT; + CONSOLE_OUT("\n\n>>> AuthVal - %d <<<\n\n", authnum); + pauth = (UCHAR*)&authnum; + authsize = sizeof(UINT32); + } + + /* Call to input the oob */ + CONSOLE_OUT("Setting the Authval...\n"); + retval = MS_prov_set_authval(&UI_prov_handle, pauth, authsize); + CONSOLE_OUT("Retval - 0x%04X\n", retval); + break; + + case PROV_EVT_OOB_ENTRY: + CONSOLE_OUT("Recvd PROV_EVT_OOB_ENTRY\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Authenticatio Type information */ + oob_info = (PROV_OOB_TYPE_S*)event_data; + CONSOLE_OUT("Authenticaion Action - 0x%02X\n", oob_info->action); + CONSOLE_OUT("Authenticaion Size - 0x%02X\n", oob_info->size); + break; + + case PROV_EVT_DEVINPUT_COMPLETE: + CONSOLE_OUT("Recvd PROV_EVT_DEVINPUT_COMPLETE\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + break; + + case PROV_EVT_PROVDATA_INFO: + CONSOLE_OUT("Recvd PROV_EVT_PROVDATA_INFO\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Provisioning Data */ + rdata = (PROV_DATA_S*)event_data; + CONSOLE_OUT("NetKey : "); + appl_dump_bytes(rdata->netkey, PROV_KEY_NETKEY_SIZE); + CONSOLE_OUT("Key ID : 0x%04X\n", rdata->keyid); + CONSOLE_OUT("Flags : 0x%02X\n", rdata->flags); + CONSOLE_OUT("IVIndex : 0x%08X\n", rdata->ivindex); + CONSOLE_OUT("UAddr : 0x%04X\n", rdata->uaddr); + /* Provide Provisioning Data to Access Layer */ + MS_access_cm_set_prov_data + ( + rdata + ); + break; + + case PROV_EVT_PROVISIONING_COMPLETE: + CONSOLE_OUT("Recvd PROV_EVT_PROVISIONING_COMPLETE\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + + if (API_SUCCESS == event_result) + { + /* Already Set while handling PROV_EVT_PROVDATA_INFO */ + } + + break; + + default: + CONSOLE_OUT("Unknown Event - 0x%02X\n", event_type); + } + + return API_SUCCESS; +} + +void UI_register_prov(void) +{ + API_RESULT retval; + CONSOLE_OUT("Registering with Provisioning layer...\n"); + retval = MS_prov_register(&UI_prov_capab, UI_prov_callback); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void UI_setup_prov(UCHAR role, UCHAR brr) +{ + API_RESULT retval; + + if (PROV_ROLE_PROVISIONER != role) + { + CONSOLE_OUT("Setting up Device for Provisioning ...\n"); + retval = MS_prov_setup + ( + brr, + role, + &UI_lprov_device, + UI_PROV_SETUP_TIMEOUT_SECS + ); + UI_prov_role = PROV_ROLE_DEVICE; + } + else + { + CONSOLE_OUT("Setting up Provisioner for Provisioning ...\n"); + retval = MS_prov_setup + ( + brr, + role, + NULL, + UI_PROV_SETUP_TIMEOUT_SECS + ); + UI_prov_role = PROV_ROLE_PROVISIONER; + } + + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void UI_prov_bind(UCHAR brr, UCHAR index) +{ + API_RESULT retval; + /* Call to bind with the selected device */ + CONSOLE_OUT("Binding with the selected device...\n"); + retval = MS_prov_bind(brr, &UI_lprov_device, UI_PROV_DEVICE_ATTENTION_TIMEOUT, &UI_prov_handle); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void appl_mesh_sample (void) +{ + MS_ACCESS_NODE_ID node_id; + MS_ACCESS_ELEMENT_DESC element; + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + UCHAR role, brr; + MS_CONFIG* config_ptr; + #ifdef MS_HAVE_DYNAMIC_CONFIG + MS_CONFIG config; + /* Initialize dynamic configuration */ + MS_INIT_CONFIG(config); + config_ptr = &config; + #else + config_ptr = NULL; + #endif /* MS_HAVE_DYNAMIC_CONFIG */ + /* Initialize OSAL */ + EM_os_init(); + /* Initialize Debug Module */ + EM_debug_init(); + /* Initialize Timer Module */ + EM_timer_init(); + timer_em_init(); + /* Initialize utilities */ + nvsto_init(); + /* Initialize Mesh Stack */ + MS_init(config_ptr); + /* Register with underlying BLE stack */ + blebrr_register(); + /* Create Node */ + retval = MS_access_create_node(&node_id); + /* Register Element */ + /** + TBD: Define GATT Namespace Descriptions from + https://www.bluetooth.com/specifications/assigned-numbers/gatt-namespace-descriptors + + Using 'main' (0x0106) as Location temporarily. + */ + element.loc = 0x0106; + retval = MS_access_register_element + ( + node_id, + &element, + &element_handle + ); + + if (API_SUCCESS == retval) + { + /* Register foundation model servers */ + retval = UI_register_foundation_model_servers(element_handle); + } + + if (API_SUCCESS == retval) + { + /* Register Generic OnOff model server */ + retval = UI_register_generic_onoff_model_server(element_handle); + } + + if (API_SUCCESS == retval) + { + /* Register Vendor Defined model server */ + retval = UI_register_vendor_defined_model_server(element_handle); + } + + if (API_SUCCESS == retval) + { + /* Initialize model states */ + UI_model_states_initialization(); + } + + /* Configure as provisionee/device */ + UI_register_prov(); + /** + setup uuid, UI_device_uuid, 16)) + { + /* Beacon not from device of interest. Do no process */ + break; + } + + CONSOLE_OUT ("Recvd PROV_EVT_UNPROVISIONED_BEACON\n"); + CONSOLE_OUT ("Status - 0x%04X\n", event_result); + CONSOLE_OUT("\nUUID : ["); + EM_mem_set(pdata, 0x0, sizeof(pdata)); + t_data = pdata; + + for (i = 0; i < (MS_DEVICE_UUID_SIZE); i++) + { + sprintf(t_data,"%02X", rdev->uuid[i]); + t_data += 2; + } + + CONSOLE_OUT(" %s ", pdata); + CONSOLE_OUT("]"); + CONSOLE_OUT("\nOOB : 0x%04X", rdev->oob); + CONSOLE_OUT("\nURI : 0x%08X", rdev->uri); + CONSOLE_OUT("\n\n"); + /* Bind to the device */ + retval = MS_prov_bind(PROV_BRR_ADV, rdev, UI_PROV_DEVICE_ATTENTION_TIMEOUT, phandle); + CONSOLE_OUT("Retval - 0x%04X\n", retval); + /* Set provision started */ + UI_prov_started = MS_TRUE; + break; + + case PROV_EVT_PROVISIONING_SETUP: + CONSOLE_OUT("Recvd PROV_EVT_PROVISIONING_SETUP\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + + /* Decipher the data based on the role */ + if (PROV_ROLE_PROVISIONER == UI_prov_role) + { + /* Display the capabilities */ + rcap = (PROV_CAPABILITIES_S*)event_data; + CONSOLE_OUT ("Remote Device Capabilities:\n"); + CONSOLE_OUT ("\tNum Elements - %d\n", rcap->num_elements); + CONSOLE_OUT ("\tSupp Algorithms - 0x%04X\n", rcap->supp_algorithms); + CONSOLE_OUT ("\tSupp PublicKey - 0x%02X\n", rcap->supp_pubkey); + CONSOLE_OUT ("\tSupp Static OOB - 0x%02X\n", rcap->supp_soob); + CONSOLE_OUT ("\tOutput OOB Size - %d\n", rcap->ooob.size); + CONSOLE_OUT ("\tOutput OOB Action- 0x%04X\n", rcap->ooob.action); + CONSOLE_OUT ("\tInput OOB Size - %d\n", rcap->ioob.size); + CONSOLE_OUT ("\tInput OOB Action - 0x%04X\n", rcap->ioob.action); + /* Start with default method */ + CONSOLE_OUT ("Start Provisioning with default method...\n"); + retval = MS_prov_start (phandle, &UI_prov_method); + CONSOLE_OUT ("Retval - 0x%04X\n", retval); + } + else + { + /* Display the attention timeout */ + CONSOLE_OUT("Attention TImeout - %d\n", *((UCHAR*)event_data)); + } + + break; + + case PROV_EVT_OOB_DISPLAY: + CONSOLE_OUT("Recvd PROV_EVT_OOB_DISPLAY\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Authenticatio Type information */ + oob_info = (PROV_OOB_TYPE_S*)event_data; + CONSOLE_OUT("Authenticaion Action - 0x%02X\n", oob_info->action); + CONSOLE_OUT("Authenticaion Size - 0x%02X\n", oob_info->size); + + /* If role is Device, the action is of Output OOB, else Input OOB */ + if (PROV_ROLE_DEVICE == UI_prov_role) + { + if (PROV_OOOB_ACTION_ALPHANUMERIC == oob_info->action) + { + authtype = 1; + } + else if (PROV_OOOB_ACTION_NUMERIC == oob_info->action) + { + authtype = 2; + } + else + { + authtype = 0; + } + } + else + { + if (PROV_IOOB_ACTION_ALPHANUMERIC == oob_info->action) + { + authtype = 1; + } + else if (PROV_IOOB_ACTION_NUMERIC == oob_info->action) + { + authtype = 2; + } + else + { + authtype = 0; + } + } + + if (1 == authtype) + { + EM_str_copy (authstr, UI_DISPLAY_AUTH_STRING); + CONSOLE_OUT("\n\n>>> AuthVal - %s <<<\n\n", authstr); + pauth = authstr; + authsize = EM_str_len(authstr); + } + else if (2 == authtype) + { + authnum = (UINT32)UI_DISPLAY_AUTH_NUMERIC; + CONSOLE_OUT("\n\n>>> AuthVal - %d <<<\n\n", authnum); + pauth = (UCHAR*)&authnum; + authsize = sizeof(UINT32); + } + else + { + authnum = (UINT32)UI_DISPLAY_AUTH_DIGIT; + CONSOLE_OUT("\n\n>>> AuthVal - %d <<<\n\n", authnum); + pauth = (UCHAR*)&authnum; + authsize = sizeof(UINT32); + } + + /* Call to input the oob */ + CONSOLE_OUT("Setting the Authval...\n"); + retval = MS_prov_set_authval(phandle, pauth, authsize); + CONSOLE_OUT("Retval - 0x%04X\n", retval); + break; + + case PROV_EVT_OOB_ENTRY: + CONSOLE_OUT("Recvd PROV_EVT_OOB_ENTRY\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Authenticatio Type information */ + oob_info = (PROV_OOB_TYPE_S*)event_data; + CONSOLE_OUT("Authenticaion Action - 0x%02X\n", oob_info->action); + CONSOLE_OUT("Authenticaion Size - 0x%02X\n", oob_info->size); + break; + + case PROV_EVT_DEVINPUT_COMPLETE: + CONSOLE_OUT("Recvd PROV_EVT_DEVINPUT_COMPLETE\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + break; + + case PROV_EVT_PROVDATA_INFO_REQ: + CONSOLE_OUT ("Recvd PROV_EVT_PROVDATA_INFO_REQ\n"); + CONSOLE_OUT ("Status - 0x%04X\n", event_result); + /* Send Provisioning Data */ + CONSOLE_OUT ("Send Provisioning Data...\n"); + retval = MS_prov_data (phandle, &UI_prov_data); + CONSOLE_OUT ("Retval - 0x%04X\n", retval); + break; + + case PROV_EVT_PROVISIONING_COMPLETE: + CONSOLE_OUT("Recvd PROV_EVT_PROVISIONING_COMPLETE\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + + if (API_SUCCESS == event_result) + { + if (PROV_ROLE_PROVISIONER == UI_prov_role) + { + /* Set provision started */ + UI_prov_started = MS_FALSE; + + if (0x0002 == UI_prov_data.uaddr) + { + /* Holding a temporary structure for local prov data */ + PROV_DATA_S temp_ps_prov_data; + EM_mem_copy + ( + &temp_ps_prov_data, + &UI_prov_data, + sizeof(UI_prov_data) + ); + /** + Assigning the Local Unicast Address of the Provisioner + to the Access Layer along with other related keys. + */ + temp_ps_prov_data.uaddr = 0x0001; + /* Provide Provisioning Data to Access Layer */ + MS_access_cm_set_prov_data + ( + &temp_ps_prov_data + ); + /** + NOTE: + Increment the appl_prov_data.uaddr for the next + set of device which is getting provisioned based on + the address and number of elements present in the last + provisioned device. + */ + } + + /* Set the Publish address for Config Client */ + UI_set_publish_address(UI_prov_data.uaddr, UI_config_client_model_handle); + /* Get the Composition data */ + UI_config_client_get_composition_data(0x00); + } + } + + break; + + default: + CONSOLE_OUT("Unknown Event - 0x%02X\n", event_type); + } + + return API_SUCCESS; +} + +void UI_register_prov(void) +{ + API_RESULT retval; + CONSOLE_OUT("Registering with Provisioning layer...\n"); + retval = MS_prov_register(&UI_prov_capab, UI_prov_callback); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void UI_setup_prov(UCHAR role, UCHAR brr) +{ + API_RESULT retval; + + if (PROV_ROLE_PROVISIONER == role) + { + CONSOLE_OUT("Setting up Provisioner for Provisioning ...\n"); + retval = MS_prov_setup + ( + brr, + role, + NULL, + UI_PROV_SETUP_TIMEOUT_SECS + ); + UI_prov_role = PROV_ROLE_PROVISIONER; + } + + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void appl_mesh_sample (void) +{ + MS_ACCESS_NODE_ID node_id; + MS_ACCESS_ELEMENT_DESC element; + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + UCHAR role, brr; + MS_CONFIG* config_ptr; + #ifdef MS_HAVE_DYNAMIC_CONFIG + MS_CONFIG config; + /* Initialize dynamic configuration */ + MS_INIT_CONFIG(config); + config_ptr = &config; + #else + config_ptr = NULL; + #endif /* MS_HAVE_DYNAMIC_CONFIG */ + /* Initialize OSAL */ + EM_os_init(); + /* Initialize Debug Module */ + EM_debug_init(); + /* Initialize Timer Module */ + EM_timer_init(); + timer_em_init(); + /* Initialize utilities */ + nvsto_init(); + /* Initialize Mesh Stack */ + MS_init(config_ptr); + /* Register with underlying BLE stack */ + blebrr_register(); + /* Create Node */ + retval = MS_access_create_node(&node_id); + /* Register Element */ + /** + TBD: Define GATT Namespace Descriptions from + https://www.bluetooth.com/specifications/assigned-numbers/gatt-namespace-descriptors + + Using 'main' (0x0106) as Location temporarily. + */ + element.loc = 0x0106; + retval = MS_access_register_element + ( + node_id, + &element, + &element_handle + ); + + if (API_SUCCESS == retval) + { + /* Register Configuration model client */ + retval = UI_register_config_model_client(element_handle); + } + + if (API_SUCCESS == retval) + { + /* Register Generic OnOff model client */ + retval = UI_register_generic_onoff_model_client(element_handle); + } + + /* Configure as provisioner */ + UI_register_prov(); + /** + setup onoff; + *param_p = UI_generic_onoff; + CONSOLE_OUT("[state] current: 0x%02X\n", UI_generic_onoff.onoff); + CONSOLE_OUT("[state] target: 0x%02X\n", UI_generic_onoff.target_onoff); + CONSOLE_OUT("[state] remaining_time: 0x%02X\n", UI_generic_onoff.transition_time); + /* Ignoring Instance and direction right now */ + /* LED ON/OFF for GENERIC ONOFF Abstraction Call */ + generic_onoff_set_pl (param_p->onoff); + } + break; + + default: + break; + } + + return retval; +} + +/* Model state Initialization */ +void UI_model_states_initialization(void) +{ + /* Generic OnOff States */ + UI_generic_onoff_model_states_initialization(); +} + +/* Generic OnOff Model Server */ +/** + \brief Server Application Asynchronous Notification Callback. + + \par Description + Generic_Onoff server calls the registered callback to indicate events occurred to the application. + + \param [in] ctx Context of message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +API_RESULT UI_generic_onoff_server_cb +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + /* IN */ MS_ACCESS_MODEL_REQ_MSG_T* req_type, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* state_params, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params +) +{ + MS_STATE_GENERIC_ONOFF_STRUCT param; + MS_ACCESS_MODEL_STATE_PARAMS current_state_params; + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(ext_params); + MS_IGNORE_UNUSED_PARAM(msg_raw); + retval = API_SUCCESS; + + /* Check message type */ + if (MS_ACCESS_MODEL_REQ_MSG_T_GET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] GET Request.\n"); + UI_generic_onoff_model_state_get(state_params->state_type, 0, ¶m, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = ¶m; + /* Using same as target state and remaining time as 0 */ + } + else if (MS_ACCESS_MODEL_REQ_MSG_T_SET == req_type->type) + { + CONSOLE_OUT("[GENERIC_ONOFF] SET Request.\n"); + retval = UI_generic_onoff_model_state_set(state_params->state_type, 0, (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state, 0); + current_state_params.state_type = state_params->state_type; + current_state_params.state = (MS_STATE_GENERIC_ONOFF_STRUCT*)state_params->state; + } + + /* See if to be acknowledged */ + if (0x01 == req_type->to_be_acked) + { + CONSOLE_OUT("[GENERIC_ONOFF] Sending Response.\n"); + /* Parameters: Request Context, Current State, Target State (NULL: to be ignored), Remaining Time (0: to be ignored), Additional Parameters (NULL: to be ignored) */ + retval = MS_generic_onoff_server_state_update(ctx, ¤t_state_params, NULL, 0, NULL); + } + + return retval; +} + +API_RESULT UI_register_generic_onoff_model_server +( + MS_ACCESS_ELEMENT_HANDLE element_handle +) +{ + /* Generic OnOff Server */ + MS_ACCESS_MODEL_HANDLE UI_generic_onoff_server_model_handle; + API_RESULT retval; + CONSOLE_OUT("In Generic OnOff Model Server\n"); + retval = MS_generic_onoff_server_init + ( + element_handle, + &UI_generic_onoff_server_model_handle, + UI_generic_onoff_server_cb + ); + + if (API_SUCCESS == retval) + { + CONSOLE_OUT( + "Generic Onoff Server Initialized. Model Handle: 0x%04X\n", + UI_generic_onoff_server_model_handle); + } + else + { + CONSOLE_OUT( + "[ERR] Generic Onoff Server Initialization Failed. Result: 0x%04X\n", + retval); + } + + return retval; +} + +/* Provisionee */ +/** Public Key OOB Flag */ +#define UI_PROV_PUBKEY_OOBINFO 0x00 + +/** Static OOB Flag */ +#define UI_PROV_STATIC_OOBINFO 0x00 + +/** Output OOB Actions Supported */ +#ifdef MESH_SAMPLE_HAVE_OUTPUT_OOB_DISPLAY + /** Currently Selecting the Output OOB Actions as Alphanumeric OOB Action */ + #define UI_PROV_OUTPUT_OOB_ACTIONS PROV_MASK_OOOB_ACTION_ALPHANUMERIC + + /** Output OOB Maximum size supported */ + #define UI_PROV_OUTPUT_OOB_SIZE 0x04 +#else /* MESH_SAMPLE_HAVE_OUTPUT_OOB_DISPLAY */ + /** Currently Selecting the Output OOB Actions as Alphanumeric OOB Action */ + #define UI_PROV_OUTPUT_OOB_ACTIONS 0x00 + + /** Output OOB Maximum size supported */ + #define UI_PROV_OUTPUT_OOB_SIZE 0x00 +#endif /* MESH_SAMPLE_HAVE_OUTPUT_OOB_DISPLAY */ + +/** Input OOB Actions supported */ +#define UI_PROV_INPUT_OOB_ACTIONS 0x00 + +/** Input OOB Maximum size supported */ +#define UI_PROV_INPUT_OOB_SIZE 0x00 + +/** Beacon setup timeout in seconds */ +#define UI_PROV_SETUP_TIMEOUT_SECS 30 + +/** Attention timeout for device in seconds */ +#define UI_PROV_DEVICE_ATTENTION_TIMEOUT 30 + +#define PROV_AUTHVAL_SIZE_PL 16 + +/** Authentication values for OOB Display - To be made random */ +#define UI_DISPLAY_AUTH_DIGIT 3 +#define UI_DISPLAY_AUTH_NUMERIC 35007 +#define UI_DISPLAY_AUTH_STRING "F00L" + +/** Provisioning capabilities of local device */ +DECL_STATIC PROV_CAPABILITIES_S UI_prov_capab = +{ + /** Number of Elements */ + 0x01, + + /** Supported algorithms */ + PROV_MASK_ALGO_EC_FIPS_P256, + + /** Public key type */ + UI_PROV_PUBKEY_OOBINFO, + + /** Static OOB type */ + UI_PROV_STATIC_OOBINFO, + + /** Output OOB information */ + { UI_PROV_OUTPUT_OOB_ACTIONS, UI_PROV_OUTPUT_OOB_SIZE }, + + /** Input OOB information */ + { UI_PROV_INPUT_OOB_ACTIONS, UI_PROV_INPUT_OOB_SIZE }, +}; + +/** Unprovisioned device identifier */ +//DECL_STATIC PROV_DEVICE_S UI_lprov_device = +PROV_DEVICE_S UI_lprov_device = +{ + /** UUID */ + {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}, + + /** OOB Flag */ + 0x00, + + /** + Encoded URI Information + For example, to give a web address, "https://www.abc.com" + the URI encoded data would be - + 0x17 0x2F 0x2F 0x77 0x77 0x77 0x2E 0x61 0x62 0x63 0x2E 0x63 0x6F 0x6D + where 0x17 is the URI encoding for https: + */ + NULL +}; + +/** Current role of application - Provisioner/Device */ +DECL_STATIC UCHAR UI_prov_role; + +/** Provisioning Handle */ +DECL_STATIC PROV_HANDLE UI_prov_handle; + +API_RESULT UI_prov_callback +( + PROV_HANDLE* phandle, + UCHAR event_type, + API_RESULT event_result, + void* event_data, + UINT16 event_datalen +) +{ + PROV_DATA_S* rdata; + PROV_OOB_TYPE_S* oob_info; + API_RESULT retval; + UCHAR authstr[PROV_AUTHVAL_SIZE_PL << 1]; + UINT32 authnum; + UCHAR authtype; + UCHAR* pauth; + UINT16 authsize; + MS_IGNORE_UNUSED_PARAM(event_datalen); + MS_IGNORE_UNUSED_PARAM(phandle); + + switch (event_type) + { + case PROV_EVT_PROVISIONING_SETUP: + CONSOLE_OUT("Recvd PROV_EVT_PROVISIONING_SETUP\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Display the attention timeout */ + CONSOLE_OUT("Attention TImeout - %d\n", *((UCHAR*)event_data)); + break; + + case PROV_EVT_OOB_DISPLAY: + CONSOLE_OUT("Recvd PROV_EVT_OOB_DISPLAY\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Authenticatio Type information */ + oob_info = (PROV_OOB_TYPE_S*)event_data; + CONSOLE_OUT("Authenticaion Action - 0x%02X\n", oob_info->action); + CONSOLE_OUT("Authenticaion Size - 0x%02X\n", oob_info->size); + + /* If role is Device, the action is of Output OOB, else Input OOB */ + if (PROV_ROLE_DEVICE == UI_prov_role) + { + if (PROV_OOOB_ACTION_ALPHANUMERIC == oob_info->action) + { + authtype = 1; + } + else if (PROV_OOOB_ACTION_NUMERIC == oob_info->action) + { + authtype = 2; + } + else + { + authtype = 0; + } + } + else + { + if (PROV_IOOB_ACTION_ALPHANUMERIC == oob_info->action) + { + authtype = 1; + } + else if (PROV_IOOB_ACTION_NUMERIC == oob_info->action) + { + authtype = 2; + } + else + { + authtype = 0; + } + } + + if (1 == authtype) + { + EM_str_copy (authstr, UI_DISPLAY_AUTH_STRING); + CONSOLE_OUT("\n\n>>> AuthVal - %s <<<\n\n", authstr); + pauth = authstr; + authsize = (UINT16)EM_str_len(authstr); + } + else if (2 == authtype) + { + authnum = (UINT32)UI_DISPLAY_AUTH_NUMERIC; + CONSOLE_OUT("\n\n>>> AuthVal - %d <<<\n\n", authnum); + pauth = (UCHAR*)&authnum; + authsize = sizeof(UINT32); + } + else + { + authnum = (UINT32)UI_DISPLAY_AUTH_DIGIT; + CONSOLE_OUT("\n\n>>> AuthVal - %d <<<\n\n", authnum); + pauth = (UCHAR*)&authnum; + authsize = sizeof(UINT32); + } + + /* Call to input the oob */ + CONSOLE_OUT("Setting the Authval...\n"); + retval = MS_prov_set_authval(&UI_prov_handle, pauth, authsize); + CONSOLE_OUT("Retval - 0x%04X\n", retval); + break; + + case PROV_EVT_OOB_ENTRY: + CONSOLE_OUT("Recvd PROV_EVT_OOB_ENTRY\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Authenticatio Type information */ + oob_info = (PROV_OOB_TYPE_S*)event_data; + CONSOLE_OUT("Authenticaion Action - 0x%02X\n", oob_info->action); + CONSOLE_OUT("Authenticaion Size - 0x%02X\n", oob_info->size); + break; + + case PROV_EVT_DEVINPUT_COMPLETE: + CONSOLE_OUT("Recvd PROV_EVT_DEVINPUT_COMPLETE\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + break; + + case PROV_EVT_PROVDATA_INFO: + CONSOLE_OUT("Recvd PROV_EVT_PROVDATA_INFO\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Provisioning Data */ + rdata = (PROV_DATA_S*)event_data; + CONSOLE_OUT("NetKey : "); + appl_dump_bytes(rdata->netkey, PROV_KEY_NETKEY_SIZE); + CONSOLE_OUT("Key ID : 0x%04X\n", rdata->keyid); + CONSOLE_OUT("Flags : 0x%02X\n", rdata->flags); + CONSOLE_OUT("IVIndex : 0x%08X\n", rdata->ivindex); + CONSOLE_OUT("UAddr : 0x%04X\n", rdata->uaddr); + /* Provide Provisioning Data to Access Layer */ + MS_access_cm_set_prov_data + ( + rdata + ); + break; + + case PROV_EVT_PROVISIONING_COMPLETE: + CONSOLE_OUT("Recvd PROV_EVT_PROVISIONING_COMPLETE\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + + if (API_SUCCESS == event_result) + { + /* Already Set while handling PROV_EVT_PROVDATA_INFO */ + /* LED ON/OFF for Provisioning Indication Abstraction Call */ + mesh_model_device_provisioned_ind_pl(); + } + + break; + + default: + CONSOLE_OUT("Unknown Event - 0x%02X\n", event_type); + } + + return API_SUCCESS; +} + +void UI_register_prov(void) +{ + API_RESULT retval; + CONSOLE_OUT("Registering with Provisioning layer...\n"); + retval = MS_prov_register(&UI_prov_capab, UI_prov_callback); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void UI_setup_prov(UCHAR role, UCHAR brr) +{ + API_RESULT retval; + + if (PROV_BRR_GATT == brr) + { + blebrr_gatt_mode_set(BLEBRR_GATT_PROV_MODE); + } + + if (PROV_ROLE_PROVISIONER != role) + { + CONSOLE_OUT("Setting up Device for Provisioning ...\n"); + retval = MS_prov_setup + ( + brr, + role, + &UI_lprov_device, + UI_PROV_SETUP_TIMEOUT_SECS + ); + UI_prov_role = PROV_ROLE_DEVICE; + } + else + { + CONSOLE_OUT("Setting up Provisioner for Provisioning ...\n"); + retval = MS_prov_setup + ( + brr, + role, + NULL, + UI_PROV_SETUP_TIMEOUT_SECS + ); + UI_prov_role = PROV_ROLE_PROVISIONER; + } + + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void UI_prov_bind(UCHAR brr, UCHAR index) +{ + API_RESULT retval; + MS_IGNORE_UNUSED_PARAM(index); + /* Call to bind with the selected device */ + CONSOLE_OUT("Binding with the selected device...\n"); + retval = MS_prov_bind(brr, &UI_lprov_device, UI_PROV_DEVICE_ATTENTION_TIMEOUT, &UI_prov_handle); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void UI_proxy_start_adv(MS_SUBNET_HANDLE subnet_handle, UCHAR proxy_adv_mode) +{ + #ifdef MS_PROXY_SERVER + API_RESULT retval; + DECL_STATIC UINT8 first_time = 0; + + if (0 == first_time) + { + /** + Register with Proxy Module as Device is going to be a Proxy. + This is typically a one-time-event, and hence registering the + PROXY when Proxy ADV is being initiated! + */ + UI_register_proxy(); + first_time = 1; + } + + /* Set the role to Proxy with bearer */ + blebrr_gatt_mode_set(BLEBRR_GATT_PROXY_MODE); + CONSOLE_OUT("Start Proxy Advertisements with %s for Subnet 0x%04X\n", + (proxy_adv_mode == MS_PROXY_NET_ID_ADV_MODE) ? "Network ID" : "Node Identity", + subnet_handle); + retval = MS_proxy_server_adv_start + ( + subnet_handle, + proxy_adv_mode + ); + CONSOLE_OUT("Retval - 0x%04X\n", retval); + #else /* MS_PROXY_SERVER */ + CONSOLE_OUT("\n [** ERR **] MS_PROXY_SERVER feature is DISABLED!\n"); + return; + #endif /* MS_PROXY_SERVER */ +} + +void UI_proxy_callback +( + NETIF_HANDLE* handle, + UCHAR p_evt, + UCHAR* data_param, + UINT16 data_len +) +{ + UCHAR role; + MS_IGNORE_UNUSED_PARAM(data_len); + + switch(p_evt) + { + case MS_PROXY_UP_EVENT: + CONSOLE_OUT( + "\n\n[PROXY APPL]: MS_PROXY_UP_EVENT Received for NETIF Handle 0x%02X\n\n", *handle); + + if (NULL != data_param) + { + /* Catch the current role into a local */ + role = data_param[0]; + + if (BRR_SERVER_ROLE == role) + { + /* Send Secure Network Beacons */ + /* MS_net_broadcast_secure_beacon(0x0000); */ + } + } + + break; + + case MS_PROXY_DOWN_EVENT: + CONSOLE_OUT( + "\n\n[PROXY APPL]: MS_PROXY_DOWN_EVENT Received for NETIF Handle 0x%02X\n\n", *handle); + break; + + default: + CONSOLE_OUT( + "\n\n[PROXY APPL ERR]: Unknown Event Received for NETIF Handle 0x%02X!!\n\n", *handle); + break; + } +} + +#ifdef MS_PROXY_SUPPORT +void UI_register_proxy(void) +{ + API_RESULT retval; + CONSOLE_OUT("Registering with Proxy layer...\n"); + retval = MS_proxy_register(UI_proxy_callback); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} +#endif + + +API_RESULT UI_set_brr_scan_rsp_data (void) +{ + /** + Currently setting MT-MESH-SAMPLE-8 as Complete Device Name! + This can be updated to each individual devices as per requirement. + */ + UCHAR UI_brr_scanrsp_data[] = + { + /** + Shortened Device Name: MT-MESH-SAMPLE-8 + */ + 0x11, 0x09, 'M', 'T', '-', 'M', 'E', 'S', 'H', '-', 'S', 'A', 'M', 'P', 'L', 'E', '-', '8' + }; + CONSOLE_OUT("\n Setting MT-MESH-SAMPLE-8 as Complete Device Name!\n"); + /* Set the Scan Response Data at the Bearer Layer */ + blebrr_set_adv_scanrsp_data_pl + ( + UI_brr_scanrsp_data, + sizeof(UI_brr_scanrsp_data) + ); + return API_SUCCESS; +} + +EM_timer_handle thandle; +void timeout_cb (void* args, UINT16 size) +{ + thandle = EM_TIMER_HANDLE_INIT_VAL; + UI_sample_reinit(); +} + +void UI_gatt_iface_event_pl_cb +( + UCHAR ev_name, + UCHAR ev_param +) +{ + switch(ev_name) + { + /* GATT Bearer BLE Link Layer Disconnected */ + case BLEBRR_GATT_IFACE_DOWN: + CONSOLE_OUT("\r\n >> GATT Bearer BLE Link Layer Disconnection Event Received!\r\n"); + //UI_sample_reinit(); + EM_start_timer (&thandle, 3, timeout_cb, NULL, 0); + break; + + /* GATT Bearer BLE Link Layer Connected */ + case BLEBRR_GATT_IFACE_UP: + CONSOLE_OUT("\r\n >> GATT Bearer BLE Link Layer Connection Event Received!\r\n"); + + /* Do Nothing! */ + if (BLEBRR_GATT_PROV_MODE == blebrr_gatt_mode_get()) + { + MS_brr_bcast_end(BRR_BCON_TYPE_UNPROV_DEVICE, BRR_BCON_ACTIVE); + } + else if (BLEBRR_GATT_PROXY_MODE == blebrr_gatt_mode_get()) + { + #ifdef MS_PROXY_SERVER + MS_proxy_server_adv_stop(); + #endif + } + + break; + + case BLEBRR_GATT_IFACE_ENABLE: + CONSOLE_OUT("\r\n >> GATT Bearer Active Event Received!\r\n"); + { + if (BLEBRR_GATT_PROV_MODE == ev_param) + { + /* Call to bind with the selected device */ + UI_prov_bind(PROV_BRR_GATT, 0); + } + } + break; + + case BLEBRR_GATT_IFACE_DISABLE: + CONSOLE_OUT("\r\n >> GATT Bearer Inactive Event Received!\r\n"); + break; + + /* Unknown Event! */ + default: + CONSOLE_OUT("\r\n >> GATT Bearer BLE Link Layer Unknown Event 0x%02X Received!\r\n", ev_name); + /* Do Nothing! */ + break; + } +} + +void appl_mesh_sample (void) +{ + MS_ACCESS_NODE_ID node_id; + MS_ACCESS_ELEMENT_DESC element; + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + MS_CONFIG* config_ptr; + #ifdef MS_HAVE_DYNAMIC_CONFIG + MS_CONFIG config; + /* Initialize dynamic configuration */ + MS_INIT_CONFIG(config); + config_ptr = &config; + #else + config_ptr = NULL; + #endif /* MS_HAVE_DYNAMIC_CONFIG */ + /* Initialize OSAL */ + EM_os_init(); + /* Initialize Debug Module */ + EM_debug_init(); + /* Initialize Timer Module */ + EM_timer_init(); + timer_em_init(); + /* Initialize utilities */ + nvsto_init(); + /* Initialize Mesh Stack */ + MS_init(config_ptr); + /* Register with underlying BLE stack */ + blebrr_register(); + /* Register GATT Bearer Connection/Disconnection Event Hook */ + blebrr_register_gatt_iface_event_pl(UI_gatt_iface_event_pl_cb); + /* Enable LED Port */ + /* Platform Abstraction Initializations of GPIOs/LEDs etc. */ + mesh_model_platform_init_pl(); + /* LED ON */ + /* LED ON/OFF for BOOT UP Indication Abstraction Call */ + mesh_model_device_bootup_ind_pl(); + /* Create Node */ + retval = MS_access_create_node(&node_id); + /* Register Element */ + /** + TBD: Define GATT Namespace Descriptions from + https://www.bluetooth.com/specifications/assigned-numbers/gatt-namespace-descriptors + + Using 'main' (0x0106) as Location temporarily. + */ + element.loc = 0x0106; + retval = MS_access_register_element + ( + node_id, + &element, + &element_handle + ); + + if (API_SUCCESS == retval) + { + /* Register foundation model servers */ + retval = UI_register_foundation_model_servers(element_handle); + } + + if (API_SUCCESS == retval) + { + /* Register Generic OnOff model server */ + retval = UI_register_generic_onoff_model_server(element_handle); + } + + if (API_SUCCESS == retval) + { + /* Initialize model states */ + UI_model_states_initialization(); + } + + /* Configure as provisionee/device */ + UI_register_prov(); + /** + Set Scan Response Data Before Starting Provisioning. + This is optional/additional set of Data that the device can + set to enhance the User Experience. + For Example, set a specific device name or URL as part of the + Scan Response Data when awaiting connections over GATT bearer. + */ + UI_set_brr_scan_rsp_data(); + //UI_sample_reinit(); + EM_start_timer (&thandle, 5, timeout_cb, NULL, 0); + return; +} + +API_RESULT UI_sample_check_app_key(void) +{ + MS_APPKEY_HANDLE handle; + UINT8* key; + UINT8 aid; + DECL_CONST UINT8 t_key[16] = {0}; + API_RESULT retval; + CONSOLE_OUT("Fetching App Key for Handle 0x0000\n"); + handle = 0x0000; + retval = MS_access_cm_get_app_key + ( + handle, + &key, + &aid + ); + + /* Check Retval. Print App Key */ + if (API_SUCCESS == retval) + { + CONSOLE_OUT("App Key[0x%02X]: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\r\n", + handle, key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7], + key[8], key[9], key[10], key[11], key[12], key[13], key[14], key[15]); + + if (0 == EM_mem_cmp(key, t_key, 16)) + { + /* NO AppKey Bound */ + retval = API_FAILURE; + } + else + { + /* Found a Valid App Key */ + /* Keeping the retval as API_SUCCESS */ + } + } + + return retval; +} + +/** + On GATT Bearer Disconnection or on Startup: + 1. If device not provisioned, start unprovisioned beacons over GATT bearer + 2. If device is provisioned and App Key is bound i.e. Device is Configured + - Check if Proxy Feature is enabled then Start ADV as Proxy, + Else, + Do nothing! + Else, + If device is provisioned and App Key is not bound i.e. Device is not Configured + Start ADV as Proxy. +*/ +void UI_sample_reinit(void) +{ + API_RESULT retval; + MS_NET_ADDR addr; + UCHAR is_prov_req; + UCHAR role, brr; + UCHAR state; + retval = API_SUCCESS; + is_prov_req = MS_TRUE; + retval = MS_access_cm_get_primary_unicast_address(&addr); + + if (API_SUCCESS == retval) + { + if (MS_NET_ADDR_UNASSIGNED != addr) + { + /* Set Provisioning is not Required */ + is_prov_req = MS_FALSE; + } + } + + if (MS_TRUE == is_prov_req) + { + /* Start Provisioning over GATT here */ + /** + setup action); + CONSOLE_OUT("Authenticaion Size - 0x%02X\n", oob_info->size); + + /* If role is Device, the action is of Output OOB, else Input OOB */ + if (PROV_ROLE_DEVICE == UI_prov_role) + { + if (PROV_OOOB_ACTION_ALPHANUMERIC == oob_info->action) + { + authtype = 1; + } + else if (PROV_OOOB_ACTION_NUMERIC == oob_info->action) + { + authtype = 2; + } + else + { + authtype = 0; + } + } + else + { + if (PROV_IOOB_ACTION_ALPHANUMERIC == oob_info->action) + { + authtype = 1; + } + else if (PROV_IOOB_ACTION_NUMERIC == oob_info->action) + { + authtype = 2; + } + else + { + authtype = 0; + } + } + + if (1 == authtype) + { + EM_str_copy (authstr, UI_DISPLAY_AUTH_STRING); + CONSOLE_OUT("\n\n>>> AuthVal - %s <<<\n\n", authstr); + pauth = authstr; + authsize = (UINT16)EM_str_len(authstr); + } + else if (2 == authtype) + { + authnum = (UINT32)UI_DISPLAY_AUTH_NUMERIC; + CONSOLE_OUT("\n\n>>> AuthVal - %d <<<\n\n", authnum); + pauth = (UCHAR*)&authnum; + authsize = sizeof(UINT32); + } + else + { + authnum = (UINT32)UI_DISPLAY_AUTH_DIGIT; + CONSOLE_OUT("\n\n>>> AuthVal - %d <<<\n\n", authnum); + pauth = (UCHAR*)&authnum; + authsize = sizeof(UINT32); + } + + /* Call to input the oob */ + CONSOLE_OUT("Setting the Authval...\n"); + retval = MS_prov_set_authval(&UI_prov_handle, pauth, authsize); + CONSOLE_OUT("Retval - 0x%04X\n", retval); + break; + + case PROV_EVT_OOB_ENTRY: + CONSOLE_OUT("Recvd PROV_EVT_OOB_ENTRY\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Authenticatio Type information */ + oob_info = (PROV_OOB_TYPE_S*)event_data; + CONSOLE_OUT("Authenticaion Action - 0x%02X\n", oob_info->action); + CONSOLE_OUT("Authenticaion Size - 0x%02X\n", oob_info->size); + break; + + case PROV_EVT_DEVINPUT_COMPLETE: + CONSOLE_OUT("Recvd PROV_EVT_DEVINPUT_COMPLETE\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + break; + + case PROV_EVT_PROVDATA_INFO: + CONSOLE_OUT("Recvd PROV_EVT_PROVDATA_INFO\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + /* Reference the Provisioning Data */ + rdata = (PROV_DATA_S*)event_data; + CONSOLE_OUT("NetKey : "); + appl_dump_bytes(rdata->netkey, PROV_KEY_NETKEY_SIZE); + CONSOLE_OUT("Key ID : 0x%04X\n", rdata->keyid); + CONSOLE_OUT("Flags : 0x%02X\n", rdata->flags); + CONSOLE_OUT("IVIndex : 0x%08X\n", rdata->ivindex); + CONSOLE_OUT("UAddr : 0x%04X\n", rdata->uaddr); + /* Provide Provisioning Data to Access Layer */ + MS_access_cm_set_prov_data + ( + rdata + ); + break; + + case PROV_EVT_PROVISIONING_COMPLETE: + CONSOLE_OUT("Recvd PROV_EVT_PROVISIONING_COMPLETE\n"); + CONSOLE_OUT("Status - 0x%04X\n", event_result); + + if (API_SUCCESS == event_result) + { + /* Already Set while handling PROV_EVT_PROVDATA_INFO */ + /* LED ON/OFF for Provisioning Indication Abstraction Call */ + mesh_model_device_provisioned_ind_pl(); + } + + break; + + default: + CONSOLE_OUT("Unknown Event - 0x%02X\n", event_type); + } + + return API_SUCCESS; +} + +void UI_register_prov(void) +{ + API_RESULT retval; + CONSOLE_OUT("Registering with Provisioning layer...\n"); + retval = MS_prov_register(&UI_prov_capab, UI_prov_callback); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void UI_setup_prov(UCHAR role, UCHAR brr) +{ + API_RESULT retval; + + if (PROV_BRR_GATT == brr) + { + blebrr_gatt_mode_set(BLEBRR_GATT_PROV_MODE); + } + + if (PROV_ROLE_PROVISIONER != role) + { + CONSOLE_OUT("Setting up Device for Provisioning ...\n"); + retval = MS_prov_setup + ( + brr, + role, + &UI_lprov_device, + UI_PROV_SETUP_TIMEOUT_SECS + ); + UI_prov_role = PROV_ROLE_DEVICE; + } + else + { + CONSOLE_OUT("Setting up Provisioner for Provisioning ...\n"); + retval = MS_prov_setup + ( + brr, + role, + NULL, + UI_PROV_SETUP_TIMEOUT_SECS + ); + UI_prov_role = PROV_ROLE_PROVISIONER; + } + + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void UI_prov_bind(UCHAR brr, UCHAR index) +{ + API_RESULT retval; + /* Call to bind with the selected device */ + CONSOLE_OUT("Binding with the selected device...\n"); + retval = MS_prov_bind(brr, &UI_lprov_device, UI_PROV_DEVICE_ATTENTION_TIMEOUT, &UI_prov_handle); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void UI_proxy_start_adv(MS_SUBNET_HANDLE subnet_handle, UCHAR proxy_adv_mode) +{ + API_RESULT retval; + DECL_STATIC UINT8 first_time = 0; + + if (0 == first_time) + { + /** + Register with Proxy Module as Device is going to be a Proxy. + This is typically a one-time-event, and hence registering the + PROXY when Proxy ADV is being initiated! + */ + UI_register_proxy(); + first_time = 1; + } + + /* Set the role to Proxy with bearer */ + blebrr_gatt_mode_set(BLEBRR_GATT_PROXY_MODE); + CONSOLE_OUT("Start Proxy Advertisements with %s for Subnet 0x%04X\n", + (proxy_adv_mode == MS_PROXY_NET_ID_ADV_MODE) ? "Network ID" : "Node Identity", + subnet_handle); + retval = MS_proxy_server_adv_start + ( + subnet_handle, + proxy_adv_mode + ); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +void UI_proxy_callback +( + NETIF_HANDLE* handle, + UCHAR p_evt, + UCHAR* data_param, + UINT16 data_len +) +{ + UCHAR role; + MS_IGNORE_UNUSED_PARAM(data_len); + + switch(p_evt) + { + case MS_PROXY_UP_EVENT: + CONSOLE_OUT( + "\n\n[PROXY APPL]: MS_PROXY_UP_EVENT Received for NETIF Handle 0x%02X\n\n", *handle); + + if (NULL != data_param) + { + /* Catch the current role into a local */ + role = data_param[0]; + + if (BRR_SERVER_ROLE == role) + { + /* Send Secure Network Beacons */ + /* MS_net_broadcast_secure_beacon(0x0000); */ + } + } + + break; + + case MS_PROXY_DOWN_EVENT: + CONSOLE_OUT( + "\n\n[PROXY APPL]: MS_PROXY_DOWN_EVENT Received for NETIF Handle 0x%02X\n\n", *handle); + break; + + default: + CONSOLE_OUT( + "\n\n[PROXY APPL ERR]: Unknown Event Received for NETIF Handle 0x%02X!!\n\n", *handle); + break; + } +} + +void UI_register_proxy(void) +{ + API_RESULT retval; + CONSOLE_OUT("Registering with Proxy layer...\n"); + retval = MS_proxy_register(UI_proxy_callback); + CONSOLE_OUT("Retval - 0x%04X\n", retval); +} + +API_RESULT UI_set_brr_scan_rsp_data (void) +{ + /** + Currently setting MT-MESH-SAMPLE-9 as Complete Device Name! + This can be updated to each individual devices as per requirement. + */ + UCHAR UI_brr_scanrsp_data[] = + { + /** + Shortened Device Name: MT-MESH-SAMPLE-9 + */ + 0x11, 0x09, 'M', 'T', '-', 'M', 'E', 'S', 'H', '-', 'S', 'A', 'M', 'P', 'L', 'E', '-', '9' + }; + CONSOLE_OUT("\n Setting MT-MESH-SAMPLE-8 as Complete Device Name!\n"); + /* Set the Scan Response Data at the Bearer Layer */ + blebrr_set_adv_scanrsp_data_pl + ( + UI_brr_scanrsp_data, + sizeof(UI_brr_scanrsp_data) + ); + return API_SUCCESS; +} + +EM_timer_handle thandle; +void timeout_cb (void* args, UINT16 size) +{ + thandle = EM_TIMER_HANDLE_INIT_VAL; + UI_sample_reinit(); +} + +void UI_gatt_iface_event_pl_cb +( + UCHAR ev_name, + UCHAR ev_param +) +{ + switch(ev_name) + { + /* GATT Bearer BLE Link Layer Disconnected */ + case BLEBRR_GATT_IFACE_DOWN: + CONSOLE_OUT("\r\n >> GATT Bearer BLE Link Layer Disconnection Event Received!\r\n"); + //UI_sample_reinit(); + EM_start_timer (&thandle, 3, timeout_cb, NULL, 0); + break; + + /* GATT Bearer BLE Link Layer Connected */ + case BLEBRR_GATT_IFACE_UP: + CONSOLE_OUT("\r\n >> GATT Bearer BLE Link Layer Connection Event Received!\r\n"); + + /* Do Nothing! */ + if (BLEBRR_GATT_PROV_MODE == blebrr_gatt_mode_get()) + { + MS_brr_bcast_end(BRR_BCON_TYPE_UNPROV_DEVICE, BRR_BCON_ACTIVE); + } + else if (BLEBRR_GATT_PROXY_MODE == blebrr_gatt_mode_get()) + { + MS_proxy_server_adv_stop(); + } + + break; + + case BLEBRR_GATT_IFACE_ENABLE: + CONSOLE_OUT("\r\n >> GATT Bearer Active Event Received!\r\n"); + { + if (BLEBRR_GATT_PROV_MODE == ev_param) + { + /* Call to bind with the selected device */ + UI_prov_bind(PROV_BRR_GATT, 0); + } + } + break; + + case BLEBRR_GATT_IFACE_DISABLE: + CONSOLE_OUT("\r\n >> GATT Bearer Inactive Event Received!\r\n"); + break; + + /* Unknown Event! */ + default: + CONSOLE_OUT("\r\n >> GATT Bearer BLE Link Layer Unknown Event 0x%02X Received!\r\n", ev_name); + /* Do Nothing! */ + break; + } +} + +void appl_mesh_sample (void) +{ + MS_ACCESS_NODE_ID node_id; + MS_ACCESS_ELEMENT_DESC element; + MS_ACCESS_ELEMENT_HANDLE element_handle; + API_RESULT retval; + MS_CONFIG* config_ptr; + #ifdef MS_HAVE_DYNAMIC_CONFIG + MS_CONFIG config; + /* Initialize dynamic configuration */ + MS_INIT_CONFIG(config); + config_ptr = &config; + #else + config_ptr = NULL; + #endif /* MS_HAVE_DYNAMIC_CONFIG */ + /* Initialize OSAL */ + EM_os_init(); + /* Initialize Debug Module */ + EM_debug_init(); + /* Initialize Timer Module */ + EM_timer_init(); + timer_em_init(); + /* Initialize utilities */ + nvsto_init(); + /* Initialize Mesh Stack */ + MS_init(config_ptr); + /* Register with underlying BLE stack */ + blebrr_register(); + /* Register GATT Bearer Connection/Disconnection Event Hook */ + blebrr_register_gatt_iface_event_pl(UI_gatt_iface_event_pl_cb); + /* Enable LED Port */ + /* Platform Abstraction Initializations of GPIOs/LEDs etc. */ + mesh_model_platform_init_pl(); + /* LED ON */ + /* LED ON/OFF for BOOT UP Indication Abstraction Call */ + mesh_model_device_bootup_ind_pl(); + /* Create Node */ + retval = MS_access_create_node(&node_id); + /* Register Element */ + /** + TBD: Define GATT Namespace Descriptions from + https://www.bluetooth.com/specifications/assigned-numbers/gatt-namespace-descriptors + + Using 'main' (0x0106) as Location temporarily. + */ + element.loc = 0x0106; + retval = MS_access_register_element + ( + node_id, + &element, + &element_handle + ); + + if (API_SUCCESS == retval) + { + /* Register foundation model servers */ + retval = UI_register_foundation_model_servers(element_handle); + } + + if (API_SUCCESS == retval) + { + /* Register Generic OnOff model client */ + retval = UI_register_generic_onoff_model_client(element_handle); + } + + /* Configure as provisionee/device */ + UI_register_prov(); + /** + Set Scan Response Data Before Starting Provisioning. + This is optional/additional set of Data that the device can + set to enhance the User Experience. + For Example, set a specific device name or URL as part of the + Scan Response Data when awaiting connections over GATT bearer. + */ + UI_set_brr_scan_rsp_data(); + //UI_sample_reinit(); + EM_start_timer (&thandle, 5, timeout_cb, NULL, 0); + return; +} + +API_RESULT UI_sample_check_app_key(void) +{ + MS_APPKEY_HANDLE handle; + UINT8* key; + UINT8 aid; + DECL_CONST UINT8 t_key[16] = {0}; + API_RESULT retval; + CONSOLE_OUT("Fetching App Key for Handle 0x0000\n"); + handle = 0x0000; + retval = MS_access_cm_get_app_key + ( + handle, + &key, + &aid + ); + + /* Check Retval. Print App Key */ + if (API_SUCCESS == retval) + { + CONSOLE_OUT("App Key[0x%02X]: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\r\n", + handle, key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7], + key[8], key[9], key[10], key[11], key[12], key[13], key[14], key[15]); + + if (0 == EM_mem_cmp(key, t_key, 16)) + { + /* NO AppKey Bound */ + retval = API_FAILURE; + } + else + { + /* Found a Valid App Key */ + /* Keeping the retval as API_SUCCESS */ + } + } + + return retval; +} + +/** + On GATT Bearer Disconnection or on Startup: + 1. If device not provisioned, start unprovisioned beacons over GATT bearer + 2. If device is provisioned and App Key is bound i.e. Device is Configured + - Check if Proxy Feature is enabled then Start ADV as Proxy, + Else, + Do nothing! + Else, + If device is provisioned and App Key is not bound i.e. Device is not Configured + Start ADV as Proxy. +*/ +void UI_sample_reinit(void) +{ + API_RESULT retval; + MS_NET_ADDR addr; + UCHAR is_prov_req; + UCHAR role, brr; + UCHAR state; + retval = API_SUCCESS; + is_prov_req = MS_TRUE; + retval = MS_access_cm_get_primary_unicast_address(&addr); + + if (API_SUCCESS == retval) + { + if (MS_NET_ADDR_UNASSIGNED != addr) + { + /* Set Provisioning is not Required */ + is_prov_req = MS_FALSE; + } + } + + if (MS_TRUE == is_prov_req) + { + /* Start Provisioning over GATT here */ + /** + setup 3) +// { +// _data_pram = EM_alloc_mem(data_len - 3); +// EM_mem_copy(_data_pram, data_param+marker, data_len-3); +// } +// EM_mem_copy((UCHAR *)state_params.state,data_param+marker,data_len-3); + state_params.vendormodel_param = &data_param[marker]; +// EM_free_mem(_data_pram); + /* Set Request Type */ + req_type.type = MS_ACCESS_MODEL_REQ_MSG_T_OTHERS; + req_type.to_be_acked = 0x00; + } + break; + + case MS_ACCESS_VENDORMODEL_NOTIFY_OPCODE: + { +// UCHAR *_data_pram; + state_params.vendormodel_type = MS_STATE_VENDORMODEL_NOTIFY_T; + marker = 1; +// if(data_len > 1) +// { +// _data_pram = EM_alloc_mem(data_len - 1); +// EM_mem_copy(_data_pram, data_param+marker, data_len-1); +// } + state_params.vendormodel_param = &data_param[marker]; +// EM_free_mem(_data_pram); + /* Set Request Type */ + req_type.type = MS_ACCESS_MODEL_REQ_MSG_T_OTHERS; + req_type.to_be_acked = 0x00; + } + break; + + default: +// printf( +// "MS_ACCESS_PHY_MODEL_NONE_OPCODE\n"); + break; + } + + /* Application callback */ + if (NULL != vendormodel_client_UI_cb) + { + vendormodel_client_UI_cb(&req_context, &req_raw, &req_type, &state_params, ext_params_p); + } + + return retval; +} + +/* ----------------------------------------- Functions */ +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_vendormodel_client_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_VENDORMODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params, + /* IN */ UINT16 data_length +) +{ + API_RESULT retval; + /* TODO: Check what should be maximum length */ + UCHAR buffer[256]; + UCHAR* pdu_ptr; + UINT16 marker; + UINT32 opcode; + retval = API_FAILURE; + marker = 0; + +// printf( +// "current_state_params->state_type 0x%04X.\n",current_state_params->phy_mode_type); + + switch (current_state_params->vendormodel_type) + { + case MS_STATE_VENDORMODEL_ONOFF_T: + { + buffer[marker] = ++vendor_tid; + marker++; + MS_PACK_LE_2_BYTE_VAL(&buffer[marker], current_state_params->vendormodel_type); + marker += 2; + EM_mem_copy(&buffer[marker], current_state_params->vendormodel_param, 1); + marker++; + /* Set Opcode */ + opcode = MS_ACCESS_VENDORMODEL_CONFIRMATION_OPCODE; + } + break; + + default: + break; + } + + /* Publish - reliable */ + if (0 == marker) + { + pdu_ptr = NULL; + } + else + { + pdu_ptr = buffer; + } + + retval = MS_access_reply + ( + &ctx->handle, + ctx->daddr, + ctx->saddr, + ctx->subnet_handle, + ctx->appkey_handle, + ACCESS_INVALID_DEFAULT_TTL, + opcode, + pdu_ptr, + marker + ); + return retval; +} + + +/** + \brief API to send acknowledged commands + + \par Description + This is to initialize sending acknowledged commands. + + \param [in] req_opcode Request Opcode. + \param [in] param Parameter associated with Request Opcode. + \param [in] rsp_opcode Response Opcode. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_vendormodel_client_send_reliable_pdu +( + /* IN */ UINT32 req_opcode, + /* IN */ void* param, + /* IN */ MS_NET_ADDR dst_addr +) +{ + API_RESULT retval; + /* TODO: Check what should be maximum length */ + UCHAR buffer[256]; + UCHAR* pdu_ptr; + UINT16 marker; + MS_APPKEY_HANDLE key_handle; + retval = API_FAILURE; + marker = 0; + +// printf( +// "[VENDOR_MODEL_CLIENT] Send Reliable PDU. Req Opcode 0x%08X\n", +// req_opcode); + + switch(req_opcode) + { + case MS_ACCESS_VENDORMODEL_GET_OPCODE: + { + MS_ACCESS_VENDORMODEL_STATE_PARAMS* param_p; + buffer[marker] = ++vendor_tid; + marker++; + param_p = (MS_ACCESS_VENDORMODEL_STATE_PARAMS*) param; + MS_PACK_LE_2_BYTE_VAL(&buffer[marker], param_p->vendormodel_type); + marker += 2; + } + break; + + case MS_ACCESS_VENDORMODEL_SET_OPCODE: + case MS_ACCESS_VENDORMODEL_SET_UNACKNOWLEDGED_OPCODE: + { + MS_ACCESS_VENDORMODEL_STATE_PARAMS* param_p; + buffer[marker] = ++vendor_tid; + marker++; + param_p = (MS_ACCESS_VENDORMODEL_STATE_PARAMS*) param; + MS_PACK_LE_2_BYTE_VAL(&buffer[marker], param_p->vendormodel_type); + marker += 2; + + switch(param_p->vendormodel_type) + { + case MS_STATE_VENDORMODEL_ONOFF_T: + { + EM_mem_copy(&buffer[marker], param_p->vendormodel_param, 1); + marker += 1; + } + break; + + case MS_STATE_VENDORMODEL_HSL_T: + { + EM_mem_copy(&buffer[marker], param_p->vendormodel_param, 6); + marker += 6; + } + break; + + default : + break; + } + } + break; + + case MS_ACCESS_VENDORMODEL_NOTIFY_OPCODE: + { + UINT16 len; + MS_ACCESS_VENDORMODEL_STATE_PARAMS* param_p; + param_p = (MS_ACCESS_VENDORMODEL_STATE_PARAMS*) param; + MS_IGNORE_UNUSED_PARAM(param_p->vendormodel_type); + MS_UNPACK_LE_2_BYTE(&len, param_p->vendormodel_param); + buffer[marker] = ++vendor_tid; + marker ++; + + if(len) + { + EM_mem_copy(&buffer[marker], ¶m_p->vendormodel_param[2], len); + marker += len; + } + } + break; + + default: + break; + } + + /* Publish - reliable */ + if (0 == marker) + { + pdu_ptr = NULL; + } + else + { + pdu_ptr = buffer; + } + + MS_access_get_appkey_handle + ( + &vendormodel_client_model_handle, + &key_handle + ); + retval = MS_access_raw_data + ( + &vendormodel_client_model_handle, + req_opcode, + dst_addr, + key_handle, + pdu_ptr, + marker, + MS_FALSE + ); + return retval; +} + + + +/** + \brief API to initialize Vendor_Example_1 Server model + + \par Description + This is to initialize Vendor_Example_1 Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] UI_cb Application Callback to be used by the Vendor_Example_1 Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_vendormodel_client_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_VENDORMODEL_CLIENT_CB UI_cb +) +{ + API_RESULT retval; + MS_ACCESS_NODE_ID node_id; + MS_ACCESS_MODEL model; + /* TBD: Initialize MUTEX and other data structures */ + /* Using default node ID */ + node_id = MS_ACCESS_DEFAULT_NODE_ID; +// printf( +// "[PHY_MODEL] Registered Element Handle 0x%02X\n", element_handle); + /* Configure Model */ + model.model_id.id = MS_MODEL_ID_VENDORMODEL_CLIENT; + model.model_id.type = MS_ACCESS_MODEL_TYPE_VENDOR; + model.elem_handle = element_handle; + /* Register Callback */ + model.cb = vendormodel_client_cb; + /* List of Opcodes */ + model.opcodes = vendormodel_client_opcode_list; + model.num_opcodes = sizeof(vendormodel_client_opcode_list) / sizeof(UINT32); + retval = MS_access_register_model + ( + node_id, + &model, + model_handle + ); + /* Save Application Callback */ + vendormodel_client_UI_cb = UI_cb; + vendormodel_client_model_handle = *model_handle; + return retval; +} + + + diff --git a/src/components/ethermind/mesh/export/vendormodel/client/vendormodel_client.h b/src/components/ethermind/mesh/export/vendormodel/client/vendormodel_client.h new file mode 100644 index 0000000..fafafea --- /dev/null +++ b/src/components/ethermind/mesh/export/vendormodel/client/vendormodel_client.h @@ -0,0 +1,108 @@ +/** + \file appl_config_client.h + + \brief This file defines the Mesh Configuration Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_VENDORMODEL_CLIENT_ +#define _H_VENDORMODEL_CLIENT_ + +#include "vendormodel_common.h" +#include "MS_access_api.h" +#include "access_extern.h" + + +/* --------------------------------------------- Header File Inclusion */ + + + +/* --------------------------------------------- Global Definitions */ + +/* --------------------------------------------- Data Types/ Structures */ +/** + Vendor Example Server application Asynchronous Notification Callback. + + Vendor Example Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_VENDORMODEL_CLIENT_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_VENDORMODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; + +/* ----------------------------------------- Functions */ +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_vendormodel_client_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_VENDORMODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params, + /* IN */ UINT16 data_length +); + + +/** + \brief API to send acknowledged commands + + \par Description + This is to initialize sending acknowledged commands. + + \param [in] req_opcode Request Opcode. + \param [in] param Parameter associated with Request Opcode. + \param [in] rsp_opcode Response Opcode. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_vendormodel_client_send_reliable_pdu +( + /* IN */ UINT32 req_opcode, + /* IN */ void* param, + /* IN */ MS_NET_ADDR dst_addr +); + + + + +/* --------------------------------------------- Function */ +API_RESULT MS_vendormodel_client_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_VENDORMODEL_CLIENT_CB UI_cb +); + + + +#endif /*_H_APPL_CONFIG_CLIENT_ */ diff --git a/src/components/ethermind/mesh/export/vendormodel/server/vendormodel_server.c b/src/components/ethermind/mesh/export/vendormodel/server/vendormodel_server.c new file mode 100644 index 0000000..ddb3829 --- /dev/null +++ b/src/components/ethermind/mesh/export/vendormodel/server/vendormodel_server.c @@ -0,0 +1,335 @@ +/** + \file phy_model_server.c + + \brief This file defines the Mesh Configuration Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + + + +/* --------------------------------------------- Header File Inclusion */ +#include "vendormodel_server.h" + + +/* --------------------------------------------- Data Types/ Structures */ + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Static Global Variables */ +static DECL_CONST UINT32 vendormodel_server_opcode_list[] = +{ + MS_ACCESS_VENDORMODEL_GET_OPCODE, + MS_ACCESS_VENDORMODEL_SET_OPCODE, + MS_ACCESS_VENDORMODEL_SET_UNACKNOWLEDGED_OPCODE, + MS_ACCESS_VENDORMODEL_WRITECMD_OPCODE, + MS_ACCESS_VENDORMODEL_CONFIRMATION_OPCODE, + MS_ACCESS_VENDORMODEL_NOTIFY_OPCODE +}; + +//static MS_ACCESS_MODEL_HANDLE phy_model_server_model_handle; +static MS_VENDORMODEL_SERVER_CB vendormodel_server_UI_cb; + +/* ----------------------------------------- Functions */ +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +__ATTR_SECTION_XIP__ API_RESULT MS_vendormodel_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_VENDORMODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params, + /* IN */ UINT16 data_length +) +{ + API_RESULT retval; + /* TODO: Check what should be maximum length */ + UCHAR buffer[256]; + UCHAR* pdu_ptr; + UINT16 marker; + UINT32 opcode; +// UINT16 ttl; +// ACCESS_CM_GET_RX_TTL(ttl); + retval = API_FAILURE; + marker = 0; + +// printf( +// "current_state_params->state_type 0x%04X.\n",current_state_params->phy_mode_type); + + switch (current_state_params->vendormodel_type) + { + case MS_STATE_VENDORMODEL_ONOFF_T: + { + buffer[marker] = ++vendor_tid; + marker++; + MS_PACK_LE_2_BYTE_VAL(&buffer[marker], current_state_params->vendormodel_type); + marker += 2; + EM_mem_copy(&buffer[marker], current_state_params->vendormodel_param, 1); + marker++; + /* Set Opcode */ + opcode = MS_ACCESS_VENDORMODEL_STATUS_OPCODE; + } + break; + + case MS_STATE_VENDORMODEL_NOTIFY_T: + { + EM_mem_copy(&buffer[marker], current_state_params->vendormodel_param, data_length); + marker += data_length; + /* Set Opcode */ + opcode = MS_ACCESS_VENDORMODEL_NOTIFY_OPCODE; + } + break; + + default: + break; + } + + /* Publish - reliable */ + if (0 == marker) + { + pdu_ptr = NULL; + } + else + { + pdu_ptr = buffer; + } + + retval = MS_access_reply + ( + &ctx->handle, + ctx->daddr, + ctx->saddr, + ctx->subnet_handle, + ctx->appkey_handle, + ACCESS_INVALID_DEFAULT_TTL, + opcode, + pdu_ptr, + marker + ); + return retval; +} + +/** + \brief Access Layer Application Asynchronous Notification Callback. + + \par Description + Access Layer calls the registered callback to indicate events occurred to the application. + + \param [in] handle Model Handle. + \param [in] saddr 16 bit Source Address. + \param [in] daddr 16 bit Destination Address. + \param [in] appkey_handle AppKey Handle. + \param [in] subnet_handle Subnet Handle. + \param [in] opcode Opcode. + \param [in] data_param Data associated with the event if any or NULL. + \param [in] data_len Size of the event data. 0 if event data is NULL. +*/ +__ATTR_SECTION_XIP__ API_RESULT vendormodel_server_cb +( + /* IN */ MS_ACCESS_MODEL_HANDLE* handle, + /* IN */ MS_NET_ADDR saddr, + /* IN */ MS_NET_ADDR daddr, + /* IN */ MS_SUBNET_HANDLE subnet_handle, + /* IN */ MS_APPKEY_HANDLE appkey_handle, + /* IN */ UINT32 opcode, + /* IN */ UCHAR* data_param, + /* IN */ UINT16 data_len +) +{ + MS_ACCESS_MODEL_REQ_MSG_CONTEXT req_context; + MS_ACCESS_MODEL_REQ_MSG_RAW req_raw; + MS_ACCESS_MODEL_REQ_MSG_T req_type; + MS_ACCESS_MODEL_EXT_PARAMS* ext_params_p; + MS_ACCESS_VENDORMODEL_STATE_PARAMS state_params; + UINT16 marker; + API_RESULT retval; + retval = API_SUCCESS; + ext_params_p = NULL; + marker = 0; + /* Request Context */ + req_context.handle = *handle; + req_context.saddr = saddr; + req_context.daddr = daddr; + req_context.subnet_handle = subnet_handle; + req_context.appkey_handle = appkey_handle; + /* Request Raw */ + req_raw.opcode = opcode; + req_raw.data_param = data_param; + req_raw.data_len = data_len; + state_params.vendormodel_param = NULL; + + switch(opcode) + { + case MS_ACCESS_VENDORMODEL_GET_OPCODE: + { +// printf( +// "MS_ACCESS_PHY_MODEL_GET_OPCODE\n"); + MODEL_OPCODE_HANDLER_CALL(vendor_example_get_handler); + marker = 1; + MS_UNPACK_LE_2_BYTE(&state_params.vendormodel_type, data_param+marker); + marker += 2; + /* Get Request Type */ + req_type.type = MS_ACCESS_MODEL_REQ_MSG_T_GET; + req_type.to_be_acked = 0x01; + /* Assign reqeusted state type to the application */ + } + break; + + case MS_ACCESS_VENDORMODEL_SET_OPCODE: + case MS_ACCESS_VENDORMODEL_SET_UNACKNOWLEDGED_OPCODE: + { +// printf( +// "MS_ACCESS_PHY_MODEL_SET_OPCODE\n"); + MODEL_OPCODE_HANDLER_CALL(vendor_example_set_handler); + marker = 1; + MS_UNPACK_LE_2_BYTE(&state_params.vendormodel_type, data_param+marker); + marker += 2; + state_params.vendormodel_param = &data_param[marker]; + /* Set Request Type */ + req_type.type = MS_ACCESS_MODEL_REQ_MSG_T_SET; + + if(MS_ACCESS_VENDORMODEL_SET_OPCODE == opcode) + { + req_type.to_be_acked = 0x01; + } + else + { + req_type.to_be_acked = 0x00; + } + } + break; + + case MS_ACCESS_VENDORMODEL_STATUS_OPCODE: + { +// printf( +// "MS_ACCESS_PHY_MODEL_STATUS\n"); + MODEL_OPCODE_HANDLER_CALL(vendor_example_status_handler); + /* Set Request Type */ + req_type.type = MS_ACCESS_MODEL_REQ_MSG_T_OTHERS; + req_type.to_be_acked = 0x00; + } + break; + + case MS_ACCESS_VENDORMODEL_CONFIRMATION_OPCODE: + { +// printf( +// "MS_ACCESS_PHY_MODEL_CONFIRMATION\n"); + MODEL_OPCODE_HANDLER_CALL(vendor_example_confirmation_handler); + /* Set Request Type */ + req_type.type = MS_ACCESS_MODEL_REQ_MSG_T_OTHERS; + req_type.to_be_acked = 0x00; + } + break; + + case MS_ACCESS_VENDORMODEL_WRITECMD_OPCODE: + { +// printf( +// "MS_ACCESS_PHY_MODEL_WRITECMD_OPCODE\n"); + marker = 1; + MS_UNPACK_LE_2_BYTE(&state_params.vendormodel_type, data_param+marker); + marker += 2; + state_params.vendormodel_param = &data_param[marker]; + /* Set Request Type */ + req_type.type = MS_ACCESS_MODEL_REQ_MSG_T_OTHERS; + req_type.to_be_acked = 0x00; + } + break; + + case MS_ACCESS_VENDORMODEL_NOTIFY_OPCODE: + { +// printf( +// "MS_ACCESS_PHY_MODEL_NOTIFY_OPCODE\n"); + state_params.vendormodel_type = MS_STATE_VENDORMODEL_NOTIFY_T; + marker = 1; + state_params.vendormodel_param = &data_param[marker]; + /* Set Request Type */ + req_type.type = MS_ACCESS_MODEL_REQ_MSG_T_OTHERS; + req_type.to_be_acked = 0x00; + } + break; + + default: + printf( + "MS_ACCESS_VENDORMODEL_NONE_OPCODE\n"); + break; + } + + /* Application callback */ + if (NULL != vendormodel_server_UI_cb) + { + vendormodel_server_UI_cb(&req_context, &req_raw, &req_type, &state_params, ext_params_p); + } + + return retval; +} + + + +/** + \brief API to initialize Vendor_Example_1 Server model + + \par Description + This is to initialize Vendor_Example_1 Server model and to register with Acess layer. + + \param [in] element_handle + Element identifier to be associated with the model instance. + + \param [in, out] model_handle + Model identifier associated with the model instance on successful initialization. + After power cycle of an already provisioned node, the model handle will have + valid value and the same will be reused for registration. + + \param [in] UI_cb Application Callback to be used by the Vendor_Example_1 Server. + + \return API_SUCCESS or an error code indicating reason for failure +*/ +__ATTR_SECTION_XIP__ API_RESULT MS_vendormodel_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_VENDORMODEL_SERVER_CB UI_cb +) +{ + API_RESULT retval; + MS_ACCESS_NODE_ID node_id; + MS_ACCESS_MODEL model; + /* TBD: Initialize MUTEX and other data structures */ + /* Using default node ID */ + node_id = MS_ACCESS_DEFAULT_NODE_ID; + /* Configure Model */ + model.model_id.id = MS_MODEL_ID_VENDORMODEL_SERVER; + model.model_id.type = MS_ACCESS_MODEL_TYPE_VENDOR; + model.elem_handle = element_handle; + /* Register Callback */ + model.cb = vendormodel_server_cb; + /* List of Opcodes */ + model.opcodes = vendormodel_server_opcode_list; + model.num_opcodes = sizeof(vendormodel_server_opcode_list) / sizeof(UINT32); + retval = MS_access_register_model + ( + node_id, + &model, + model_handle + ); + /* Save Application Callback */ + vendormodel_server_UI_cb = UI_cb; + // /* TODO: Remove */ +// phy_model_server_model_handle = *model_handle; + return retval; +} + + diff --git a/src/components/ethermind/mesh/export/vendormodel/server/vendormodel_server.h b/src/components/ethermind/mesh/export/vendormodel/server/vendormodel_server.h new file mode 100644 index 0000000..5ed6764 --- /dev/null +++ b/src/components/ethermind/mesh/export/vendormodel/server/vendormodel_server.h @@ -0,0 +1,85 @@ +/** + \file appl_generic_onoff_server.h +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_VENDORMODEL_SERVER_ +#define _H_VENDORMODEL_SERVER_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "vendormodel_common.h" +#include "MS_access_api.h" +#include "access_extern.h" + + + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ +/** + Vendor Example Server application Asynchronous Notification Callback. + + Vendor Example Server calls the registered callback to indicate events occurred to the + application. + + \param [in] ctx Context of the message received for a specific model instance. + \param [in] msg_raw Uninterpreted/raw received message. + \param [in] req_type Requested message type. + \param [in] state_params Model specific state parameters. + \param [in] ext_params Additional parameters. +*/ +typedef API_RESULT (* MS_VENDORMODEL_SERVER_CB) +( + MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + MS_ACCESS_MODEL_REQ_MSG_RAW* msg_raw, + MS_ACCESS_MODEL_REQ_MSG_T* req_type, + MS_ACCESS_VENDORMODEL_STATE_PARAMS* state_params, + MS_ACCESS_MODEL_EXT_PARAMS* ext_params + +) DECL_REENTRANT; + +/* ----------------------------------------- Functions */ +/** + \brief API to send reply or to update state change + + \par Description + This is to send reply for a request or to inform change in state. + + \param [in] ctx Context of the message. + \param [in] current_state_params Model specific current state parameters. + \param [in] target_state_params Model specific target state parameters (NULL: to be ignored). + \param [in] remaining_time Time from current state to target state (0: to be ignored). + \param [in] ext_params Additional parameters (NULL: to be ignored). + + \return API_SUCCESS or an error code indicating reason for failure +*/ +API_RESULT MS_vendormodel_server_state_update +( + /* IN */ MS_ACCESS_MODEL_REQ_MSG_CONTEXT* ctx, + /* IN */ MS_ACCESS_VENDORMODEL_STATE_PARAMS* current_state_params, + /* IN */ MS_ACCESS_MODEL_STATE_PARAMS* target_state_params, + /* IN */ UINT16 remaining_time, + /* IN */ MS_ACCESS_MODEL_EXT_PARAMS* ext_params, + /* IN */ UINT16 data_length +); + + + + +/* --------------------------------------------- Function */ +API_RESULT MS_vendormodel_server_init +( + /* IN */ MS_ACCESS_ELEMENT_HANDLE element_handle, + /* INOUT */ MS_ACCESS_MODEL_HANDLE* model_handle, + /* IN */ MS_VENDORMODEL_SERVER_CB UI_cb +); + + +#endif /*_H_APPL_GENERIC_ONOFF_SERVER_ */ diff --git a/src/components/ethermind/mesh/export/vendormodel/vendormodel_common.h b/src/components/ethermind/mesh/export/vendormodel/vendormodel_common.h new file mode 100644 index 0000000..dfb12d5 --- /dev/null +++ b/src/components/ethermind/mesh/export/vendormodel/vendormodel_common.h @@ -0,0 +1,75 @@ +/** + \file appl_config_client.h + + \brief This file defines the Mesh Configuration Model Application Interface + - includes Data Structures and Methods for both Server and Client. +*/ + +/* + Copyright (C) 2018. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_VENDORMODEL_COMMON_ +#define _H_VENDORMODEL_COMMON_ + + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_common.h" + + + +//vendor model att +#define MS_STATE_VENDORMODEL_HSL_T 0x0123 +#define MS_STATE_VENDORMODEL_ONOFF_T 0x0100 +#define MS_STATE_VENDORMODEL_LIGHTNESS_T 0x0121 +#define MS_STATE_VENDORMODEL_CTL_T 0x0122 +#define MS_STATE_VENDORMODEL_MAINLIGHTONOFF_T 0x0534 +#define MS_STATE_VENDORMODEL_BACKLIGHTONOFF_T 0x0533 +#define MS_STATE_VENDORMODEL_HB_CALLBACK_T 0x0801 +#define MS_STATE_VENDORMODEL_RESET_T 0x0802 +#define MS_STATE_VENDORMODEL_MODENUMBER_T 0xF004 +#define MS_STATE_VENDORMODEL_EVENT_INDICATE_T 0xF009 +#define MS_STATE_VENDORMODEL_NOTIFY_T 0xFFFE + + + + +//phy model opcode +#define MS_ACCESS_VENDORMODEL_GET_OPCODE 0x00D00405 +#define MS_ACCESS_VENDORMODEL_SET_OPCODE 0x00D10405 +#define MS_ACCESS_VENDORMODEL_SET_UNACKNOWLEDGED_OPCODE 0x00D20405 +#define MS_ACCESS_VENDORMODEL_STATUS_OPCODE 0x00D30405 +#define MS_ACCESS_VENDORMODEL_INDICATION_OPCODE 0x00D40405 +#define MS_ACCESS_VENDORMODEL_CONFIRMATION_OPCODE 0x00D50405 +#define MS_ACCESS_VENDORMODEL_WRITECMD_OPCODE 0x00E00405 +#define MS_ACCESS_VENDORMODEL_NOTIFY_OPCODE 0x00E10405 + +#define MS_MODEL_ID_VENDORMODEL_SERVER 0x00000059 +#define MS_MODEL_ID_VENDORMODEL_CLIENT 0x00010059 + + + + + +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Data Types/ Structures */ +typedef struct _MS_access_vendormodel_state_params +{ + /** State Type */ + UINT16 vendormodel_type; + + /** State pointer */ + UCHAR* vendormodel_param; + +} MS_ACCESS_VENDORMODEL_STATE_PARAMS; + + + + + +/* --------------------------------------------- Function */ + +#endif /*_H_APPL_CONFIG_CLIENT_ */ diff --git a/src/components/ethermind/osal/src/phyos/EM_assert.h b/src/components/ethermind/osal/src/phyos/EM_assert.h new file mode 100644 index 0000000..11d1a12 --- /dev/null +++ b/src/components/ethermind/osal/src/phyos/EM_assert.h @@ -0,0 +1,55 @@ + +/** + \file EM_assert.h + + This file contains the implementation of EM_assert() macro, + used to evaluate an expression and take action based on whether + the expression is true or false. + + Version: Windows User Mode +*/ + +/* + Copyright (C) 2013. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_EM_ASSERT_ +#define _H_EM_ASSERT_ + +/* -------------------------------------------- Header File Inclusion */ +/* The EtherMind Debug Library */ +#include "EM_debug.h" + + +/* -------------------------------------------- Macros */ +/* + Macro to assert the validity (truth-value) of an expression. + This is similar to the standard C macro assert(). + + The default behaviour of this macro is to dump the following + information to the debug system (which could be a file or + a serial port or some other interface, as abstracted by the + Debug Library): + 1. The expression under assertion + 2. The source file (using the macro __FILE__) + 3. The source line number (using the macro __LINE__) + + This macro is diagnostic in nature and its default implementation + does not abort the system as opposed to the standard assert() macro, + since in an embedded system or even when running in the kernel/driver + mode, if the system aborts it is very difficult and sometime even + impossible to find out what caused this catastrophic effect. + + This macro can be modified to suit the target environment and + also according to the various stages of life-cycle of the system. +*/ +#define EM_assert(exp) \ + if (!(exp)) \ + { \ + EM_debug_error(0, \ + "[ASSERT] %s:%d `" #exp "`\n", __FILE__, __LINE__); \ + } + +#endif /* _H_EM_ASSERT_ */ + diff --git a/src/components/ethermind/osal/src/phyos/EM_debug.c b/src/components/ethermind/osal/src/phyos/EM_debug.c new file mode 100644 index 0000000..a8e61c9 --- /dev/null +++ b/src/components/ethermind/osal/src/phyos/EM_debug.c @@ -0,0 +1,268 @@ + +/** + \file EM_debug.c + + This file contains source codes for the EtherMind Debug Library + Implementation for Windows (User-mode). +*/ + +/* + Copyright (C) 2013. Mindtree Ltd. + All rights reserved. +*/ + +/* --------------------------------------------------- Header File Inclusion */ +#include "EM_debug_internal.h" + +/* --------------------------------------------------- Global Definitions */ + +/* ------------------------------------------------- Static Global Variables */ +#ifdef EM_ENABLE_DISABLE_RUNTIME_DEBUG + /* Runtime debug level */ + DECL_STATIC UCHAR em_runtime_debug_level; + + /* Module Specific debug enabled/disabled flag */ + DECL_STATIC UINT32 em_runtime_debug_flag[EM_MAX_MODULE_PAGE_COUNT]; +#endif /* EM_ENABLE_DISABLE_RUNTIME_DEBUG */ + +/* Hack. TBD */ +#define EM_MODULE_ID_DEBUG 0 +/* ------------------------------------------------- Functions */ + +void EM_debug_init (void) +{ + #ifdef EM_ENABLE_DISABLE_RUNTIME_DEBUG + UINT32 enable_all_bit_mask, page_index; + #endif /* EM_ENABLE_DISABLE_RUNTIME_DEBUG */ + #ifdef EM_ENABLE_DISABLE_RUNTIME_DEBUG + /* Initialize runtime debug level */ + em_runtime_debug_level = EM_DEBUG_LEVEL_ALL; + #ifndef EM_DISABLE_DEBUG_LOG_ON_STARTUP + /* Enable all module debug log - by default */ + enable_all_bit_mask = 0xFFFFFFFF; + #else + enable_all_bit_mask = 0x00000000; + #endif /* EM_DISABLE_DEBUG_LOG_ON_STARTUP */ + + for (page_index = 0; page_index < EM_MAX_MODULE_PAGE_COUNT; page_index++) + { + em_runtime_debug_flag[page_index] = enable_all_bit_mask; + } + + #endif /* EM_ENABLE_DISABLE_RUNTIME_DEBUG */ + return; +} + +void EM_debug_shutdown (void) +{ + return; +} + +#ifndef EM_DISABLE_ALL_DEBUG +INT32 EM_debug_printf(UCHAR msg_type, UINT32 module_id, const CHAR* fmt, ...) +{ + #ifdef EM_ENABLE_DISABLE_RUNTIME_DEBUG + UINT32 page_index; + UINT32 module_bit_mask; + #endif /* EM_ENABLE_DISABLE_RUNTIME_DEBUG */ + va_list parg; +// return 0; + #ifdef EM_ENABLE_DISABLE_RUNTIME_DEBUG + + /* Check Message Level */ + if (msg_type > em_runtime_debug_level) + { + return -1; + } + + /* Extract Page Index and Module Bit Mask */ + EM_GET_PAGE_IDX_MODULE_BIT_MASK(module_id, page_index, module_bit_mask); + + /* Check if the module debug log is enabled */ + if ((em_runtime_debug_flag[page_index] & module_bit_mask) != module_bit_mask) + { + return -1; + } + + #endif /* EM_ENABLE_DISABLE_RUNTIME_DEBUG */ + va_start (parg, fmt); + vprintf (fmt, parg); + va_end (parg); + return 0; +} + +INT32 EM_debug_dump_bytes(UINT32 module_id, UCHAR* buffer, UINT32 length) +{ + char hex_stream[49]; + char char_stream[17]; + UINT32 i; + UINT16 offset, count; + UCHAR c; + EM_debug_dump(module_id, "-- Dumping %d Bytes --\n", + (int)length); + EM_debug_dump(module_id, + "-------------------------------------------------------------------\n"); + count = 0; + offset = 0; + + for(i = 0; i < length; i ++) + { + c = buffer[i]; + sprintf(hex_stream + offset, "%02X ", c); + + if ( (c >= 0x20) && (c <= 0x7E) ) + { + char_stream[count] = c; + } + else + { + char_stream[count] = '.'; + } + + count ++; + offset += 3; + + if(16 == count) + { + char_stream[count] = '\0'; + count = 0; + offset = 0; + EM_debug_dump(module_id, "%s %s\n", + hex_stream, char_stream); + EM_mem_set(hex_stream, 0, 49); + EM_mem_set(char_stream, 0, 17); + } + } + + if(0 != offset) + { + char_stream[count] = '\0'; + /* Maintain the alignment */ + EM_debug_dump(module_id, "%-48s %s\n", + hex_stream, char_stream); + } + + EM_debug_dump(module_id, + "-------------------------------------------------------------------\n"); + return 0; +} + + +INT32 EM_debug_dump_decimal(UINT32 module_id, UCHAR* buffer, UINT32 length) +{ + char stream[100]; + UINT32 i; + UINT16 offset, count; + EM_debug_dump(module_id, "Dumping %d Bytes (In Decimal): ------>\n", + (int)length); + count = 0; + offset = 0; + + for(i = 0; i < length; i ++) + { + sprintf(stream + offset, "%3d ", (unsigned int)buffer[i]); + count ++; + offset += 4; + + if(16 == count) + { + count = 0; + offset = 0; + EM_debug_dump(module_id, "%s\n", stream); + EM_mem_set(stream, 0, 100); + } + } + + if(0 != offset) + { + EM_debug_dump(module_id, "%s\n", stream); + } + + EM_debug_dump(module_id, "<------------------------------------>\n"); + return 0; +} +#endif /* EM_DISABLE_ALL_DEBUG */ + +#ifdef EM_LOG_TIMESTAMP +UCHAR* EM_debug_get_current_timestamp (void) +{ + #ifndef FREERTOS + static UCHAR time_str[20]; + struct tm* dt; + time_t now = time (0); + dt = localtime (&now); + /* Use gmtime for UTC */ + /* dt = gmtime (&now); */ + strftime (time_str, sizeof(time_str), "%H:%M:%S", dt); + /* Use following piece of code to print date along with time */ + /* strftime (time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", dt); */ + return time_str; + #else + return NULL; + #endif /* FREERTOS */ +} +#endif /* BT_LOG_TIMESTAMP */ + + +#ifdef EM_ENABLE_DISABLE_RUNTIME_DEBUG +void EM_set_debug_level(UCHAR level) +{ + /* Parameter validation */ + if (EM_DEBUG_LEVEL_ALL < level) + { + /* Failure */ + return; + } + + /* Set runtime debug level */ + em_runtime_debug_level = level; + return; +} + +void EM_update_module_debug_flag(UINT32 module_id, UCHAR flag) +{ + UINT32 page_index; + UINT32 module_bit_mask; + + /* Parameter Validation */ + if (EM_DEBUG_ENABLE < flag) + { + return; + } + + /* Check if the request is for enable/disable all */ + if (EM_MODULE_ALL == module_id) + { + if (EM_DEBUG_ENABLE == flag) + { + module_bit_mask = 0xFFFFFFFF; + } + else + { + module_bit_mask = 0x00000000; + } + + for (page_index = 0; page_index < EM_MAX_MODULE_PAGE_COUNT; page_index++) + { + em_runtime_debug_flag[page_index] = module_bit_mask; + } + + return; + } + + /* Extract Page Index and Module Bit Mask */ + EM_GET_PAGE_IDX_MODULE_BIT_MASK(module_id, page_index, module_bit_mask); + + /* Enable/disable based on the flag */ + if (EM_DEBUG_ENABLE == flag) + { + em_runtime_debug_flag[page_index] |= (module_bit_mask); + } + else + { + em_runtime_debug_flag[page_index] &= ~(module_bit_mask); + } +} +#endif /* EM_ENABLE_DISABLE_RUNTIME_DEBUG */ + + diff --git a/src/components/ethermind/osal/src/phyos/EM_debug.h b/src/components/ethermind/osal/src/phyos/EM_debug.h new file mode 100644 index 0000000..0b608ab --- /dev/null +++ b/src/components/ethermind/osal/src/phyos/EM_debug.h @@ -0,0 +1,25 @@ + +/** + \file EM_debug.h + + This Header File contains the APIs exported by the + EtherMind Debug Library for Windows (User-mode). +*/ + +/* + Copyright (C) 2013. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_EM_DEBUG_ +#define _H_EM_DEBUG_ + +/* ----------------------------------------------- Header File Inclusion */ +#include "EM_os.h" + +/* extern FILE *em_debug_fd; */ + +#include "EM_debug_api.h" + +#endif /* _H_EM_DEBUG_ */ + diff --git a/src/components/ethermind/osal/src/phyos/EM_debug_api.h b/src/components/ethermind/osal/src/phyos/EM_debug_api.h new file mode 100644 index 0000000..fd99e8e --- /dev/null +++ b/src/components/ethermind/osal/src/phyos/EM_debug_api.h @@ -0,0 +1,186 @@ + +/** + \file EM_debug_api.h + + This Header File contains the APIs and the ADTs exported by the + EtherMind Debug Library for Windows (User-mode). +*/ + +/* + Copyright (C) 2013. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_EM_DEBUG_API_ +#define _H_EM_DEBUG_API_ + +/* ----------------------------------------------- Header File Inclusion */ +#include "EM_os.h" + +#define EM_DEBUG_DONT_LOG_FILE_PATH +#define EM_ENABLE_DISABLE_RUNTIME_DEBUG + +/* ----------------------------------------------- Debug Macros */ +/* Define Debug Message Types */ +/* Message Type - ERR */ +#define EM_DEBUG_MSG_ERR 1 + +/* Message Type - TRC */ +#define EM_DEBUG_MSG_TRC 2 + +/* Message Type - INF */ +#define EM_DEBUG_MSG_INF 3 + +/* Define Debug Levels */ +/* No runtime error logging */ +#define EM_DEBUG_LEVEL_NONE 0 + +/* Log only ERR messages */ +#define EM_DEBUG_LEVEL_ERR 1 + +/* Log ERR and TRC messages */ +#define EM_DEBUG_LEVEL_TRC 2 + +/* Log ERR, TRC and INF messages */ +#define EM_DEBUG_LEVEL_INF 3 +#define EM_DEBUG_LEVEL_ALL 3 + +/* Maximum number of module pages */ +#define EM_MODULE_PAGE_BITS_COUNT 4 +#define EM_MAX_MODULE_PAGE_COUNT (1 << EM_MODULE_PAGE_BITS_COUNT) + +/* Debug Enable/Disable flag */ +#define EM_DEBUG_ENABLE 0x01 +#define EM_DEBUG_DISABLE 0x00 + +/** + Special wildcard define to represent all modules. + Used to enable/disable all module at once. +*/ +#define EM_MODULE_ALL 0xFFFFFFFF + +#define EM_GET_PAGE_IDX_MODULE_BIT_MASK(module_id, page_idx, m_bit_mask) \ + { \ + /* Extract the Page Number and Module Bit Mask */ \ + (page_idx) = ((module_id) >> (32 - EM_MODULE_PAGE_BITS_COUNT)); \ + (m_bit_mask) = (((page_idx) << (32 - EM_MODULE_PAGE_BITS_COUNT)) ^ (module_id)); \ + } + +#define EM_GET_MODULE_ID(module_id, page_idx, m_bit_mask) \ + { \ + /* Create Module Id from the Page Number and Module Bit Mask */ \ + (module_id) = (((page_idx) << (32 - EM_MODULE_PAGE_BITS_COUNT)) | (m_bit_mask)); \ + } + + +#ifdef EM_ENABLE_DISABLE_RUNTIME_DEBUG +#define EM_enable_module_debug_flag(module_id) \ + EM_update_module_debug_flag((module_id), EM_DEBUG_ENABLE) + +#define EM_disable_module_debug_flag(module_id) \ + EM_update_module_debug_flag((module_id), EM_DEBUG_DISABLE) +#endif /* EM_ENABLE_DISABLE_RUNTIME_DEBUG */ + +#ifdef EM_DEBUG_DONT_LOG_FILE_PATH +#define EM_FILE_NAME \ + (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) +#else +#define EM_FILE_NAME __FILE__ +#endif /* EM_DEBUG_DONT_LOG_FILE_PATH */ + +/* Debug print macros, based on the debug message types */ +#define EM_debug_printf_err(module_id, ...) EM_debug_printf(EM_DEBUG_MSG_ERR, (module_id), __VA_ARGS__) +#define EM_debug_printf_trc(module_id, ...) EM_debug_printf(EM_DEBUG_MSG_TRC, (module_id), __VA_ARGS__) +#define EM_debug_printf_inf(module_id, ...) EM_debug_printf(EM_DEBUG_MSG_INF, (module_id), __VA_ARGS__) + +#ifdef EM_LOG_TIMESTAMP +#define EM_debug_error(module_id, ...) \ + EM_debug_printf_err((module_id), "\n[** ERR **]:[%s]:[%s]:[%d]: [<%s>] ", \ + EM_debug_get_current_timestamp(), EM_FILE_NAME, __LINE__); \ + EM_debug_printf_err((module_id), __VA_ARGS__) + +#define EM_debug_trace(module_id, ...) \ + EM_debug_printf_trc((module_id), "\n[-- TRC --]:[%s]:[%s]:[%d]: [<%s>] ", \ + EM_debug_get_current_timestamp(), EM_FILE_NAME, __LINE__); \ + EM_debug_printf_trc((module_id), __VA_ARGS__) + +#define EM_debug_info(module_id, ...) \ + EM_debug_printf_inf((module_id), "\n[== INF ==]:[%s]:[%s]:[%d]: [<%s>] ", \ + EM_debug_get_current_timestamp(), EM_FILE_NAME, __LINE__); \ + EM_debug_printf_inf((module_id), __VA_ARGS__) + +#define EM_debug_dump(module_id, ...) \ + EM_debug_printf_inf((module_id), "\n[++ HEX ++]:[%s]:[%s]:[%d]: [<%s>] ", \ + EM_debug_get_current_timestamp(), EM_FILE_NAME, __LINE__); \ + EM_debug_printf_inf((module_id), __VA_ARGS__) + +#else /* EM_LOG_TIMESTAMP */ +#define EM_debug_error(module_id, ...) \ + EM_debug_printf_err((module_id), "\n[** ERR **]:[%s]:[%d]: ", \ + EM_FILE_NAME, __LINE__); \ + EM_debug_printf_err((module_id), __VA_ARGS__) + +#define EM_debug_trace(module_id, ...) \ + EM_debug_printf_trc((module_id), "\n[-- TRC --]:[%s]:[%d]: ", \ + EM_FILE_NAME, __LINE__); \ + EM_debug_printf_trc((module_id), __VA_ARGS__) + +#define EM_debug_info(module_id, ...) \ + EM_debug_printf_inf((module_id), "\n[== INF ==]:[%s]:[%d]: ", \ + EM_FILE_NAME, __LINE__); \ + EM_debug_printf_inf((module_id), __VA_ARGS__) + +#define EM_debug_dump(module_id, ...) \ + EM_debug_printf_inf((module_id), "\n[++ HEX ++]:[%s]:[%d]: ", \ + EM_FILE_NAME, __LINE__); \ + EM_debug_printf_inf((module_id), __VA_ARGS__) + +#endif /* EM_LOG_TIMESTAMP */ + +/* TBD: Check where is this being used */ +#define EM_debug_direct(module_id, ...) \ + EM_debug_printf_inf((module_id), "\n[~~ LOG ~~]: "); \ + EM_debug_printf_inf((module_id), __VA_ARGS__) + + +/* ----------------------------------------------- Global Definitions */ +#define EM_debug_null(...) + +/* ----------------------------------------------- Structures/Data Types */ + + +/* ----------------------------------------------- Function Declarations */ +#ifdef __cplusplus +extern "C" { +#endif + +/* Debug Library Init & Shutdown Routines */ +void EM_debug_init ( void ); +void EM_debug_shutdown ( void ); + +#ifndef EM_DISABLE_ALL_DEBUG +INT32 EM_debug_printf(UCHAR msg_type, UINT32 module_id, const CHAR* fmt, ...); +INT32 EM_debug_dump_bytes(UINT32 module_id, UCHAR* buffer, UINT32 length); +INT32 EM_debug_dump_decimal(UINT32 module_id, UCHAR* buffer, UINT32 length); +#else +#define EM_debug_printf(...) +#define EM_debug_dump_bytes(module_id, buffer, length) +#define EM_debug_dump_decimal(module_id, buffer, length ) +#endif /* EM_DISABLE_ALL_DEBUG */ + +#ifdef EM_LOG_TIMESTAMP +UCHAR* EM_debug_get_current_timestamp (void); +#endif /* EM_LOG_TIMESTAMP */ + +#ifdef EM_ENABLE_DISABLE_RUNTIME_DEBUG +void EM_set_debug_level(UCHAR level); + +void EM_update_module_debug_flag(UINT32 module_id, UCHAR flag); +#endif /* EM_ENABLE_DISABLE_RUNTIME_DEBUG */ + +#ifdef __cplusplus +}; +#endif + +#endif /* _H_EM_DEBUG_API_ */ + diff --git a/src/components/ethermind/osal/src/phyos/EM_debug_internal.h b/src/components/ethermind/osal/src/phyos/EM_debug_internal.h new file mode 100644 index 0000000..934fbb8 --- /dev/null +++ b/src/components/ethermind/osal/src/phyos/EM_debug_internal.h @@ -0,0 +1,31 @@ + +/** + \file EM_debug_internal.h + + Internal Header File of EtherMind Debug Library + for Windows (User-mode). +*/ + +/* + Copyright (C) 2013. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_EM_DEBUG_INTERNAL_ +#define _H_EM_DEBUG_INTERNAL_ + +/* ----------------------------------------------- Header File Inclusion */ +#include "EM_debug.h" + +/* ----------------------------------------------- Internal Functions */ +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef __cplusplus +}; +#endif + +#endif /* _H_EM_DEBUG_INTERNAL_ */ + diff --git a/src/components/ethermind/osal/src/phyos/EM_os.c b/src/components/ethermind/osal/src/phyos/EM_os.c new file mode 100644 index 0000000..3c7dfcd --- /dev/null +++ b/src/components/ethermind/osal/src/phyos/EM_os.c @@ -0,0 +1,409 @@ + +/** + \file EM_os.c + + This source file is part of EtherMind OS Abstraction module. + In this file the platform dependent library calls are abstracted + and mapped to calls used within the EtherMind Stack. +*/ + +/* + Copyright (C) 2013. Mindtree Ltd. + All rights reserved. +*/ + +/* -------------------------------------------- Header File Inclusion */ +#include "EM_os.h" + + +/* -------------------------------------------- External Global Variables */ +extern uint32_t osal_sys_tick; + + +/* -------------------------------------------- Exported Global Variables */ + +/* -------------------------------------------- Static Global Variables */ + +/* -------------------------------------------- Functions */ + +void EM_os_init (void) +{ +} + +/** + \fn EM_thread_create + + \brief To create a task/thread + + \par Description: + This function implements the OS Wrapper for the Thread Create call. + It creates a new thread of control that executes concurrently with + the calling thread. + + \param [out] thread + Caller allocated location to hold the Thread ID + for the newly Created Thread + \param [in] attr + The Thread Attributes, pre-initialized using EM_thread_attr_init() + \param [in] start_routine + The Thread Start Routine for the newly created task/thread. + Upon creation, the new task/thread calls this function, + passing it 'thread_args' as the argument + \param [in] thread_args + This parameter points to a caller allocated "resident" memory + location, containing the arguments to be passed to + the newly created task's/thread's start routine + + \return INT32 : 0 on Success. -1 on Failure. +*/ +INT32 EM_thread_create +( + /* OUT */ EM_thread_type* thread, + /* IN */ EM_thread_attr_type* attr, + /* IN */ EM_THREAD_START_ROUTINE start_routine, + /* IN */ void* thread_args +) +{ + return 0; +} + + +/** + \fn EM_thread_attr_init + + \brief To initialize a task's/thread's attributes to default settings + + \par Description: + This function implements the OS Wrapper for the Thread attribute init + call. It initializes the given thread attribute object with default + values. + + \param [out] attr + Thread attribute object to be initialized + + \return INT32 : 0 on Success. -1 on Failure. +*/ +INT32 EM_thread_attr_init +( + /* OUT */ EM_thread_attr_type* attr +) +{ + (void) attr; + return 0; +} + + +/** + \fn EM_thread_mutex_init + + \brief To initialize a Mutex object + + \par Description: + This function implements the OS Wrapper for the Thread Mutex Init Call. + It creates or initializes the mutex object and fills it with default + values for the attributes. + + \param [out] mutex + The Mutex variable to be Initialized + \param [in] mutex_attr + Attribute of the mutex variable on initialization + + \return INT32 : 0 on Success. -1 on Failure. +*/ +INT32 EM_thread_mutex_init +( + /* OUT */ EM_thread_mutex_type* mutex, + /* IN */ EM_thread_mutex_attr_type* mutex_attr +) + +{ + (void) mutex_attr; + return 0; +} + + +/** + \fn EM_thread_mutex_lock + + \brief To lock a Mutex object + + \par Description: + This function implements the OS Wrapper for the Thread Mutex Lock call. + It locks the given mutex. + If the given mutex is currently unlocked, it becomes locked and owned by + the calling thread, and this routine returns immediately. + If the mutex is already locked by another thread, this routine suspends + the calling thread until the mutex is unlocked. + + \param [in,out] mutex + The Mutex variable to be locked + + \return INT32 : 0 on Success. -1 on Failure. +*/ +INT32 EM_thread_mutex_lock +( + /* INOUT */ EM_thread_mutex_type* mutex +) +{ + return 0; +} + + +/** + \fn EM_thread_mutex_unlock + + \brief To unlock a Mutex object + + \par Description: + This function implements the OS Wrapper for the Mutex Unlock call. + It unlocks the given mutex. The mutex is assumed to be locked and + owned by the calling thread. + + \param [in,out] mutex + The Mutex variable to be unlocked + + \return INT32 : 0 on Success. -1 on Failure. +*/ +INT32 EM_thread_mutex_unlock +( + /* INOUT */ EM_thread_mutex_type* mutex +) +{ + return 0; +} + + +/** + \fn EM_thread_cond_init + + \brief To initialize a Conditional Variable object + + \par Description: + This function implements the Conditional Variable Initialisation call. + It initializes the given conditional variable. + + \param [out] cond + The Conditional Variable + \param [in] cond_attr + Attributes of the conditional variable on initialization + + \return INT32 : 0 on Success. -1 on Failure. + + \note + A conditional variable is a synchronization primitive that allows + threads to suspend execution and relinquish the processors + until some predicate on shared resources is satisfied. +*/ +INT32 EM_thread_cond_init +( + /* OUT */ EM_thread_cond_type* cond, + /* IN */ EM_thread_cond_attr_type* cond_attr +) +{ + (void) cond_attr; + return 0; +} + + +/** + \fn EM_thread_cond_wait + + \brief To wait on a Conditional Variable object + + \par Description: + This function implements the OS Wrapper for the Thread Wait on + Conditional Variable call. + It waits for the conditional variable to be signaled. + This routine releases the mutex and waits for the condition variable + to be signaled. The execution of the calling thread is suspended + until the conditional variable is signaled. + The mutex must be locked by the calling thread before + calling this function. Before returning to the calling thread, + it will re-acquire the mutex variable. + + \param [in,out] cond + The Conditional Variable + \param [in,out] cond_mutex + The Conditional Mutex Variable + + \return INT32 : 0 on Success. -1 on Failure. +*/ +void EM_thread_cond_wait +( + /* INOUT */ EM_thread_cond_type* cond, + /* INOUT */ EM_thread_mutex_type* cond_mutex +) +{ + EM_thread_mutex_unlock (cond_mutex); + EM_thread_mutex_lock (cond_mutex); +} + + +/** + \fn EM_thread_cond_signal + + \brief To signal a Conditional Variable object + + \par Description: + This function implements the OS Wrapper for the Thread Signalling on + Conditional Variable Call. + It will signal and restart one of the threads that are waiting on + the given conditional variable. + + \param [in,out] cond + The Conditional Variable to signal + + \return INT32 : 0 on Success. -1 on Failure. +*/ +INT32 EM_thread_cond_signal +( + /* INOUT */ EM_thread_cond_type* cond +) +{ + return 0; +} + +extern uint32 osal_memory_statics(void); +/** + \fn EM_alloc_mem + + \brief To allocate memory dynamically + + \par Description: + This function implements the OS Wrapper for the Memory Allocation call. + It allocates memory of 'size' bytes and returns a pointer to + the allocated memory. + + \param [in] size + The number of bytes to allocate + + \return void * : Pointer to the newly Allocated Memory segment. + NULL, in case of failure +*/ +void* EM_alloc_mem ( /* IN */ UINT32 size ) +{ + void* buf; + buf = osal_mem_alloc (size); + + if (NULL == buf) + { + printf ("Memory Allocation Failed!, size = %d ", size); +// osal_memory_statics(); + } + +// printf("<+%d> ", size); + return buf; +} + + +/** + \fn EM_free_mem + + \brief To free dynamically allocated memory + + \par Description: + This function implements the OS Wrapper for the Memory Free call. + It frees the memory space specified by the given pointer. + + \param [in] ptr + Pointer to the Memory location to be freed + + \return None +*/ +void EM_free_mem ( /* IN */ void* ptr ) +{ + osal_mem_free(ptr); + return; +} + + +/** + \fn EM_sleep + + \brief To delay execution for a specified number of seconds + + \par Description: + This function implements the OS Wrapper for a Thread or task to sleep + for specified number of seconds. + + \param [in] tm + Number of seconds the calling task or thread wants to sleep + + \return None +*/ +void EM_sleep( /* IN */ UINT32 tm ) +{ + /* + 1s = 1000 ms. + 1ms = portTICK_RATE_MS Ticks + */ + /* The number of ticks for which the calling task should be held in the Blocked state. */ +} + + +/** + \fn EM_usleep + + \brief To delay execution for a specified number of microseconds + + \par Description: + This function implements the OS Wrapper for a Thread or task to sleep + for specified number of micro-seconds. + + \param [in] tm + Number of micro-seconds the calling task or thread wants to sleep + + \return None +*/ +void EM_usleep( /* IN */ UINT32 tm ) +{ + /* + 1000 us = 1ms. + 1ms = portTICK_RATE_MS Ticks + */ + /* The number of ticks for which the calling task should be held in the Blocked state. */ +} + + +/** + \fn EM_get_current_time + + \brief To get the current system time + + \par Description: + This function implements the OS Wrapper to get current time + from the system. + + \param [out] curtime + Current Time + + \return None +*/ +void EM_get_current_time (/* OUT */ UINT32* curtime) +{ + *curtime = osal_sys_tick; + return; +} + + +/** + \fn EM_get_local_time + + \brief To get the local time + + \par Description: + This function implements the OS Wrapper to get local time + from the system. + + \param [out] buf + Local Time and date buffer + \param [out] buflen + Size of buffer provided + + \return None +*/ +void EM_get_local_time( /* OUT */ UCHAR* buf, /* IN */ UINT16 buf_len) +{ + return; +} + diff --git a/src/components/ethermind/osal/src/phyos/EM_os.h b/src/components/ethermind/osal/src/phyos/EM_os.h new file mode 100644 index 0000000..70246d2 --- /dev/null +++ b/src/components/ethermind/osal/src/phyos/EM_os.h @@ -0,0 +1,206 @@ + +/** + \file EM_os.h + + This header file is part of EtherMind OS Abstraction module. + In this file the platform specific data types are abstracted and + mapped to data types used within the EtherMind Stack. + + Version: FreeRTOS +*/ + +/* + Copyright (C) 2013. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_EM_OS_ +#define _H_EM_OS_ + +/* OSAL Defines */ +//#define EM_DISABLE_ALL_DEBUG +/* #define EM_ENABLE_DISABLE_RUNTIME_DEBUG */ +/* #define EM_DISABLE_DEBUG_LOG_ON_STARTUP */ + +/* -------------------------------------------- Header File Inclusion */ +#include "EM_platform.h" + +/* -------------------------------------------- Global Definitions */ +#define EM_SUCCESS 0x0000 +#define EM_FAILURE 0xFFFF + +#undef EM_USE_EXT_TIMER + +/* -------------------------------------------- Structures/Data Types */ +/* 'signed' datatype of size '1 octet' */ +typedef char CHAR; +/* 'signed' datatype of size '1 octet' */ +typedef char INT8; +/* 'unsigned' datatype of size '1 octet' */ +typedef unsigned char UCHAR; +/* 'unsigned' datatype of size '1 octet' */ +typedef unsigned char UINT8; +/* 'signed' datatype of size '2 octet' */ +typedef short int INT16; +/* 'unsigned' datatype of size '2 octet' */ +typedef unsigned short int UINT16; +/* 'signed' datatype of size '4 octet' */ +typedef int INT32; +/* 'unsigned' datatype of size '4 octet' */ +typedef unsigned int UINT32; +/* 'unsigned' datatype of size '8 octet' */ +typedef unsigned long long UINT64; + +/* 'unsigned' datatype of size '1 octet' */ +typedef unsigned char BOOLEAN; + +/* + Generic handle can used for the unknow + datatypes (e.g. Mutex Type, Conditional Type etc.) +*/ +typedef void* EM_GENERIC_HANDLE; + +/* Datatype to represent Thread or Task Identifier */ +typedef void EM_thread_type; +/* Datatype to represent Thread or Task Attribute */ +typedef void EM_thread_attr_type; +/* Datatype to represent Mutex object */ +typedef void EM_thread_mutex_type; +/* Datatype to represent Attributes of a Mutex object */ +typedef void EM_thread_mutex_attr_type; +/* Datatype to represent Conditional Variable object */ +typedef void EM_thread_cond_type; +/* Datatype to represent Attributes of a Conditional Variable object */ +typedef void EM_thread_cond_attr_type; + +/* Datatype to represent File Handle */ +typedef EM_GENERIC_HANDLE EM_FILE_HANDLE; + +/* Data type to represent the OS time for the platform */ +typedef int EM_time_type; + +/* Data types for task parameters and retun types */ +typedef void* EM_THREAD_RETURN_TYPE; +typedef void* EM_THREAD_ARGS; +typedef EM_THREAD_RETURN_TYPE (*EM_THREAD_START_ROUTINE)(EM_THREAD_ARGS); + +/* Function Return Value typwe */ +typedef UINT16 EM_RESULT; + +/* --------------------------------------------------- Macros */ + +#define EM_THREAD_RETURN_VAL_SUCCESS NULL +#define EM_THREAD_RETURN_VAL_FAILURE NULL + +/* Declaration of 'static' variable/function */ +#ifdef EM_HAVE_STATIC_DECL + #define DECL_STATIC static +#else /* EM_HAVE_STATIC_DECL */ + #define DECL_STATIC +#endif /* EM_HAVE_STATIC_DECL */ + +/* Declaration of 'const' variable */ +#ifdef EM_HAVE_CONST_DECL + #define DECL_CONST const +#else /* EM_HAVE_CONST_DECL */ + #define DECL_CONST +#endif /* EM_HAVE_CONST_DECL */ + +/* Reentrant Function Declaration */ +#ifdef EM_HAVE_REENTRANT_DECL + #define DECL_REENTRANT reentrant +#else /* EM_HAVE_REENTRANT_DECL */ + #define DECL_REENTRANT +#endif /* EM_HAVE_REENTRANT_DECL */ + +#define DECL_CONST_QUALIFIER + +/* Abstractions for String library functions */ +#define EM_str_len(s) strlen((char *)(s)) +#define EM_str_copy(d, s) strcpy((char *)(d), (char *)(s)) +#define EM_str_n_copy(d, s, n) strncpy((char *)(d), (char *)(s), n) +#define EM_str_cmp(s1, s2) strcmp((char *)(s1), (char *)(s2)) +#define EM_str_n_cmp(s1, s2, n) strncmp((char *)(s1), (char *)(s2), n) +#define EM_str_cat(d, s) strcat((char *)(d), (char *)(s)) +#define EM_str_str(s, ss) strstr((char *)(s), (char *)(ss)) +#define EM_str_n_casecmp(s1, s2, n) _strnicmp ((char *)(s1), (char *)(s2), n) + +/* Abstractions for memory functions */ +#define EM_mem_move(d, s, n) memmove((d), (s), (n)) +#define EM_mem_cmp(p1, p2, n) memcmp((p1), (p2), (n)) +#define EM_mem_set(p, v, n) memset((p), (v), (n)) +#define EM_mem_copy(p1, p2, n) memcpy((p1), (p2), (n)) + +/* -------------------------------------------- Function Declarations */ +#ifdef __cplusplus +extern "C" { +#endif + +/** Initialize the OS */ +void EM_os_init(void); + +/* Task/Thread Creation Primitives */ +INT32 EM_thread_create +( + /* OUT */ EM_thread_type* thread, + /* IN */ EM_thread_attr_type* thread_attr, + /* IN */ EM_THREAD_START_ROUTINE start_routine, + /* IN */ void* thread_args +); + +INT32 EM_thread_attr_init +( + /* OUT */ EM_thread_attr_type* thread_attr +); + +/* Task/Thread Synchronization Primitives */ +INT32 EM_thread_mutex_init +( + /* OUT */ EM_thread_mutex_type* mutex, + /* IN */ EM_thread_mutex_attr_type* mutex_attr +); + +INT32 EM_thread_mutex_lock +( + /* INOUT */ EM_thread_mutex_type* mutex +); + +INT32 EM_thread_mutex_unlock +( + /* INOUT */ EM_thread_mutex_type* mutex +); + +INT32 EM_thread_cond_init +( + /* OUT */ EM_thread_cond_type* cond, + /* IN */ EM_thread_cond_attr_type* cond_attr +); + +void EM_thread_cond_wait +( + /* INOUT */ EM_thread_cond_type* cond, + /* INOUT */ EM_thread_mutex_type* cond_mutex +); + +INT32 EM_thread_cond_signal +( + /* INOUT */ EM_thread_cond_type* cond +); + +/* Memory Management Primitives */ +void* EM_alloc_mem (/* IN */ UINT32 size); +void EM_free_mem (/* IN */ void* ptr); + +/* Task/Thread Delay Primitives */ +void EM_sleep ( /* IN */ UINT32 tm ); +void EM_usleep ( /* IN */ UINT32 tm ); +void EM_get_current_time (/* OUT */ UINT32* curtime); +void EM_get_local_time( /* OUT */ UCHAR* buf, /* IN */ UINT16 buf_len); + +#ifdef __cplusplus +}; +#endif + +#endif /* _H_EM_OS_ */ + + diff --git a/src/components/ethermind/osal/src/phyos/EM_timer.c b/src/components/ethermind/osal/src/phyos/EM_timer.c new file mode 100644 index 0000000..7d43a74 --- /dev/null +++ b/src/components/ethermind/osal/src/phyos/EM_timer.c @@ -0,0 +1,985 @@ + +/** + \file EM_timer.c + + This File contains source codes for the EtherMind + Timer Library Implementation for FreeRTOS. +*/ + +/* + Copyright (C) 2013. Mindtree Ltd. + All rights reserved. +*/ + +/* ----------------------------------------------- Header File Inclusion */ +#include "EM_timer_internal.h" +#include "OSAL_Clock.h" + +/* ----------------------------------------------- Global Definitions */ +/* Timer Elements */ +TIMER_ENTITY timer_entity[EM_TIMER_MAX_ENTITIES]; +TIMER_ENTITY* timer_q_start = NULL; +TIMER_ENTITY* timer_q_end = NULL; + +#if 0 + /* Timer Library Mutex */ + EM_thread_mutex_type timer_mutex; +#endif /* 0 */ + +#if 1 +/* Timer */ +#if defined ( OSAL_CBTIMER_NUM_TASKS ) + #include "osal_cbtimer.h" +#endif + + +/* ----------------------------------------------- Static Global Variables */ +/********************************************************************* + CONSTANTS +*/ +// Number of callback timers supported per task (limited by the number of OSAL event timers) +#define NUM_CBTIMERS_PER_TASK 15 + +// Total number of callback timers +#define NUM_CBTIMERS ( OSAL_CBTIMER_NUM_TASKS * NUM_CBTIMERS_PER_TASK ) + + +typedef struct +{ + pfnCbTimer_t pfnCbTimer; // callback function to be called when timer expires + uint8* pData; // data to be passed in to callback function +} cbTimer_t; + +extern cbTimer_t cbTimers[]; + +extern uint16 baseTaskID; +#define EVENT_ID( timerId ) ( 0x0001 << ( ( timerId ) % NUM_CBTIMERS_PER_TASK ) ) + +// Find out task id using timer id +#define TASK_ID( timerId ) ( ( ( timerId ) / NUM_CBTIMERS_PER_TASK ) + baseTaskID ) + +// Find out bank task id using task id +#define BANK_TASK_ID( taskId ) ( ( baseTaskID - ( taskId ) ) * NUM_CBTIMERS ) + + +//extern uint16 $Sub$$osal_CbTimerProcessEvent( uint8 taskId, uint16 events ); +//uint16 $Sub$$osal_CbTimerProcessEvent( uint8 taskId, uint16 events ) +//{ +// if ( events & SYS_EVENT_MSG ) +// { +// // Process OSAL messages + +// // return unprocessed events +// return ( events ^ SYS_EVENT_MSG ); +// } + +// if ( events ) +// { +// uint8 i; +// uint16 event; + +// // Process event timers +// for ( i = 0; i < NUM_CBTIMERS_PER_TASK32; i++ ) +// { +// if ( ( events >> i ) & 0x0001 ) +// { +// cbTimer_t *pTimer = &cbTimers[BANK_TASK_ID32( taskId )+i]; + +// // Found the first event +// event = 0x0001 << i; + +// // Timer expired, call the registered callback function +// if(pTimer->pfnCbTimer==NULL) +// { +// } +// pTimer->pfnCbTimer( pTimer->pData ); + +// // Mark entry as free +// pTimer->pfnCbTimer = NULL; +// +// // Null out data pointer +// pTimer->pData = NULL; +// +// // We only process one event at a time +// break; +// } +// } + +// // return unprocessed events +// return ( events ^ event ); +//} +//} + + +#endif + +#undef EM_RESTART_TIMER + +/* ----------------------------------------------- Functions */ + +void EM_timer_init (void) +{ + UINT16 index; + EM_TIMER_TRC( + "Initializing EtherMind Timer Library Module ...\n"); + #if 0 + /* Initialize Timer Mutex */ + EM_thread_mutex_init(&timer_mutex, NULL); + #endif /* 0 */ + + /* Initialize Timer Elements */ + for (index = 0; index < EM_TIMER_MAX_ENTITIES; index ++) + { + timer_init_entity(&timer_entity[index]); + timer_entity[index].timer_id = PHYOS_INVALID_TIMER_ID; + timer_entity[index].handle = index; + } + + return; +} + + +void timer_em_init ( void ) +{ + TIMER_ENTITY* timer; + UINT16 index; + /* Lock Timer */ + timer_lock(); + EM_TIMER_TRC( + "Stack ON Initialization for Timer Library ...\n"); + + /* Initialize Timer Entities */ + for (index = 0; index < EM_TIMER_MAX_ENTITIES; index ++) + { + timer = &timer_entity[index]; + timer->timer_id = PHYOS_INVALID_TIMER_ID; + } + + /* Initialize Timer Q */ + timer_q_start = timer_q_end = NULL; + timer_unlock(); + return; +} + + +void timer_em_shutdown ( void ) +{ + UINT16 index; + TIMER_ENTITY* timer; + /* Lock Timer */ + timer_lock(); + /* Initialize Timer Q */ + timer_q_start = timer_q_end = NULL; + + /* Initialize Timer Entities */ + for (index = 0; index < EM_TIMER_MAX_ENTITIES; index++) + { + timer = &timer_entity[index]; + + if (TIMER_ENTITY_IN_USE == timer->in_use) + { + /* Stop Timer */ + osal_CbTimerStop(timer->timer_id); + + if (timer->data_length > EM_TIMER_STATIC_DATA_SIZE) + { + timer_free(timer->allocated_data); + } + + timer_init_entity(timer); + timer->timer_id = PHYOS_INVALID_TIMER_ID; + } + } + + EM_TIMER_TRC( + "Stack OFF on Timer Library Module ...\n"); + timer_unlock(); + return; +} + +#if 0 +Status_t osal_CbTimerStart32( pfnCbTimer_t pfnCbTimer, uint8* pData, + uint32 timeout, uint8* pTimerId ) +{ + uint8 i; + + // Validate input parameters + if ( pfnCbTimer == NULL ) + { + return ( INVALIDPARAMETER ); + } + + // Look for an unused timer first + for ( i = 0; i < NUM_CBTIMERS32; i++ ) + { + if ( cbTimers[i].pfnCbTimer == NULL ) + { + // Start the OSAL event timer first + if ( osal_start_timerEx( TASK_ID32( i ), EVENT_ID32( i ), timeout ) == SUCCESS ) + { + // Set up the callback timer + cbTimers[i].pfnCbTimer = pfnCbTimer; + cbTimers[i].pData = pData; + + if ( pTimerId != NULL ) + { + // Caller is intreseted in the timer id + *pTimerId = i; + } + + return ( SUCCESS ); + } + } + } + + // No timer available + return ( NO_TIMER_AVAIL ); +} +#endif + + +EM_RESULT EM_start_timer +( + EM_timer_handle* handle, + UINT32 timeout, + void (* callback) (void*, UINT16), + void* data, + UINT16 data_length +) +{ + UCHAR* data_ptr = NULL; + EM_RESULT retval; + TIMER_ENTITY current_timer; + // HZF + osalTimeUpdate(); + + if (NULL == handle) + { + EM_TIMER_ERR( + "NULL Argument Unacceptable for Timer Handles.\n"); + return EM_TIMER_HANDLE_IS_NULL; + } + + EM_TIMER_TRC( + "Preparing to Add New Timer Entity. Timeout = %d, Data Size = %d.\n", + timeout, data_length); + + /* Timer Library expects to have a valid callback */ + if (NULL == callback) + { + EM_TIMER_ERR( + "FAILED to Add New Timer Element. NULL Callback.\n"); + return EM_TIMER_CALLBACK_IS_NULL; + } + + if (0 != data_length) + { + if (data_length > EM_TIMER_STATIC_DATA_SIZE) + { + data_ptr = (UCHAR*) timer_malloc (data_length); + + if (NULL == data_ptr) + { + EM_TIMER_ERR( + "FAILED to allocate Memory for Timer Handler Argument.\n"); + return EM_TIMER_MEMORY_ALLOCATION_FAILED; + } + + current_timer.allocated_data = data_ptr; + } + else + { + data_ptr = current_timer.static_data; + } + + /* Copy the Data to be passed to the Timer Handler */ + EM_mem_copy(data_ptr, data, data_length); + } + + /* Store Timer Data Length, Callback & Timeout */ + current_timer.callback = callback; + current_timer.data_length = data_length; + current_timer.timeout = timeout; + /* Lock Timer */ + timer_lock(); + /* Insert this Timer Entity into the List */ + retval = timer_add_entity(¤t_timer); + + if (EM_SUCCESS != retval) + { + EM_TIMER_ERR( + "FAILED to Add New Timer to Timer Queue. Error Code = 0x%04X\n", + retval); + + if (current_timer.data_length > EM_TIMER_STATIC_DATA_SIZE) + { + timer_free (current_timer.allocated_data); + } + + timer_unlock(); + return retval; + } + + /* Store the Handle */ + *handle = current_timer.handle; + EM_TIMER_TRC( + "Successfully Added New Timer to Timer Queue. Handle = 0x%02X\n", + *handle); + timer_unlock(); + return EM_SUCCESS; +} + + +/* Callback registered with timer module */ +void timer_timeout_handler (UINT8* handle) +{ + EM_RESULT retval; + TIMER_ENTITY* timer; + EM_TIMER_TRC ( + "In Timer handler (Timer Handle: 0x%02X)\n", *handle); + /* Lock Timer */ + timer_lock(); + /* Get the appropriate timer entity */ + retval = timer_search_entity_timer_id (&timer, *handle); + + if (EM_SUCCESS != retval) + { + EM_TIMER_ERR( + "*** UNKNOWN Spurious Timeout Callback?!?!\n"); + /* Unlock Timer */ + timer_unlock (); + return; + } + + /* Unlock Timer */ + timer_unlock (); + + if (timer->data_length > EM_TIMER_STATIC_DATA_SIZE) + { + /* Call the registered timeout handler */ + timer->callback (timer->allocated_data, timer->data_length); + } + else + { + /* Use Static Data */ + timer->callback (timer->static_data, timer->data_length); + } + + /* Lock Timer */ + timer_lock (); + #if 0 + /* Stop Timer */ + xTimerStop (timer->timer_id, 0); + #endif /* 0 */ + /* Free the Timer */ + timer_del_entity (timer, 1); + /* Unlock Timer */ + timer_unlock (); + return; +} + + +EM_RESULT EM_stop_timer +( + EM_timer_handle* handle +) +{ + TIMER_ENTITY* timer; + EM_RESULT retval; + UINT8 timer_id; + UINT32 new_timeout; + Status_t status; + + if (EM_TIMER_MAX_ENTITIES <= *handle) + { + EM_TIMER_ERR( + "NULL Argument Unacceptable for Timer Handles.\r\n"); + /* TODO: Use appropriate error value */ + *handle = EM_TIMER_HANDLE_INIT_VAL; + return EM_TIMER_HANDLE_IS_NULL; + } + + osalTimeUpdate(); + retval = EM_FAILURE; + /* Lock Timer */ + timer_lock(); + timer = &timer_entity[*handle]; + /* Store the timer id before deleting entity */ + timer_id = timer->timer_id; + new_timeout = 0x10; + + if(timer_search_entity(timer) == EM_SUCCESS) + { + if((osal_CbTimerUpdate(timer_id,new_timeout) == EM_SUCCESS) + || (osalFindTimer(TASK_ID( timer->timer_id ),EVENT_ID( timer->timer_id )) == NULL)) + { + retval = timer_del_entity(timer, 0x01); + + if (EM_SUCCESS != retval) + { + EM_TIMER_ERR( + "FAILED to find Timer Element. Handle = 0x%02X. Error Code = 0x%04X\n", + *handle, retval); + } + else + { + EM_TIMER_TRC( + "Successfully Deleted Timer Element for Handle 0x%02X.\n", + *handle); + /* Stop Timer */ + status = osal_CbTimerStop(timer_id); + osal_clear_event(TASK_ID( timer->timer_id ),EVENT_ID( timer->timer_id )); + + if (SUCCESS != status) + { + retval = EM_FAILURE; + } + else + { + retval = EM_SUCCESS; + EM_TIMER_TRC("*** Stopped Timer [ID: %04X]\n", + timer_id); + } + } + } + } + + *handle = EM_TIMER_HANDLE_INIT_VAL; + /* Unlock Timer */ + timer_unlock(); + return retval; +} + + +UINT32 EM_get_remain_timer +( + EM_timer_handle handle +) +{ + TIMER_ENTITY* timer; + UINT32 remain_timeout; + + if (EM_TIMER_MAX_ENTITIES <= handle) + { + EM_TIMER_ERR( + "NULL Argument Unacceptable for Timer Handles.\r\n"); + /* TODO: Use appropriate error value */ + return EM_TIMER_HANDLE_IS_NULL; + } + + /* Lock Timer */ + timer_lock(); + timer = &timer_entity[handle]; + remain_timeout = osal_get_timeoutEx(TASK_ID( timer->timer_id ),EVENT_ID( timer->timer_id )); + /* Unlock Timer */ + timer_unlock(); + return remain_timeout; +} + + + +EM_RESULT EM_restart_timerEx +( + EM_timer_handle handle, + UINT32 new_timeout +) +{ + TIMER_ENTITY* timer; + EM_RESULT retval; + + if (EM_TIMER_MAX_ENTITIES <= handle) + { + EM_TIMER_ERR( + "NULL Argument Unacceptable for Timer Handles.\n"); + /* TODO: Use appropriate error value */ + return EM_TIMER_HANDLE_IS_NULL; + } + + timer_lock(); + timer = &timer_entity[handle]; + retval = timer_search_entity(timer); + + if (EM_SUCCESS != retval) + { + EM_TIMER_ERR( + "FAILED to Find Timer ELement for Handle 0x%02X. Error Code = 0x%04X\n", + handle, retval); + } + else + { + if(osal_CbTimerUpdate(timer->timer_id,new_timeout) == EM_SUCCESS) + { + return ( SUCCESS ); + } + } + + // No timer available + return ( NO_TIMER_AVAIL ); +} + +#ifdef EM_RESTART_TIMER +EM_RESULT EM_restart_timer +( + EM_timer_handle handle, + UINT32 new_timeout +) +{ + TIMER_ENTITY* timer; + Status_t ret; + EM_RESULT retval; + // HZF + osalTimeUpdate(); + + if (EM_TIMER_MAX_ENTITIES <= handle) + { + EM_TIMER_ERR( + "NULL Argument Unacceptable for Timer Handles.\n"); + /* TODO: Use appropriate error value */ + return EM_TIMER_HANDLE_IS_NULL; + } + + /* Lock Timer */ + timer_lock(); + timer = &timer_entity[handle]; + retval = timer_search_entity(timer); + + if (EM_SUCCESS != retval) + { + EM_TIMER_ERR( + "FAILED to Find Timer ELement for Handle 0x%02X. Error Code = 0x%04X\n", + handle, retval); + } + else + { + timer->timeout = new_timeout; + /* Stop the existing timer */ + osal_CbTimerStop(timer->timer_id); + /* Start Timer. */ + ret = osal_CbTimerStart + ( + timer_timeout_handler, + &timer->handle, + ((EM_TIMEOUT_MILLISEC & timer->timeout) ? + (timer->timeout & (UINT32)~(EM_TIMEOUT_MILLISEC)): + (timer->timeout * 1000)), + &timer->timer_id + ); + + if (SUCCESS != ret) + { + EM_TIMER_ERR("*** FAILED to Restart timer\n"); + timer_del_entity (timer, 0x01); + return EM_TIMER_FAILED_SET_TIME_EVENT; + } + + EM_TIMER_TRC( + "Successfully restarted Timer [ID: %02X]. Handle: 0x%02X\n", timer->timer_id, timer->handle); + } + + timer_unlock(); + return retval; +} +#endif + +EM_RESULT EM_is_active_timer +( + EM_timer_handle handle +) +{ + TIMER_ENTITY* timer; + EM_RESULT retval; + + if (EM_TIMER_MAX_ENTITIES <= handle) + { + EM_TIMER_ERR( + "NULL Argument Unacceptable for Timer Handles.\n"); + /* TODO: Use appropriate error value */ + return EM_TIMER_HANDLE_IS_NULL; + } + + /* Lock Timer */ + timer_lock(); + timer = &timer_entity[handle]; + retval = timer_search_entity(timer); + + if (EM_SUCCESS != retval) + { + EM_TIMER_ERR( + "FAILED to Find the Timer Entity for Handle 0x%02X. Error Code = 0x%04X\n", + handle, retval); + } + + timer_unlock(); + return retval; +} + + +EM_RESULT timer_search_entity ( TIMER_ENTITY* timer ) +{ + TIMER_ENTITY* current_timer; + + /* Is Queue Empty */ + if (NULL == timer_q_start) + { + return EM_TIMER_QUEUE_EMPTY; + } + + /* Handle the first Element */ + if (timer == timer_q_start) + { + return EM_SUCCESS; + } + + current_timer = timer_q_start->next; + + while (NULL != current_timer) + { + if (timer == current_timer) + { + return EM_SUCCESS; + } + + current_timer = current_timer->next; + } + + return EM_TIMER_ENTITY_SEARCH_FAILED; +} + +/* Get the timer based on obtained timer id */ +EM_RESULT timer_search_entity_timer_id +( + TIMER_ENTITY** timer, + UINT8 handle +) +{ + TIMER_ENTITY* current_timer; + + /* Is Queue Empty */ + if (NULL == timer_q_start) + { + return EM_TIMER_QUEUE_EMPTY; + } + + /* Handle the first Element */ + if (handle == timer_q_start->handle) + { + /* Note the timer entity */ + *timer = timer_q_start; + return EM_SUCCESS; + } + + current_timer = timer_q_start->next; + + while (NULL != current_timer) + { + if (handle == current_timer->handle) + { + /* Note the timer entity */ + *timer = current_timer; + return EM_SUCCESS; + } + + current_timer = current_timer->next; + } + + return EM_TIMER_ENTITY_SEARCH_FAILED; +} + +EM_RESULT timer_add_entity ( TIMER_ENTITY* timer ) +{ + UINT16 index; + Status_t ret; + TIMER_ENTITY* new_timer; + new_timer = NULL; + + for (index = 0; index < EM_TIMER_MAX_ENTITIES; index++) + { + new_timer = &timer_entity[index]; + + if (TIMER_ENTITY_FREE == new_timer->in_use) + { + new_timer->in_use = TIMER_ENTITY_IN_USE; + break; + } + else + { + new_timer = NULL; + } + } + + if (NULL == new_timer) + { + EM_TIMER_ERR( + "FAILED to Allocate New Timer Entity. Timer List FULL !\n"); +// printf( +// "FAILED to Allocate New Timer Entity. Timer List FULL !\n"); + #ifdef EM_STATUS + /* Timer List Full: Update EtherMind Status Flag */ + EM_status_set_bit (STATUS_BIT_TIMER_ENTITY_FULL, STATUS_BIT_SET); + #endif /* EM_STATUS */ + return EM_TIMER_QUEUE_FULL; + } + + new_timer->next = NULL; + new_timer->timeout = timer->timeout; + new_timer->callback = timer->callback; + new_timer->data_length = timer->data_length; + + if (new_timer->data_length > EM_TIMER_STATIC_DATA_SIZE) + { + new_timer->allocated_data = timer->allocated_data; + } + else + { + EM_mem_copy + ( + new_timer->static_data, + timer->static_data, + new_timer->data_length + ); + } + + /* Start the timer */ + #ifdef EM_TIMER_SUPPORT_REMAINING_TIME + new_timer->start_timestamp = em_timer_get_ms_timestamp(); + #endif /* EM_TIMER_SUPPORT_REMAINING_TIME */ + /* Start timer. Set Timeout. This will also start the timer. */ + ret = osal_CbTimerStart + ( + timer_timeout_handler, + &new_timer->handle, + ((EM_TIMEOUT_MILLISEC & new_timer->timeout) ? + (new_timer->timeout & (UINT32)~(EM_TIMEOUT_MILLISEC)): + (new_timer->timeout * 1000)), + &new_timer->timer_id + ); + + if (SUCCESS != ret) + { + EM_TIMER_ERR("*** FAILED to Start timer\n"); +// printf("*** FAILED to Start timer, ret = %d\r\n", ret); + return EM_TIMER_FAILED_SET_TIME_EVENT; + } + + EM_TIMER_TRC("Successfully started Timer [ID: %02X]. Handle: 0x%02X\n", + new_timer->timer_id, timer->handle); + timer->handle = new_timer->handle; + timer->timer_id = new_timer->timer_id; + + /* If the Timer Q Empty */ + if (NULL == timer_q_start) + { + timer_q_start = timer_q_end = new_timer; + return EM_SUCCESS; + } + + timer_q_end->next = new_timer; + timer_q_end = new_timer; + return EM_SUCCESS; +} + + +EM_RESULT timer_del_entity +( + TIMER_ENTITY* timer, + UCHAR free +) +{ + TIMER_ENTITY* current_timer, *previous_timer; + + /* Either None or One Element */ + if (timer_q_start == timer_q_end) + { + if (NULL == timer_q_start) + { + /* Queue is Empty */ + return EM_TIMER_QUEUE_EMPTY; + } + else + { + if (timer == timer_q_start) + { + /* Queue has One Element */ + timer_q_start = timer_q_end = NULL; + } + else + { + /* Match NOT found in the Only element in Timer Queue */ + return EM_TIMER_ENTITY_SEARCH_FAILED; + } + } + } + else + { + /* Queue has more than One Element */ + if (timer == timer_q_start) + { + /* Match in the First Element */ + timer_q_start = timer_q_start->next; + } + else + { + previous_timer = timer_q_start; + current_timer = timer_q_start->next; + + while (NULL != current_timer) + { + if (timer == current_timer) + { + previous_timer->next = current_timer->next; + + if (current_timer == timer_q_end) + { + timer_q_end = previous_timer; + } + + break; + } + + previous_timer = current_timer; + current_timer = current_timer->next; + } + + if (NULL == current_timer) + { + return EM_TIMER_ENTITY_SEARCH_FAILED; + } + } + } + + /* Free Allocated Data */ + if ((0x01 == free) && + (timer->data_length > EM_TIMER_STATIC_DATA_SIZE)) + { + timer_free (timer->allocated_data); + } + + timer_init_entity(timer); + return EM_SUCCESS; +} + + +EM_RESULT timer_init_entity (TIMER_ENTITY* timer) +{ + timer->in_use = TIMER_ENTITY_FREE; + timer->timeout = 0; + timer->callback = NULL; + timer->allocated_data = NULL; + timer->data_length = 0; + timer->next = NULL; + #ifdef EM_TIMER_SUPPORT_REMAINING_TIME + timer->start_timestamp = 0; + #endif /* EM_TIMER_SUPPORT_REMAINING_TIME */ + return EM_SUCCESS; +} + + +#ifdef EM_TIMER_SUPPORT_REMAINING_TIME + +/* + This function returns elapsed time in microsecond since system power on. +*/ +UINT64 em_timer_get_ms_timestamp(void) +{ + return osal_GetSystemClock(); +} + +EM_RESULT EM_timer_get_remaining_time +( + EM_timer_handle handle, + UINT32* remaining_time_ms +) +{ + TIMER_ENTITY* timer; + EM_RESULT retval; + UINT64 current_timestamp; + UINT32 time_ms; + + if (NULL == handle) + { + EM_TIMER_ERR( + "NULL Argument Unacceptable for Timer Handles.\n"); + return EM_TIMER_HANDLE_IS_NULL; + } + + /* Lock Timer */ + timer_lock(); + timer = (TIMER_ENTITY*)handle; + retval = timer_search_entity(timer); + + if (EM_SUCCESS != retval) + { + EM_TIMER_ERR( + "FAILED to Find Timer ELement for Handle %p. Error Code = 0x%04X\n", + (void*)handle, retval); + } + else + { + time_ms = ((EM_TIMEOUT_MILLISEC & timer->timeout) ? + (timer->timeout & (UINT32)~(EM_TIMEOUT_MILLISEC)) : + (timer->timeout * 1000)); + /* Get Current Time */ + /* Remaining Time = (Timeout in ms) - (Current Time - Timer Start Time) */ + current_timestamp = em_timer_get_ms_timestamp(); + + if ((current_timestamp < timer->start_timestamp) || + (time_ms < (current_timestamp - timer->start_timestamp)) + ) + { + EM_TIMER_ERR( + "FAILED to Find Remaining Time.TO:%d < (CurT:%lld - StartT:%lld\n", + time_ms, current_timestamp, timer->start_timestamp); + } + else + { + time_ms -= (UINT32)(current_timestamp - timer->start_timestamp); + *remaining_time_ms = time_ms; + EM_TIMER_TRC( + "[EM_TIMER] Remaining Time (ms): %d\n", time_ms); + retval = EM_SUCCESS; + } + } + + timer_unlock(); + return retval; +} +#endif /* EM_TIMER_SUPPORT_REMAINING_TIME */ + +EM_RESULT EM_list_timer ( void ) +{ + #ifdef EM_TIMERL_DEBUG + UINT16 index, free; + TIMER_ENTITY* timer; + timer_lock(); + EM_TIMERL_TRC("\n"); + EM_TIMERL_TRC("========================================= \n"); + EM_TIMERL_TRC("Start Q = %p\n", timer_q_start); + timer = timer_q_start; + + while(NULL != timer) + { + EM_TIMERL_TRC(" Handle = 0x%02X", + timer->handle); + timer = timer->next; + } + + EM_TIMERL_TRC("End Q = %p\n", timer_q_end); + free = 0; + + for (index = 0; index < EM_TIMER_MAX_ENTITIES; index ++) + { + if (TIMER_ENTITY_FREE == timer_entity[index].in_use) + { + free ++; + } + } + + EM_TIMERL_TRC("Max Q Entity = %d, Free = %d\n", + EM_TIMER_MAX_ENTITIES, free); + EM_TIMERL_TRC("========================================= \n"); + EM_TIMERL_TRC("\n"); + timer_unlock(); + #endif /* EM_TIMERL_DEBUG */ + return EM_SUCCESS; +} + diff --git a/src/components/ethermind/osal/src/phyos/EM_timer.h b/src/components/ethermind/osal/src/phyos/EM_timer.h new file mode 100644 index 0000000..a06076f --- /dev/null +++ b/src/components/ethermind/osal/src/phyos/EM_timer.h @@ -0,0 +1,166 @@ + +/** + \file EM_timer.h + + This Header File contains the APIs and the ADTs exported by the + EtherMind Timer Library for Windows (User-mode). +*/ + +/* + Copyright (C) 2013. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_EM_TIMER_ +#define _H_EM_TIMER_ + +/* --------------------------------------------------- Header File Inclusion */ +#include "EM_os.h" +#include "osal_cbtimer.h" + +/* Enable support to get remaining time to expire of a timer entity */ +#define EM_TIMER_SUPPORT_REMAINING_TIME + +/* --------------------------------------------------- Global Definitions */ +/* Maximum number of timer entities */ +#define EM_TIMER_MAX_ENTITIES 15 + +/* Mask to indicate millisecond timeout */ +#define EM_TIMEOUT_MILLISEC 0x80000000 + +/* Timer Handles must be initialized to this value */ +#define EM_TIMER_HANDLE_INIT_VAL 0xFF + +#define EM_TIMER_STATIC_DATA_SIZE 32 + +/* Flag: Timer Entity State */ +#define TIMER_ENTITY_FREE 0x00 +#define TIMER_ENTITY_IN_USE 0x01 +#define TIMER_ENTITY_IN_FREE 0x02 + +/* Flag: Timer Entity Data to be freed or not */ +#define TIMER_ENTITY_HOLD_ALLOC_DATA 0x00 +#define TIMER_ENTITY_FREE_ALLOC_DATA 0x01 + +/* Timer module ID and Error codes */ +#define EM_TIMER_ERR_ID 0xC000 + +#define EM_TIMER_MUTEX_INIT_FAILED (0x0001 | EM_TIMER_ERR_ID) +#define EM_TIMER_COND_INIT_FAILED (0x0002 | EM_TIMER_ERR_ID) +#define EM_TIMER_MUTEX_LOCK_FAILED (0x0003 | EM_TIMER_ERR_ID) +#define EM_TIMER_MUTEX_UNLOCK_FAILED (0x0004 | EM_TIMER_ERR_ID) +#define EM_TIMER_MEMORY_ALLOCATION_FAILED (0x0005 | EM_TIMER_ERR_ID) + +#define EM_TIMER_HANDLE_IS_NULL (0x0011 | EM_TIMER_ERR_ID) +#define EM_TIMER_CALLBACK_IS_NULL (0x0012 | EM_TIMER_ERR_ID) +#define EM_TIMER_QUEUE_EMPTY (0x0013 | EM_TIMER_ERR_ID) +#define EM_TIMER_QUEUE_FULL (0x0014 | EM_TIMER_ERR_ID) +#define EM_TIMER_ENTITY_SEARCH_FAILED (0x0015 | EM_TIMER_ERR_ID) +#define EM_TIMER_NULL_PARAMETER_NOT_ALLOWED (0x0016 | EM_TIMER_ERR_ID) +#define EM_TIMER_TIMEOUT_ZERO_NOT_ALLOWED (0x0017 | EM_TIMER_ERR_ID) +#define EM_TIMER_FAILED_SET_TIME_EVENT (0x0018 | EM_TIMER_ERR_ID) + +/** + Invalid Timer ID for PhyOS. + NUM_CBTIMERS is not exposed from osal_cbtimer.c +*/ +#define PHYOS_INVALID_TIMER_ID 0xFF + +/* ----------------------------------------------- Structures/Data Types */ + +/* Timer Entity */ +typedef struct timer_entity_struct +{ + /* The Timer Handle - Index of the timer entity */ + UINT8 handle; + + /* Callback to call when Timer expires */ + void (* callback) (void*, UINT16); + + /** + Timer Callback Parameter if + data_length > EM_TIMER_STATIC_DATA_SIZE + */ + UCHAR* allocated_data; + + /* Next Element in the Timer Q */ + struct timer_entity_struct* next; + + /** + Timer Callback Parameter if + data_length <= EM_TIMER_STATIC_DATA_SIZE + */ + UCHAR static_data[EM_TIMER_STATIC_DATA_SIZE]; + + /* Timeout Value asked by the User */ + UINT32 timeout; + + #ifdef EM_TIMER_SUPPORT_REMAINING_TIME + /* Start Time Stamp - used to calculate remaining time */ + UINT64 start_timestamp; + #endif /* EM_TIMER_SUPPORT_REMAINING_TIME */ + + /* Length of the data */ + UINT16 data_length; + + /* Is this Entity Allocated ? */ + UCHAR in_use; + + /* PhyOS Timer ID */ + UINT8 timer_id; + +} TIMER_ENTITY; + +typedef UINT8 EM_timer_handle; + + + +/* --------------------------------------------------- Function Declarations */ + +#ifdef __cplusplus +extern "C" { +#endif + +void EM_timer_init ( void ); +void timer_em_init ( void ); +void timer_em_shutdown ( void ); + +EM_RESULT EM_start_timer +( + EM_timer_handle* handle, + UINT32 timeout, + void (* callback) (void*, UINT16), + void* args, UINT16 size_args +); + +EM_RESULT EM_restart_timer +( + EM_timer_handle handle, + UINT32 new_timeout +); + +EM_RESULT EM_stop_timer ( EM_timer_handle* handle ); + +UINT32 EM_get_remain_timer +( + EM_timer_handle handle +); + + +EM_RESULT EM_timer_get_remaining_time +( + EM_timer_handle handle, + UINT32* remaining_time_ms +); + +EM_RESULT EM_is_active_timer ( EM_timer_handle handle ); + +/* Debug Routine - Internal Use Only */ +EM_RESULT EM_list_timer ( void ); + +#ifdef __cplusplus +}; +#endif + +#endif /* _H_EM_TIMER_ */ + diff --git a/src/components/ethermind/osal/src/phyos/EM_timer_internal.h b/src/components/ethermind/osal/src/phyos/EM_timer_internal.h new file mode 100644 index 0000000..fcfb1a0 --- /dev/null +++ b/src/components/ethermind/osal/src/phyos/EM_timer_internal.h @@ -0,0 +1,116 @@ + +/** + \file EM_timer_internal.h + + This Header File contains Internal Declarations of Structures, + Functions and Global Definitions for FreeRTOS. +*/ + +/* + Copyright (C) 2013. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_EM_TIMER_INTERNAL_ +#define _H_EM_TIMER_INTERNAL_ + +/* ----------------------------------------------- Header File Inclusion */ +#include "EM_timer.h" +#include "EM_debug.h" + +/* ----------------------------------------------- Timer Debug Macros */ + +#ifdef EM_TIMERL_DEBUG + #define EM_TIMERL_TRC(...) EM_debug_trace(bt_debug_fd, __VA_ARGS__) +#else /* EM_TIMERL_DEBUG */ + #define EM_TIMERL_TRC EM_debug_null +#endif /* EM_TIMERL_DEBUG */ + +#ifdef EM_TIMERT_DEBUG + #define EM_TIMERT_TRC(...) EM_debug_trace(bt_debug_fd, __VA_ARGS__) +#else /* EM_TIMERT_DEBUG */ + #define EM_TIMERT_TRC EM_debug_null +#endif /* EM_TIMERT_DEBUG */ + +#ifdef EM_TIMER_DEBUG + + #define EM_TIMER_ERR(...) EM_debug_error(bt_debug_fd, __VA_ARGS__) + #define EM_TIMER_TRC(...) EM_debug_trace(bt_debug_fd, __VA_ARGS__) + #define EM_TIMER_INF(...) EM_debug_info(bt_debug_fd, __VA_ARGS__) + +#else /* EM_TIMER_DEBUG */ + + #define EM_TIMER_ERR EM_debug_null + #define EM_TIMER_TRC EM_debug_null + #define EM_TIMER_INF EM_debug_null + +#endif /* EM_TIMER_DEBUG */ + + +/* ----------------------------------------------- Global Definitions */ + +/* Timer Malloc/Free Related --------- */ +#define timer_malloc EM_alloc_mem +#define timer_free EM_free_mem + +/* Lock/Unlock Timer Library */ +/* TODO: Check if PhyOS is pre-emptive */ +#if 0 + #define timer_lock() EM_thread_mutex_lock(&timer_mutex) + #define timer_unlock() EM_thread_mutex_unlock(&timer_mutex) +#else + #define timer_lock() + #define timer_unlock() +#endif /* 0 */ + +/* Null Check for Timer Handles */ +#define timer_null_check(p) if (NULL == (p)) return -1; + +/* Timer Task State Values */ +#define TIMER_INIT 0x00 +#define TIMER_WAITING 0x01 +#define TIMER_RUNNING 0x02 +#define TIMER_SHUTDOWN 0x03 +#define TIMER_IMMEDIATE 0x04 + +/* One Timer Tick => 10 MilliSecond */ +#define TIMER_TICK 10 + +/* Timer task yield period (in Microsecond) */ +#define TIMER_YIELD_PERIOD (1 * 1000) + +/* ----------------------------------------------- Structures/Data Types */ + + +/* ----------------------------------------------- Internal Functions */ + +#ifdef __cplusplus +extern "C" { +#endif + +EM_THREAD_RETURN_TYPE timer_start_routine (EM_THREAD_ARGS args); +void timer_service_queue (void); + +EM_RESULT timer_add_entity ( TIMER_ENTITY* timer ); +EM_RESULT timer_del_entity ( TIMER_ENTITY* timer, UCHAR free ); +EM_RESULT timer_search_entity ( TIMER_ENTITY* timer ); +EM_RESULT timer_init_entity ( TIMER_ENTITY* timer ); + +/* Get the timer based on obtained timer id */ +EM_RESULT timer_search_entity_timer_id +( + TIMER_ENTITY** timer, + UINT8 timer_id +); + +/* Callback registered with timer module */ +void timer_timeout_handler (UINT8* timer_id); + +UINT64 em_timer_get_ms_timestamp(void); + +#ifdef __cplusplus +}; +#endif + +#endif /* _H_EM_TIMER_INTERNAL_ */ + diff --git a/src/components/ethermind/platforms/EM_platform.c b/src/components/ethermind/platforms/EM_platform.c new file mode 100644 index 0000000..ed4b2ba --- /dev/null +++ b/src/components/ethermind/platforms/EM_platform.c @@ -0,0 +1,70 @@ +/** + \file EM_platform.c + + +*/ + +/* + Copyright (C) 2013. Mindtree Limited. + All rights reserved. +*/ + +/* --------------------------------------------- Header File Inclusion */ +#include "EM_platform.h" +#include "uart.h" + +#pragma import(__use_no_semihosting_swi) + +/* --------------------------------------------- Global Definitions */ + +/* --------------------------------------------- Static Global Variables */ +struct __FILE +{ + int handle; /* whatever required */ +}; +FILE __stdout; +FILE __stdin; + +/* --------------------------------------------- External Global Variables */ + +/* --------------------------------------------- Exported Global Variables */ + +/* --------------------------------------------- Function */ +void EM_enter_sleep_pl(void) +{ +} + +void EM_exit_sleep_pl(void) +{ +} + +int fputc(int c, FILE* f) +{ + return hal_uart_send_buff(UART0,(uint8_t*)&c, 1); +} + + +int fgetc(FILE* f) +{ + return 0; +} + + +int ferror(FILE* f) +{ + /* Your implementation of ferror */ + return EOF; +} + + +void _ttywrch(int c) +{ + hal_uart_send_buff(UART0,(uint8_t*)&c, 1); +} + + +void _sys_exit(int return_code) +{ +label: + goto label; /* endless loop */ +} diff --git a/src/components/ethermind/platforms/EM_platform.h b/src/components/ethermind/platforms/EM_platform.h new file mode 100644 index 0000000..ebba4bc --- /dev/null +++ b/src/components/ethermind/platforms/EM_platform.h @@ -0,0 +1,51 @@ + +/** + \file EM_platform.h + + +*/ + +/* + Copyright (C) 2013. Mindtree Limited. + All rights reserved. +*/ + +#ifndef _H_EM_PLATFORM_ +#define _H_EM_PLATFORM_ + +/* --------------------------------------------- Header File Inclusion */ +#include +#include +#include +#include + +#include "osal.h" + +/* --------------------------------------------- Global Definitions */ +#define EM_HAVE_STATIC_DECL +#define EM_HAVE_CONST_DECL + +/* --------------------------------------------- Structures/Data Types */ + +/* --------------------------------------------- Macros */ +#define printf(...) {printf (__VA_ARGS__); printf("\r\n"); fflush(stdout);} +#define scanf(...) + +/* --------------------------------------------- Internal Functions */ + +/* --------------------------------------------- API Declarations */ +void EM_enter_sleep_pl(void); +void EM_exit_sleep_pl(void); + +int _write (int fd, char* ptr, int len); +int _read (int fd, char* ptr, int len); +int _close (int fd); +int _fstat (int fd); +int _isatty (int fd); +int _lseek (int fd); + +void HardFault_Handler(void); +void debugHardfault(uint32_t* sp); + +#endif /* _H_EM_PLATFORM_ */ + diff --git a/src/components/ethermind/platforms/interfaces/crypto/cry.c b/src/components/ethermind/platforms/interfaces/crypto/cry.c new file mode 100644 index 0000000..3ce6959 --- /dev/null +++ b/src/components/ethermind/platforms/interfaces/crypto/cry.c @@ -0,0 +1,549 @@ + +/** + \file cry.c + + Interface implementation file for cryptographic functions that will be used + from other IP modules +*/ + +/* + Copyright (C) 2013. Mindtree Limited. + All rights reserved. +*/ + +/* --------------------------------------------- Header File Inclusion */ +#include "cry.h" +#include "ll.h" +/* Platform and Internal Crypto Includes */ +#include "aes_cmac.h" +#include "crypto.h" + +/* Third Party Crypto Includes TODO: Temporary */ +#include "aes.h" +#include "P256-cortex-ecdh.h" +#include "rf_phy_driver.h" +/* --------------------------------------------- Global Defines */ + +/* --------------------------------------------- External Global Variables */ + +/* --------------------------------------------- Exported Global Variables */ + +/* --------------------------------------------- Static Global Variables */ +/** Context for AES-CMAC */ +DECL_STATIC AES_CMAC_CONTEXT cry_aescmac; + +#ifndef MESH_ECDH_ENABLE + DECL_STATIC ssp_prkey_t cry_ecpvtkey; + DECL_STATIC ssp_pukey_t cry_ecpubkey; + + DECL_STATIC ssp_pukey_t cry_prpubkey; + DECL_STATIC ssp_dhkey_t cry_ecdhkey; + + DECL_STATIC void (*cry_ecdh_cb)(UCHAR*); +#endif +/* --------------------------------------------- Functions */ + +void cry_reverse_bytestream_endianness(UCHAR* src, UCHAR* dst, UINT16 len) +{ + UINT16 i; + + for (i = 0; i < len; i++) + { + dst[i] = src[(len - 1) - i]; + } +} + +void cry_reverse_bytestream_in_place(UCHAR* src, UINT16 len) +{ + UINT16 i; + UCHAR temp; + + for (i = 0; i < len/2; i++) + { + temp = src[i]; + src[i] = src[(len - 1) - i]; + src[(len - 1) - i] = temp; + } +} + +INT32 cry_rand_generate(UCHAR* prand, UINT16 randlen) +{ + TRNG_Rand(prand, randlen); + return 0; +} + +INT32 cry_aes_128_encrypt +( + UCHAR* pdata, + UCHAR* pkey, + UCHAR* pencdata +) +{ + LL_Encrypt (pkey, pdata, pencdata); + return CRY_AES128_DATALEN; +} + +INT32 cry_aes_128_decrypt +( + UCHAR* pencdata, + UCHAR* pkey, + UCHAR* pdata +) +{ + return -1; +} + +INT32 cry_aes_128_ccm_encrypt +( + UCHAR* pkey, + UCHAR* pnonce, + UINT16 noncelen, + UCHAR* pdata, + UINT16 datalen, + UCHAR* paddata, + UINT16 addatalen, + UCHAR* pencdata, + UCHAR* pmac, + UINT16 maclen +) +{ + UCHAR mac[CRY_AES128CMAC_MACLEN]; + INT32 ciphertext_len; + int ret; + (void)noncelen; + /* Validate input length check */ + ciphertext_len = -1; + ret = aes_ccm_ae + ( + pkey, + CRY_AES128_KEYLEN, + pnonce, + maclen, + pdata, + datalen, + paddata, + addatalen, + pencdata, + mac + ); + + /* TODO: Check if this is the success return */ + if (0 == ret) + { + ciphertext_len = datalen; + + if (NULL != pmac) + { + EM_mem_copy (pmac, mac, maclen); + } + } + + return ciphertext_len; +} + +INT32 cry_aes_128_ccm_decrypt +( + UCHAR* pkey, + UCHAR* pnonce, + UINT16 noncelen, + UCHAR* pencdata, + UINT16 encdatalen, + UCHAR* paddata, + UINT16 addatalen, + UCHAR* pdata, + UCHAR* pmac, + UINT16 maclen +) +{ + int plaintext_len; + int ret; + (void)noncelen; + /* Validate input length check */ + plaintext_len = -1; + ret = aes_ccm_ad + ( + pkey, + CRY_AES128_KEYLEN, + pnonce, + maclen, + pencdata, + encdatalen, + paddata, + addatalen, + pmac, + pdata + ); + + if (0 == ret) + { + plaintext_len = encdatalen; + } + + return plaintext_len; +} + + +INT32 cry_aes_128_cmac +( + UCHAR op, + UCHAR* pdata, + UINT16 datalen, + UCHAR* pkey, + UCHAR* pmac, + UINT16 maclen +) +{ + INT32 ret; + UCHAR mac[CRY_AES128_KEYLEN]; + EM_RESULT retval; + UCHAR lkey[CRY_AES128_KEYLEN]; + UCHAR* ldata; + /* Allocate local data memory */ + ldata = EM_alloc_mem (datalen); + + if (NULL == ldata) + { + return -1; + } + + /* Form the data for our required endianness */ + cry_reverse_bytestream_endianness (pdata, ldata, datalen); + cry_reverse_bytestream_endianness (pkey, lkey, CRY_AES128_KEYLEN); + /* Initialize the AES-CMAC context */ + aes_cmac_context_init (&cry_aescmac); + ret = -1; + /* Populate the context for operation */ + cry_aescmac.key = lkey; + cry_aescmac.data = ldata; + cry_aescmac.datalen = datalen; + cry_aescmac.mac = mac; + cry_aescmac.maclen = sizeof(mac); + cry_aescmac.action = (CRY_AES_128_CMAC_SIGN == op)? + AES_CMAC_MAC_GENERATE: AES_CMAC_MAC_VERIFY; + /* Call to perform the operation */ + retval = aes_cmac (&cry_aescmac); + + if (EM_SUCCESS == retval) + { + ret = 0; + /* Get back the input endianness */ + cry_reverse_bytestream_in_place (mac, CRY_AES128_KEYLEN); + + if (CRY_AES_128_CMAC_SIGN == op) + { + EM_mem_copy(pmac, mac, maclen); + } + else if (CRY_AES_128_CMAC_VERIFY == op) + { + if (0 != EM_mem_cmp(pmac, mac, maclen)) + { + ret = -1; + } + } + } + + /* Free the local data memory allocated */ + EM_free_mem (ldata); + return ret; +} + +INT32 cry_ecdh_init(void) +{ + #ifdef MESH_ECDH_ENABLE + return (mesh_ecdh_init()); + #else + UINT8 ret; + ssp_init(); + + do + { + ret = ssp_get_ecdh_keypair(&cry_ecpvtkey, &cry_ecpubkey); + } + while (0 == ret); + + ssp_shutdown(); + return 0; + #endif +} + +INT32 cry_ecdh_get_public_key(UCHAR* pubkey) +{ + #ifdef MESH_ECDH_ENABLE + return (mesh_ecdh_get_public_key(pubkey)); + #else + /* TODO: Check Endianness */ + cry_reverse_bytestream_endianness(cry_ecpubkey.x, pubkey, DHKEY_LEN); + cry_reverse_bytestream_endianness(cry_ecpubkey.y, (pubkey + DHKEY_LEN), DHKEY_LEN); + return 0; + #endif +} + +INT32 cry_ecdh_generate_secret +( + UCHAR* peer_pubkey, + UCHAR* secret, + UINT16 secret_len, + void (*ecdh_cb)(UCHAR*) +) +{ + #ifdef MESH_ECDH_ENABLE + return (mesh_ecdh_generate_secret(peer_pubkey,secret,secret_len)); + #else + UINT8 ret; + INT32 retval; + #ifdef CRY_ECDH_TIMESLICE + + /* Validate if block is idle */ + if (NULL != cry_ecdh_cb) + { + return -1; + } + + #endif /* CRY_ECDH_TIMESLICE */ + /* Reverse Endianness */ + cry_reverse_bytestream_endianness(peer_pubkey, cry_prpubkey.x, DHKEY_LEN); + cry_reverse_bytestream_endianness((peer_pubkey + DHKEY_LEN), cry_prpubkey.y, DHKEY_LEN); + ssp_init(); + #ifndef CRY_ECDH_TIMESLICE + + do + { + #endif /* CRY_ECDH_TIMESLICE */ + ret = ssp_get_dhkey + ( + &cry_ecpvtkey, + &cry_prpubkey, + &cry_ecdhkey + ); + #ifndef CRY_ECDH_TIMESLICE + } + while (0 == ret); + + #endif /* CRY_ECDH_TIMESLICE */ + + /* Check if valid dhkey */ + if (2 == ret) + { + /* Invalid DHKey. Return Failure */ + retval = -1; + } + + #ifdef CRY_ECDH_TIMESLICE + else if (0 == ret) + { + if (NULL == ecdh_cb) + { + /* Procedure cannot be completed */ + retval = -2; + } + else + { + /* Save the callback */ + cry_ecdh_cb = ecdh_cb; + /* DHKey calculation pending. */ + retval = 1; + /* Schedule at platform for sliced processing */ + BLE_ecdh_yield(); + } + } + + #endif /* CRY_ECDH_TIMESLICE */ + else + { + /* Reverse Endianness */ + cry_reverse_bytestream_endianness(cry_ecdhkey, secret, DHKEY_LEN); + ssp_shutdown(); + /* Valid DHKey. Return Success */ + retval = 0; + } + + return retval; + #endif +} + +#ifdef CRY_ECDH_TIMESLICE +INT32 cry_ecdh_process_secret(void) +{ + UCHAR secret[DHKEY_LEN]; + UINT8 ret; + INT32 retval; + void (*ecdh_cb)(UCHAR*); + + /* Validate if block is idle */ + if (NULL == cry_ecdh_cb) + { + return -1; + } + + ret = ssp_get_dhkey + ( + &cry_ecpvtkey, + &cry_prpubkey, + &cry_ecdhkey + ); + + if (0 == ret) + { + /* DHKey calculation pending. */ + retval = 1; + /* Schedule at platform for sliced processing */ + BLE_ecdh_yield(); + } + else + { + /* Reverse Endianness */ + cry_reverse_bytestream_endianness(cry_ecdhkey, secret, DHKEY_LEN); + ssp_shutdown(); + /* Valid DHKey. Return Success */ + retval = 0; + /* Invoke the corresponding callback */ + ecdh_cb = cry_ecdh_cb; + cry_ecdh_cb = NULL; + ecdh_cb (secret); + } + + return retval; +} +#endif /* CRY_ECDH_TIMESLICE */ +INT32 cry_set_ecdh_debug_keypair(UCHAR* pvtkey, UCHAR* pubkey) +{ + (void)pvtkey; + (void)pubkey; + return -1; +} + +#define PHY_PLUS_ECDH_KEYGEN_RETRY_LIMT 64 + +int cry_generate_random_bytes(uint8* p, uint32_t size) +{ + LL_Rand(p,(uint8)size); + return 0; +} + +DECL_STATIC ssp_prkey_t phy_ecpvtkey; +DECL_STATIC ssp_pukey_t phy_ecpubkey; +DECL_STATIC uCrypto_RNG_Function g_rng_function = 0; + +void uCrypto_set_rng(uCrypto_RNG_Function rng_function) +{ + g_rng_function = rng_function; +} +uCrypto_RNG_Function uCrypto_get_rng(void) +{ + return g_rng_function; +} + + +INT32 mesh_ecdh_init(void) +{ +// uint32 T1; + uint8 my_public_point0[64], my_private_key0[32]; + uint32 cnt=0; + uCrypto_RNG_Function gen_rng; + + if(uCrypto_get_rng()==0) + uCrypto_set_rng(cry_generate_random_bytes); + + gen_rng =uCrypto_get_rng(); + + do + { + gen_rng(my_public_point0, 32); + + if(++cnt>PHY_PLUS_ECDH_KEYGEN_RETRY_LIMT) + return cnt; + } + while (!P256_ecdh_keygen(my_public_point0, my_private_key0)); + +// + EM_mem_copy(phy_ecpvtkey,my_private_key0,DHKEY_LEN); + EM_mem_copy(phy_ecpubkey.x,my_public_point0,DHKEY_LEN); + EM_mem_copy(phy_ecpubkey.y,my_public_point0+DHKEY_LEN,DHKEY_LEN); +// cry_reverse_bytestream_endianness(my_private_key0,cry_ecpvtkey,DHKEY_LEN); +// +// cry_reverse_bytestream_endianness(my_public_point0,cry_ecpubkey.x,DHKEY_LEN); +// cry_reverse_bytestream_endianness(my_public_point0+DHKEY_LEN,cry_ecpubkey.y,DHKEY_LEN); + return 0; +} + +INT32 mesh_ecdh_generate_secret(UCHAR* peer_pubkey, UCHAR* secret, UINT16 secret_len) +{ + uint8 pubkey[64]; + uint8 dhkey[32]; + /* TODO: Check Endianness */ + cry_reverse_bytestream_endianness(peer_pubkey, pubkey, DHKEY_LEN); + cry_reverse_bytestream_endianness((peer_pubkey + DHKEY_LEN), (pubkey+DHKEY_LEN), DHKEY_LEN); + + if (!P256_ecdh_shared_secret(dhkey, pubkey, phy_ecpvtkey)) + { + // The other part sent an invalid public point, so abort + return 1; + } + else + { + cry_reverse_bytestream_endianness(dhkey, secret, DHKEY_LEN); + // The shared_secret is now the same for both parts and may be used for cryptographic purposes + return 0; + } +} + +INT32 mesh_ecdh_get_public_key(UCHAR* pubkey) +{ + /* TODO: Check Endianness */ + cry_reverse_bytestream_endianness(phy_ecpubkey.x, pubkey, DHKEY_LEN); + cry_reverse_bytestream_endianness(phy_ecpubkey.y, (pubkey + DHKEY_LEN), DHKEY_LEN); +// EM_mem_copy(pubkey, phy_ecpubkey.x,DHKEY_LEN); +// EM_mem_copy(pubkey+DHKEY_LEN,phy_ecpubkey.y,DHKEY_LEN); + return 0; +} + +//#define cry_dump_key(a,b,c) do{cry_printf(a);for(int i=0;i_NO_DEBUG flag. + Example: Define BRR_NO_DEBUG to disable error logging of Bearer layer. + + By default, the Trace, Information, Data and other Logs + of all the layers are disabled. + To enable debug logging of a module, define _DEBUG flag. + Example: Define BRR_DEBUG to enable debug logging (Trace and Information) + of Bearer layer. +*/ + +/* Protocol Modules */ +#define COMMON_NO_DEBUG +/* #define COMMON_DEBUG */ + +//#define BRR_DEBUG +#define BRR_NO_DEBUG +/* #define BRR_DEBUG */ + +//#define NET_DEBUG +#define NET_NO_DEBUG +/* #define NET_DEBUG */ + +#define LTRN_NO_DEBUG +//#define LTRN_DEBUG +/* #define LTRN_DEBUG */ + +#define TRN_NO_DEBUG +//#define TRN_DEBUG +/* #define TRN_DEBUG */ + +#define APP_NO_DEBUG +//#define APP_DEBUG + +/* #define APP_DEBUG */ + +#define STBX_NO_DEBUG +//#define STBX_DEBUG +/* #define STBX_DEBUG */ + +#define ACCESS_NO_DEBUG +//#define ACCESS_DEBUG +/* #define ACCESS_DEBUG */ + +#define PROV_NO_DEBUG +//#define PROV_DEBUG +/* #define PROV_DEBUG */ + +#define CONFIG_NO_DEBUG +//#define CONFIG_DEBUG +/* #define CONFIG_DEBUG */ + +#endif /* _H_MS_FEATURES_ */ + diff --git a/src/components/ethermind/platforms/mesh/MS_limits.h b/src/components/ethermind/platforms/mesh/MS_limits.h new file mode 100644 index 0000000..57cf448 --- /dev/null +++ b/src/components/ethermind/platforms/mesh/MS_limits.h @@ -0,0 +1,339 @@ + +/** + \file MS_limits.h + + This file lists all the Tunable constants used in + EtherMind Mesh Stack modules. +*/ + +/* + Copyright (C) 2016. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_MS_LIMITS_ +#define _H_MS_LIMITS_ + + +/* ----------------------------------------------------------------------- */ +/* ============================= Bearer ================================ */ +/* ----------------------------------------------------------------------- */ +#define MS_NUM_NETWORK_INTERFACES 2 +#define MS_NUM_PROVISIONING_INTERFACES 2 + + +/* ----------------------------------------------------------------------- */ +/* ============================= Network =============================== */ +/* ----------------------------------------------------------------------- */ +/* + In a 'flooding' mesh implementation, one of the methods used to restrict + unlimited flooding, is using message cache. + This parameter specifies the size of the Network message cache. + + Minimum Value: 2 + Maximum Value: can be anything. +*/ +#define MS_NET_CACHE_SIZE 30 //10->30 by ZQ + +/* + Maximum number of subnets the device can store information about. + + Minimum Value: 1 + Maximum Value: can be anything. +*/ +#define MS_MAX_SUBNETS 3 + +/* + Maximum number of device keys the device can store information about. + As a configuration client, there should be one additional space to + contain device key of configuration server. + + Minimum Value: 1 + Maximum Value: can be anything. +*/ +#define MS_MAX_DEV_KEYS 5 + +/* + Maximum number of addresses present in each proxy filter list. + + Minimum Value: 1 + Maximum Value: can be anything. +*/ +#define MS_PROXY_FILTER_LIST_SIZE 5 + +/* + The distance between the network sequence numbers, for every persistent + storage write. If the device is powered cycled, it will resume transmission + using the sequence number from start of next block. + + Minimum Value: can be anything. A smaller value will reduce the flash lifetime. + Maximum Value: can be anything. +*/ +#define MS_NET_SEQ_NUMBER_BLOCK_SIZE 512// 2048 + +/* + The timeout in millisecond for proxy advertisement with Network ID for + each subnet + + Minimum Value: can be anything. Larger value will have lesser timeout load. + Maximum Value: can be anything. +*/ +#define PROXY_SUBNET_NETID_ADV_TIMEOUT (300 | EM_TIMEOUT_MILLISEC) //100 + +/* + The timeout in millisecond for proxy advertisement with Node Identity for + each subnet + + Minimum Value: can be anything. Larger value will have lesser timeout load. + Maximum Value: can be anything. +*/ +#define PROXY_SUBNET_NODEID_ADV_TIMEOUT (300 | EM_TIMEOUT_MILLISEC) //100 + +/* + The time period for proxy advertisement with Node Identity + + Minimum Value: Default 60 seconds as in specification + Maximum Value: can be anything. +*/ +#define PROXY_NODEID_ADV_TIMEOUT (60000 | EM_TIMEOUT_MILLISEC) + + +/* ----------------------------------------------------------------------- */ +/* ============================= Transport ============================= */ +/* ----------------------------------------------------------------------- */ +/* + This parameter specifies the maximum number of Low Power Nodes (LPNs) + to which friendship can be established as a Friend. + + Minimum Value: 1 + Maximum Value: can be anything. +*/ +#define MS_MAX_LPNS 1 + +/* + Replay Protection cache is required to protect against relay attacks. + This parameter specifies the size of the Replay Protection cache. + + Minimum Value: 2 + Maximum Value: can be anything. +*/ +#define MS_REPLAY_CACHE_SIZE 30 + +/* + Reassembled SAR Rx cache is to avoid handling of segmented frames + which are already received and acked by the local implementation. + Saves the unnecessary effort of reassmbly and complex handling by + the upper layers to handle reception of same payload again from + the same source device. + + Minimum Value: 2 + Maximum Value: can be anything. +*/ +#define MS_REASSEMBLED_CACHE_SIZE 30 + +/* + The number of times to retry the FriendPoll message when + the FriendUpdate message is not received for the first attempt + of FriendPoll in the current sequence. When this count expires, + the friendship will be terminated with the Friend node. + + Minimum Value: 1 + Maximum Value: can be anything. +*/ +#define MS_FRND_POLL_RETRY_COUNT 10 + +/* + Number of Segmentation and Reassembly contexts. + Used during both reception and transmission and also for associated + LPNs. + + Minimum Value: 2 + Maximum Value: can be anything. +*/ +#define LTRN_SAR_CTX_MAX 16 + +/* + Segment Transmission Timeout. + + Minimum Value: 200 MS + Maximum Value: can be anything. +*/ +#define LTRN_RTX_TIMEOUT 200 /* Millisecond */ + +/* + Segment Transmission Count. + + Minimum Value: 2 + Maximum Value: can be anything. +*/ +#define LTRN_RTX_COUNT_UNICASS 5 +#define LTRN_RTX_COUNT_GROUP 3 + + +/* + Ack Timeout. + Minimum Value: 200 MS + Maximum Value: can be anything. +*/ +/* TODO: Use ack timeout configured based on the TTL in the received frame */ +#define LTRN_ACK_TIMEOUT 50 /* Millisecond */ + + +/* + Incomplete Timeout. + + Minimum Value: 10 Seconds (10000 MS) + Maximum Value: can be anything. +*/ +/* TODO: Use ack timeout configured based on the TTL in the received frame */ +#define LTRN_INCOMPLETE_TIMEOUT (20*1000) /* Millisecond */ + + +/* + Receive window is the time in ms for which the Friend will be transmitting the + response to any request from the LPN after the Receive delay time of + getting any request + + Minimum Value: 100 + Maximum Value: As required +*/ +#define MS_FRND_RECEIVE_WINDOW 100 + +/* + This parameter defines the maximum number of messages that the friend + is capabale to queue for a single Low Power Node + + Minimum Value: 2 + Maximum Value: As required +*/ +#define MS_FRIEND_MESSAGEQUEUE_SIZE 8 + +/* + This parameter defines the maximum number of subscription addresses + that the friend is capabale to store for a single Low Power Node + + Minimum Value: 1 + Maximum Value: As required +*/ +#define MS_FRIEND_SUBSCRIPTION_LIST_SIZE 8 + +/* + This parameter defines the initial timeout in milliseconds + to be used to track the Friend clear Confirmation after + sending of a Friend Clear message + + Minimum Value: 1000 + Maximum Value: As required +*/ +#define LPN_CLEAR_RETRY_TIMEOUT_INITIAL 1000 + +/* + This parameter defines the timeout in milliseconds + to be used to retry friend request attempts in case an + offer is not received. + + Minimum Value: 1100 + Maximum Value: As required +*/ +#define MS_TRN_FRNDREQ_RETRY_TIMEOUT 1200 + +/* ----------------------------------------------------------------------- */ +/* ============================= Access ================================= */ +/* ----------------------------------------------------------------------- */ +/* + This parameter specifies the maximum number of elements. + + Minimum Value: 1 + Maximum Value: can be anything. +*/ +#define MS_ACCESS_ELEMENT_COUNT 3 + +/* + This parameter specifies the maximum number of models. + + Minimum Value: 1 + Maximum Value: can be anything. +*/ +#define MS_ACCESS_MODEL_COUNT 20// 5 + +/* + Maximum number of Applications (keys) the device can store information about. + + Minimum Value: 1 + Maximum Value: can be anything. +*/ +#define MS_MAX_APPS 3 + +/* + Maximum number of Virtual Addresses the device can store information about. + + Minimum Value: 1 + Maximum Value: can be anything. +*/ +#define MS_MAX_VIRTUAL_ADDRS 1 + +/* + Maximum number of Non-Virtual Addresses the device can store information about. + + Minimum Value: 1 + Maximum Value: can be anything. +*/ +#define MS_MAX_NON_VIRTUAL_ADDRS 32 + +/* + Maximum number of Addresses the device can store information about. + This includes both the Virtual and non-virtual addresses. + + Note: This depends on the other configurations. + Defined here for easy reference. Do not change manually. +*/ +#define MS_MAX_ADDRS (MS_MAX_VIRTUAL_ADDRS + MS_MAX_NON_VIRTUAL_ADDRS) + +#if (MS_MAX_ADDRS != (MS_MAX_VIRTUAL_ADDRS + MS_MAX_NON_VIRTUAL_ADDRS)) + #error "MS_MAX_ADDRS != (MS_MAX_VIRTUAL_ADDRS + MS_MAX_NON_VIRTUAL_ADDRS)" +#endif /* (MS_MAX_ADDRS != (MS_MAX_VIRTUAL_ADDRS + MS_MAX_NON_VIRTUAL_ADDRS)) */ + +/* + Maximum number of Transition Timers. + + Minimum Value: 1 + Maximum Value: can be anything. +*/ +#define MS_MAX_NUM_TRANSITION_TIMERS 5 + +/* + Maximum number of Periodic Step Timers. + + Minimum Value: 1 + Maximum Value: can be anything. +*/ +#define MS_MAX_NUM_PERIODIC_STEP_TIMERS 5 + + +/* ----------------------------------------------------------------------- */ +/* ========================== Health Model ============================== */ +/* ----------------------------------------------------------------------- */ +/* + This parameter specifies the maximum number of Health Servers + to be supported. + + Minimum Value: 1 + Maximum Value: can be anything. +*/ +#define MS_HEALTH_SERVER_MAX 2 + + +#define MS_DEFAULT_COMPANY_ID 0x0059 + +/* + This parameter specifies a 16-bit vendor-assigned product identifier. +*/ +#define MS_DEFAULT_PID 0x000f + +/* + This parameter specifies a 16-bit vendor-assigned product version identifier. +*/ +#define MS_DEFAULT_VID 0x0003 + +#endif /* _H_MS_LIMITS_ */ + diff --git a/src/components/ethermind/platforms/mesh/blebrr_pl.c b/src/components/ethermind/platforms/mesh/blebrr_pl.c new file mode 100644 index 0000000..3483a4a --- /dev/null +++ b/src/components/ethermind/platforms/mesh/blebrr_pl.c @@ -0,0 +1,1249 @@ + +/** + \file blebrr_pl.c + + +*/ + +/* + Copyright (C) 2018. Mindtree Limited. + All rights reserved. +*/ + +/* --------------------------------------------- Header File Inclusion */ +/* Platform Stack Headers */ +#include +#include +#include + +#undef BLE_CLIENT_ROLE + +/* Povisioning API headers */ +#include "MS_prov_api.h" + +/* BLE Bearer related Headers */ +#include "blebrr.h" + +#include "mesh_services.h" + +#include "appl_main.h" + +extern uint8 llState, llSecondaryState; + +#ifdef BLE_CLIENT_ROLE + #include "mesh_clients.h" +#endif /* BLE_CLIENT_ROLE */ + +/* Platform log to be mapped */ +#define BLEBRRPL_LOG printf +#define BLEBRRPL_dump_bytes appl_dump_bytes + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ +bStatus_t BLE_gap_set_scan_enable(uint8_t scan_enable); +bStatus_t BLE_gap_connect(uint8_t whitelist, uint8_t* addr, uint8_t addr_type); +bStatus_t BLE_gap_set_advscanrsp_data(uint8_t type, uint8_t* adv_data, uint16_t adv_datalen); +bStatus_t BLE_gap_set_scan_params(uint8_t scan_type, uint16_t scan_interval, uint16_t scan_window, uint8_t scan_filterpolicy); +bStatus_t BLE_gap_set_adv_params(uint8_t adv_type, uint16_t adv_intervalmin, uint16_t adv_intervalmax, uint8_t adv_filterpolicy); +bStatus_t BLE_gap_disconnect(uint16_t conn_handle); +bStatus_t BLE_gap_set_adv_enable(uint8_t adv_enable); + + +API_RESULT blebrr_scan_cmd_handler_pl(UCHAR enable); + +void blebrr_enable_mesh_serv_pl (UCHAR serv_type); +void blebrr_disable_mesh_serv_pl (UCHAR serv_type); + +API_RESULT blebrr_handle_le_connection_pl +( + uint16_t conn_idx, + uint16_t conn_hndl, + uint8_t peer_addr_type, + uint8_t* peer_addr +); + +API_RESULT blebrr_handle_le_disconnection_pl +( + uint16_t conn_idx, + uint16_t conn_hndl, + uint8_t reason +); + +void blebrr_handle_evt_adv_complete (UINT8 enable); +void blebrr_handle_evt_adv_report (gapDeviceInfoEvent_t* adv); +void blebrr_handle_evt_scan_complete (UINT8 enable); + +/** + Value for invalid connection index + + Portable code should use this value wherever it's required to mark connection index as invalid. +*/ +#define BLEBRR_CONN_IDX_INVALID (0xFFFF) +#define BLEBRR_CONN_HNDL_INVALID (0xFFFF) + +/* --------------------------------------------- Global Definitions */ +#define BLEBRR_ADVDATA_OFFSET 0 /* 3 */ + +#define BLEBRR_NCON_ADVINTMIN 0xA0 /* ADV for NON_CONN_IND should be greater than 0x00A0 */ +#define BLEBRR_NCON_ADVINTMAX 0xA0 /* ADV for NON_CONN_IND should be greater than 0x00A0 */ +#define BLEBRR_NCON_ADVTYPE 0x03 +#define BLEBRR_NCON_DIRADDRTYPE 0x00 +#define BLEBRR_NCON_ADVCHMAP 0x07 +#define BLEBRR_NCON_ADVFILTERPOLICY 0x00 + +#define BLEBRR_CON_ADVINTMIN 0x320 +#define BLEBRR_CON_ADVINTMAX 0x320 +#define BLEBRR_CON_ADVTYPE 0x00 +#define BLEBRR_CON_DIRADDRTYPE 0x00 +#define BLEBRR_CON_ADVCHMAP 0x07 +#define BLEBRR_CON_ADVFILTERPOLICY 0x00 +#define BLEBRR_CON_SCANRSP_DATALEN 31 + +#define BLEBRR_SCANTYPE 0x00 +#define BLEBRR_SCANINTERVAL 0x18 //0x18->15ms 0x20->20ms +#define BLEBRR_SCANWINDOW 0x18 //0x18->15ms 0x20->20ms +#define BLEBRR_SCANFILTERPOLICY 0x00 +#define BLEBRR_SCANFILTERDUPS 0x00 + +#define BLEBRR_CONN_FILTER_POLICY_WL 0x01 +#define BLEBRR_CONN_FILTER_POLICY_NWL 0x00 +#define BLEBRR_CONN_INTERVAL_MIN 0x0040 +#define BLEBRR_CONN_INTERVAL_MAX 0x0040 +#define BLEBRR_CONN_LATENCY 0x0000 +#define BLEBRR_CONN_SUPERVISION_TO 0x03BB +#define BLEBRR_CONN_MIN_CE_LEN 0x0000 +#define BLEBRR_CONN_MAX_CE_LEN 0x0000 + +#define BLEBRR_OWNADDRTYPE 0x00 + +#define BLEBRR_ADVSCANEN_TIMEOUT 50 + +/* Active connection handle used to send measurements */ +static uint16_t active_conn_hndl = BLEBRR_CONN_HNDL_INVALID; + +/* Call Back to Inform Application Layer about GATT Bearer Iface Events */ +typedef void (* blebrr_gatt_iface_event_pl_cb) +( + uint8_t ev_name, + uint8_t status +); + +API_RESULT blebrr_register_gatt_iface_event_pl +( + blebrr_gatt_iface_event_pl_cb gatt_iface_evt_cb +); + +/* --------------------------------------------- External Global Variables */ + +/* --------------------------------------------- Exported Global Variables */ + +/* --------------------------------------------- Static Global Variables */ + +/* Bearer Scan Response Data related */ +DECL_STATIC UCHAR blebrr_scanrsp_data[BLEBRR_CON_SCANRSP_DATALEN]; +DECL_STATIC UCHAR blebrr_scanrsp_datalen; + +//DECL_STATIC UCHAR BLEBRR_DIRADDR[6]; + +DECL_STATIC UCHAR blebrr_advstate; +DECL_STATIC UCHAR blebrr_scanstate; + +DECL_STATIC UCHAR curr_service; + +UCHAR blebrr_advtype; + + +#ifdef BLE_CLIENT_ROLE +/* BLE Bearer GAP Connection State */ +/** + 0x00 - Idle/Disconnected + 0x01 - To Initiate Connection + 0x02 - Connected Initiated + 0x03 - Connected +*/ +static UCHAR blebrr_connect_state = 0x00; +static UCHAR blebrr_addr_to_conn[6] = {0}; +static UCHAR blebrr_addr_type_to_conn = 0xFF; +#endif /* BLE_CLIENT_ROLE */ + +/* Global to hold the Role of GATT */ +UCHAR blebrr_gatt_role; + +BRR_HANDLE blebrr_gatt_handle_pl; + +/* Mesh Provisioning service related data structures */ +static uint16_t appl_mesh_prov_data_out_ccd_cb(uint16_t conn_hndl, uint8_t enabled); +static uint16_t appl_mesh_prov_data_in_wt_cb +( + uint16_t conn_hndl, + uint16_t offset, + uint16_t length, + uint8_t* value +); +static mesh_prov_cb appl_mesh_prov_cb = +{ + .prov_data_in_cb = appl_mesh_prov_data_in_wt_cb, + .prov_data_out_ccd_cb = appl_mesh_prov_data_out_ccd_cb, +}; + +/* Mesh Proxy service related data structures */ +static uint16_t appl_mesh_proxy_data_out_ccd_cb(uint16_t conn_hndl, uint8_t enabled); +static uint16_t appl_mesh_proxy_data_in_wt_cb +( + uint16_t conn_hndl, + uint16_t offset, + uint16_t length, + uint8_t* value +); +static mesh_proxy_cb appl_mesh_proxy_cb = +{ + .proxy_data_in_cb = appl_mesh_proxy_data_in_wt_cb, + .proxy_data_out_ccd_cb = appl_mesh_proxy_data_out_ccd_cb, +}; + +/* Global to hold GATT Iface events Application Callback pointer */ +DECL_STATIC BLEBRR_GATT_IFACE_EVENT_PL_CB blebrr_gatt_iface_pl_cb; + +/* --------------------------------------------- Functions */ +API_RESULT blebrr_register_gatt_iface_event_pl +( + BLEBRR_GATT_IFACE_EVENT_PL_CB gatt_iface_evt_cb +) +{ + if (NULL != gatt_iface_evt_cb) + { + blebrr_gatt_iface_pl_cb = gatt_iface_evt_cb; + BLEBRRPL_LOG("\r\n Registered GATT Bearer Iface Events Appl Callback!\r\n"); + return API_SUCCESS; + } + + /* If NULL callback is registered */ + return API_FAILURE; +} + +void appl_dump_bytes(UCHAR* buffer, UINT16 length) +{ + char hex_stream[49]; + char char_stream[17]; + UINT32 i; + UINT16 offset, count; + UCHAR c; + BLEBRRPL_LOG("\n"); + BLEBRRPL_LOG("-- Dumping %d Bytes --\n", + (int)length); + BLEBRRPL_LOG( + "-------------------------------------------------------------------\n"); + count = 0; + offset = 0; + + for (i = 0; i < length; i++) + { + c = buffer[i]; + sprintf(hex_stream + offset, "%02X ", c); + + if ((c >= 0x20) && (c <= 0x7E)) + { + char_stream[count] = c; + } + else + { + char_stream[count] = '.'; + } + + count++; + offset += 3; + + if (16 == count) + { + char_stream[count] = '\0'; + count = 0; + offset = 0; + BLEBRRPL_LOG("%s %s\n", + hex_stream, char_stream); + EM_mem_set(hex_stream, 0, 49); + EM_mem_set(char_stream, 0, 17); + } + } + + if (offset != 0) + { + char_stream[count] = '\0'; + /* Maintain the alignment */ + BLEBRRPL_LOG("%-48s %s\n", + hex_stream, char_stream); + } + + BLEBRRPL_LOG( + "-------------------------------------------------------------------\n"); + BLEBRRPL_LOG("\n"); + return; +} + + +void blebrr_handle_evt_adv_report (gapDeviceInfoEvent_t* adv) +{ + UCHAR* pdata; + UCHAR type; + /* Reference the event type, data and datalength */ + type = (HCI_NONCONNECTABLE_UNDIRECTED_ADV == (UCHAR)adv->eventType)? BRR_BCON_PASSIVE: BRR_BCON_ACTIVE; + pdata = (UCHAR*)adv->pEvtData; + #if 0 + + if (BRR_BCON_ACTIVE == type) + { + BLEBRRPL_LOG("Adv Report. Type: 0x%02X\r\n", adv->eventType); + BLEBRRPL_LOG("BD Addr [0x%02X]: ", adv->addrType); + BLEBRRPL_dump_bytes(adv->addr, 6); + BLEBRRPL_LOG("Data [datalen]:"); + BLEBRRPL_dump_bytes(pdata, (UCHAR)adv->dataLen); + } + + #endif /* 0 */ + + /* Pass advertising data to the bearer */ + if ((MESH_AD_TYPE_BCON == pdata[1]) || (MESH_AD_TYPE_PB_ADV == pdata[1]) || (MESH_AD_TYPE_PKT == pdata[1])) + { + if (BRR_BCON_PASSIVE == type) + { + blebrr_pl_recv_advpacket (type, &pdata[1], pdata[0], (UCHAR)adv->rssi); + } + } +} + +void blebrr_handle_evt_adv_complete (UINT8 enable) +{ + /* if (blebrr_advstate == enable) */ + { + blebrr_pl_advertise_setup (blebrr_advstate); + } + #if 0 + else if (0x01 == blebrr_advstate) + { + blebrr_advstate = 0x00; + blebrr_pl_advertise_end(); + } + + #endif /* 0 */ +} + +void blebrr_handle_evt_scan_complete (UINT8 enable) +{ + /* if (blebrr_scanstate == enable) */ + #ifdef BLE_CLIENT_ROLE + bStatus_t ret; + + /* BLEBRRPL_LOG ("\r\n blebrr_handle_evt_scan_complete with 0x%04X\r\n", enable); + BLEBRRPL_LOG ("\r\n blebrr_connect_state is 0x%04X\r\n", blebrr_connect_state); */ + + if (0x00 == enable) + { + /* Initiate Connection on Scan Disable */ + if (0x01 == blebrr_connect_state) + { + BLEBRRPL_LOG ("Scan Disabled! Initiating Connection..."); + ret = BLE_gap_connect + ( + 0x00, + blebrr_addr_to_conn, + blebrr_addr_type_to_conn + ); + BLEBRRPL_LOG("Initiating Connection to Address " + "0x%02X:0x%02X:0x%02X:0x%02X:0x%02X:0x%02X Type 0x%02X " + "with retval 0x%04X\r\n", + blebrr_addr_to_conn[0], blebrr_addr_to_conn[1], blebrr_addr_to_conn[2], + blebrr_addr_to_conn[3], blebrr_addr_to_conn[4], blebrr_addr_to_conn[5], + blebrr_addr_type_to_conn, ret); + blebrr_connect_state = 0x02; + /* Set GATT Role as Client */ + blebrr_gatt_role = BLEBRR_CLIENT_ROLE; + } + else + { + /* Indicate Scan disable to bearer */ + blebrr_pl_scan_setup (blebrr_scanstate); + } + } + else + #endif /* BLE_CLIENT_ROLE */ + { + /* Indicate Scan disable to bearer */ + blebrr_pl_scan_setup (blebrr_scanstate); + } +} + +void blebrr_init_pl (void) +{ +// hciStatus_t ret; + BLEBRR_LOG("Done.\n"); + /* Configure the local device address */ + GAP_ConfigDeviceAddr(ADDRTYPE_PUBLIC, NULL); + /* Initialize */ + blebrr_gatt_iface_pl_cb = NULL; + BLE_gap_set_scan_params + ( + BLEBRR_SCANTYPE, + BLEBRR_SCANINTERVAL, + BLEBRR_SCANWINDOW, + BLEBRR_SCANFILTERPOLICY + ); + /** + NOTE: Enabling Both the services at the start. + + TODO: Check if this needs to be flag protected. + */ + BLEBRRPL_LOG ("Enabling Mesh Prov Service...\r\n"); + //mesh_prov_init((mesh_prov_cb *)&appl_mesh_prov_cb); + /* Initialize the bearer handle */ + blebrr_gatt_handle_pl = BRR_HANDLE_INVALID; +} + +void blebrr_scan_pl (UCHAR enable) +{ + hciStatus_t ret; + UCHAR prevstate; + prevstate = blebrr_scanstate; + + /* Is request to enable? */ + if (MS_TRUE == enable) + { + /* Update global scan state */ + blebrr_scanstate = 0x01; + #ifdef BLEBRR_ENABLE_SCAN_TRACE + BLEBRRPL_LOG ("Enabling Scan..."); + #endif /* BLEBRR_ENABLE_SCAN_TRACE */ + /* Enable Scan */ + ret = BLE_gap_set_scan_enable (0x01); + } + else + { + /* Update global scan state */ + blebrr_scanstate = 0x00; + #ifdef BLEBRR_ENABLE_SCAN_TRACE + BLEBRRPL_LOG ("Disabling Scan..."); + #endif /* BLEBRR_ENABLE_SCAN_TRACE */ + /* Disable Scan */ + ret = BLE_gap_set_scan_enable (0x00); + } + + /* Is operation failed? */ + if (0 != ret) + { +// BLEBRRPL_LOG ("Scan Operation (%d - %d) failed with reason 0x%04X", blebrr_scanstate, prevstate, ret); + blebrr_scanstate = prevstate; + + if(blebrr_scanstate != prevstate) + BLEBRRPL_LOG ("Scan Operation (%d - %d) failed with reason 0x%04X", blebrr_scanstate, prevstate, ret); + } + else + { + /* Update state */ + if(MS_TRUE == enable) + BLEBRR_SET_STATE(BLEBRR_STATE_IN_SCAN_ENABLE); + else + BLEBRR_SET_STATE(BLEBRR_STATE_IN_SCAN_DISABLE); + } +} + +UCHAR blebrr_get_advdata_offset_pl (void) +{ + return BLEBRR_ADVDATA_OFFSET; +} + +API_RESULT blebrr_set_adv_scanrsp_data_pl +( + UCHAR* srp_data, + UCHAR srp_datalen +) +{ + /* Initialize the Globals */ + EM_mem_set + ( + blebrr_scanrsp_data, + 0x0, + sizeof(blebrr_scanrsp_data) + ); + blebrr_scanrsp_datalen = 0; + + /* Set the application provided Scan Response Data to Global */ + if ((NULL != srp_data) && (0 != srp_datalen)) + { + EM_mem_copy + ( + blebrr_scanrsp_data, + srp_data, + srp_datalen + ); + blebrr_scanrsp_datalen = srp_datalen; + return API_SUCCESS; + } + + return API_FAILURE; +} + +void blebrr_advertise_data_pl (CHAR type, UCHAR* pdata, UINT16 pdatalen) +{ + blebrr_advtype = type; + + /* Is request to enable? */ + if ((NULL != pdata) && (0 != pdatalen)) + { + /* Set Advertising Parameters */ + if (BRR_BCON_PASSIVE == type) + { + /* Set Non-Connectable Adv Params */ + BLE_gap_set_adv_params + ( + BLEBRR_NCON_ADVTYPE, + BLEBRR_NCON_ADVINTMIN, + BLEBRR_NCON_ADVINTMAX, + BLEBRR_NCON_ADVFILTERPOLICY + ); + } + else + { + /* Set Connectable Adv Params */ + BLE_gap_set_adv_params + ( + BLEBRR_CON_ADVTYPE, + BLEBRR_CON_ADVINTMIN, + BLEBRR_CON_ADVINTMAX, + BLEBRR_CON_ADVFILTERPOLICY + ); + + /* Set the Scan Response Data to Stack if length is valid */ + if (0 != blebrr_scanrsp_datalen) + { + BLE_gap_set_advscanrsp_data + ( + FALSE, + blebrr_scanrsp_data, + blebrr_scanrsp_datalen + ); + } + } + + /* Set Advertising Data */ + BLE_gap_set_advscanrsp_data(TRUE, pdata, pdatalen); + //BLEBRRPL_LOG ("Adv Data - Retval: %d\r\n",ret); + /* Enable Advertising */ + blebrr_advertise_pl(MS_TRUE); + } + else + { + /* Disable Advertising */ + blebrr_advertise_pl(MS_FALSE); + } +} + +extern UCHAR blebrr_state; + +API_RESULT blebrr_advertise_pl (UCHAR state) // HZF +{ + hciStatus_t ret = API_SUCCESS; // HZF + UCHAR prevstate; + prevstate = blebrr_advstate; + + if (MS_TRUE == state) + { + #ifdef BLEBRR_ENABLE_ADV_TRACE + BLEBRRPL_LOG ("Enabling Adv..."); + #endif /* BLEBRR_ENABLE_ADV_TRACE */ + /* Update global adv state */ + blebrr_advstate = 0x01; + ret = BLE_gap_set_adv_enable(0x01); + } + else + { + #ifdef BLEBRR_ENABLE_ADV_TRACE + BLEBRRPL_LOG ("Disabling Adv..."); + #endif /* BLEBRR_ENABLE_ADV_TRACE */ + /* Update global adv state */ + blebrr_advstate = 0x00; + //BLEBRRPL_LOG ("Disabling Adv..."); + ret = BLE_gap_set_adv_enable(0x00); + } + + /* Is operation failed? */ + if (0 != ret) + { + BLEBRRPL_LOG ("Adv Operation (%d - %d) failed with reason 0x%04X", blebrr_advstate, prevstate, ret); + blebrr_advstate = prevstate; + } + else + { + /* Update state */ + if(MS_TRUE == state) + BLEBRR_SET_STATE(BLEBRR_STATE_IN_ADV_ENABLE); + else + BLEBRR_SET_STATE(BLEBRR_STATE_IN_ADV_DISABLE); + } + + return ret; +} + +API_RESULT blebrr_gatt_send_pl(BRR_HANDLE* handle, UCHAR* data, UINT16 datalen) +{ + UCHAR type; + API_RESULT retval; + /* TODO */ + /* BLEBRR_LOG("\n >>>> GATT PL Data Tx:\n"); + appl_dump_bytes(data, datalen); */ + retval = API_SUCCESS; + /* Get the current mode */ + /* TODO: See if we need to get specific mode for a GATT transport */ + type = blebrr_gatt_mode_get(); + + /* Check the PDU type received and Add bearer to Mesh stack */ + if (BLEBRR_GATT_PROV_MODE == type) + { + /* BLEBRRPL_LOG("\r\nBLEBRR_GATT_PROV_MODE with role 0x%02X\r\n", blebrr_gatt_role); */ + if (BLEBRR_SERVER_ROLE == blebrr_gatt_role) + { + mesh_prov_notify_data_out + ( + active_conn_hndl, + MESH_PROV_DATA_OUT_VALUE_VAL, + data, + datalen + ); + } + + #ifdef BLE_CLIENT_ROLE + else + { + /* TODO SRIKKANTH */ + mesh_prov_client_data_in_write(active_conn_hndl, data, datalen); + retval = API_SUCCESS; + } + + #endif /* BLE_CLIENT_ROLE */ + } + else + { + /* BLEBRRPL_LOG("\r\nBLEBRR_GATT_PROXY_MODE with role 0x%02X\r\n", blebrr_gatt_role); */ + if (BLEBRR_SERVER_ROLE == blebrr_gatt_role) + { + retval = mesh_proxy_notify_data_out + ( + active_conn_hndl, + MESH_PROXY_DATA_OUT_VALUE_VAL, + data, + datalen + ); + + if(retval) + { + return retval; + } + } + + #ifdef BLE_CLIENT_ROLE + else + { + mesh_proxy_client_data_in_write(active_conn_hndl, data, datalen); + retval = API_SUCCESS; + } + + #endif /* BLE_CLIENT_ROLE */ + } + + return retval; +} + +static API_RESULT blebrr_recv_mesh_packet_pl +( + void* handle, + UINT16 attr_handle, + UCHAR* data, + UINT16 data_len +) +{ + /** + TODO: MAP the incoming handle to BLEBRR specific handle for + */ + /* BLEBRR_LOG("\n >>>> GATT PL Data Rx: %d bytes\n", data_len); + appl_dump_bytes(data, data_len); */ + blebrr_pl_recv_gattpacket + ( + &blebrr_gatt_handle_pl, + data, + data_len + ); + return API_SUCCESS; +} + +API_RESULT blebrr_handle_le_connection_pl +( + uint16_t conn_idx, + uint16_t conn_hndl, + uint8_t peer_addr_type, + uint8_t* peer_addr +) +{ + /** + If Needed, + Store the provided handle according to platform exposed data type + */ + BLEBRR_LOG("Device Connected - Handle: 0x%04X\r\n", conn_hndl); + + if (active_conn_hndl == BLEBRR_CONN_HNDL_INVALID) + { + /* Store the incoming connection handle in global */ + active_conn_hndl = conn_hndl; + #ifdef BLE_CLIENT_ROLE + mesh_client_update_conidx(active_conn_hndl); + /* Setting State To Connected */ + blebrr_connect_state = 0x03; + #endif /* BLE_CLIENT_ROLE */ + } + + /* Advertisement is disable by connection mostly */ + blebrr_advstate = 0x00; + blebrr_pl_advertise_end(); + + /** + Inform Application of GATT/BLE Link Layer Connection. + */ + if (NULL != blebrr_gatt_iface_pl_cb) + { + blebrr_gatt_iface_pl_cb + ( + BLEBRR_GATT_IFACE_UP, /* BLE Link Layer Connection */ + 0x00 /* Status is Success */ + ); + } + + return API_SUCCESS; +} + +static API_RESULT blebrr_gatt_com_channel_setup_pl +( + UCHAR role, + UCHAR mode, + UCHAR evt +) +{ + API_RESULT retval; + UINT16 mtu; + /** + Possible Values of Role are + 1. 0x00 - GATT Client ~ BLEBRR_CLIENT_ROLE + 2. 0x01 - GATT Server ~ BLEBRR_SERVER_ROLE + */ + /** + Possible Values of Mode are + 1. 0x00 - BLEBRR_GATT_PROV_MODE + 2. 0x01 - BLEBRR_GATT_PROXY_MODE + */ + /** + Possible Values of evt are + 1. 0x00 - BLEBRR_COM_CHANNEL_CONNECT + 2. 0x01 - BLEBRR_COM_CHANNEL_DISCONNECT + */ + retval = API_FAILURE; + + if (BLEBRR_COM_CHANNEL_CONNECT == evt) + { + /* Store the gatt role to be used during write */ + blebrr_gatt_role = role; + /* Initialie MTU */ + mtu = BLEBRR_GATT_MIN_MTU; + + if (BLEBRR_SERVER_ROLE == role) + { + /* Fetch MTU from ATT and adjust it for Mesh */ + } + else if (BLEBRR_CLIENT_ROLE == role) + { + /* Fetch MTU from ATT and adjust it for Mesh */ + } + else + { + /* Empty */ + } + + retval = blebrr_pl_gatt_connection + ( + &blebrr_gatt_handle_pl, + role, + mode, + mtu + ); + + if (NULL != blebrr_gatt_iface_pl_cb) + { + blebrr_gatt_iface_pl_cb + ( + BLEBRR_GATT_IFACE_ENABLE, + mode /* BLEBRR_GATT_PROV_MODE or BLEBRR_GATT_PROXY_MODE */ + ); + } + } + else if (BLEBRR_COM_CHANNEL_DISCONNECT == evt) + { + /** + Currently BLE Bearer GATT Channel Disconnection + is called only from HCI/ACL link disconnection. + */ + blebrr_gatt_role = 0xFF; + /* Delete Device from the Bearer */ + retval = blebrr_pl_gatt_disconnection (&blebrr_gatt_handle_pl); + blebrr_gatt_handle_pl = BRR_HANDLE_INVALID; + + if (NULL != blebrr_gatt_iface_pl_cb) + { + blebrr_gatt_iface_pl_cb + ( + BLEBRR_GATT_IFACE_DISABLE, + mode /* BLEBRR_GATT_PROV_MODE or BLEBRR_GATT_PROXY_MODE */ + ); + } + } + else + { + /* Empty */ + } + + return retval; +} + +static uint16_t appl_mesh_prov_data_out_ccd_cb(uint16_t conn_hndl, uint8_t enabled) +{ + /* Check the Current mode is not PROV */ + if (BLEBRR_GATT_PROV_MODE != blebrr_gatt_mode_get()) + { + BLEBRRPL_LOG("Mesh Prov Out CCD being Written when PROV is not Active!\r\n"); + return 0xFFFF; + } + + if (TRUE == enabled) + { + BLEBRRPL_LOG("Mesh Prov Out CCD Enabled"); + } + else + { + BLEBRRPL_LOG("Mesh Prov Out CCD Disabled"); + } + + blebrr_gatt_com_channel_setup_pl + ( + BLEBRR_SERVER_ROLE, + BLEBRR_GATT_PROV_MODE, + (enabled) ? BLEBRR_COM_CHANNEL_CONNECT : BLEBRR_COM_CHANNEL_DISCONNECT + ); + return 0x0000; +} + +static uint16_t appl_mesh_prov_data_in_wt_cb +( + uint16_t conn_hndl, + uint16_t offset, + uint16_t length, + uint8_t* value +) +{ + if (NULL != value) + { + /* BLEBRRPL_LOG("Mesh Prov Data IN received"); + appl_dump_bytes(value, length); */ + BLEBRRPL_LOG("Mesh Prov Data IN received"); + blebrr_recv_mesh_packet_pl + ( + &conn_hndl, + offset, + value, + length + ); + } + + return 0x0000; +} + +static uint16_t appl_mesh_proxy_data_out_ccd_cb(uint16_t conn_hndl, uint8_t enabled) +{ + /* Check the Current mode is not PROV */ + if (BLEBRR_GATT_PROXY_MODE != blebrr_gatt_mode_get()) + { + BLEBRRPL_LOG("Mesh Proxy Out CCD being Written when PROXY is not Active!\r\n"); + return 0xFFFF; + } + + if (TRUE == enabled) + { + BLEBRRPL_LOG("Mesh Proxy Out CCD Enabled"); + blebrr_scan_enable(); + } + else + { + BLEBRRPL_LOG("Mesh Proxy Out CCD Disabled"); + } + + blebrr_gatt_com_channel_setup_pl + ( + BLEBRR_SERVER_ROLE, + BLEBRR_GATT_PROXY_MODE, + (enabled) ? BLEBRR_COM_CHANNEL_CONNECT : BLEBRR_COM_CHANNEL_DISCONNECT + ); + return 0x0000; +} + +static uint16_t appl_mesh_proxy_data_in_wt_cb +( + uint16_t conn_hndl, + uint16_t offset, + uint16_t length, + uint8_t* value +) +{ + if (NULL != value) + { + BLEBRRPL_LOG("Mesh Proxy Data IN received"); + //appl_dump_bytes(value, length); + blebrr_recv_mesh_packet_pl + ( + &conn_hndl, + offset, + value, + length + ); + } + + return 0x0000; +} + +#ifdef BLE_CLIENT_ROLE +void appl_mesh_prov_data_out_notif_cb +( + uint16_t conidx, + uint16_t length, + uint8_t* value +) +{ + #if 0 + printf("\r\n Mesh PROV Data Out NTFs:\r\n"); + appl_dump_bytes + ( + value, + length + ); + #endif /* 0 */ + blebrr_recv_mesh_packet_pl + ( + &active_conn_hndl, + 0x0000, + (UCHAR*)value, + length + ); +} + +void appl_mesh_prov_notif_config_status_cb +( + uint16_t conidx, + uint8_t flag, + uint8_t status +) +{ + if (status == 0x00) + { + printf("Mesh Provisioning Data Out notifications %s\r\n", + flag ? "enabled" : "disabled"); + blebrr_gatt_mode_set(BLEBRR_GATT_PROV_MODE); + appl_prov_register(); + appl_prov_setup(PROV_ROLE_PROVISIONER, PROV_BRR_GATT); + blebrr_gatt_com_channel_setup_pl + ( + BLEBRR_CLIENT_ROLE, + BLEBRR_GATT_PROV_MODE, + (flag)? BLEBRR_COM_CHANNEL_CONNECT : BLEBRR_COM_CHANNEL_DISCONNECT + ); + } + else + { + printf("ERROR: failed to set notifications (0x%02x)\r\n", status); + } +} + +static mesh_prov_client_cb mesh_prov_callbacks = +{ + .mesh_prov_data_out_notif = appl_mesh_prov_data_out_notif_cb, + .mesh_prov_ntf_status = appl_mesh_prov_notif_config_status_cb, +}; + +void appl_mesh_proxy_data_out_notif_cb +( + uint16_t conidx, + uint16_t length, + uint8_t* value +) +{ + #if 0 + printf("\r\n Mesh PROXY Data Out NTFs:\r\n"); + appl_dump_bytes + ( + value, + length + ); + #endif /* 0 */ + blebrr_recv_mesh_packet_pl + ( + &active_conn_hndl, + 0x0000, + (UCHAR*)value, + length + ); +} + +void appl_mesh_proxy_notif_config_status_cb +( + uint16_t conidx, + uint8_t flag, + uint8_t status +) +{ + if (status == 0x00) + { + printf("Mesh Proxy Data Out notifications %s\r\n", + flag ? "enabled" : "disabled"); + blebrr_gatt_mode_set(BLEBRR_GATT_PROXY_MODE); + blebrr_gatt_com_channel_setup_pl + ( + BLEBRR_CLIENT_ROLE, + BLEBRR_GATT_PROXY_MODE, + (flag)? BLEBRR_COM_CHANNEL_CONNECT : BLEBRR_COM_CHANNEL_DISCONNECT + ); + } + else + { + printf("ERROR: failed to set notifications (0x%02x)\r\n", status); + } +} + +static mesh_proxy_client_cb mesh_proxy_callbacks = +{ + .mesh_proxy_data_out_notif = appl_mesh_proxy_data_out_notif_cb, + .mesh_proxy_ntf_status = appl_mesh_proxy_notif_config_status_cb, +}; +#endif /* BLE_CLIENT_ROLE */ + +/** Dummy Interfaces: To be filled for Client Role */ +API_RESULT blebrr_scan_cmd_handler_pl(UCHAR enable) +{ + if (enable) + { + BLEBRRPL_LOG("\n Scan Start Feature to be extended for CLI\n"); + } + else + { + BLE_gap_set_scan_enable (0x00); + } + + return API_SUCCESS; +} + +API_RESULT blebrr_create_gatt_conn_pl +( + UCHAR p_bdaddr_type, + UCHAR* p_bdaddr +) +{ + #ifdef BLE_CLIENT_ROLE + bStatus_t ret; + + if (0x00 != blebrr_scanstate) + { + /* Update global scan state */ + blebrr_scanstate = 0x00; + /* Disable Scan */ + ret = BLE_gap_set_scan_enable (0x00); + BLEBRRPL_LOG ("Disabling Scan...with retval 0x%04X\r\n", ret); + + if (0x00 == ret) + { + /* Scan Disable Successful */ + /* Move to To Initiate Connection Phase */ + blebrr_connect_state = 0x01; + /** Save the global Address */ + EM_mem_copy(blebrr_addr_to_conn, p_bdaddr, 6); + blebrr_addr_type_to_conn = p_bdaddr_type; + } + else + { + /* Scan Stop Failed */ + BLEBRRPL_LOG ("Scan Disabled Failed wit ret 0x%02X", ret); + } + + return (0 == ret) ? API_SUCCESS : API_FAILURE; + } + else + { + BLEBRRPL_LOG ("Scan already Disabled! Initiating Connection..."); + ret = BLE_gap_connect + ( + 0x00, + p_bdaddr, + p_bdaddr_type + ); + blebrr_connect_state = 0x02; + /* Set GATT Role as Client */ + blebrr_gatt_role = BLEBRR_CLIENT_ROLE; + BLEBRRPL_LOG("Initiating Connection to Address " + "0x%02X:0x%02X:0x%02X:0x%02X:0x%02X:0x%02X Type 0x%02X " + "with retval 0x%04X\r\n", + p_bdaddr[0], p_bdaddr[1], p_bdaddr[2], p_bdaddr[3], + p_bdaddr[4], p_bdaddr[5], p_bdaddr_type, ret); + return (0 == ret) ? API_SUCCESS : API_FAILURE; + } + + #else /* BLE_CLIENT_ROLE */ + return API_FAILURE; + #endif /* BLE_CLIENT_ROLE */ +} + +API_RESULT blebrr_disconnect_pl(void) +{ + bStatus_t ret; + ret = BLE_gap_disconnect(active_conn_hndl); + BLEBRRPL_LOG("\r\n Initiating Disconnection with Connection Handle 0x%04X" + "with retval 0x%04X\r\n", active_conn_hndl, ret); + return (0 == ret) ? API_SUCCESS : API_FAILURE; +} + +API_RESULT blebrr_discover_service_pl(UCHAR serv) +{ + /* Set the mode with bearer */ + (serv == 0) ? blebrr_gatt_mode_set(BLEBRR_GATT_PROV_MODE) : + blebrr_gatt_mode_set(BLEBRR_GATT_PROXY_MODE); + #ifdef BLE_CLIENT_ROLE + /* Register the corresponding Callbacks */ + (serv == BLEBRR_GATT_PROV_MODE) ? \ + mesh_prov_client_init(&mesh_prov_callbacks) : \ + mesh_proxy_client_init(&mesh_proxy_callbacks); + return mesh_client_discover_services + ( + active_conn_hndl, + serv + ); + #else + return API_FAILURE; + #endif /* BLE_CLIENT_ROLE */ +} + +API_RESULT blebrr_confige_ntf_pl(UCHAR config_ntf, UCHAR mode) +{ + #ifdef BLE_CLIENT_ROLE + return mesh_client_config_ntf(active_conn_hndl, mode, (0x00 == config_ntf) ? false:true); + #else /* BLE_CLIENT_ROLE */ + BLEBRRPL_LOG("\r\n BLE_CLIENT_ROLE Disabled!\r\n"); + return API_FAILURE; + #endif /* BLE_CLIENT_ROLE */ +} + +API_RESULT blebrr_handle_le_disconnection_pl +( + uint16_t conn_idx, + uint16_t conn_hndl, + uint8_t reason +) +{ + API_RESULT retval; + retval = API_FAILURE; + BLEBRRPL_LOG("Device Disconnected - Handle: 0x%04X with Reason: 0x%02X\r\n", conn_hndl, reason); + + if (active_conn_hndl == conn_hndl) + { + /* Reinitialize Connection Handle */ + active_conn_hndl = BLEBRR_CONN_HNDL_INVALID; + #ifdef BLE_CLIENT_ROLE + mesh_client_update_conidx(active_conn_hndl); + /* Setting State to Idle/Disconnected */ + blebrr_connect_state = 0x00; + #endif /* BLE_CLIENT_ROLE */ + } + + /* Inform Disconnection to GATT Bearer */ + blebrr_gatt_role = 0xFF; + retval = blebrr_pl_gatt_disconnection + ( + &blebrr_gatt_handle_pl + ); + blebrr_gatt_handle_pl = BRR_HANDLE_INVALID; + + /** + Inform Application of GATT/BLE Link Layer Connection. + */ + if (NULL != blebrr_gatt_iface_pl_cb) + { + blebrr_gatt_iface_pl_cb + ( + BLEBRR_GATT_IFACE_DOWN, /* BLE Link Layer Disconnection */ + 0x00 /* Status is Success */ + ); + } + + return retval; +} + +void blebrr_enable_mesh_serv_pl (UCHAR serv_type) +{ + BLEBRRPL_LOG ("Serv Enable called with 0x%02X", serv_type); + + /* If serv_type : + BLEBRR_GATT_PROVILINK - Mesh Prov + BLEBRR_GATT_PROXYLINK - Mesh Proxy + */ + if (BLEBRR_GATT_PROV_MODE == serv_type) + { + BLEBRRPL_LOG ("Enabling Mesh Prov Service...\r\n"); + mesh_prov_init(&appl_mesh_prov_cb); + } + else + { + BLEBRRPL_LOG ("Enabling Mesh Proxy Service...\r\n"); + mesh_proxy_init(&appl_mesh_proxy_cb); + } +} + +void blebrr_disable_mesh_serv_pl (UCHAR serv_type) +{ + BLEBRRPL_LOG ("Serv Disable called with 0x%02X", serv_type); + + /* If serv_type : + BLEBRR_GATT_PROVILINK - Mesh Prov + BLEBRR_GATT_PROXYLINK - Mesh Proxy + */ + if (BLEBRR_GATT_PROV_MODE == serv_type) + { + BLEBRRPL_LOG ("Disabling Mesh Prov Service...\r\n"); + /* + Disable Mesh Provisioing Serivce + */ + mesh_prov_deinit(); + } + else + { + BLEBRRPL_LOG ("Disabling Mesh Proxy Service...\r\n"); + /* + Disable Mesh Proxy Serivce + */ + mesh_proxy_deinit(); + } + + BLEBRRPL_LOG("Service Disable yet to be Supported\r\n"); +} + +void blebrr_set_gattmode_pl (UCHAR flag) +{ + /* Setting Provisioning or Proxy Mode */ + if (0xFF != flag) + { + blebrr_disable_mesh_serv_pl(curr_service); + blebrr_enable_mesh_serv_pl(flag); + curr_service = flag; + } + else + { + /* Do Nothing */ + } +} + diff --git a/src/components/ethermind/platforms/mesh/mesh_clients.c b/src/components/ethermind/platforms/mesh/mesh_clients.c new file mode 100644 index 0000000..91d3fdf --- /dev/null +++ b/src/components/ethermind/platforms/mesh/mesh_clients.c @@ -0,0 +1,566 @@ + +/** + \file mesh_clients.c + + +*/ + +/* + Copyright (C) 2018. Mindtree Limited. + All rights reserved. +*/ + +/* --------------------------------------------- Header File Inclusion */ +#include "mesh_clients.h" + +/* --------------------------------------------- Global Definitions */ +/* Compilation Switch to have this module print trace on console */ +#define MESH_CLIENT_CONSOLE_DEBUG + +/* --------------------------------------------- Macros */ +#ifdef MESH_CLIENT_CONSOLE_DEBUG + #define MESH_CLIENT_TRC(...) printf(__VA_ARGS__) +#else /* MESH_CLIENT_CONSOLE_DEBUG */ + #define MESH_CLIENT_TRC(...) +#endif /* MESH_CLIENT_CONSOLE_DEBUG */ + +/* --------------------------------------------- External Global Variables */ + +/* --------------------------------------------- Exported Global Variables */ + +/* --------------------------------------------- Static Global Variables */ +/** + This Task ID is the identifier used by the GATT APIs to reference + the BLE Mesh Application Task. + The definition and usage of this is from the bleMesh.c application + file. +*/ +extern uint8_t bleMesh_TaskID; + +/* --------------------------------------------- Functions */ + +#define MESH_MAX_CLI_ENV 1 + +/* Global variable definition */ +struct mesh_cli_env_tag mesh_cli_env[MESH_MAX_CLI_ENV]; + +/* Mesh Provisioning Service Client Related Callbacks */ +static mesh_prov_client_cb* prov_cli_cb; + +/* Mesh Proxy Service Client Related Callbacks */ +static mesh_proxy_client_cb* proxy_cli_cb; + +/* Track current UUID being Discovered */ +static uint16_t mesh_client_curr_dis_uuid; + +/* ---------------------------------------------------------------------------- + Function : void mesh_client_init(void) + ---------------------------------------------------------------------------- + Description : Initialize Mesh Client environment + Inputs : None + Outputs : None + Assumptions : None + ------------------------------------------------------------------------- */ +void mesh_client_init(void) +{ + for (unsigned int i = 0; i < MESH_MAX_CLI_ENV; i++) + { + /* Reset the application manager environment */ + memset(&mesh_cli_env[i], 0, sizeof(struct mesh_cli_env_tag)); + } + + mesh_client_curr_dis_uuid = 0x0000; + prov_cli_cb = NULL; + proxy_cli_cb = NULL; +} + +/** + Routine to update the connection identifier for Mesh. +*/ +void mesh_client_update_conidx (uint16_t conidx) +{ + mesh_cli_env[0].conidx = conidx; +} + +/** + \brief Register Mesh Provisioning Client instance + + Function registers new Mesh Provisioning Client instance. + + \param [in] cb client application callbacks + + \return None + +*/ +void mesh_prov_client_init(mesh_prov_client_cb* cb) +{ + /* Register the upper layer provided Provisioning Client Callbacks */ + if (NULL != cb) + { + prov_cli_cb = cb; + } +} + +/** + \brief Register Mesh Proxy Client instance + + Function registers new Mesh Proxy Client instance. + + \param [in] cb client application callbacks + + \return None + +*/ +void mesh_proxy_client_init(mesh_proxy_client_cb* cb) +{ + /* Register the upper layer provided Provisioning Client Callbacks */ + if (NULL != cb) + { + proxy_cli_cb = cb; + } +} + +API_RESULT mesh_client_discover_services +( + uint16_t conidx, + uint8_t serv_mode +) +{ + uint8_t svc_uuid[2]; + bStatus_t ret; + + if (BLEBRR_GATT_PROV_MODE == serv_mode) + { + /* UUID is Provisioning Service */ + svc_uuid[0] = (uint8_t)(UUID_MESH_PROVISIONING_SERVICE); + svc_uuid[1] = (uint8_t)(UUID_MESH_PROVISIONING_SERVICE >> 8); + /* EM_mem_copy(svc_uuid, MESH_PROV_SERVICE_UUID128, 16); */ + mesh_client_curr_dis_uuid = UUID_MESH_PROVISIONING_SERVICE; + } + else + { + /* UUID is Proxy Service */ + svc_uuid[0] = (uint8_t)(UUID_MESH_PROXY_SERVICE); + svc_uuid[1] = (uint8_t)(UUID_MESH_PROXY_SERVICE >> 8); + /* EM_mem_copy(svc_uuid, MESH_PROXY_SERVICE_UUID128, 16); */ + mesh_client_curr_dis_uuid = UUID_MESH_PROVISIONING_SERVICE; + } + + /* Discover service by UUID */ + ret = GATT_DiscPrimaryServiceByUUID + ( + conidx, + svc_uuid, + ATT_BT_UUID_SIZE, + bleMesh_TaskID + ); + MESH_CLIENT_TRC( + "Discovery Primiary Service UUID 0x%04X " + "returned with retval 0x%04X\r\n", + mesh_client_curr_dis_uuid, ret); + return (0 == ret) ? API_SUCCESS : API_FAILURE; +} + +/* ---------------------------------------------------------------------------- + Function : void mesh_client_send_wwr(uint8_t conidx, uint8_t *value, + uint16_t handle, uint8_t offset, + uint16_t length, uint8_t type) + ---------------------------------------------------------------------------- + Description : Send a write command or request to the client device + Inputs : - conidx - Connection index + - value - Pointer to value + - handle - Attribute handle + - length - Length of value + - type - Type of write message + Outputs : None + Assumptions : None + ------------------------------------------------------------------------- */ +void mesh_client_send_wwr +( + uint16_t conidx, + uint8_t* value, + uint16_t length, + uint8_t serv_pref +) +{ + attWriteReq_t req; + bStatus_t ret; + /* Assign the Handle Based on the Service Preference for Write */ + req.handle = (BLEBRR_GATT_PROV_MODE == serv_pref) ? \ + mesh_cli_env[0].prov_data_in_hdl : \ + mesh_cli_env[0].proxy_data_in_hdl; + req.len = length; + req.sig = 0x00; + req.cmd = 0x01; /* Write witout response */ + osal_memcpy(req.value, value, length); + ret = GATT_WriteNoRsp(conidx, &req); + MESH_CLIENT_TRC( + "Writing data : len 0x%04X : handle 0x%02X : ret 0x%04X\n", + req.len, req.handle, ret); + return; +} + +/* ---------------------------------------------------------------------------- + Function : void mesh_client_config_ntf + ( + uint16_t conidx, + uint8_t serv_pref, + uint8_t flag + ) + ---------------------------------------------------------------------------- + Description : Send a write command or request to the client device + Inputs : - conidx - Connection index + - serv_pref - Provisioning or Proxy Service + - flag - enable or disable + Outputs : None + Assumptions : None + ------------------------------------------------------------------------- */ +API_RESULT mesh_client_config_ntf +( + uint16_t conidx, + uint8_t serv_pref, + uint8_t flag +) +{ + attWriteReq_t req; + bStatus_t ret; + /* Assign the Handle Based on the Service Preference for Write */ + /** + Increment the Handle by 1 as the CCCD is present in the handle next to + the Value handle + */ + req.handle = (BLEBRR_GATT_PROV_MODE == serv_pref) ? \ + mesh_cli_env[0].prov_data_out_cccd_hdl : \ + mesh_cli_env[0].proxy_data_out_cccd_hdl; + req.len = 0x02; + req.sig = 0x00; + req.cmd = 0x00; + req.value[0] = (true == flag) ? 0x01 : 0x00; + req.value[1] = 0x00; + /* Store CCCD Mode and State in global */ + mesh_cli_env[0].curr_notif_state = flag; + mesh_cli_env[0].curr_notif_mode = (BLEBRR_GATT_PROV_MODE == serv_pref) ? \ + BLEBRR_GATT_PROV_MODE : \ + BLEBRR_GATT_PROXY_MODE; + ret = GATT_WriteCharValue(mesh_cli_env[0].conidx, &req, bleMesh_TaskID); + MESH_CLIENT_TRC + ("Writing %d to CCCD 0x%04X for Mode 0x%02X\n", + flag, req.handle, serv_pref); + return (0 == ret) ? API_SUCCESS : API_FAILURE; +} + +void mesh_client_process_gattMsg +( + gattMsgEvent_t* pMsg, + uint8_t t_id +) +{ + bStatus_t ret; + uint16_t serv_start_hndl, serv_end_hndl; + MESH_CLIENT_TRC("Processing GATT Messages:\n"); + MESH_CLIENT_TRC("pMsg->method: 0x%X\n",pMsg->method); + MESH_CLIENT_TRC("pMsg->hdr.status: 0x%X\n",pMsg->hdr.status); + /* Cache the Task ID */ + bleMesh_TaskID = t_id; + + /* Process the GATT server message */ + switch ( pMsg->method ) + { + case ATT_EXCHANGE_MTU_RSP: + break; + + case ATT_FIND_BY_TYPE_VALUE_RSP: + { + if (bleProcedureComplete == pMsg->hdr.status) + { + if (UUID_MESH_PROVISIONING_SERVICE == mesh_client_curr_dis_uuid) + { + serv_start_hndl = mesh_cli_env[0].prov_start_hdl; + serv_end_hndl = mesh_cli_env[0].prov_end_hdl; + } + else if (UUID_MESH_PROXY_SERVICE == mesh_client_curr_dis_uuid) + { + serv_start_hndl = mesh_cli_env[0].proxy_start_hdl; + serv_end_hndl = mesh_cli_env[0].proxy_end_hdl; + } + else + { + MESH_CLIENT_TRC( "Mesh Services not Present\r\n"); + } + + /* Start Charactertistic Discovery */ + ret = GATT_DiscAllChars + ( + mesh_cli_env[0].conidx, + serv_start_hndl, + serv_end_hndl, + bleMesh_TaskID + ); + MESH_CLIENT_TRC( + "Disc Characteristics btw Handles 0x%04X :: 0x%04X" + "returned with retval 0x%04X\r\n", + serv_start_hndl, serv_end_hndl, ret); + } + else + { + if (pMsg->msg.findByTypeValueRsp.numInfo > 0) + { + MESH_CLIENT_TRC( + "\nServices found :%d\n", + pMsg->msg.findByTypeValueRsp.numInfo); + MESH_CLIENT_TRC( + "Service Handles are 0x%04X :: 0x%04X", + pMsg->msg.findByTypeValueRsp.handlesInfo[0].handle, + pMsg->msg.findByTypeValueRsp.handlesInfo[0].grpEndHandle); + + if (mesh_client_curr_dis_uuid == UUID_MESH_PROVISIONING_SERVICE) + { + mesh_cli_env[0].prov_start_hdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].handle; + mesh_cli_env[0].prov_end_hdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].grpEndHandle; + MESH_CLIENT_TRC( + "\r\n Prov Service Start Handle is 0x%04X\r\n", + mesh_cli_env[0].prov_start_hdl); + MESH_CLIENT_TRC( + "\r\n Prov Service End Handle is 0x%04X\r\n", + mesh_cli_env[0].prov_end_hdl); + } + else if (mesh_client_curr_dis_uuid == UUID_MESH_PROXY_SERVICE) + { + mesh_cli_env[0].proxy_start_hdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].handle; + mesh_cli_env[0].proxy_end_hdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].grpEndHandle; + MESH_CLIENT_TRC( + "\r\nProxy Service Start Handle is 0x%04X\r\n", + mesh_cli_env[0].proxy_start_hdl); + MESH_CLIENT_TRC( + "\r\nProxy Service End Handle is 0x%04X\r\n", + mesh_cli_env[0].proxy_end_hdl); + } + } + else + { + MESH_CLIENT_TRC("\n No Services Found!\n"); + /** + TODO: Provide Discovery completion Callback. + */ + } + } + } + break; + + case ATT_READ_BY_TYPE_RSP: + { + if (bleProcedureComplete == pMsg->hdr.status) + { + uint16_t t_char_start_hndl; + + if (UUID_MESH_PROVISIONING_SERVICE == mesh_client_curr_dis_uuid) + { + t_char_start_hndl = mesh_cli_env[0].prov_data_out_hdl; + serv_end_hndl = mesh_cli_env[0].prov_end_hdl; + } + else if (UUID_MESH_PROXY_SERVICE == mesh_client_curr_dis_uuid) + { + t_char_start_hndl = mesh_cli_env[0].proxy_data_out_hdl; + serv_end_hndl = mesh_cli_env[0].proxy_end_hdl; + } + + ret = GATT_DiscAllCharDescs + ( + mesh_cli_env[0].conidx, + t_char_start_hndl, + serv_end_hndl, + bleMesh_TaskID + ); + MESH_CLIENT_TRC( + "Disc Char Desc btw Handles 0x%04X :: 0x%04X" + "returned with retval 0x%04X\r\n", + t_char_start_hndl, serv_end_hndl, ret); + } + else + { + // Pointer to the pair list data in the GATT response. + uint8_t* pCharPairList; + // Will store the start and end handles of the current pair. + uint16_t charStartHandle; + // Stores to the UUID of the current pair. + uint16_t charUuid; + // Stores what pair the loop is currently processing. + uint8_t currentCharIndex; + // Set the pair pointer to the first pair. + pCharPairList = pMsg->msg.readByTypeRsp.dataList; + + // Iterate through all three pairs found. + for(currentCharIndex = 0; currentCharIndex < pMsg->msg.readByTypeRsp.numPairs ; currentCharIndex++) + { + /* uint16_t* p_chars_hdl = pservie->chars_hdl; */ + // Extract the starting handle, ending handle, and UUID of the current characteristic. + charStartHandle = BUILD_UINT16(pCharPairList[3], pCharPairList[4]); + charUuid = BUILD_UINT16(pCharPairList[5], pCharPairList[6]); + MESH_CLIENT_TRC( + "Chars found handle is %d, uuid is %x\n", + charStartHandle, charUuid); + + switch (charUuid) + { + /* "Mesh Provisioning Data IN" */ + case UUID_MESH_PROVISIONING_DATA_IN: + mesh_cli_env[0].prov_data_in_hdl = charStartHandle; + break; + + /* "Mesh Provisioning Data OUT" */ + case UUID_MESH_PROVISIONING_DATA_OUT: + mesh_cli_env[0].prov_data_out_hdl = charStartHandle; + mesh_cli_env[0].prov_data_out_cccd_hdl = charStartHandle + 1; + break; + + /* "Mesh Proxy Data IN" */ + case UUID_MESH_PROXY_DATA_IN: + mesh_cli_env[0].proxy_data_in_hdl = charStartHandle; + break; + + /* "Mesh Proxy Data OUT" */ + case UUID_MESH_PROXY_DATA_OUT: + mesh_cli_env[0].proxy_data_out_hdl = charStartHandle; + mesh_cli_env[0].proxy_data_out_cccd_hdl = charStartHandle + 1; + break; + } + + // Increment the pair pointer to the next pair. + pCharPairList += 5 + 2; + } + } + } + break; + + case ATT_FIND_INFO_RSP: + { + if (bleProcedureComplete == pMsg->hdr.status) + { + /** + TODO: Provide Discovery completion Callback. + */ + } + else + { + if ( (pMsg->msg.findInfoRsp.numInfo > 0) && + (pMsg->msg.findInfoRsp.format == ATT_HANDLE_BT_UUID_TYPE) ) + { + // This will keep track of the current pair being processed. + uint8_t currentPair; + + // Iterate through the pair list. + for(currentPair = 0; currentPair < pMsg->msg.findInfoRsp.numInfo; currentPair++) + { + // Check if the pair is a CCCD. + uint16_t uuid = BUILD_UINT16(pMsg->msg.findInfoRsp.info.btPair[currentPair].uuid[0], pMsg->msg.findInfoRsp.info.btPair[currentPair].uuid[1]); + + if (uuid == GATT_CLIENT_CHAR_CFG_UUID) + { + MESH_CLIENT_TRC( + "CCCD is found at handle 0x%X for Mode %d\n", + pMsg->msg.findInfoRsp.info.btPair[currentPair].handle, blebrr_gatt_mode_get()); + + if (BLEBRR_GATT_PROV_MODE == blebrr_gatt_mode_get()) + { + mesh_cli_env[0].prov_data_out_cccd_hdl = pMsg->msg.findInfoRsp.info.btPair[currentPair].handle; + } + else + { + mesh_cli_env[0].proxy_data_out_cccd_hdl = pMsg->msg.findInfoRsp.info.btPair[currentPair].handle; + } + } + } + } + } + } + break; + + case ATT_HANDLE_VALUE_NOTI: + { + uint16_t notifHandle = pMsg->msg.handleValueNoti.handle; + + if (pMsg->msg.handleValueNoti.len > 0) + { + /* Check the Attribute Handle: + - If Provisioning Data Out Handle: then call the Prov Callback + - If Proxy Data Out Handle: the ncall the Proxy Callback + */ + if (mesh_cli_env[0].prov_data_out_hdl == notifHandle) + { + if (NULL != prov_cli_cb) + { + prov_cli_cb->mesh_prov_data_out_notif + ( + mesh_cli_env[0].conidx, + pMsg->msg.handleValueNoti.len, + pMsg->msg.handleValueNoti.value + ); + } + } + else if (mesh_cli_env[0].proxy_data_out_hdl == notifHandle) + { + if (NULL != proxy_cli_cb) + { + proxy_cli_cb->mesh_proxy_data_out_notif + ( + mesh_cli_env[0].conidx, + pMsg->msg.handleValueNoti.len, + pMsg->msg.handleValueNoti.value + ); + } + } + } + } + break; + + case ATT_WRITE_RSP: + { + if (BLEBRR_GATT_PROV_MODE == mesh_cli_env[0].curr_notif_mode) + { + /* Call the Prov CCCD ntf complete Callback */ + if (NULL != prov_cli_cb) + { + prov_cli_cb->mesh_prov_ntf_status + ( + mesh_cli_env[0].conidx, + mesh_cli_env[0].curr_notif_state, + 0x00 + ); + } + } + else if (BLEBRR_GATT_PROXY_MODE == mesh_cli_env[0].curr_notif_mode) + { + /* Call the Proxy CCCD ntf complete Callback */ + if (NULL != proxy_cli_cb) + { + proxy_cli_cb->mesh_proxy_ntf_status + ( + mesh_cli_env[0].conidx, + mesh_cli_env[0].curr_notif_state, + 0x00 + ); + } + } + else + { + /* DO Nothing ! */ + } + } + break; + + case ATT_ERROR_RSP: + { + attErrorRsp_t* perr = &(pMsg->msg.errorRsp); + MESH_CLIENT_TRC( + "\nATT_ERROR_RSP 0x%x, 0x%x, 0x%x\n", + perr->errCode, perr->handle, perr->reqOpcode); + } + break; + + default: + break; + } + + (void)ret; +} + diff --git a/src/components/ethermind/platforms/mesh/mesh_clients.h b/src/components/ethermind/platforms/mesh/mesh_clients.h new file mode 100644 index 0000000..cc8ae67 --- /dev/null +++ b/src/components/ethermind/platforms/mesh/mesh_clients.h @@ -0,0 +1,255 @@ + +/** + \file mesh_clients.h + + +*/ + +/* + Copyright (C) 2018. Mindtree Limited. + All rights reserved. +*/ + +#ifndef _MESH_CLIENTS_H +#define _MESH_CLIENTS_H + +/* --------------------------------------------- Header File Inclusion */ +#include "EM_os.h" +#include "blebrr.h" + +#include "gatt.h" +#include "gatt_uuid.h" + +#include "bleMesh.h" + +/* --------------------------------------------- Global Definitions */ + +/* Mesh GATT Bearer Related Service Assigned Numbers as arrays */ +#define MESH_PROV_SERVICE_UUID16 { 0x27, 0x18} +#define MESH_PROV_DATA_IN_UUID16 { 0xDB, 0x2A} +#define MESH_PROV_DATA_OUT_UUID16 { 0xDC, 0x2A} + +#define MESH_PROXY_SERVICE_UUID16 { 0x28, 0x18} +#define MESH_PROXY_DATA_IN_UUID16 { 0xDD, 0x2A} +#define MESH_PROXY_DATA_OUT_UUID16 { 0xDE, 0x2A} + +/* Mesh GATT Bearer Related Service Assigned Numbers */ +/* Use the UUID from Mesh Asigned numbers headers */ +#define UUID_MESH_PROVISIONING_SERVICE (0x1827) +#define UUID_MESH_PROVISIONING_DATA_IN (0x2ADB) +#define UUID_MESH_PROVISIONING_DATA_OUT (0x2ADC) +/* Use the UUID from Mesh Asigned numbers headers */ +#define UUID_MESH_PROXY_SERVICE (0x1828) +#define UUID_MESH_PROXY_DATA_IN (0x2ADD) +#define UUID_MESH_PROXY_DATA_OUT (0x2ADE) + + +/* --------------------------------------------- Structures/Data Types */ +/** + \brief Mesh Provisioning Data Out notification callback + + Called when Client received Mesh Provisioning data out + notification from server. + + \param [in] client client instance + \param [in] length length of data + \param [in] value mesh prov data out value from Server + +*/ +typedef void (* mesh_prov_client_data_out_cb) +( + uint16_t conidx, + uint16_t length, + uint8_t* value +); +/** + \brief Set Notifications Enable Disable Callback + + \param [in] conidx connection index + \param [in] flag Enable/Disable State Flag + \param [in] status operation status + +*/ +typedef void (* mesh_prov_client_data_out_ntf_status_cb) +( + uint16_t conidx, + uint8_t flag, + uint8_t status +); + +/** + \brief MEsh Provisioning Cliet application callbacks + +*/ +typedef struct +{ + /** Mesh Procv Client Data Out callback */ + mesh_prov_client_data_out_cb mesh_prov_data_out_notif; + + /** + Called once client enabled/disabled event + characteristic notifications/indications + */ + mesh_prov_client_data_out_ntf_status_cb mesh_prov_ntf_status; + +} mesh_prov_client_cb; + +/** + \brief Mesh Provisioning Data Out notification callback + + Called when Client received Mesh Provisioning data out + notification from server. + + \param [in] client client instance + \param [in] length length of data + \param [in] value mesh prov data out value from Server + +*/ +typedef void (* mesh_proxy_client_data_out_cb) +( + uint16_t conidx, + uint16_t length, + uint8_t* value +); +/** + \brief Set Notifications Enable Disable Callback + + \param [in] conidx connection index + \param [in] flag Enable/Disable State Flag + \param [in] status operation status + +*/ +typedef void (* mesh_proxy_client_data_out_ntf_status_cb) +( + uint16_t conidx, + uint8_t flag, + uint8_t status +); + +/** + \brief Mesh Provisioning Cliet application callbacks + +*/ +typedef struct +{ + /** Mesh Procv Client Data Out callback */ + mesh_proxy_client_data_out_cb mesh_proxy_data_out_notif; + + /** + Called once client enabled/disabled event + characteristic notifications/indications + */ + mesh_proxy_client_data_out_ntf_status_cb mesh_proxy_ntf_status; + +} mesh_proxy_client_cb; + +struct mesh_cli_env_tag +{ + /* Connection index */ + uint16_t conidx; + + /* Provisioning Service Related Handles */ + uint16_t prov_start_hdl; + uint16_t prov_end_hdl; + uint16_t prov_data_in_hdl; + uint16_t prov_data_out_hdl; + uint16_t prov_data_out_cccd_hdl; + + /* Proxy Service Related Handles */ + uint16_t proxy_start_hdl; + uint16_t proxy_end_hdl; + uint16_t proxy_data_in_hdl; + uint16_t proxy_data_out_hdl; + uint16_t proxy_data_out_cccd_hdl; + + /* Current Notification Mode and State */ + uint16_t curr_notif_state; + uint8_t curr_notif_mode; + +}; + +extern struct mesh_cli_env_tag mesh_cli_env[]; + +/* --------------------------------------------- Macros */ +#define mesh_prov_client_discover_serv(cidx) \ + mesh_client_discover_services((BLEBRR_GATT_PROV_MODE), (cidx)); + +#define mesh_proxy_client_discover_serv(cidx) \ + mesh_client_discover_services((BLEBRR_GATT_PROXY_MODE), (cidx)); + +#define mesh_prov_client_data_in_write(cidx, val, len) \ + mesh_client_send_wwr((cidx), (val), (len), BLEBRR_GATT_PROV_MODE); + +#define mesh_proxy_client_data_in_write(cidx, val, len) \ + mesh_client_send_wwr((cidx), (val), (len), BLEBRR_GATT_PROXY_MODE); + +#define mesh_prov_client_enable_data_out(cidx) \ + mesh_client_config_ntf((cidx), BLEBRR_GATT_PROV_MODE, (true)); + +#define mesh_proxy_client_enable_data_out(cidx) \ + mesh_client_config_ntf((cidx), BLEBRR_GATT_PROXY_MODE, (true)); + +#define mesh_prov_client_disable_data_out(cidx) \ + mesh_client_config_ntf((cidx), BLEBRR_GATT_PROV_MODE, (false)); + +#define mesh_proxy_client_disable_data_out(cidx) \ + mesh_client_config_ntf((cidx), BLEBRR_GATT_PROXY_MODE, (false)); + +/* --------------------------------------------- Internal Functions */ +void mesh_client_process_gattMsg +( + gattMsgEvent_t* pMsg, + uint8_t t_id +); + +/* --------------------------------------------- API Declarations */ +/** + \brief Register Mesh Provisioning Client instance + + Function registers new Mesh Provisioning Client instance. + + \param [in] cb client application callbacks + + \return None + +*/ +void mesh_prov_client_init +( + mesh_prov_client_cb* cb +); + +/** + \brief Register Mesh Proxy Client instance + + Function registers new Mesh Proxy Client instance. + + \param [in] cb client application callbacks + + \return None + +*/ +void mesh_proxy_client_init +( + mesh_proxy_client_cb* cb +); + +void mesh_client_send_wwr +( + uint16_t conidx, + uint8_t* value, + uint16_t length, + uint8_t serv_pref +); + +API_RESULT mesh_client_config_ntf +( + uint16_t conidx, + uint8_t serv_pref, + uint8_t flag +); + +void mesh_client_init(void); +API_RESULT mesh_client_discover_services(uint16_t conidx, uint8_t serv_mode); +void mesh_client_update_conidx (uint16_t conidx); + +#endif /* _MESH_CLIENTS_H */ diff --git a/src/components/ethermind/platforms/mesh/mesh_services.c b/src/components/ethermind/platforms/mesh/mesh_services.c new file mode 100644 index 0000000..0977733 --- /dev/null +++ b/src/components/ethermind/platforms/mesh/mesh_services.c @@ -0,0 +1,772 @@ + +/** + \file mesh_services.c + + Generic Module to handle both + - Mesh Provisioning Service :: 0x1827 + - Mesh Proxy Service :: 0x1828 +*/ + +/* + Copyright (C) 2018. Mindtree Limited. + All rights reserved. +*/ + +#include "mesh_services.h" + +/********************************************************************* + GLOBAL VARIABLES +*/ +/* Mesh Prov Service UUID: 0x1827 */ +CONST uint8 mesh_prov_UUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(MESH_PROV_SERVICE_UUID), HI_UINT16(MESH_PROV_SERVICE_UUID) +}; + +/* Mesh Prov Data IN UUID: 0x2ADB */ +CONST uint8 mesh_prov_data_in_UUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(MESH_PROV_DATA_IN_UUID), HI_UINT16(MESH_PROV_DATA_IN_UUID) +}; + +/* Mesh Prov Data OUT UUID: 0x2ADC */ +CONST uint8 mesh_prov_data_out_UUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(MESH_PROV_DATA_OUT_UUID), HI_UINT16(MESH_PROV_DATA_OUT_UUID) +}; + +/* Mesh Proxy Service UUID: 0x1828 */ +CONST uint8 mesh_proxy_UUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(MESH_PROXY_SERVICE_UUID), HI_UINT16(MESH_PROXY_SERVICE_UUID) +}; + +/* Mesh Proxy Data IN UUID: 0x2ADD */ +CONST uint8 mesh_proxy_data_in_UUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(MESH_PROXY_DATA_IN_UUID), HI_UINT16(MESH_PROXY_DATA_IN_UUID) +}; + +/* Mesh Proxy Data OUT UUID: 0x2ADE */ +CONST uint8 mesh_proxy_data_out_UUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(MESH_PROXY_DATA_OUT_UUID), HI_UINT16(MESH_PROXY_DATA_OUT_UUID) +}; + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ +/* Mesh Provisioning Service Related Callbacks */ +static mesh_prov_cb* prov_cb; + +/* Mesh Proxy Service Related Callbacks */ +static mesh_proxy_cb* proxy_cb; + +/********************************************************************* + Profile Attributes - variables +*/ + +/* Mesh Provisioning Service */ +static CONST gattAttrType_t mesh_prov_service = +{ATT_BT_UUID_SIZE, mesh_prov_UUID}; + +/* Mesh Prov Data IN Properties */ +static uint8 mesh_prov_data_in_props = GATT_PROP_WRITE_NO_RSP; + +/* Mesh Prov Data IN Value */ +static uint8 mesh_prov_data_in_val[20]; + +/* Mesh Prov Data OUT Properties */ +static uint8 mesh_prov_data_out_props = GATT_PROP_NOTIFY; + +/* Mesh Prov Data OUT Value */ +static uint8 mesh_prov_data_out_val[20]; + +/* Mesh Prov Data OUT CCCD value array */ +static gattCharCfg_t mesh_prov_data_out_cccd[GATT_MAX_NUM_CONN]; + +/* Mesh Proxy Service */ +static CONST gattAttrType_t mesh_proxy_service = +{ATT_BT_UUID_SIZE, mesh_proxy_UUID}; + +/* Mesh Proxy Data IN Properties */ +static uint8 mesh_proxy_data_in_props = GATT_PROP_WRITE_NO_RSP; + +/* Mesh Proxy Data IN Value */ +static uint8 mesh_proxy_data_in_val[20]; + +/* Mesh Proxy Data OUT Properties */ +static uint8 mesh_proxy_data_out_props = GATT_PROP_NOTIFY; + +/* Mesh Proxy Data OUT Value */ +static uint8 mesh_proxy_data_out_val[20]; + +/* Mesh Proxy Data OUT CCCD value array */ +static gattCharCfg_t mesh_proxy_data_out_cccd[GATT_MAX_NUM_CONN]; + +/********************************************************************* + Profile Attributes - Table +*/ +/* Mesh Provisioning Service Attribute Table */ +static gattAttribute_t mesh_prov_attr_tbl[MESH_PROV_IDX_NB] = +{ + /* Mesh Provisioning Service Declaration */ + { + { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */ + GATT_PERMIT_READ, /* permissions */ + 0, /* handle */ + (uint8*)& mesh_prov_service /* pValue */ + }, + + /* Mesh Prov Data IN Characteristic Declaration */ + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &mesh_prov_data_in_props + }, + + /* Mesh Prov Data IN Characteristic Value */ + { + { ATT_BT_UUID_SIZE, mesh_prov_data_in_UUID }, + GATT_PERMIT_WRITE, + 0, + &mesh_prov_data_in_val[0] + }, + + /* Mesh Prov Data OUT Characteristic Declaration */ + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &mesh_prov_data_out_props + }, + + /* Mesh Prov Data OUT Characteristic Value */ + { + { ATT_BT_UUID_SIZE, mesh_prov_data_out_UUID }, + 0, + 0, + &mesh_prov_data_out_val[0] + }, + + /* Mesh Prov Data OUT CCCD */ + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8*)& mesh_prov_data_out_cccd + }, +}; + +/* Mesh Proxy Service Attribute Table */ +static gattAttribute_t mesh_proxy_attr_tbl[MESH_PROXY_IDX_NB] = +{ + /* Mesh Proxy Service Declaration */ + { + { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */ + GATT_PERMIT_READ, /* permissions */ + 0, /* handle */ + (uint8*)& mesh_proxy_service /* pValue */ + }, + + /* Mesh Proxy Data IN Characteristic Declaration */ + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &mesh_proxy_data_in_props + }, + + /* Mesh Proxy Data IN Characteristic Value */ + { + { ATT_BT_UUID_SIZE, mesh_proxy_data_in_UUID }, + GATT_PERMIT_WRITE, + 0, + &mesh_proxy_data_in_val[0] + }, + + /* Mesh Proxy Data OUT Characteristic Declaration */ + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &mesh_proxy_data_out_props + }, + + /* Mesh Proxy Data OUT Characteristic Value */ + { + { ATT_BT_UUID_SIZE, mesh_proxy_data_out_UUID }, + 0, + 0, + &mesh_proxy_data_out_val[0] + }, + + /* Mesh Proxy Data OUT CCCD */ + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8*)& mesh_proxy_data_out_cccd + }, +}; + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static bStatus_t mesh_prov_write_cb +( + uint16 connHandle, + gattAttribute_t* pAttr, + uint8* pValue, + uint16 len, + uint16 offset +); + +static bStatus_t mesh_proxy_write_cb +( + uint16 connHandle, + gattAttribute_t* pAttr, + uint8* pValue, + uint16 len, + uint16 offset +); + +static void mesh_prov_handle_conn +( + uint16 connHandle, + uint8 changeType +); + +static void mesh_proxy_handle_conn +( + uint16 connHandle, + uint8 changeType +); + +/********************************************************************* + PROFILE CALLBACKS +*/ +/* Mesh Provisioning Service Internal Callbacks */ +CONST gattServiceCBs_t mesh_prov_internal_cbs = +{ + NULL, // Read callback function pointer + mesh_prov_write_cb, // Write callback function pointer + NULL // Authorization callback function pointer +}; + +/* Mesh Proxy Service Internal Callbacks */ +CONST gattServiceCBs_t mesh_proxy_internal_cbs = +{ + NULL, // Read callback function pointer + mesh_proxy_write_cb, // Write callback function pointer + NULL // Authorization callback function pointer +}; + + +/* ---------------------------------------------------------------------------- + Function : bStatus_t mesh_prov_init(mesh_prov_cb *cb) + ---------------------------------------------------------------------------- + Description : Send request to add Mesh Provisioning Service[0x1827] + into the attribute database. + Defines the different access functions + .* (setter/getter commands to access the different + characteristic attributes). + Inputs : Pointer to mesh_prov_cb. + Outputs : bStatus_t : SUCCESS or failure reasons + Assumptions : None + ------------------------------------------------------------------------- */ +bStatus_t mesh_prov_init(mesh_prov_cb* cb) +{ + uint8 status = FAILURE; + /* Initialize Client Characteristic Configuration attributes */ + GATTServApp_InitCharCfg + ( + INVALID_CONNHANDLE, + mesh_prov_data_out_cccd + ); + /* Register with Link DB to receive link status change callback */ + VOID linkDB_Register(mesh_prov_handle_conn); + /* Register GATT attribute list and CBs with GATT Server App */ + status = GATTServApp_RegisterService + ( + mesh_prov_attr_tbl, + GATT_NUM_ATTRS(mesh_prov_attr_tbl), + &mesh_prov_internal_cbs + ); + /* Save the Callback Provided */ + prov_cb = cb; + return (status); +} + +/* ---------------------------------------------------------------------------- + Function : bStatus_t mesh_proxy_init(mesh_proxy_cb *cb) + ---------------------------------------------------------------------------- + Description : Send request to add Mesh Proxy Service[0x1828] + into the attribute database. + Defines the different access functions + .* (setter/getter commands to access the different + characteristic attributes). + Inputs : Pointer to mesh_proxy_cb. + Outputs : bStatus_t : SUCCESS or failure reasons + Assumptions : None + ------------------------------------------------------------------------- */ +bStatus_t mesh_proxy_init(mesh_proxy_cb* cb) +{ + uint8 status = FAILURE; + /* Initialize Client Characteristic Configuration attributes */ + GATTServApp_InitCharCfg + ( + INVALID_CONNHANDLE, + mesh_proxy_data_out_cccd + ); + /* Register with Link DB to receive link status change callback */ + VOID linkDB_Register(mesh_proxy_handle_conn); + /* Register GATT attribute list and CBs with GATT Server App */ + status = GATTServApp_RegisterService + ( + mesh_proxy_attr_tbl, + GATT_NUM_ATTRS(mesh_proxy_attr_tbl), + &mesh_proxy_internal_cbs + ); + /* Save the Callback Provided */ + proxy_cb = cb; + return (status); +} + +/* ---------------------------------------------------------------------------- + Function : bStatus_t mesh_prov_deinit(void) + ---------------------------------------------------------------------------- + Description : Send request to delete Mesh Provisioning Service[0x1827] + from the attribute database. + Inputs : None + Outputs : bStatus_t : SUCCESS or failure reasons + Assumptions : None + ------------------------------------------------------------------------- */ +bStatus_t mesh_prov_deinit(void) +{ + uint8 status = SUCCESS; + /* Reset the Callback Provided */ + prov_cb = NULL; + /** + Deregister Mesh Prov Service attribute list and + CBs from GATT Server Application + */ + status = GATTServApp_DeregisterService + ( + GATT_SERVICE_HANDLE(mesh_prov_attr_tbl), + NULL + ); + return ( status ); +} + +/* ---------------------------------------------------------------------------- + Function : bStatus_t mesh_proxy_deinit(void) + ---------------------------------------------------------------------------- + Description : Send request to delete Mesh Proxy Service[0x1828] + from the attribute database. + Inputs : None + Outputs : bStatus_t : SUCCESS or failure reasons + Assumptions : None + ------------------------------------------------------------------------- */ +bStatus_t mesh_proxy_deinit(void) +{ + uint8 status = SUCCESS; + /* Reset the Callback Provided */ + proxy_cb = NULL; + /** + Deregister Mesh Prov Service attribute list and + CBs from GATT Server Application + */ + status = GATTServApp_DeregisterService + ( + GATT_SERVICE_HANDLE(mesh_proxy_attr_tbl), + NULL + ); + return ( status ); +} + + +/* ---------------------------------------------------------------------------- + Function : bStatus_t mesh_prov_notify_data_out(uint16 conn_hndl, + uint8 attidx, uint8 *val, uint8 val_len) + ---------------------------------------------------------------------------- + Description : Send Mesh Provisiong Data Out notification to Peer + Inputs : - conn_hndl - connection index + - attidx - index to attributes in the service + - val - pointer to value + - val_len - length of value + Outputs : bStatus_t : SUCCESS or failure reasons + Assumptions : None + ------------------------------------------------------------------------- */ +bStatus_t mesh_prov_notify_data_out +( + uint16 conn_hndl, + uint8 attidx, + uint8* val, + uint8 val_len +) +{ + attHandleValueNoti_t mesh_prov_notif; + uint16 value = GATTServApp_ReadCharCfg + ( + conn_hndl, + mesh_prov_data_out_cccd + ); + /* NOTE: Currently the attidx is ignored */ + (void)attidx; + /* Assign the Mesh Prov Data Out Value Handle */ + mesh_prov_notif.handle =\ + mesh_prov_attr_tbl[MESH_PROV_DATA_OUT_VALUE_VAL].handle; + /* Copy the Value and Length */ + mesh_prov_notif.len = val_len; + osal_memcpy(mesh_prov_notif.value, val, val_len); + + /* If notifications enabled */ + if ( value & GATT_CLIENT_CFG_NOTIFY ) + { + /* Send the notification */ + return GATT_Notification( conn_hndl, &mesh_prov_notif, FALSE ); + } + + return bleIncorrectMode; +} + +/* ---------------------------------------------------------------------------- + Function : bStatus_t mesh_proxy_notify_data_out(uint16 conn_hndl, + uint8 attidx, uint8 *val, uint8 val_len) + ---------------------------------------------------------------------------- + Description : Send Mesh Proxy Data Out notification to Peer + Inputs : - conn_hndl - connection index + - attidx - index to attributes in the service + - val - pointer to value + - val_len - length of value + Outputs : bStatus_t : SUCCESS or failure reasons + Assumptions : None + ------------------------------------------------------------------------- */ +bStatus_t mesh_proxy_notify_data_out +( + uint16 conn_hndl, + uint8 attidx, + uint8* val, + uint8 val_len +) +{ + attHandleValueNoti_t mesh_proxy_notif; + uint16 value = GATTServApp_ReadCharCfg + ( + conn_hndl, + mesh_proxy_data_out_cccd + ); + /* NOTE: Currently the attidx is ignored */ + (void)attidx; + /* Assign the Mesh Prov Data Out Value Handle */ + mesh_proxy_notif.handle =\ + mesh_proxy_attr_tbl[MESH_PROV_DATA_OUT_VALUE_VAL].handle; + /* Copy the Value and Length */ + mesh_proxy_notif.len = val_len; + osal_memcpy(mesh_proxy_notif.value, val, val_len); + + /* If notifications enabled */ + if ( value & GATT_CLIENT_CFG_NOTIFY ) + { + /* Send the notification */ + return GATT_Notification( conn_hndl, &mesh_proxy_notif, FALSE ); + } + + return bleIncorrectMode; +} + +/* ---------------------------------------------------------------------------- + Function : bStatus_t mesh_prov_write_cb (uint16 connHandle, + gattAttribute_t * pAttr, uint8 * pValue, + uint8 len, uint16 offset) + ---------------------------------------------------------------------------- + Description : Validate attribute data prior to a write operation + Inputs : - connHandle - connection Handle + - pAttr - pointer to attribute + - pValue - pointer to data to be written + - len - length of data + - offset - offset of the first octet to be written + Outputs : Success or Failure + Assumptions : None + ------------------------------------------------------------------------- */ +static bStatus_t mesh_prov_write_cb +( + uint16 connHandle, + gattAttribute_t* pAttr, + uint8* pValue, + uint16 len, + uint16 offset +) +{ + bStatus_t status = SUCCESS; + + /* If attribute permissions require authorization to write, return error */ + if ( gattPermitAuthorWrite( pAttr->permissions ) ) + { + /* Insufficient authorization */ + return ( ATT_ERR_INSUFFICIENT_AUTHOR ); + } + + if ( pAttr->type.len == ATT_BT_UUID_SIZE ) + { + /* 16-bit UUID */ + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + switch (uuid) + { + case MESH_PROV_DATA_IN_UUID: + + /* Validate the value */ + /* Make sure it's not a blob oper */ + /* dbg_printf("\r\n MESH_PROV_DATA_IN WWR of length %d\r\n", len); */ + if ( offset != 0 ) + { + status = ATT_ERR_ATTR_NOT_LONG; + } + + /* Write the value */ + if (SUCCESS == status) + { + /* TODO: Check if this is needed */ + /* len = (len <= MESH_PROV_DATA_IN_MAX_LENGTH) ?\ + len : MESH_PROV_DATA_IN_MAX_LENGTH; */ + + /* Notify Data IN Write Callback */ + /* Invoke Data IN Callback */ + if (NULL != prov_cb) + { + prov_cb->prov_data_in_cb + ( + connHandle, + offset, + len, + pValue + ); + } + } + + break; + + case GATT_CLIENT_CHAR_CFG_UUID: + /* dbg_printf("\r\n MESH_PROV_DATA_OUT CCCD Write for %d Attr Handle of length %d\r\n", pAttr->handle, len); */ + status = GATTServApp_ProcessCCCWriteReq + ( + connHandle, + pAttr, + pValue, + len, + offset, + GATT_CLIENT_CFG_NOTIFY + ); + + if ( status == SUCCESS ) + { + uint16 t_cccd_val = BUILD_UINT16( pValue[0], pValue[1] ); + t_cccd_val = (GATT_CLIENT_CFG_NOTIFY == t_cccd_val) ?\ + TRUE : FALSE; + + /* Invoke CCCD Update Callback */ + if (NULL != prov_cb) + { + prov_cb->prov_data_out_ccd_cb + ( + connHandle, + t_cccd_val + ); + } + } + + break; + + default: + status = ATT_ERR_ATTR_NOT_FOUND; + break; + } + } + else + { + // 128-bit UUID + status = ATT_ERR_INVALID_HANDLE; + } + + return ( status ); +} + +/* ---------------------------------------------------------------------------- + Function : bStatus_t mesh_proxy_write_cb (uint16 connHandle, + gattAttribute_t * pAttr, uint8 * pValue, + uint8 len, uint16 offset) + ---------------------------------------------------------------------------- + Description : Validate attribute data prior to a write operation + Inputs : - connHandle - connection Handle + - pAttr - pointer to attribute + - pValue - pointer to data to be written + - len - length of data + - offset - offset of the first octet to be written + Outputs : Success or Failure + Assumptions : None + ------------------------------------------------------------------------- */ +static bStatus_t mesh_proxy_write_cb +( + uint16 connHandle, + gattAttribute_t* pAttr, + uint8* pValue, + uint16 len, + uint16 offset +) +{ + bStatus_t status = SUCCESS; + + /* If attribute permissions require authorization to write, return error */ + if ( gattPermitAuthorWrite( pAttr->permissions ) ) + { + /* Insufficient authorization */ + return ( ATT_ERR_INSUFFICIENT_AUTHOR ); + } + + if ( pAttr->type.len == ATT_BT_UUID_SIZE ) + { + /* 16-bit UUID */ + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + switch (uuid) + { + case MESH_PROXY_DATA_IN_UUID: + + /* Validate the value */ + /* Make sure it's not a blob oper */ + /* dbg_printf("\r\n MESH_PROXY_DATA_IN WWR of length %d\r\n", len); */ + if ( offset != 0 ) + { + status = ATT_ERR_ATTR_NOT_LONG; + } + + /* Write the value */ + if (SUCCESS == status) + { + /* TODO: Check if this is needed */ + /* len = (len <= MESH_PROXY_DATA_IN_MAX_LENGTH) ?\ + len : MESH_PROXY_DATA_IN_MAX_LENGTH; */ + + /* Notify Data IN Write Callback */ + /* Invoke Data IN Callback */ + if (NULL != proxy_cb) + { + proxy_cb->proxy_data_in_cb + ( + connHandle, + offset, + len, + pValue + ); + } + } + + break; + + case GATT_CLIENT_CHAR_CFG_UUID: + /* dbg_printf("\r\n MESH_PROXY_DATA_OUT CCCD Write for %d Attr Handle of length %d\r\n", pAttr->handle, len); */ + status = GATTServApp_ProcessCCCWriteReq + ( + connHandle, + pAttr, + pValue, + len, + offset, + GATT_CLIENT_CFG_NOTIFY + ); + + if ( status == SUCCESS ) + { + uint16 t_cccd_val = BUILD_UINT16( pValue[0], pValue[1] ); + t_cccd_val = (GATT_CLIENT_CFG_NOTIFY == t_cccd_val) ?\ + TRUE : FALSE; + + /* Invoke CCCD Update Callback */ + if (NULL != proxy_cb) + { + proxy_cb->proxy_data_out_ccd_cb + ( + connHandle, + t_cccd_val + ); + } + } + + break; + + default: + status = ATT_ERR_ATTR_NOT_FOUND; + break; + } + } + else + { + // 128-bit UUID + status = ATT_ERR_INVALID_HANDLE; + } + + return ( status ); +} + +/* ---------------------------------------------------------------------------- + Function : void mesh_prov_handle_conn(uint16 connHandle, + uint8 changeType) + ---------------------------------------------------------------------------- + Description : Callback to Handle Mesh Prov Connection event + Inputs : - connHandle - connection Handle + - changeType - type of change + Outputs : None + Assumptions : None + ------------------------------------------------------------------------- */ +static void mesh_prov_handle_conn( uint16 connHandle, uint8 changeType ) +{ + // Make sure this is not loopback connection + if ( connHandle != LOOPBACK_CONNHANDLE ) + { + // Reset Client Char Config if connection has dropped + if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) || + ( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && + ( !linkDB_Up( connHandle ) ) ) ) + { + GATTServApp_InitCharCfg( connHandle, mesh_prov_data_out_cccd ); + } + } +} + +/* ---------------------------------------------------------------------------- + Function : void mesh_proxy_handle_conn(uint16 connHandle, + uint8 changeType) + ---------------------------------------------------------------------------- + Description : Callback to Handle Mesh Proxy Connection event + Inputs : - connHandle - connection Handle + - changeType - type of change + Outputs : None + Assumptions : None + ------------------------------------------------------------------------- */ +static void mesh_proxy_handle_conn( uint16 connHandle, uint8 changeType ) +{ + // Make sure this is not loopback connection + if ( connHandle != LOOPBACK_CONNHANDLE ) + { + // Reset Client Char Config if connection has dropped + if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) || + ( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && + ( !linkDB_Up( connHandle ) ) ) ) + { + GATTServApp_InitCharCfg( connHandle, mesh_proxy_data_out_cccd ); + } + } +} + + diff --git a/src/components/ethermind/platforms/mesh/mesh_services.h b/src/components/ethermind/platforms/mesh/mesh_services.h new file mode 100644 index 0000000..20f2932 --- /dev/null +++ b/src/components/ethermind/platforms/mesh/mesh_services.h @@ -0,0 +1,258 @@ + +/** + \file mesh_services.h + + Generic Module to handle both + - Mesh Provisioning Service :: 0x1827 + - Mesh Proxy Service :: 0x1828 +*/ + +/* + Copyright (C) 2018. Mindtree Limited. + All rights reserved. +*/ +#ifndef _MESH_SERVICES_H +#define _MESH_SERVICES_H + +/* ---------------------------------------------------------------------------- + If building with a C++ compiler, make all of the definitions in this header + have a C binding. + ------------------------------------------------------------------------- */ +#ifdef __cplusplus +extern "C" +{ +#endif + +/* ---------------------------------------------------------------------------- + Include files + --------------------------------------------------------------------------*/ +/* Mesh OS Specific Inclusion */ +#include "EM_os.h" + +/* BLE Stack Specific Inclusion */ +#include "bcomdef.h" +#include "OSAL.h" +#include "linkdb.h" +#include "att.h" +#include "gatt.h" +#include "gatt_uuid.h" +#include "gattservapp.h" +#include "gapbondmgr.h" + +/* ---------------------------------------------------------------------------- + Defines + --------------------------------------------------------------------------*/ + +/* Mesh GATT Bearer Related Service Assigned Numbers */ +#define MESH_PROV_SERVICE_UUID128 { 0x27, 0x18, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00 } +#define MESH_PROXY_SERVICE_UUID128 { 0x28, 0x18, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00 } + +#define MESH_PROV_DATA_IN_UUID128 { 0xDB, 0x2A, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00 } +#define MESH_PROV_DATA_OUT_UUID128 { 0xDC, 0x2A, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00 } +#define MESH_PROXY_DATA_IN_UUID128 { 0xDD, 0x2A, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00 } +#define MESH_PROXY_DATA_OUT_UUID128 { 0xDE, 0x2A, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00 } + +/* 16 Bit UUID Defines */ +#define MESH_PROV_SERVICE_UUID 0x1827 +#define MESH_PROXY_SERVICE_UUID 0x1828 + +#define MESH_PROV_DATA_IN_UUID 0x2ADB +#define MESH_PROV_DATA_OUT_UUID 0x2ADC +#define MESH_PROXY_DATA_IN_UUID 0x2ADD +#define MESH_PROXY_DATA_OUT_UUID 0x2ADE + +/* Mesh GATT Bearer Serivce Characterisitic Length Definitions */ +#define MESH_PROV_DATA_IN_MAX_LENGTH (ATT_MTU_SIZE - 3) +#define MESH_PROV_DATA_OUT_MAX_LENGTH (ATT_MTU_SIZE - 3) +#define MESH_PROXY_DATA_IN_MAX_LENGTH (ATT_MTU_SIZE - 3) +#define MESH_PROXY_DATA_OUT_MAX_LENGTH (ATT_MTU_SIZE - 3) + +enum mesh_prov_idx_att +{ + /* Mesh Provisioning Service Primary Service Declaration */ + MESH_PROV_SERV_DECL = 0x00, + + /* Mesh Provisioning Data IN Characteristic */ + MESH_PROV_DATA_IN_VALUE_CHAR, + MESH_PROV_DATA_IN_VALUE_VAL, + + /* Mesh Provisioning Data OUT Characteristic */ + MESH_PROV_DATA_OUT_VALUE_CHAR, + MESH_PROV_DATA_OUT_VALUE_VAL, + MESH_PROV_DATA_OUT_VALUE_CCC, + + /* Max number of characteristics */ + MESH_PROV_IDX_NB, +}; + +enum mesh_proxy_idx_att +{ + /* Mesh Proxy Service Primary Service Declaration */ + MESH_PROXY_SERV_DECL = 0x00, + + /* Mesh Proxy Data IN Characteristic */ + MESH_PROXY_DATA_IN_VALUE_CHAR, + MESH_PROXY_DATA_IN_VALUE_VAL, + + /* Mesh Provisioning Data OUT Characteristic */ + MESH_PROXY_DATA_OUT_VALUE_CHAR, + MESH_PROXY_DATA_OUT_VALUE_VAL, + MESH_PROXY_DATA_OUT_VALUE_CCC, + + /* Max number of characteristics */ + MESH_PROXY_IDX_NB, +}; + +/* Define the available custom service states */ +enum mesh_serv_state +{ + MESH_NO_SERVICES, + MESH_PROV_SERVICE_DONE, + MESH_PROXY_SERVICE_DONE, + MESH_SERV_STATE_MAX +}; + +/* ---------------------------------------------------------------------------- + Global variables and types + --------------------------------------------------------------------------*/ + +typedef uint16 (* mesh_prov_data_in_wt_cb) +( + uint16 conn_hndl, + uint16 offset, + uint16 length, + uint8* value +); + +typedef uint16 (* mesh_prov_data_out_ccd_cb) +( + uint16 conn_hndl, + uint8 enabled +); + +/** + Mesh Prov application callbacks +*/ +typedef struct +{ + /** Provisioning Data IN Callback */ + mesh_prov_data_in_wt_cb prov_data_in_cb; + + /** Provisioning Data OUT notif Changed */ + mesh_prov_data_out_ccd_cb prov_data_out_ccd_cb; + +} mesh_prov_cb; + +typedef uint16 (* mesh_proxy_data_in_wt_cb) +( + uint16 conn_hndl, + uint16 offset, + uint16 length, + uint8* value +); + +typedef uint16 (* mesh_proxy_data_out_ccd_cb) +( + uint16 conn_hndl, + uint8 enabled +); + +/** + Mesh Proxy application callbacks +*/ +typedef struct +{ + /** Proxy Data IN Callback */ + mesh_proxy_data_in_wt_cb proxy_data_in_cb; + + /** Proxy Data OUT notif Changed */ + mesh_proxy_data_out_ccd_cb proxy_data_out_ccd_cb; + +} mesh_proxy_cb; + +/* ---------------------------------------------------------------------------- + Function prototype definitions + --------------------------------------------------------------------------*/ + +/** + Register Mesh Provisioning Service Instance + + \param [in] cb application callbacks +*/ +bStatus_t mesh_prov_init (mesh_prov_cb* cb); + +/** + Deregister Mesh Provisioning Service Instance + +*/ +bStatus_t mesh_prov_deinit(void); + +/** + Mesh Provisioning Data out Notifications + + Notification will only be sent if given client enabled notifications before. + + \param [in] conn_hndl Connection Identifier + \param [in] attidx Attribute Index + \param [in] val Pointer to Data to be sent + \param [in] val_len Length of Data to be sent +*/ +bStatus_t mesh_prov_notify_data_out +( + uint16 conn_hndl, + uint8 attidx, + uint8* val, + uint8 val_len +); + +/** + Register Mesh Proxy Service Instance + + \param [in] cb application callbacks +*/ +bStatus_t mesh_proxy_init (mesh_proxy_cb* cb); + +/** + Deregister Mesh Proxy Service Instance + +*/ +bStatus_t mesh_proxy_deinit(void); + +/** + Mesh Proxy Data out Notifications + + Notification will only be sent if given client enabled notifications before. + + \param [in] conn_hndl Connection Identifier + \param [in] attidx Attribute Index + \param [in] val Pointer to Data to be sent + \param [in] val_len Length of Data to be sent +*/ +bStatus_t mesh_proxy_notify_data_out +( + uint16 conn_hndl, + uint8 attidx, + uint8* val, + uint8 val_len +); + +/* ---------------------------------------------------------------------------- + Close the 'extern "C"' block + ------------------------------------------------------------------------- */ +#ifdef __cplusplus +} +#endif + +#endif /* _MESH_SERVICES_H */ diff --git a/src/components/ethermind/platforms/mesh/model_state_handler_pl.c b/src/components/ethermind/platforms/mesh/model_state_handler_pl.c new file mode 100644 index 0000000..0ab4f17 --- /dev/null +++ b/src/components/ethermind/platforms/mesh/model_state_handler_pl.c @@ -0,0 +1,180 @@ + +/** + \file model_state_handler_pl.c + + +*/ + +/* + Copyright (C) 2013. Mindtree Limited. + All rights reserved. +*/ + +/* --------------------------------------------- Header File Inclusion */ +#include "model_state_handler_pl.h" +#include "led_light.h" + +/* --------------------------------------------- External Global Variables */ + +/* --------------------------------------------- Exported Global Variables */ + +/* --------------------------------------------- Static Global Variables */ + +/* --------------------------------------------- Functions */ +void mesh_model_platform_init_pl(void) +{ + /* Map Platform related initializations of GPIOs/LEDs etc here */ +} + +void mesh_model_device_bootup_ind_pl(void) +{ + /* LED ON/OFF for BOOT UP Indication to be mapped here */ +} + +void mesh_model_device_provisioned_ind_pl(void) +{ + /* LED ON/OFF for Provisioning Indication to be mapped here */ +} + +void generic_onoff_set_pl (UINT8 state) +{ + /* LED ON/OFF for GENERIC ONOFF to be mapped here */ + if (state) + { + light_ctrl(LIGHT_RED, LIGHT_TOP_VALUE-1); + light_ctrl(LIGHT_GREEN, LIGHT_TOP_VALUE-1); + light_ctrl(LIGHT_BLUE, LIGHT_TOP_VALUE-1); + } + else + { + light_ctrl(LIGHT_RED, 0); + light_ctrl(LIGHT_GREEN, 0); + light_ctrl(LIGHT_BLUE, 0); + } +} + +void vendor_mode_mainlight_onoff_set_pl (UINT8 state) +{ + /* LED ON/OFF for vendor model mainlight ONOFF to be mapped here */ + if (state) + { + light_ctrl(LIGHT_GREEN, LIGHT_TOP_VALUE-1); + } + else + { + light_ctrl(LIGHT_GREEN, 0); + } +} + +void vendor_mode_backlight_onoff_set_pl (UINT8 state) +{ + /* LED ON/OFF for vendor model backlight ONOFF to be mapped here */ + if (state) + { + light_ctrl(LIGHT_RED, LIGHT_TOP_VALUE-1); + } + else + { + light_ctrl(LIGHT_RED, 0); + } +} + + + +void light_lightness_set_pl (uint16_t ligtnessValue) +{ + light_ctrl(LIGHT_RED, ligtnessValue>>10); + light_ctrl(LIGHT_GREEN, ligtnessValue>>10); + light_ctrl(LIGHT_BLUE, ligtnessValue>>10); +} + +void light_ctl_set_pl (uint16_t ctlValue,uint16_t dltUV) +{ + if(ctlValue<6600) + { + light_ctrl(LIGHT_RED, 255); + } + else + { + light_ctrl(LIGHT_RED, 255-(ctlValue-6600)*(255-160)/(20000-6600)); + } + + if(ctlValue<6600) + { + light_ctrl(LIGHT_GREEN, 50+200*(6600-ctlValue)/6600); + } + else + { + light_ctrl(LIGHT_GREEN, 255-(ctlValue-6600)*(255-190)/(20000-6600)); + } + + if(ctlValue<2000) + { + light_ctrl(LIGHT_BLUE, 0); + } + else if(ctlValue<6500) + { + light_ctrl(LIGHT_BLUE, 255*(6600-ctlValue)/(6500-2000)); + } + else + { + light_ctrl(LIGHT_BLUE, 255); + } +} + +static float Hue_2_RGB( float v1, float v2, float vH ) //Function Hue_2_RGB +{ + if ( vH < 0 ) vH += 1; + + if ( vH > 1 ) vH -= 1; + + if (( 6 * vH ) < 1 ) return ( v1 + ( v2 - v1 ) * 6 * vH ); + + if (( 2 * vH ) < 1 ) return ( v2 ); + + if (( 3 * vH ) < 2 ) return ( v1 + ( v2 - v1 ) * ( ( 2/3.0 ) - vH ) * 6 ); + + return ( v1 ); +} + +void light_hsl_set_pl (uint16_t H_int,uint16_t S_int,uint16_t L_int) +{ + float H = (float)H_int / 65535.0; + float S = (float)S_int / 65535.0; + float L = (float)L_int / 65535.0; + float R,G,B,var_1,var_2; + + if ( S == 0 ) + { + R = L; + G = L; + B = L; + } + else + { + if ( L < 0.5 ) + var_2 = L * ( 1 + S ); + else + var_2 = ( L + S ) - ( S * L ); + + var_1 = 2 * L - var_2; + R = Hue_2_RGB( var_1, var_2, H + ( 1/3.0 )); + G = Hue_2_RGB( var_1, var_2, H ); + B = Hue_2_RGB( var_1, var_2, H - ( 1/3.0 )); + } + + uint16_t R_int = (uint16_t)(R*LIGHT_TURN_ON); + uint16_t G_int = (uint16_t)(G*LIGHT_TURN_ON); + uint16_t B_int = (uint16_t)(B*LIGHT_TURN_ON); +// printf("[HSL_f] %f %f %f\n",R,G,B); +// printf("[HSL_I] %02x %02x %02x\n",R_int,G_int,B_int); + light_ctrl(LIGHT_RED, R_int); + light_ctrl(LIGHT_GREEN, G_int); + light_ctrl(LIGHT_BLUE, B_int); +} + +// light_hsl_set_pl(0x5555,0xffff,0x8000); // 0x00 0xFF 0x00 Green +// light_hsl_set_pl(0xaaaa,0xffff,0x8000); // 0x00 0x00 0xFF Blue +// light_hsl_set_pl(0x0000,0xffff,0x8000);// 0xFF 0x00 0x00 Red +// + diff --git a/src/components/ethermind/platforms/mesh/model_state_handler_pl.h b/src/components/ethermind/platforms/mesh/model_state_handler_pl.h new file mode 100644 index 0000000..d3e0980 --- /dev/null +++ b/src/components/ethermind/platforms/mesh/model_state_handler_pl.h @@ -0,0 +1,39 @@ + +/** + \file model_state_handler_pl.h + + +*/ + +/* + Copyright (C) 2013. Mindtree Limited. + All rights reserved. +*/ + +#ifndef _H_MODEL_STATE_HANDLER_ +#define _H_MODEL_STATE_HANDLER_ + +/* --------------------------------------------- Header File Inclusion */ +#include "MS_common.h" + +/* --------------------------------------------- Global Definitions */ + +/* --------------------------------------------- Structures/Data Types */ + +/* --------------------------------------------- Macros */ + +/* --------------------------------------------- Internal Functions */ + +/* --------------------------------------------- API Declarations */ +void mesh_model_platform_init_pl(void); +void mesh_model_device_bootup_ind_pl(void); +void mesh_model_device_provisioned_ind_pl(void); +void generic_onoff_set_pl (UINT8 state); +void vendor_mode_mainlight_onoff_set_pl (UINT8 state); +void vendor_mode_backlight_onoff_set_pl (UINT8 state); +void light_lightness_set_pl (uint16_t ligtnessValue); +void light_ctl_set_pl (uint16_t ctlValue,uint16_t dltUV); +void light_hsl_set_pl (uint16_t H,uint16_t S,uint16_t L); + +#endif /* _H_MODEL_STATE_HANDLER_ */ + diff --git a/src/components/ethermind/utils/include/aes_cmac.h b/src/components/ethermind/utils/include/aes_cmac.h new file mode 100644 index 0000000..f1876c6 --- /dev/null +++ b/src/components/ethermind/utils/include/aes_cmac.h @@ -0,0 +1,109 @@ + +/** + \file aes_cmac.h + + +*/ + +/* + Copyright (C) 2013. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_AES_CMAC_ +#define _H_AES_CMAC_ + +/* --------------------------------------------- Header File Inclusion */ +#include "EM_os.h" + +/* --------------------------------------------- Global Definitions */ +/* TODO: Make it proper error id */ +#define AES_CMAC_PROC_PENDING 0x1100 + +/* Operations */ +#define AES_CMAC_MAC_GENERATE 0x00 +#define AES_CMAC_MAC_VERIFY 0x01 + +/* AES-CMAC key and data block size */ +#define AES_CMAC_KEY_SIZE 16 +#define AES_CMAC_BLOCK_SIZE 16 +#define AES_128_ENC_KEY_SIZE 16 +#define AES_128_ENC_DATA_SIZE 16 +#define AES_128_ENC_OUT_SIZE 16 + +/* AES-CMAC Block size exponent (2^4 = 16) */ +#define AES_CMAC_BLOCK_EXPONENT 4 + +/* AES-CMAC state masks */ +#define AES_CMAC_STATE_INIT 0x01 +#define AES_CMAC_STATE_OPERATING 0x02 +#define AES_CMAC_STATE_IN_ENCRYPT 0x04 + +#define AES_CMAC_STATE_SUBKEY_GEN 0x10 +#define AES_CMAC_STATE_MAC_GENERATE 0x20 +#define AES_CMAC_STATE_MAC_VERIFY 0x40 + +/* --------------------------------------------- Structures/Data Types */ +/* AES-CMAC context callback type */ +typedef void (* AES_CMAC_CB) (void); + +/* AES-CMAC Context */ +typedef struct _AES_CMAC_CONTEXT +{ + /** Application Use */ + + /* 128-Bit Key to be used for the CMAC algorithm */ + UCHAR* key; + + /* Message to be used */ + UCHAR* data; + + /* Message Length */ + UINT16 datalen; + + /* MAC */ + UCHAR* mac; + + /* MAC length, in bytes */ + UCHAR maclen; + + /* Action - Generate MAC or Verify MAC */ + UCHAR action; + + /* Context callback */ + AES_CMAC_CB cb; + + /** Internal Use */ + + /* Context state */ + UCHAR state; + + /* Number of data blocks */ + UINT16 num_blocks; + + /* Number of processed data blocks */ + UINT16 processed; + + /* Subkey references */ + UCHAR subkey1[AES_CMAC_KEY_SIZE]; + UCHAR subkey2[AES_CMAC_KEY_SIZE]; + +} AES_CMAC_CONTEXT; + +/* --------------------------------------------- Macros */ + +/* --------------------------------------------- API Declarations */ +/* Initialize module */ +EM_RESULT aes_cmac_init (void); + +/* Initialize Context */ +EM_RESULT aes_cmac_context_init (AES_CMAC_CONTEXT* context); + +/* Generate/Verify MAC for Context */ +EM_RESULT aes_cmac (AES_CMAC_CONTEXT* context); + +/* Interface to indicate encrypt complete */ +void aes_cmac_aes_128_encryption_complete (UCHAR status, UCHAR* data, UINT16 datalen); + +#endif /* _H_AES_CMAC_ */ + diff --git a/src/components/ethermind/utils/include/aes_cmac_pl.h b/src/components/ethermind/utils/include/aes_cmac_pl.h new file mode 100644 index 0000000..87fab86 --- /dev/null +++ b/src/components/ethermind/utils/include/aes_cmac_pl.h @@ -0,0 +1,39 @@ + +/** + \file aes_cmac_pl.h + + +*/ + +/* + Copyright (C) 2013. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_AES_CMAC_PL_ +#define _H_AES_CMAC_PL_ + +/* --------------------------------------------- Header File Inclusion */ +#include "EM_os.h" +#include "cry.h" + +/* --------------------------------------------- Global Definitions */ + +/* --------------------------------------------- Structures/Data Types */ + +/* --------------------------------------------- Macros */ +/* Hack. TBD */ +#define EM_MODULE_ID_AES_CMAC 0 + +/* --------------------------------------------- Internal Functions */ + +/* --------------------------------------------- API Declarations */ +/* Platform Init */ +void aes_cmac_init_pl (void); + +/* Platform Encrypt */ +EM_RESULT aes_cmac_128B_encrypt_pl (UCHAR* key, UCHAR* data, UCHAR* encout); +void aes_cmac_128B_encrypt_complete_pl(UCHAR status, UCHAR* data, UINT16 length); + +#endif /* _H_AES_CMAC_PL_ */ + diff --git a/src/components/ethermind/utils/include/bitarray.h b/src/components/ethermind/utils/include/bitarray.h new file mode 100644 index 0000000..6aafd2e --- /dev/null +++ b/src/components/ethermind/utils/include/bitarray.h @@ -0,0 +1,194 @@ + +/** + \file bitarray.h + + \brief This module defines interfaces to efficiently process + an array of booleans represented as bits in an array of 32-bit integers. +*/ + +/* + Copyright (C) 2017. Mindtree Limited. + All rights reserved. +*/ + +#ifndef _H_BITARRAY_ +#define _H_BITARRAY_ + +/* --------------------------------------------- Header File Inclusion */ +#include "EM_os.h" + +/* --------------------------------------------- Global Definitions */ +/** Size of a single block in bitarray data structure */ +#define BITARRAY_BLOCK_SIZE 32u + +/** Number of blocks required to store a given number of bits */ +#define BITARRAY_NUM_BLOCKS(bit_count) \ + (((bit_count) + (BITARRAY_BLOCK_SIZE - 1)) / (BITARRAY_BLOCK_SIZE)) + +/* --------------------------------------------- Structures/Data Types */ + +/* --------------------------------------------- Macros */ + +/* --------------------------------------------- API Declarations */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + \brief Set boolean value of a specific bit position + + \par Description + This routine sets the boolean value of a specific bit position in a given bitarray. + + \param [in] bitarray The bitarray in which the bit position to be set. + \param [in] bit_position The bit position to be set. +*/ +void bitarray_set_bit +( + /* IN */ UINT32* bitarray, + /* IN */ UINT32 bit_position +); + +/** + \brief Get boolean value of a specific bit position + + \par Description + This routine returns the boolean value of a specific bit position in a given bitarray. + + \param [in] bitarray The bitarray from which the bit position to be fetched. + \param [in] bit_position The bit position to be fetched. + + \return Boolean value 1 if bit is set, otherwise 0 +*/ +UINT8 bitarray_get_bit +( + /* IN */ UINT32* bitarray, + /* IN */ UINT32 bit_position +); + +/** + \brief Reset/clear boolean value of a specific bit position + + \par Description + This routine resets/clear the boolean value of a specific bit position in a given bitarray. + + \param [in] bitarray The bitarray in which the bit position to be reset. + \param [in] bit_position The bit position to be reset. +*/ +void bitarray_reset_bit +( + /* IN */ UINT32* bitarray, + /* IN */ UINT32 bit_position +); + +/** + \brief Set boolean value of all bits + + \par Description + This routine sets the boolean value of all bits in a given bitarray. + + \param [in] bitarray The bitarray to be set. + \param [in] bit_count Number of bits in the bitarray. +*/ +void bitarray_set_all +( + /* IN */ UINT32* bitarray, + /* IN */ UINT32 bit_count +); + +/** + \brief Reset/clear boolean value of all bits + + \par Description + This routine resets/clear the boolean value of all bits in a given bitarray. + + \param [in] bitarray The bitarray to be reset. + \param [in] bit_count Number of bits in the bitarray. +*/ +void bitarray_reset_all +( + /* IN */ UINT32* bitarray, + /* IN */ UINT32 bit_count +); + +/** + \brief To check if all bits are set + + \par Description + This routine checks if all bits in a given bitarray are set. + + \param [in] bitarray The bitarray to be checked. + \param [in] bit_count Number of bits in the bitarray. + + \return Boolean value 1 if all bits are set, otherwise 0 +*/ +UINT8 bitarray_is_all_set +( + /* IN */ UINT32* bitarray, + /* IN */ UINT32 bit_count +); + +/** + \brief To check if all bits are reset/clear + + \par Description + This routine checks if all bits in a given bitarray are reset/clear. + + \param [in] bitarray The bitarray to be checked. + \param [in] bit_count Number of bits in the bitarray. + + \return Boolean value 1 if all bits are reset/clear, otherwise 0 +*/ +UINT8 bitarray_is_all_reset +( + /* IN */ UINT32* bitarray, + /* IN */ UINT32 bit_count +); + +/** + \brief Get the index of lowest bit that is set + + \par Description + This routine returns the index of the lowest bit set in a given bitarray. + + \param [in] bitarray The bitarray to be checked. + \param [in] bit_count Number of bits in the bitarray. + \param [in] start_index Index in the bitarray from where to start looking for. + + \return Index of the lowest bit that is set from the given start_index. + Return start_index itself, if no further bits are set. +*/ +UINT32 bitarray_get_lowest_bit_set +( + /* IN */ UINT32* bitarray, + /* IN */ UINT32 bit_count, + /* IN */ UINT32 start_index +); + +/** + \brief Get the index of highest bit that is set + + \par Description + This routine returns the index of the highest bit set in a given bitarray. + + \param [in] bitarray The bitarray to be checked. + \param [in] bit_count Number of bits in the bitarray. + \param [in] start_index Index in the bitarray from where to start looking for. + + \return Index of the highest bit that is set from the given start_index. + Return start_index itself, if no further bits are set. +*/ +UINT32 bitarray_get_highest_bit_set +( + /* IN */ UINT32* bitarray, + /* IN */ UINT32 bit_count, + /* IN */ UINT32 start_index +); + +#ifdef __cplusplus +}; +#endif + +#endif /* _H_BITARRAY_ */ + diff --git a/src/components/ethermind/utils/include/btypes.h b/src/components/ethermind/utils/include/btypes.h new file mode 100644 index 0000000..fadd1d1 --- /dev/null +++ b/src/components/ethermind/utils/include/btypes.h @@ -0,0 +1,116 @@ +/*************************************************************************** + Copyright (C) Mindtree Consulting Ltd. + This module is a confidential and proprietary property of Mindtree and + a possession or use of this module requires written permission of Mindtree. + ***************************************************************************/ + +/** + \file btypes.h + Basic types definition. This file should be modified based on the target + platform. + + \date 2007-08-20 +*/ + +#ifndef _BTYPES_H_ +#define _BTYPES_H_ + +/* #define CRYPTO_TEST_FRAMEWORK */ +#define CRYPTO_STANDALONE_ECDH +#define ENABLE_LE_ECDH +#define SUPPORT_REMOTE_PUBLIC_KEY_VALIDATION + +#ifndef CRYPTO_TEST_FRAMEWORK + #ifndef CRYPTO_STANDALONE_ECDH + #include "bt_le_features.h" + #include "platform.h" + #include "bt_os_common.h" + #else + #include "EM_os.h" + #endif /* CRYPTO_STANDALONE_ECDH */ + + /* Enable if using drbg random generator */ + #ifndef CRYPTO_STANDALONE_ECDH + #define USE_DRBG_RAND_GEN + #endif /* CRYPTO_STANDALONE_ECDH */ + + /* Enable if the using big endian input/out format */ + /* #define ECDH_BIG_ENDIAN_IO */ + +#else + /* Test framework */ + #define ENABLE_LE_ECDH + + #include + #include + #include + +#endif /* CRYPTO_TEST_FRAMEWORK */ + +#ifdef ENABLE_LE_ECDH +#define ECDH_FALSE (0) +#define ECDH_TRUE (!(ECDH_FALSE)) + +/* ========================= Include File Section ========================= */ + + +/* ====================== Macro Declaration Section ======================= */ +#ifndef IN + #define IN /*@in@*/ +#endif +#ifndef OUT + #define OUT /*@out@*/ +#endif +#ifndef INOUT + #define INOUT IN OUT +#endif + +#ifndef CRYPTO_STANDALONE_ECDH + #ifndef ALIGN + #define ALIGN(n) __attribute__((aligned(n))) + #endif +#else + #define ALIGN(n) +#endif /* CRYPTO_STANDALONE_ECDH */ +/* Macro to remove: unsed param warning */ +#define CRYPTO_IGNORE_PARAM(v) (void)(v) +#define ecdh_memset memset +#define ecdh_memcpy memcpy + +#ifdef BLUEWIZ_BIG_ENDIAN +#define ld32_msb(v, m) (v) = (*((u32*)(m))) +#define st32_msb(m, v) ecdh_memcpy((m), &(v), 4) +#else +#define ld32_msb(v, m) (v) = (((m)[0]<<24) | ((m)[1]<<16) | \ + ((m)[2]<<8) | (m)[3]) +#define st32_msb(m, v) (m)[0]=(u8)((v)>>24); (m)[1]=(u8)((v)>>16); \ + (m)[2]=(u8)((v)>>8); (m)[3]=(u8)(v); +#endif /* BLUEWIZ_BIG_ENDIAN */ + +#define rol32(r, n) (((r) << (n)) | ((r) >> (32-(n)))) +#define ror32(r, n) (((r) >> (n)) | ((r) << (32-(n)))) + +#define USE_32BIT_PROC +#define ECDH_TIME_SLICE + +/* ==================== Data Types Declaration Section ==================== */ +typedef unsigned char u8; +typedef unsigned short int u16; +typedef unsigned int u32; +typedef unsigned long long u64; +typedef signed char s8; +typedef signed short int s16; +typedef signed int s32; +typedef signed long long s64; + +/* ==================== Data Types Declaration Section ==================== */ + +/* ================ Exported Variables Declaration Section ================ */ + + +/* ============================= API Section ============================== */ + + +#endif /* ENABLE_LE_ECDH */ + +#endif /* _BTYPES_H_ */ diff --git a/src/components/ethermind/utils/include/cliface.h b/src/components/ethermind/utils/include/cliface.h new file mode 100644 index 0000000..7ff0813 --- /dev/null +++ b/src/components/ethermind/utils/include/cliface.h @@ -0,0 +1,123 @@ + +/** + \file cliface.h + + This file contains definitions for command line interface (CLI) framework. +*/ + +/* + Copyright (C) 2017. Mindtree Ltd. + All rights reserved. +*/ + +#ifndef _H_CLIFACE_ +#define _H_CLIFACE_ + +/* --------------------------------------------- Header File Inclusion */ +#include "EM_os.h" + + +/* --------------------------------------------- Macros */ + +/* Debug Macros */ +/* TBD: Mapped with debug sub-system */ +#define CLI_ERR(...) /* printf(__VA_ARGS__) */ +#define CLI_TRC(...) /* printf(__VA_ARGS__) */ +#define CLI_INF(...) /* printf(__VA_ARGS__) */ + +#define CLI_STR_COMPARE(s0, s1) strcmp((const char *)(s0), (const char *)(s1)) + +#define CLI_NULL_CHECK(ptr) \ + if (NULL == (ptr)) \ + {\ + CLI_ERR( \ + "[CLI] NULL Pointer\n"); \ + \ + return EM_FAILURE; \ + } + +#define CLI_IS_WHITE_SPACE(ch) ((' ' == (ch)) || ('\t' == (ch))) +#define CLI_IS_CMD_SEPARATOR(ch) ((' ' == (ch)) || ('\t' == (ch)) || ('\r' == (ch)) || ('\n' == (ch))) + +/** TBD: Move to limits/configuration header file */ +#define CLI_MAX_ARGS 16 + +#define CLI_strlen(s) EM_str_len(s) + +/* --------------------------------------------- Data Types/ Structures */ +/** + CLI command handler. + + CLI will call the handler for the received command. + + \param [in] argc Number of arguments. + \param [in] argv List of arguments. +*/ +typedef EM_RESULT (* CLI_CMD_HANDLER) +( + UINT32 argc, + UCHAR* argv[] +) DECL_REENTRANT; + +/** This data structure represents a CLI command */ +typedef struct _cli_command +{ + /** Command name */ + DECL_CONST UCHAR* cmd; + + /* Command description */ + DECL_CONST UCHAR* desc; + + /** Command handler */ + DECL_CONST CLI_CMD_HANDLER cmd_hdlr; + +} CLI_COMMAND; + +/* --------------------------------------------- Global Definitions */ +extern CLI_COMMAND* g_cli_cmd_list; +extern UINT8 g_cli_cmd_len; + + + +/* --------------------------------------------- Functions */ +uint16_t CLI_init +( + CLI_COMMAND* list, + UINT8 len +); + + +EM_RESULT CLI_process_line +( + /* IN */ UCHAR* buffer, + /* IN */ UINT32 buffer_len +// /* IN */ CLI_COMMAND* cmd_list, +// /* IN */ UINT32 cmd_count +); + +INT32 CLI_strtoi +( + /* IN */ UCHAR* data, + /* IN */ UINT16 data_length, + /* IN */ UINT8 base +); + +EM_RESULT CLI_strtoarray +( + /* IN */ UCHAR* data, + /* IN */ UINT16 data_length, + /* OUT */ UINT8* output_array, + /* IN */ UINT16 output_array_len +); + +EM_RESULT CLI_strtoarray_le +( + /* IN */ UCHAR* data, + /* IN */ UINT16 data_length, + /* OUT */ UINT8* output_array, + /* IN */ UINT16 output_array_len +); + +#endif /* _H_CLIFACE_ */ + + diff --git a/src/components/ethermind/utils/include/crypto.h b/src/components/ethermind/utils/include/crypto.h new file mode 100644 index 0000000..9c6bd04 --- /dev/null +++ b/src/components/ethermind/utils/include/crypto.h @@ -0,0 +1,105 @@ +/*************************************************************************** + Copyright (C) Mindtree Consulting Ltd. + This module is a confidential and proprietary property of Mindtree and + a possession or use of this module requires written permission of Mindtree. + ***************************************************************************/ + +/** + \file crypto.h + Contains the Interface definition of Cryptographic functions required by + the Host Controller Firmware. + + \date 2007-05-09 +*/ + +#ifndef _CRYPTO_H_ +#define _CRYPTO_H_ + +/* ========================= Include File Section ========================= */ +#include "btypes.h" + +#ifdef ENABLE_LE_ECDH + +/* #define FILE_INPUT */ +#define ECPD_ALT_ALG1 +#define ECPA_ALT_ALG1 +#include "mpal.h" + +/* ====================== Macro Declaration Section ======================= */ +/* ==================== Data Types Declaration Section ==================== */ +/** + SSP Private Key type. The private key is represented in binary format with + MSB byte ordering. +*/ + +typedef u8 ssp_prkey_t[DHKEY_LEN]; + +/** + SSP Publick Key type. Each coordinate of the public key is represented in + binary format with MSB byte ordering. +*/ + +typedef struct +{ + u8 x[DHKEY_LEN]; /**< X coordinate (Format(MSB): 23..0) */ + u8 y[DHKEY_LEN]; /**< Y coordinate (Format(MSB): 47..DHKEY_LEN) */ +} ssp_pukey_t; +/** + SSP Diffie-Hellman Key (generated shared key) type. The dhkey is + represented in binary format with MSB byte ordering. +*/ + +typedef u8 ssp_dhkey_t[DHKEY_LEN]; + + +/* ================ Exported Variables Declaration Section ================ */ + + +/* ============================= Macros Section ============================== */ +#ifdef CRYPTO_STANDALONE_ECDH + /** + The ECDH algorithm will be used in standalone configuration (in Windows + builds) . So, there should be no references to /platform/ + APIs. + This define should be enabled for Windows builds, and should not be enabled + for other platforms. + */ + + /* Return 32-bit value here. */ + #define CRYPTO_GET_RNG_SEED() 0xDEADC0DE + +#else /* CRYPTO_STANDALONE_ECDH */ + + #define CRYPTO_GET_RNG_SEED pf_get_rng_seed + +#endif /* CRYPTO_STANDALONE_ECDH */ + + +/* ============================= API Section ============================== */ +void ssp_init(void); +void ssp_shutdown(void); + +#ifdef ECDH_TIME_SLICE + +#ifdef CRYPTO_TEST_FRAMEWORK + u8 ssp_get_ecdh_keypair(const ssp_prkey_t* priv, OUT ssp_pukey_t* pub); +#else + u8 ssp_get_ecdh_keypair(OUT ssp_prkey_t* priv, OUT ssp_pukey_t* pub); +#endif + +u8 ssp_get_dhkey(ssp_prkey_t* priv, ssp_pukey_t* pub, + OUT ssp_dhkey_t* dhkey); +#else + +#ifdef CRYPTO_TEST_FRAMEWORK + u8 ssp_get_ecdh_keypair(const ssp_prkey_t* priv, OUT ssp_pukey_t* pub); +#else + u8 ssp_get_ecdh_keypair(OUT ssp_prkey_t* priv, OUT ssp_pukey_t* pub); +#endif + +u8 ssp_get_dhkey(ssp_prkey_t* priv, ssp_pukey_t* pub, + OUT ssp_dhkey_t* dhkey); +#endif + +#endif /* ENABLE_LE_ECDH */ +#endif /* _CRYPTO_H_ */ diff --git a/src/components/ethermind/utils/include/ecdh.h b/src/components/ethermind/utils/include/ecdh.h new file mode 100644 index 0000000..a2d34e9 --- /dev/null +++ b/src/components/ethermind/utils/include/ecdh.h @@ -0,0 +1,36 @@ +/*************************************************************************** + Copyright (C) Mindtree Consulting Ltd. + This module is a confidential and proprietary property of Mindtree and + a possession or use of this module requires written permission of Mindtree. + ***************************************************************************/ + +/** + \file ecdh.h + Contains the Interface definition of ECDH functions required by + the Cryptographic modules. + + \date 2008-03-07 +*/ + +#ifndef _ECDH_H_ +#define _ECDH_H_ + +/* ========================= Include File Section ========================= */ +#include "btypes.h" + +#ifdef ENABLE_LE_ECDH + #include "mpal.h" + + /* ============================= API Section ============================== */ + u8 verify_point_on_curve( DIGIT_S* X, DIGIT_S* Y); + + #ifdef ECDH_TIME_SLICE + u8 mixed_scalar_multiply(u8* S, u8* X, u8* Y); + u8 conv_coord(DIGIT_S* S, OUT DIGIT_S* X, OUT DIGIT_S* Y); + #else + void mixed_scalar_multiply(u8* S, u8* X, u8* Y); + #endif + +#endif /* ENABLE_LE_ECDH */ + +#endif /* _ECDH_H_ */ diff --git a/src/components/ethermind/utils/include/mpal.h b/src/components/ethermind/utils/include/mpal.h new file mode 100644 index 0000000..66550c3 --- /dev/null +++ b/src/components/ethermind/utils/include/mpal.h @@ -0,0 +1,84 @@ +/*************************************************************************** + Copyright (C) Mindtree Consulting Ltd. + This module is a confidential and proprietary property of Mindtree and + a possession or use of this module requires written permission of Mindtree. + ***************************************************************************/ + +/** + \file mpal.h + Multi-Precision Arithmetic Library(MPAL) interface. + + \date 2007-08-20 +*/ + +#ifndef _MPAL_H_ +#define _MPAL_H_ + +/* ========================= Include File Section ========================= */ +#include "btypes.h" + +/* ====================== Macro Declaration Section ======================= */ + +#ifdef ENABLE_LE_ECDH + +/* #define USE_ARM_ASM */ + +#ifdef USE_32BIT_PROC + #define MPAL_MAX_LEN 16 + #define MPAL_BASE 32 + #define MPAL_BASE_MASK 0xFFFFFFFF +#else /* USE_32BIT_PROC */ + #define MPAL_MAX_LEN 32 + #define MPAL_BASE 16 + #define MPAL_BASE_MASK 0xFFFF +#endif /* USE_32BIT_PROC */ + +#define PRIME_BITS 256 +#define DHKEY_LEN (PRIME_BITS/8) /* Number of bytes of key as per ECDH procedure */ +#define MPAL_PRIME_LEN (PRIME_BITS/MPAL_BASE) + + +#define mpal_set_number(A, len_A, fill) ecdh_memset((A), (fill), (MPAL_BASE/8) * (len_A)); + +/* Unsafe, fix this - or use proper Notation. Also depending on sizeof + (DIGIT ) multiplier*/ +#define MPAL_MACRO_DEF u16 macro_len_A + +/* Call MPAL_MACRO_DEF in initialization section, before calling this macro */ +#define mpal_trim(A,len,out_len) \ + macro_len_A = (u16)(len); \ + while(macro_len_A && A[--macro_len_A]==0); \ + (out_len) = (u16)(macro_len_A+1); \ + +void convert_to_lsb(u8* bytes, u8 len); +#define convert_to_msb(b, l) convert_to_lsb((b), (l)) + +/* ==================== Data Types Declaration Section ==================== */ +#ifdef USE_32BIT_PROC + typedef s64 SIGNED_BIG_DIGIT; + typedef u64 UNSIGNED_BIG_DIGIT; + typedef u32 DIGIT_S; +#else /* USE_32BIT_PROC */ + typedef s32 SIGNED_BIG_DIGIT; + typedef u32 UNSIGNED_BIG_DIGIT; + typedef u16 DIGIT_S; +#endif /* USE_32BIT_PROC */ + +/* ===================== Variable Declaration Section ===================== */ +extern const DIGIT_S PRIME[MPAL_PRIME_LEN]; +extern const DIGIT_S curve_a[MPAL_PRIME_LEN]; +extern const DIGIT_S curve_b[MPAL_PRIME_LEN]; + +/* ============================= API Section ============================== */ +void mpal_add_u8(INOUT u8* A, u16 len_A, const u8* B, u16 len_B); +void mpal_add(INOUT DIGIT_S* A, const DIGIT_S* B); +void mpal_sub(INOUT DIGIT_S* A, const DIGIT_S* B); +void mpal_mult(const DIGIT_S* A, const DIGIT_S* B, OUT DIGIT_S* C); +s8 mpal_compare(const DIGIT_S* A, const DIGIT_S* B); +u16 mpal_right_shift(INOUT DIGIT_S* A,u16 len_A); +void mpal_mod_by_sub(INOUT DIGIT_S* A); +void mpal_div_by_2(INOUT DIGIT_S* A, INOUT DIGIT_S* B); +void mpal_mult_by_2(INOUT DIGIT_S* A, INOUT DIGIT_S* B); + +#endif /* ENABLE_LE_ECDH */ +#endif /* _MPAL_H_ */ diff --git a/src/components/ethermind/utils/include/nvs.h b/src/components/ethermind/utils/include/nvs.h new file mode 100644 index 0000000..e244b8c --- /dev/null +++ b/src/components/ethermind/utils/include/nvs.h @@ -0,0 +1,72 @@ + +/** + \file nvs.h + + +*/ + +/* + Copyright (C) 2013. Mindtree Limited. + All rights reserved. +*/ + +#ifndef _H_NVS_ +#define _H_NVS_ + +/* --------------------------------------------- Header File Inclusion */ +#include "EM_os.h" + +/* --------------------------------------------- Global Definitions */ +/** NVS Bank types */ +#define NVS_BANK_PERSISTENT 0 +#define NVS_NUM_BANKS 1 + +/** NVS Access modes */ +#define NVS_ACCESS_WRITE 0 +#define NVS_ACCESS_READ 1 + +/** Bank size for the NVS in number of bytes */ +#define NVS_BLOCK_SIZE 4096 +#define NVS_NUM_BLOCKS 2 + +/* NVS bank states */ +#define NVS_CLOSE 0x00 +#define NVS_WROPEN 0x01 +#define NVS_RDOPEN 0x02 + +#define NVS_TOTAL_BASE 2 +#define NVS_FLASH_UNUSED 0x07 +#define NVS_FLASH_WRITING 0x03 +#define NVS_FLASH_READY 0x01 +#define NVS_FLASH_BAD 0x00 +#define NVS_FLASH_FIRST_OK 1 +#define NVS_FLASH_SECOND_OK 2 +#define NVS_FLASH_INVAILD 0xFF +#define NVS_FLASH_SIZE MS_PS_RECORD_CORE_MODULES_OFFSET + +extern UINT32 nvs_flash_base1,nvs_flash_base2; + +/* --------------------------------------------- Structures/Data Types */ + +/* --------------------------------------------- Macros */ + +/* --------------------------------------------- Internal Functions */ + +/* --------------------------------------------- API Declarations */ +UINT16 nvs_init (UINT8 bank); +void nvs_shutdown (UINT8 bank); +void nvs_reset (UINT8 bank); +INT8 nvs_open (UINT8 bank, UINT8 mode, UINT16 offset); +INT8 nvs_close (UINT8 bank); +INT16 nvs_write (UINT8 bank, void* buffer, UINT16 size); +INT16 nvs_read (UINT8 bank, void* buffer, UINT16 size); +INT16 nvs_seek(UINT8 bank, UINT32 offset); +INT16 nvs_write_header (UINT8 bank,UINT32 svalue); +INT16 nvs_read_crc16 (UINT8 bank, UINT16* buffer, UINT16 size); +INT16 nvs_erase (UINT8 bank); + + + +void nvs_test (void); +#endif /* _H_NVS_ */ + diff --git a/src/components/ethermind/utils/include/nvsto.h b/src/components/ethermind/utils/include/nvsto.h new file mode 100644 index 0000000..6302c4f --- /dev/null +++ b/src/components/ethermind/utils/include/nvsto.h @@ -0,0 +1,287 @@ + +/** + \file nvsto.h + + +*/ + +/* + Copyright (C) 2013. Mindtree Limited. + All rights reserved. +*/ + +#ifndef _H_NVSTO_ +#define _H_NVSTO_ + +/* --------------------------------------------- Header File Inclusion */ +#include "EM_os.h" +#include "nvs.h" + +/* --------------------------------------------- Global Definitions */ +/** Number of partitions per bank in platform */ +#define NVSTO_NUM_PARTITIONS 5 + +/* --------------------------------------------- Structures/Data Types */ +/** NVSTO Handle type */ +typedef UINT8 NVSTO_HANDLE; + +/* --------------------------------------------- Macros */ +/** Persistent storage access wrappers */ +#define nvsto_register_ps(size, handle) \ + nvsto_register(NVS_BANK_PERSISTENT, (size), (handle)) + +#define nvsto_open_pswrite(handle) \ + nvsto_open(NVS_BANK_PERSISTENT, (handle), NVS_ACCESS_WRITE) + +#define nvsto_open_psread(handle) \ + nvsto_open(NVS_BANK_PERSISTENT, (handle), NVS_ACCESS_READ) + +#define nvsto_close_ps(handle) \ + nvsto_close(NVS_BANK_PERSISTENT, (handle)) + +#define nvsto_write_ps(handle, buffer, length) \ + nvsto_write(NVS_BANK_PERSISTENT, (handle), (buffer), (length)) + +#define nvsto_read_ps(handle, buffer, length) \ + nvsto_read(NVS_BANK_PERSISTENT, (handle), (buffer), (length)) + +#define nvsto_seek_ps(handle, offset) \ + nvsto_seek(NVS_BANK_PERSISTENT, (handle), (offset)) + +//by hq +#define nvsto_erase_ps(handle) \ + nvsto_erase(NVS_BANK_PERSISTENT, (handle)) + +#define nvsto_write_header_ps(handle,value) \ + nvsto_write_header(NVS_BANK_PERSISTENT, (handle),(value)) + +#define nvsto_read_crc16_ps(handle,buffer,length) \ + nvsto_read_crc16(NVS_BANK_PERSISTENT, (handle), (buffer),(length)) + + + + + +/* --------------------------------------------- Internal Functions */ + +/* --------------------------------------------- API Declarations */ +/** + \brief + + \Description + + + \param void + + \return void +*/ +void nvsto_init (UINT32 base1,UINT32 base2); + +/** + \brief + + \Description + + + \param void + + \return void +*/ +void nvsto_shutdown (void); + +/** + \fn nvsto_register + + \brief + + \Description + + + \param storage + \param size + \param handle + + \return void +*/ +INT8 nvsto_register +( + /* IN */ UINT8 storage, + /* IN */ UINT16 size, + /* OUT */ UINT8* handle +); + +/** + \fn nvsto_open + + \brief + + \Description + + + \param storage + \param handle + \param access + + \return void +*/ +INT16 nvsto_open +( + /* IN */ UINT8 storage, + /* IN */ UINT8 handle, + /* IN */ UINT8 access +); + +/** + \fn nvsto_close + + \brief + + \Description + + + \param storage + \param handle + + \return void +*/ +INT16 nvsto_close +( + /* IN */ UINT8 storage, + /* IN */ UINT8 handle +); + +/** + \fn nvsto_write + + \brief + + \Description + + + \param storage + \param handle + \param buffer + \param length + + \return Number of bytes written +*/ +INT16 nvsto_write +( + /* IN */ UINT8 storage, + /* IN */ UINT8 handle, + /* IN */ void* buffer, + /* IN */ UINT16 length +); + +/** + \fn nvsto_read + + \brief + + \Description + + + \param storage + \param handle + \param buffer + \param length + + \return Number of bytes read +*/ +INT16 nvsto_read +( + /* IN */ UINT8 storage, + /* IN */ UINT8 handle, + /* IN */ void* buffer, + /* IN */ UINT16 length +); + +/** + \fn nvsto_read_crc16 + + \brief + + \Description + + + \param storage + \param handle + \param buffer + \param length + + \return Number of bytes read +*/ +INT16 nvsto_read_crc16 +( + /* IN */ UINT8 storage, + /* IN */ UINT8 handle, + /* IN */ UINT16* buffer, + /* IN */ UINT16 length +); + + +/** + \fn nvsto_seek + + \brief + + \Description + + + \param storage + \param handle + \param offset + + \return void +*/ +INT16 nvsto_seek +( + /* IN */ UINT8 storage, + /* IN */ UINT8 handle, + /* IN */ UINT32 offset +); + + +//by hq +/** + \fn nvsto_write_flash + + \brief + + \Description + + + \param storage + \param handle + + \return void +*/ + +INT16 nvsto_erase +( + /* IN */ UINT8 storage, + /* IN */ UINT8 handle +); + +/** + \fn nvsto_erase + + \brief + + \Description + + + \param storage + \param handle + + \return void +*/ +INT16 nvsto_write_header +( + /* IN */ UINT8 storage, + /* IN */ UINT8 handle, + /* IN */ UINT32 value +); + +#endif /* _H_NVSTO_ */ + diff --git a/src/components/inc/bus_dev.h b/src/components/inc/bus_dev.h new file mode 100644 index 0000000..0aa693c --- /dev/null +++ b/src/components/inc/bus_dev.h @@ -0,0 +1,95 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: bus_dev.h + Revised: + Revision: + + Description: This file contains the SoC MCU relate definitions + + **************************************************************************************************/ + +#ifndef __BUS_DEV_H__ +#define __BUS_DEV_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "mcu.h" + +enum +{ + RSTC_COLD_UP = 0, + RSTC_WARM_UP = 1, + RSTC_OFF_MODE = 2, + RSTC_WAKE_IO = 3, + RSTC_WAKE_RTC = 4, + RSTC_WARM_NDWC = 5 //user mode, no dwc + +}; + +/* ------------------------- Interrupt Number Definition ------------------------ */ + +typedef enum IRQn +{ + /* ------------------- Cortex-M0 Processor Exceptions Numbers ------------------- */ + NonMaskableInt_IRQn = -14, /* 2 Non Maskable Interrupt */ + HardFault_IRQn = -13, /* 3 HardFault Interrupt */ + + + + SVCall_IRQn = -5, /* 11 SV Call Interrupt */ + + PendSV_IRQn = -2, /* 14 Pend SV Interrupt */ + SysTick_IRQn = -1, /* 15 System Tick Interrupt */ + + /* ---------------------- PHY BUMBEE M0 Interrupt Numbers --------------------- */ + BB_IRQn = 4, /* Base band Interrupt */ + KSCAN_IRQn = 5, /* Key scan Interrupt */ + RTC_IRQn = 6, /* RTC Timer Interrupt */ + + WDT_IRQn = 10, /* Watchdog Timer Interrupt */ + UART0_IRQn = 11, /* UART0 Interrupt */ + I2C0_IRQn = 12, /* I2C0 Interrupt */ + I2C1_IRQn = 13, /* I2C1 Interrupt */ + SPI0_IRQn = 14, /* SPI0 Interrupt */ + SPI1_IRQn = 15, /* SPI1 Interrupt */ + GPIO_IRQn = 16, /* GPIO Interrupt */ + UART1_IRQn = 17, /* UART1 Interrupt */ + SPIF_IRQn = 18, /* SPIF Interrupt */ + DMAC_IRQn = 19, /* DMAC Interrupt */ + TIM1_IRQn = 20, /* Timer1 Interrupt */ + TIM2_IRQn = 21, /* Timer2 Interrupt */ + TIM3_IRQn = 22, /* Timer3 Interrupt */ + TIM4_IRQn = 23, /* Timer4 Interrupt */ + TIM5_IRQn = 24, /* Timer5 Interrupt */ + TIM6_IRQn = 25, /* Timer6 Interrupt */ + + AES_IRQn = 28, /* AES Interrupt */ + ADCC_IRQn = 29, /* ADC Interrupt */ + QDEC_IRQn = 30, /* QDEC Interrupt */ + RNG_IRQn = 31 /* RNG Interrupt */ +} IRQn_Type; + + + + +#if (PHY_MCU_TYPE == MCU_BUMBEE_M0) +#define ATTRIBUTE_ISR +#include "core_bumbee_m0.h" +#endif +#if(PHY_MCU_TYPE == MCU_BUMBEE_CK802) +#define ATTRIBUTE_ISR __attribute__((isr)) +#include "core_802.h" +#endif + +#if (PHY_MCU_TYPE == MCU_BUMBEE_M0 || PHY_MCU_TYPE == MCU_BUMBEE_CK802) +#include "mcu_phy_bumbee.h" +#elif ((PHY_MCU_TYPE == MCU_PRIME_A1) ||(PHY_MCU_TYPE == MCU_PRIME_A2)) +#include "mcu_phy_prime.h" +#endif + +#endif diff --git a/src/components/inc/error.h b/src/components/inc/error.h new file mode 100644 index 0000000..9ef51d3 --- /dev/null +++ b/src/components/inc/error.h @@ -0,0 +1,78 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +/******************************************************************************* + @file error.h + @brief Global error definition + @version 0.0 + @date 11. Feb. 2018 + @author Eagle.Lao + + + +*******************************************************************************/ + +#ifndef _PPLUS_ERROR_H +#define _PPLUS_ERROR_H + +#define PPlus_SUCCESS (0) /*Success*/ +#define PPlus_ERR_FATAL (1) /*unrecoverable error*/ +#define PPlus_ERR_INTERNAL (2) /*Internal Error*/ +#define PPlus_ERR_NO_MEM (3) /*No Memory for operation*/ +#define PPlus_ERR_NOT_FOUND (4) /*Not found*/ +#define PPlus_ERR_NOT_SUPPORTED (5) /*Not supported*/ +#define PPlus_ERR_INVALID_PARAM (6) /*Invalid Parameter*/ +#define PPlus_ERR_INVALID_STATE (7) /*Invalid state, operation disallowed in this state*/ +#define PPlus_ERR_INVALID_LENGTH (8) /*Invalid Length*/ +#define PPlus_ERR_INVALID_FLAGS (9) /*Invalid Flags*/ +#define PPlus_ERR_INVALID_DATA (10) /*Invalid Data*/ +#define PPlus_ERR_DATA_SIZE (11) /*Data size exceeds limit*/ +#define PPlus_ERR_DATA_ALIGN (12) /*Data alignment is not correct*/ +#define PPlus_ERR_TIMEOUT (13) /*Operation timed out*/ +#define PPlus_ERR_NULL (14) /*Null Pointer*/ +#define PPlus_ERR_FORBIDDEN (15) /*Forbidden Operation*/ +#define PPlus_ERR_INVALID_ADDR (16) /*Bad Memory Address*/ +#define PPlus_ERR_BUSY (17) /*Busy*/ +#define PPlus_ERR_NOT_REGISTED (18) /*not registed*/ +#define PPlus_ERR_IO_CONFILCT (19) /*IO config error*/ +#define PPlus_ERR_IO_FAIL (20) /*IO fail error*/ +#define PPlus_ERR_NOT_IMPLEMENTED (22) /*Function is not provide now*/ +#define PPlus_ERR_SPI_FLASH (23) /*spi falsh operation error*/ +#define PPlus_ERR_UNINITIALIZED (24) +#define PPlus_ERR_FS_WRITE_FAILED (31) +#define PPlus_ERR_FS_CONTEXT (32) +#define PPlus_ERR_FS_FULL (33) +#define PPlus_ERR_FS_PARAMETER (34) +#define PPlus_ERR_FS_NOT_ENOUGH_SIZE (35) +#define PPlus_ERR_FS_EXIST_SAME_ID (36) +#define PPlus_ERR_FS_NOT_FIND_ID (37) +#define PPlus_ERR_FS_BUFFER_TOO_SMALL (38) +#define PPlus_ERR_FS_UNINITIALIZED (39) +#define PPlus_ERR_FS_HAVE_INITED (40) +#define PPlus_ERR_FS_IN_INT (41) +#define PPlus_ERR_FS_RESERVED_ERROR (42) +#define PPlus_ERR_VERSION (43) +#define PPlus_ERR_NO_DEV (44) + +#define PPlus_ERR_SECURE_CRYPTO (50) +#define PPlus_ERR_ACCESS_REJECTED (51) + + +#define PPlus_ERR_BLE_NOT_READY (80) /*BLE not ready error*/ +#define PPlus_ERR_BLE_BUSY (81) /*BLE operation failed becuase of busy*/ +#define PPlus_ERR_BLE_FAIL (82) /*BLE operation failed*/ + +#define PPlus_ERR_OTA_INVALID_STATE (100) /*state machine error when OTA*/ +#define PPlus_ERR_OTA_DATA_SIZE (101) /*data size is not correct*/ +#define PPlus_ERR_OTA_CRC (102) /*bad checksum(crc)*/ +#define PPlus_ERR_OTA_NO_APP (103) /*No application data*/ +#define PPlus_ERR_OTA_BAD_DATA (104) /*bad application data*/ +#define PPlus_ERR_OTA_UNKNOW_CMD (105) /*unknow command*/ +#define PPlus_ERR_OTA_CRYPTO (106) /*crypto verify error*/ +#define PPlus_ERR_KEY_VERIFY (107) /*security boot key verify fail*/ +#define PPlus_ERR_DOUBLE_CONFIRM (108) /*security boot double key verify fail*/ +#define PPlus_ERR_OTA_MIC (109) /*bad checksum(mic)*/ +#endif + diff --git a/src/components/inc/global_config.h b/src/components/inc/global_config.h new file mode 100644 index 0000000..236d726 --- /dev/null +++ b/src/components/inc/global_config.h @@ -0,0 +1,207 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/** + **************************************************************************************** + + @file global_config.h + + @brief This file contains the definitions of index of global configuration which + will be configured in APP project. + + + $Rev: $ + + **************************************************************************************** +*/ + + +#ifndef _GLOBAL_CONFIG_H_ +#define _GLOBAL_CONFIG_H_ + +#include "types.h" + +/******************************************************************************* + software configuration parameters definition +*/ + +#define CONFIG_BASE_ADDR 0x1fff0400 + +#define SOFT_PARAMETER_NUM 256 +// parameter index of configuration array +#define ADV_CHANNEL_INTERVAL 0 // interval between adv channel in the same adv event +#define SCAN_RSP_DELAY 1 // to adjust scan req -> scan rsp delay +#define CONN_REQ_TO_SLAVE_DELAY 2 // to calibrate the delay between conn req & 1st slave conn event +#define SLAVE_CONN_DELAY 3 // to adjust the delay between 2 slave connection events +#define SLAVE_CONN_DELAY_BEFORE_SYNC 4 // to adjust the delay between 2 slave connection events before 1st anchor is acquired +#define MAX_SLEEP_TIME 5 // maximum sleep time in us +#define MIN_SLEEP_TIME 6 // minimum sleep time in us +#define WAKEUP_ADVANCE 7 // wakeup advance time, to cover HW delay, crystal settle time, sw delay, ... etc. +#define WAKEUP_DELAY 8 // cycles of SW delay to wait crystal settle + +#define HDC_DIRECT_ADV_INTERVAL 9 +#define LDC_DIRECT_ADV_INTERVAL 10 + + +#define LL_SWITCH 11 // Link Layer switch, 1 enable, 0 disable +#define NON_ADV_CHANNEL_INTERVAL 12 // interval between non-adv channel in the same adv event + +#define CLOCK_SETTING 14 // HCLK +#define LL_HW_BB_DELAY 15 +#define LL_HW_AFE_DELAY 16 +#define LL_HW_PLL_DELAY 17 + +#define LL_HW_RTLP_LOOP_TIMEOUT 18 +#define LL_HW_RTLP_1ST_TIMEOUT 19 + +#define MIN_TIME_TO_STABLE_32KHZ_XOSC 20 + +#define LL_TX_PKTS_PER_CONN_EVT 21 +#define LL_RX_PKTS_PER_CONN_EVT 22 + + +// ============= A1 ROM metal change add +#define DIR_ADV_DELAY 23 + + +#define LL_TX_PWR_TO_REG_BIAS 24 + + +#define LL_SMART_WINDOW_COEF_ALPHA 25 +#define LL_SMART_WINDOW_TARGET 26 +#define LL_SMART_WINDOW_INCREMENT 27 +#define LL_SMART_WINDOW_LIMIT 28 +#define LL_SMART_WINDOW_ACTIVE_THD 29 +#define LL_SMART_WINDOW_ACTIVE_RANGE 30 + +#define LL_SMART_WINDOW_FIRST_WINDOW 31 + +#define LL_HW_Tx_TO_RX_INTV 32 +#define LL_HW_Rx_TO_TX_INTV 33 + +#define INITIAL_STACK_PTR 34 +#define ALLOW_TO_SLEEP_TICK_RC32K 35 + +#define LL_HW_BB_DELAY_ADV 36 +#define LL_HW_AFE_DELAY_ADV 37 +#define LL_HW_PLL_DELAY_ADV 38 + +// For scan & master, add 2018-6-15 +#define LL_ADV_TO_SCAN_REQ_DELAY 39 +#define LL_ADV_TO_CONN_REQ_DELAY 40 + +#define LL_MOVE_TO_MASTER_DELAY 41 + +#define LL_HW_TRLP_LOOP_TIMEOUT 42 + +#define LL_CONN_REQ_WIN_SIZE 43 +#define LL_CONN_REQ_WIN_OFFSET 44 + +#define LL_MASTER_PROCESS_TARGET 45 +#define LL_MASTER_TIRQ_DELAY 46 + + +#define LL_HW_BB_DELAY_2MPHY 47 +#define LL_HW_AFE_DELAY_2MPHY 48 +#define LL_HW_PLL_DELAY_2MPHY 49 + +#define LL_HW_Tx_TO_RX_INTV_2MPHY 50 +#define LL_HW_Rx_TO_TX_INTV_2MPHY 51 + +#define LL_HW_BB_DELAY_500KPHY 52 +#define LL_HW_AFE_DELAY_500KPHY 53 +#define LL_HW_PLL_DELAY_500KPHY 54 + +#define LL_HW_Tx_TO_RX_INTV_500KPHY 55 +#define LL_HW_Rx_TO_TX_INTV_500KPHY 56 + +#define LL_HW_BB_DELAY_125KPHY 57 +#define LL_HW_AFE_DELAY_125KPHY 58 +#define LL_HW_PLL_DELAY_125KPHY 59 + +#define LL_HW_Tx_TO_RX_INTV_125KPHY 60 +#define LL_HW_Rx_TO_TX_INTV_125KPHY 61 + +#define LL_HW_TRLP_TO_GAP 62 +#define LL_HW_RTLP_TO_GAP 63 + +#define LL_TRX_NUM_ADAPTIVE_CONFIG 64 +#define OSAL_SYS_TICK_WAKEUP_TRIM 65 + +// ==== A2 add, for secondary adv/scan +#define LL_NOCONN_ADV_EST_TIME 70 +#define LL_NOCONN_ADV_MARGIN 71 +#define LL_SEC_SCAN_MARGIN 72 +#define LL_MIN_SCAN_TIME 73 +// Bumblebee ROM code +#define LL_CONN_ADV_EST_TIME 74 +#define LL_SCANABLE_ADV_EST_TIME 75 + + + +#define MAC_ADDRESS_LOC 80 + +// ==== For Extended Adv & Periodic adv +#define LL_EXT_ADV_INTER_PRI_CHN_INT 81 +#define LL_EXT_ADV_INTER_AUX_CHN_INT 82 +#define LL_EXT_ADV_RSC_POOL_PERIOD 83 +#define LL_EXT_ADV_RSC_POOL_UNIT 84 + +#define LL_EXT_ADV_TASK_DURATION 86 +#define LL_PRD_ADV_TASK_DURATION 87 +#define LL_CONN_TASK_DURATION 88 + +#define TIMER_ISR_ENTRY_TIME 90 // time from HW timer expiry to ISR entry, unit: us +#define LL_MULTICONN_MASTER_PREEMP 91 +#define LL_MULTICONN_SLAVE_PREEMP 92 + +#define LL_EXT_ADV_INTER_SEC_CHN_INT 93 +#define LL_EXT_ADV_PRI_2_SEC_CHN_INT 94 + +#define LL_EXT_ADV_RSC_PERIOD 95 +#define LL_EXT_ADV_RSC_SLOT_DURATION 96 + +#define LL_PRD_ADV_RSC_PERIOD 97 +#define LL_PRD_ADV_RSC_SLOT_DURATION 98 + +#define LL_EXT_ADV_PROCESS_TARGET 99 +#define LL_PRD_ADV_PROCESS_TARGET 100 + + + + + + + + + +// ============== + +#define RC32_TRACKINK_ALLOW 0x00000001 // enable tracking RC 32KHz clock with 16MHz hclk +#define SLAVE_LATENCY_ALLOW 0x00000002 // slave latency allow switch +#define LL_DEBUG_ALLOW 0x00000004 // enable invoke RAM project debug output fucntion +#define LL_WHITELIST_ALLOW 0x00000008 // enable whitelist filter +#define LL_RC32K_SEL 0x00000010 // select RC32K RTC, otherwise select crystal 32K RTC +#define SIMUL_CONN_ADV_ALLOW 0x00000020 // allow send adv in connect state +#define SIMUL_CONN_SCAN_ALLOW 0x00000040 // allow scan in connect state + +#define CONN_CSA2_ALLOW 0x00000080 // allow using CSA2 in connection state + +#define GAP_DUP_RPT_FILTER_DISALLOW 0x00000100 // duplicate report filter in GAP layer, allow default +#define ENH_CONN_CMP_EVENT_ALLOW 0x00000200 // allow LL to send enhanced connection complete event. +// delete 2018-7-17, should use enum H_SYSCLK_SEL +//enum +//{ +// CLOCK_16MHZ = 0, +// CLOCK_32MHZ = 1, +// CLOCK_48MHZ = 2, +// CLOCK_64MHZ = 3, +// CLOCK_96MHZ = 4, +// CLOCK_32MHZ_DBL=5 +//}; + +//extern uint32 global_config[SOFT_PARAMETER_NUM]; +extern uint32* pGlobal_config; // note: app project needn't this variable + +#endif // _GLOBAL_CONFIG_H_ diff --git a/src/components/inc/mcu.h b/src/components/inc/mcu.h new file mode 100644 index 0000000..db0f226 --- /dev/null +++ b/src/components/inc/mcu.h @@ -0,0 +1,90 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: bus_dev.h + Revised: + Revision: + + Description: Describe the purpose and contents of the file. + + + +**************************************************************************************************/ + +#ifndef _HAL_MCU_H +#define _HAL_MCU_H + + + +/* ------------------------------------------------------------------------------------------------ + Includes + ------------------------------------------------------------------------------------------------ +*/ +#include "types.h" +#include + +//enum{ +// MCU_UNDEF = 0, +// MCU_PRIME_A1 = 1, +// MCU_PRIME_A2 = 2, +// MCU_BUMBEE_M0, +// MCU_BUMBEE_CK802 +//}; + +#define MCU_UNDEF 0 +#define MCU_PRIME_A1 1 +#define MCU_PRIME_A2 2 +#define MCU_BUMBEE_M0 3 +#define MCU_BUMBEE_CK802 4 + + +#define SRAM_BASE_ADDR 0x1fff0000 +#define SRAM_END_ADDR 0x1fffffff + +#define ROM_SRAM_JUMPTABLE SRAM_BASE_ADDR +#define ROM_SRAM_GLOBALCFG (ROM_SRAM_JUMPTABLE+0x400) +#define ROM_SRAM_JUMPTABLE_MIRROR 0x1fffd000 +#define ROM_SRAM_GLOBALCFG_MIRROR (ROM_SRAM_JUMPTABLE_MIRROR+0x400) + +#define ROM_SRAM_HEAP 0x1fffe000 +#define ROM_SRAM_HEAP_SIZE (1024*8) +#define ROM_SRAM_DWC_BUF 0x1ffffc00 + + +#define APP_SRAM_START_ADDR 0x1fff2000 + + +/* ------------------------------------------------------------------------------------------------ + Target Defines + ------------------------------------------------------------------------------------------------ +*/ + +#define MAXMEMHEAP 4096 + +#define HAL_ISER *((volatile uint32_t *)(0xe000e100)) +#define HAL_ICER *((volatile uint32_t *)(0xe000e180)) + +//subWriteReg: write value to register zone: bit[high:low] +#define subWriteReg(addr,high,low,value) write_reg(addr,read_reg(addr)&\ + (~((((unsigned int)1<<((high)-(low)+1))-1)<<(low)))|\ + ((unsigned int)(value)<<(low))) + +#define TIME_BASE (0x003fffff) // 24bit count shift 2 bit as 1us/bit +#define TIME_DELTA(x,y) ( (x>=y) ? x-y : TIME_BASE-y+x ) + + +extern void drv_irq_init(void); +extern int drv_enable_irq(void); +extern int drv_disable_irq(void); + +#define HAL_CRITICAL_SECTION_INIT() drv_irq_init() +#define HAL_ENTER_CRITICAL_SECTION() drv_disable_irq() +#define HAL_EXIT_CRITICAL_SECTION() drv_enable_irq() + + + +/************************************************************************************************** +*/ +#endif diff --git a/src/components/inc/mcu_phy_bumbee.h b/src/components/inc/mcu_phy_bumbee.h new file mode 100644 index 0000000..b52892f --- /dev/null +++ b/src/components/inc/mcu_phy_bumbee.h @@ -0,0 +1,850 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ +#ifndef __MCU_BUMBEE_M0__ +#define __MCU_BUMBEE_M0__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "types.h" + +typedef enum +{ + MOD_NONE = 0, MOD_CK802_CPU = 0, + MOD_DMA = 3, + MOD_AES = 4, + MOD_IOMUX = 7, + MOD_UART0 = 8, + MOD_I2C0 = 9, + MOD_I2C1 = 10, + MOD_SPI0 = 11, + MOD_SPI1 = 12, + MOD_GPIO = 13, + MOD_QDEC = 15, + MOD_ADCC = 17, + MOD_PWM = 18, + MOD_SPIF = 19, + MOD_VOC = 20, + MOD_TIMER5 = 21, + MOD_TIMER6 = 22, + MOD_UART1 = 25, + + MOD_CP_CPU = 0+32, + MOD_BB = MOD_CP_CPU+3, + MOD_TIMER = MOD_CP_CPU+4, + MOD_WDT = MOD_CP_CPU+5, + MOD_COM = MOD_CP_CPU+6, + MOD_KSCAN = MOD_CP_CPU+7, + MOD_BBREG = MOD_CP_CPU+9, + BBLL_RST = MOD_CP_CPU+10,//can reset,but not gate in here + BBTX_RST = MOD_CP_CPU+11,//can reset,but not gate in here + BBRX_RST = MOD_CP_CPU+12,//can reset,but not gate in here + BBMIX_RST = MOD_CP_CPU+13,//can reset,but not gate in here + MOD_TIMER1 = MOD_CP_CPU+21, + MOD_TIMER2 = MOD_CP_CPU+22, + MOD_TIMER3 = MOD_CP_CPU+23, + MOD_TIMER4 = MOD_CP_CPU+24, + + MOD_PCLK_CACHE = 0+64, + MOD_HCLK_CACHE = MOD_PCLK_CACHE+1, + + MOD_USR0 = 0+96, + MOD_USR1 = MOD_USR0+1, + MOD_USR2 = MOD_USR0+2, + MOD_USR3 = MOD_USR0+3, + MOD_USR4 = MOD_USR0+4, + MOD_USR5 = MOD_USR0+5, + MOD_USR6 = MOD_USR0+6, + MOD_USR7 = MOD_USR0+7, + MOD_USR8 = MOD_USR0+8, + MOD_SYSTEM = 0xFF, +} MODULE_e; + +//SW_CLK -->0x4000f008 +#define _CLK_NONE (BIT(0)) +#define _CLK_CK802_CPU (BIT(0)) +#define _CLK_DMA (BIT(3)) +#define _CLK_AES (BIT(4)) +#define _CLK_IOMUX (BIT(7)) +#define _CLK_UART0 (BIT(8)) +#define _CLK_I2C0 (BIT(9)) +#define _CLK_I2C1 (BIT(10)) +#define _CLK_SPI0 (BIT(11)) +#define _CLK_SPI1 (BIT(12)) +#define _CLK_GPIO (BIT(13)) +#define _CLK_QDEC (BIT(15)) +#define _CLK_ADCC (BIT(17)) +#define _CLK_PWM (BIT(18)) +#define _CLK_SPIF (BIT(19)) +#define _CLK_VOC (BIT(20)) +#define _CLK_TIMER5 (BIT(21)) +#define _CLK_TIMER6 (BIT(22)) +#define _CLK_UART1 (BIT(25)) + + +//SW_CLK1 -->0x4000f014 +#define _CLK_M0_CPU (BIT(0)) +#define _CLK_BB (BIT(3)) +#define _CLK_TIMER (BIT(4)) +#define _CLK_WDT (BIT(5)) +#define _CLK_COM (BIT(6)) +#define _CLK_KSCAN (BIT(7)) +#define _CLK_BBREG (BIT(9)) +#define _CLK_TIMER1 (BIT(21)) +#define _CLK_TIMER2 (BIT(22)) +#define _CLK_TIMER3 (BIT(23)) +#define _CLK_TIMER4 (BIT(24)) + +#define BB_IRQ_HANDLER V4_IRQ_HANDLER +#define KSCAN_IRQ_HANDLER V5_IRQ_HANDLER +#define RTC_IRQ_HANDLER V6_IRQ_HANDLER +#define CP_COM_IRQ_HANDLER V7_IRQ_HANDLER +#define AP_COM_IRQ_HANDLER V8_IRQ_HANDLER +#define WDT_IRQ_HANDLER V10_IRQ_HANDLER +#define UART0_IRQ_HANDLER V11_IRQ_HANDLER +#define I2C0_IRQ_HANDLER V12_IRQ_HANDLER +#define I2C1_IRQ_HANDLER V13_IRQ_HANDLER +#define SPI0_IRQ_HANDLER V14_IRQ_HANDLER +#define SPI1_IRQ_HANDLER V15_IRQ_HANDLER +#define GPIO_IRQ_HANDLER V16_IRQ_HANDLER +#define UART1_IRQ_HANDLER V17_IRQ_HANDLER +#define SPIF_IRQ_HANDLER V18_IRQ_HANDLER +#define DMAC_IRQ_HANDLER V19_IRQ_HANDLER +#define TIM1_IRQ_HANDLER V20_IRQ_HANDLER +#define TIM2_IRQ_HANDLER V21_IRQ_HANDLER +#define TIM3_IRQ_HANDLER V22_IRQ_HANDLER +#define TIM4_IRQ_HANDLER V23_IRQ_HANDLER +#define TIM5_IRQ_HANDLER V24_IRQ_HANDLER +#define TIM6_IRQ_HANDLER V25_IRQ_HANDLER +#define AES_IRQ_HANDLER V28_IRQ_HANDLER +#define ADCC_IRQ_HANDLER V29_IRQ_HANDLER +#define QDEC_IRQ_HANDLER V30_IRQ_HANDLER + +/******************************************************************************* + TYPEDEFS +*/ +/******************************************************************************/ +/* Device Specific Peripheral registers structures */ +/******************************************************************************/ +typedef struct +{ + __IO uint32_t CH0_AP_MBOX; //0x00 + __IO uint32_t CH0_CP_MBOX; //0x04 + __IO uint32_t CH1_AP_MBOX; //0x08 + __IO uint32_t CH1_CP_MBOX; //0x0c + __IO uint32_t AP_STATUS; //0x10 + __IO uint32_t CP_STATUS; //0x14 + __IO uint32_t AP_INTEN; //0x18 + __IO uint32_t CP_INTEN; //0x1c + __IO uint32_t remap; //0x20 + __IO uint32_t RXEV_EN; //0x24 + __IO uint32_t STCALIB; //0x28 + __IO uint32_t PERI_MASTER_SELECT; //0x2c +} AP_COM_TypeDef; + +typedef struct +{ + __IO uint32_t CTRL0;//0x40 + __IO uint32_t CTRL1;//0x44 + uint32_t reserverd[13]; + __IO uint32_t REMAP_TABLE;//0x7c + __IO uint32_t REMAP_CTRL[32];//0x80 +} AP_CACHE_TypeDef; + +typedef struct +{ + __IO uint8_t CR; //0x0 + uint8_t RESERVED0[3]; + __IO uint32_t TORR; //0x4 + __O uint32_t CCVR; //0x8 + __IO uint32_t CRR; //0xc + uint8_t STAT; //0x10 + uint8_t reserverd1[3]; + __IO uint8_t EOI; //0x14 + uint8_t reserverd2[3]; +} AP_WDT_TypeDef; + + + +typedef struct +{ + __IO uint32_t SW_RESET0; //0x0 + __IO uint32_t SW_RESET1; //0x4 + __IO uint32_t SW_CLK; //0x8 + __IO uint32_t SW_RESET2; //0xc + __IO uint32_t SW_RESET3; //0x10 + __IO uint32_t SW_CLK1; //0x14 + __IO uint32_t APB_CLK; //0x18 + __IO uint32_t APB_CLK_UPDATE; //0x1c + __IO uint32_t CACHE_CLOCK_GATE;//0x20 + __IO uint32_t CACHE_RST;//0x24 + __IO uint32_t CACHE_BYPASS;//0x28 +} AP_PCR_TypeDef; + +typedef struct +{ + __IO uint32_t LoadCount; //0x0 + __IO uint32_t CurrentCount; //0x4 + __IO uint32_t ControlReg; //0x8 + __IO uint32_t EOI; //0xc + __IO uint32_t status; //0x10 + +} AP_TIM_TypeDef; + +typedef struct +{ + __IO uint32_t IntStatus; + __IO uint32_t EOI; + __IO uint32_t unMaskIntStatus; + __IO uint32_t version; +} AP_TIM_SYS_TypeDef; + + +#if defined ( __CC_ARM ) +#pragma anon_unions +#endif + +/*------------- Universal Asynchronous Receiver Transmitter (UARTx) -----------*/ + +typedef struct +{ + union + { + __I uint8_t RBR; + __IO uint8_t THR; + __IO uint8_t DLL; + uint32_t RESERVED0; //0x0 + }; + union + { + __IO uint8_t DLM; + __IO uint32_t IER; //0x4 + }; + union + { + __I uint32_t IIR; //0x8 + __IO uint8_t FCR; + }; + __IO uint8_t LCR; //0xc + uint8_t RESERVED1[3];//Reserved + __IO uint32_t MCR; //0x10 + + __I uint8_t LSR; //0x14 + uint8_t RESERVED2[3];//Reserved + __IO uint32_t MSR; //0x18 + + __IO uint8_t SCR; //0x1c + uint8_t RESERVED3[3];//Reserved + + __IO uint32_t LPDLL; //0x20 + + __IO uint32_t LPDLH; //0x24 + + __IO uint32_t recerved[2]; + + union + { + __IO uint32_t SRBR[16]; // 0x30~60xc + __IO uint32_t STHR[16]; + }; + __IO uint32_t FAR; //0x70 + + __IO uint32_t TFR; //0x74 + + __IO uint32_t RFW; // 0x78 + + __IO uint32_t USR; // 0x7c + + __IO uint32_t TFL; + + __IO uint32_t RFL; + + __IO uint32_t SRR; + + __IO uint32_t SRTS; + + __IO uint32_t SBCR; + + __IO uint32_t SDMAM; + + __IO uint32_t SFE; + + __IO uint32_t SRT; + + __IO uint32_t STET; //0xa0 + + __IO uint32_t HTX; + + __IO uint32_t DMASA; //0xa8 + + __IO uint32_t reserved[18]; + + __IO uint32_t CPR; //0xf4 + + __IO uint32_t UCV; + + __IO uint32_t CTR; + +} AP_UART_TypeDef; + + +/*------------- Inter-Integrated Circuit (I2C) setup by zjp-------------------------------*/ +typedef struct +{ + __IO uint32_t IC_CON; + __IO uint32_t IC_TAR; + __IO uint32_t IC_SAR; + __IO uint32_t IC_HS_MADDR; + __IO uint32_t IC_DATA_CMD; //0x10 + __IO uint32_t IC_SS_SCL_HCNT; + __IO uint32_t IC_SS_SCL_LCNT; + __IO uint32_t IC_FS_SCL_HCNT; + __IO uint32_t IC_FS_SCL_LCNT; //0x20 + __IO uint32_t IC_HS_SCL_HCNT; + __IO uint32_t IC_HS_SCL_LCNT; + __IO uint32_t IC_INTR_STAT; + __IO uint32_t IC_INTR_MASK; //0x30 + __IO uint32_t IC_RAW_INTR_STAT; + __IO uint32_t IC_RX_TL; + __IO uint32_t IC_TX_TL; + __IO uint32_t IC_CLR_INTR; //0x40 + __IO uint32_t IC_CLR_UNDER; + __IO uint32_t IC_CLR_RX_OVER; + __IO uint32_t IC_CLR_TX_OVER; + __IO uint32_t IC_CLR_RD_REG; //0x50 + __IO uint32_t IC_CLR_TX_ABRT; + __IO uint32_t IC_CLR_RX_DONE; + __IO uint32_t IC_CLR_ACTIVITY; + __IO uint32_t IC_CLR_STOP_DET; //0x60 + __IO uint32_t IC_CLR_START_DET; + __IO uint32_t IC_CLR_GEN_CALL; + __IO uint32_t IC_ENABLE; + __IO uint32_t IC_STATUS; //0x70 + __IO uint32_t IC_TXFLR; + __IO uint32_t IC_RXFLR; + __IO uint32_t IC_SDA_HOLD; + __IO uint32_t IC_TX_ABRT_SOURCE; //0x80 + __IO uint32_t IC_SLV_DATA_NACK_ONLY; + __IO uint32_t IC_DMA_CR; + __IO uint32_t IC_DMA_TDLR; + __IO uint32_t IC_DMA_RDLR; //0x90 + __IO uint32_t IC_SDA_SETUP; + __IO uint32_t IC_ACK_GENERAL_CALL; + __IO uint32_t IC_ENABLE_STATUS; + __IO uint32_t IC_FS_SPKLEN; //0xa0 + __IO uint32_t IC_HS_SPKLEN; + +} AP_I2C_TypeDef; + + +/*------------- Inter IC Sound (I2S) -----------------------------------------*/ +typedef struct +{ + __IO uint32_t IER; + __IO uint32_t IRER; + __IO uint32_t ITER; + __IO uint32_t CER; + __IO uint32_t CCR; + __IO uint32_t RXFFR; + __IO uint32_t TXFFR; + +} AP_I2S_BLOCK_TypeDef; + +typedef struct +{ + union + { + __IO uint32_t LRBR; //0x20 + __IO uint32_t LTHR; //0x20 + }; + union + { + __IO uint32_t RRBR; // 0x24 + __IO uint32_t RTHR; //0x24 + }; + __IO uint32_t RER; //0x28 + __IO uint32_t TER; //0x2c + __IO uint32_t RCR; //0x30 + __IO uint32_t TCR; //0x34 + __IO uint32_t ISR; //0x38 + __IO uint32_t IMR; //0x3c + __IO uint32_t ROR; //0x40 + __IO uint32_t TOR; //0x44 + __IO uint32_t RFCR; //0x48 + __IO uint32_t TFCR; //0x4c + __IO uint32_t RFF; //0x50 + __IO uint32_t TFF; //0x54 + +} AP_I2S_TypeDef; + + +/*------------- General Purpose Input/Output (GPIO) --------------------------*/ +typedef struct +{ + __IO uint32_t swporta_dr; //0x00 + __IO uint32_t swporta_ddr; //0x04 + __IO uint32_t swporta_ctl; //0x08 + uint32_t reserved8[9]; //0x18-0x2c portC&D + __IO uint32_t inten; //0x30 + __IO uint32_t intmask; //0x34 + __IO uint32_t inttype_level; //0x38 + __IO uint32_t int_polarity; //0x3c + __I uint32_t int_status; //0x40 + __IO uint32_t raw_instatus; //0x44 + __IO uint32_t debounce; //0x48 + __O uint32_t porta_eoi; //0x4c + __I uint32_t ext_porta; //0x50 + uint32_t reserved9[3]; //0x58 0x5c + __IO uint32_t ls_sync; //0x60 + __I uint32_t id_code; //0x64 + uint32_t reserved10[1]; //0x68 + __I uint32_t ver_id_code; //0x6c + __I uint32_t config_reg2; //0x70 + __I uint32_t config_reg1; //0x74 +} AP_GPIO_TypeDef; + + +/*-------------------- (SPI) --------------------------------*/ +typedef struct +{ + __IO uint16_t CR0; //0x0 /*!< Offset: 0x000 Control Register 0 (R/W) */ + uint16_t reserved1; + __IO uint16_t CR1; //0x04 /*!< Offset: 0x004 Control Register 1 (R/W) */ + uint16_t reserved2; + __IO uint8_t SSIEN; //0x08 + uint8_t reserved3[3]; + __IO uint8_t MWCR; // 0x0c + uint8_t reserved4[3]; + __IO uint8_t SER; //0x10 + uint8_t reserved5[3]; + __IO uint32_t BAUDR; //0x14 + __IO uint32_t TXFTLR; //0x18 + __IO uint32_t RXFTLR; //0x1c + __O uint32_t TXFLR; //0x20 + __O uint32_t RXFLR; //0x24 + + __IO uint8_t SR; //0x28 + uint8_t reserved7[3]; + __IO uint32_t IMR; //0x2c + __IO uint32_t ISR; //0x30 + __IO uint32_t RISR; //0x34 + __IO uint32_t TXOICR; //0x38 + __IO uint32_t RXOICR; //0x3c + __IO uint32_t RXUICR; //0x40 + __IO uint32_t MSTICR; //0x44 + __IO uint32_t ICR; //0x48 + __IO uint32_t DMACR; //0x4c + __IO uint32_t DMATDLR; //0x50 + __IO uint32_t DMARDLR; //0x54 + __IO uint32_t IDR; //0x5c + __IO uint32_t SSI_COM_VER; //0x5c + __IO uint32_t DataReg; + +} AP_SSI_TypeDef; + + +typedef struct +{ + __IO uint32_t Analog_IO_en;//0x00 + __IO uint32_t SPI_debug_en;//0x04 + __IO uint32_t debug_mux_en;//0x08 + __IO uint32_t full_mux0_en;//0x0c + __IO uint32_t full_mux1_en;//0x10 reserved in some soc + __IO uint32_t gpio_pad_en; //0x14 + __IO uint32_t gpio_sel[9]; //0x18 + __IO uint32_t pad_pe0;//0x3c + __IO uint32_t pad_pe1;//0x40 + __IO uint32_t pad_ps0;//0x44 + __IO uint32_t pad_ps1;//0x48 + __IO uint32_t keyscan_in_en;//0x4c + __IO uint32_t keyscan_out_en;//0x50 +} IOMUX_TypeDef; + + +typedef struct +{ + __IO uint32_t PWROFF; //0x00 + __IO uint32_t PWRSLP; //0x04 + __IO uint32_t IOCTL[3]; //0x08 0x0c 0x10 + __IO uint32_t PMCTL0; //0x14 + __IO uint32_t PMCTL1; //0x18 + __IO uint32_t PMCTL2_0; //0x1c + __IO uint32_t PMCTL2_1; //0x20 + __IO uint32_t RTCCTL; //0x24 + __IO uint32_t RTCCNT; //0x28 + __IO uint32_t RTCCC0; //0x2c + __IO uint32_t RTCCC1; //0x30 + __IO uint32_t RTCCC2; //0x34 + __IO uint32_t RTCFLAG; //0x38 + __IO uint32_t reserved[25]; + __IO uint32_t REG_S9; //0xa0 + __IO uint32_t REG_S10; //0xa4 + __IO uint32_t REG_S11; //0xa8 + __IO uint32_t IDLE_REG; //0xac + __IO uint32_t GPIO_WAKEUP_SRC[2]; //0xb0 b4 + __IO uint32_t PCLK_CLK_GATE; //0xb8 + __IO uint32_t XTAL_16M_CTRL; //0xbc + __IO uint32_t SLEEP_R[4]; //0xc0 c4 c8 cc + +} AP_AON_TypeDef; + + +typedef struct +{ + __IO uint32_t RTCCTL; //0x24 + __IO uint32_t RTCCNT; //0x28 + __IO uint32_t RTCCC0; //0x2c + __IO uint32_t RTCCC1; //0x30 + __IO uint32_t RTCCC2; //0x34 + __IO uint32_t RTCFLAG; //0x38 +} AP_RTC_TypeDef; + +typedef struct +{ + __IO uint32_t io_wu_mask_31_0; //0xa0 + __IO uint32_t io_wu_mask_34_32; //0xa4 +} AP_Wakeup_TypeDef; + +typedef struct +{ + __IO uint32_t CLKSEL; //0x3c + __IO uint32_t CLKHF_CTL0; //0x40 + __IO uint32_t CLKHF_CTL1; //0x44 + __IO uint32_t ANA_CTL; //0x48 + __IO uint32_t mem_0_1_dvs; //0x4c + __IO uint32_t mem_2_3_4_dvs; //0x50 + __IO uint32_t efuse_cfg; //0x54 + __IO uint32_t chip_state; //0x58 + __IO uint32_t cal_rw; //0x5c + __IO uint32_t cal_ro0; //0x60 + __IO uint32_t cal_ro1; //0x64 + __IO uint32_t cal_ro2; //0x68 + __IO uint32_t ADC_CTL0; //0x6c + __IO uint32_t ADC_CTL1; //0x70 + __IO uint32_t ADC_CTL2; //0x74 + __IO uint32_t ADC_CTL3; //0x78 + __IO uint32_t ADC_CTL4; //0x7c + uint32_t reserved1[48]; + __IO uint32_t EFUSE_PROG[2];//0x140 + uint32_t reserved2[6]; + __IO uint32_t EFUSE0[2];//0x160 + __IO uint32_t EFUSE1[2];//0x168 + __IO uint32_t EFUSE2[2];//0x170 + __IO uint32_t EFUSE3[2];//0x178 + __IO uint32_t SECURTY_STATE;//0x180 +} AP_PCRM_TypeDef; + +typedef struct +{ + __IO uint32_t enable; //0x00 + __IO uint32_t reserve0[2]; //0x04~0x08 + __IO uint32_t control_1; //0x0c + __IO uint32_t control_2; //0x10 + __IO uint32_t control_3; //0x14 + __IO uint32_t control_4; //0x18 + __IO uint32_t compare_reset; //0x1c + __IO uint32_t int_pointer_ch0_ch3; //0x20 + __IO uint32_t int_pointer_ch4_ch7; //0x24 + //__IO uint32_t int_pointer[2]; //0x20~0x24 + __IO uint32_t reserve1[3]; //0x28~0x30 + __IO uint32_t intr_mask; //0x34 + __IO uint32_t intr_clear; //0x38 + __IO uint32_t intr_status; //0x3c + __IO uint32_t compare_cfg[8]; //0x40~0x5c +} AP_ADCC_TypeDef; + +typedef struct +{ + __IO uint32_t config; //0x0,QSPI Configuration Register,R/W + __IO uint32_t read_instr; //0x4,Device Read Instruction Register,R/W + __IO uint32_t write_instr; //0x8,Device Write Instruction Register,R/W + __IO uint32_t delay; //0xC,QSPI Device Delay Register,R/W + __IO uint32_t rddata_capture; //0x10,Read Data Capture Register,R/W + __IO uint32_t dev_size; //0x14,Device Size Register,R/W + __IO uint32_t sram_part; //0x18,SRAM Partition Register,R/W + __IO uint32_t indirect_ahb_addr_trig; //0x1C,Indirect AHB Address Trigger Register,R/W + __IO uint32_t dma_peripheral; //0x20,DMA Peripheral Register,R/W + __IO uint32_t remap; //0x24,Remap Address Register,R/W + __IO uint32_t mode_bit; //0x28,Mode Bit Register,R/W + __IO uint32_t sram_fill_level; //0x2C,SRAM Fill Level Register,RO + __IO uint32_t tx_threshold; //0x30,TX Threshold Register,R/W + __IO uint32_t rx_threshold; //0x34,RX Threshold Register,R/W + __IO uint32_t wr_completion_ctrl; //0x38,Write Completion Control Register,R/W + __IO uint32_t poll_expire; //0x3C,Polling Expiration Register,R/W + __IO uint32_t int_status; //0x40,Interrupt Status Register,R/W + __IO uint32_t int_mask; //0x44,Interrupt Mask,R/W + __I uint32_t n1[2]; //0x48~0x4c,Empty + __IO uint32_t low_wr_protection; //0x50,Lower Write Protection Register,R/W + __IO uint32_t up_wr_protection; //0x54,Upper Write Protection Register,R/W + __IO uint32_t wr_protection; //0x58,Write Protection Register,R/W + __I uint32_t n2; //0x5c,Empty + __IO uint32_t indirect_rd; //0x60,Indirect Read Transfer Register,R/W + __IO uint32_t indirect_rd_watermark; //0x64,Indirect Read Transfer Watermark Register,R/W + __IO uint32_t indirect_rd_start_addr; //0x68,Indirect Read Transfer Start Address Register,R/W + __IO uint32_t indirect_rd_num; //0x6C,Indirect Read Transfer Number Bytes Register,R/W + __IO uint32_t indirect_wr; //0x70,Indirect Write Transfer Register,R/W + __IO uint32_t indirect_wr_watermark; //0x74,Indirect Write Transfer Watermark Register,R/W + __IO uint32_t indirect_wr_start_addr; //0x78,Indirect Write Transfer Start Address Register,R/W + __IO uint32_t indirect_wr_cnt; //0x7C,Indirect Write Transfer Count Register,R/W + __IO uint32_t indirect_ahb_trig_addr_range; //0x80,Indirect AHB Trigger Address Range Register,R/W + __I uint32_t n3[3]; //0x84~0x8c,Empty + __IO uint32_t fcmd; //0x90,Flash Command Register,R/W + __IO uint32_t fcmd_addr; //0x94,Flash Command Address Registers,R/W + __I uint32_t n4[2]; //0x98~0x9c,Empty + __IO uint32_t fcmd_rddata[2]; //0xA0,Flash Command Read Data Register (low-a0, up-a4),RO + __IO uint32_t fcmd_wrdata[2]; //0xA8,Flash Command Write Data Register (low-a8, up-ac),R/W + __IO uint32_t poll_fstatus; //0xB0,Polling Flash Status Register,RO + //__IO uint32_t ; //0xFC,Module ID Register,RO +} AP_SPIF_TypeDef; + +typedef struct +{ + __IO uint32_t ctrl0; //0xc0 + __IO uint32_t ctrl1; //0xc4 + __IO uint32_t mk_in_en; //0xc8 + __IO uint32_t mkc[6]; //0xcc~0xe0 +} AP_KSCAN_TypeDef; + +typedef struct +{ + __IO uint32_t pwmen; +} AP_PWM_TypeDef; + + +typedef struct +{ + __IO uint32_t ctrl0; + __IO uint32_t ctrl1; +} AP_PWMCTRL_TypeDef; + + + +typedef struct +{ + __IO uint32_t SAR; + __IO uint32_t SAR_H; + __IO uint32_t DAR; + __IO uint32_t DAR_H; + __IO uint32_t LLP; + __IO uint32_t LLP_H; + __IO uint32_t CTL; + __IO uint32_t CTL_H; + __IO uint32_t SSTAT; + __IO uint32_t SSTAT_H; + __IO uint32_t DSTAT; + __IO uint32_t DSTAT_L; + __IO uint32_t SSTATAR; + __IO uint32_t SSTATAR_H; + __IO uint32_t DSTATAR; + __IO uint32_t DSTATAR_H; + __IO uint32_t CFG; + __IO uint32_t CFG_H; + __IO uint32_t rsv[4]; + +} AP_DMA_CH_TypeDef; + +typedef struct +{ + + __IO uint32_t RawTfr; //0x2c0 + __IO uint32_t RawTfr_H; //0x2c4 + __IO uint32_t RawBlock; //0x2c8 + __IO uint32_t RawBlock_H; //0x2cc + __IO uint32_t RawSrcTran; //0x2d0 + __IO uint32_t RawSrcTran_H; //0x2d4 + __IO uint32_t RawDstTran; //0x2d8 + __IO uint32_t RawDstTran_H; //0x2dc + __IO uint32_t RawErr; //0x2e0 + __IO uint32_t RawErr_H; //0x2e4 + + __IO uint32_t StatusTfr; //0x2e8 + __IO uint32_t StatusTfr_H; //0x2ec + __IO uint32_t StatusBlock; //0x2f0 + __IO uint32_t StatusBlock_H; //0x2f4 + __IO uint32_t StatusSrcTran; //0x2f8 + __IO uint32_t StatusSrcTran_H; //0x2fc + __IO uint32_t StatusDstTran; //0x300 + __IO uint32_t StatusDstTran_H; //0x304 + __IO uint32_t StatusErr; //0x308 + __IO uint32_t StatusErr_H; //0x30c + + __IO uint32_t MaskTfr; //0x310 + __IO uint32_t MaskTfr_H; //0x314 + __IO uint32_t MaskBlock; //0x318 + __IO uint32_t MaskBlock_H; //0x31c + __IO uint32_t MaskSrcTran; //0x320 + __IO uint32_t MaskSrcTran_H; //0x324 + __IO uint32_t MaskDstTran; //0x328 + __IO uint32_t MaskDstTran_H; //0x32c + __IO uint32_t MaskErr; //0x330 + __IO uint32_t MaskErr_H; //0x334 + + __IO uint32_t ClearTfr; //0x338 + __IO uint32_t ClearTfr_H; //0x33c + __IO uint32_t ClearBlock; //0x340 + __IO uint32_t ClearBlock_H; //0x344 + __IO uint32_t ClearSrcTran; //0x348 + __IO uint32_t ClearSrcTran_H; //0x34c + __IO uint32_t ClearDstTran; //0x350 + __IO uint32_t ClearDstTran_H; //0x354 + __IO uint32_t ClearErr; //0x358 + __IO uint32_t ClearErr_H; //0x35c + __IO uint32_t StatusInt; //0x360 + __IO uint32_t StatusInt_H; //0x364 + +} AP_DMA_INT_TypeDef; + +typedef struct +{ + __IO uint32_t ReqSrcReg; //0x368 + __IO uint32_t ReqSrcReg_H; //0x36c + __IO uint32_t ReqDstReg; //0x370 + __IO uint32_t ReqDstReg_H; //0x374 + __IO uint32_t SglReqSrcReg; //0x378 + __IO uint32_t SglReqSrcReg_H; //0x37c + __IO uint32_t SglReqDstReg; //0x380 + __IO uint32_t SglReqDstReg_H; //0x384 + __IO uint32_t LstSrcReg; //0x388 + __IO uint32_t LstSrcReg_H; //0x38c + __IO uint32_t LstDstReg; //0x390 + __IO uint32_t LstDstReg_H; //0x394 + +} AP_DMA_SW_HANDSHAKE_TypeDef; + +typedef struct +{ + __IO uint32_t DmaCfgReg; //0x398 + __IO uint32_t DmaCfgReg_H; //0x39c + __IO uint32_t ChEnReg; //0x3a0 + __IO uint32_t ChEnReg_H; //0x3a4 + __IO uint32_t DmaIdReg; //0x3a8 + __IO uint32_t DmaIdReg_H; //0x3ac + __IO uint32_t DmaTestReg; //0x3b0 + __IO uint32_t DmaTestReg_H; //0x3b4 + __IO uint32_t rsv1[4]; + __IO uint32_t DMA_COMP_PARAMS_6; //0x3c8 + __IO uint32_t DMA_COMP_PARAMS_6_H; //0x3cc + __IO uint32_t DMA_COMP_PARAMS_5; //0x3d0 + __IO uint32_t DMA_COMP_PARAMS_5_H; //0x3d4 + __IO uint32_t DMA_COMP_PARAMS_4; //0x3d8 + __IO uint32_t DMA_COMP_PARAMS_4_H; //0x3dc + __IO uint32_t DMA_COMP_PARAMS_3; //0x3e0 + __IO uint32_t DMA_COMP_PARAMS_3_H; //0x3e4 + __IO uint32_t DMA_COMP_PARAMS_2; //0x3e8 + __IO uint32_t DMA_COMP_PARAMS_2_H; //0x3ec + __IO uint32_t DMA_COMP_PARAMS_1; //0x3f0 + __IO uint32_t DMA_COMP_PARAMS_1_H; //0x3f4 + __IO uint32_t DMA_ID; //0x3f8 + __IO uint32_t DMA_ID_H; //0x3fc +} AP_DMA_MISC_TypeDef; + + +#if defined ( __CC_ARM ) +#pragma no_anon_unions +#endif + + +/******************************************************************************/ +/* Peripheral memory map(AP) */ +/******************************************************************************/ +/* Base addresses */ +#define AP_APB0_BASE (0x40000000UL) +#define SPIF_BASE_ADDR (0x11000000) /*spif*/ + +#define AP_PCR_BASE (AP_APB0_BASE + 0x0000)/*pcr*//* APB0 peripherals */ + +#define AP_TIM1_BASE (AP_APB0_BASE + 0x1000) +#define AP_TIM2_BASE (AP_APB0_BASE + 0x1014) +#define AP_TIM3_BASE (AP_APB0_BASE + 0x1028) +#define AP_TIM4_BASE (AP_APB0_BASE + 0x103c) +#define AP_TIM5_BASE (AP_APB0_BASE + 0x1050) +#define AP_TIM6_BASE (AP_APB0_BASE + 0x1064) +#define AP_TIM_SYS_BASE (AP_APB0_BASE + 0x10a0) + +#define AP_WDT_BASE (AP_APB0_BASE + 0x2000) +#define AP_COM_BASE (AP_APB0_BASE + 0x3000)/*com*/ +#define AP_IOMUX_BASE (AP_APB0_BASE + 0x3800)/*iomux*/ +#define AP_UART0_BASE (AP_APB0_BASE + 0x4000)/*uart0*/ +#define AP_I2C0_BASE (AP_APB0_BASE + 0x5000)/*i2c0*/ +#define AP_I2C1_BASE (AP_APB0_BASE + 0x5800)/*i2c1*/ +#define AP_SPI0_BASE (AP_APB0_BASE + 0x6000)/*spi0*/ +#define AP_SPI1_BASE (AP_APB0_BASE + 0x7000)/*spi1*/ +#define AP_GPIOA_BASE (AP_APB0_BASE + 0x8000)/*gpio*/ +#define AP_UART1_BASE (AP_APB0_BASE + 0x9000)/*uart1*/ +#define AP_DMIC_BASE (AP_APB0_BASE + 0xA000) +#define AP_QDEC_BASE (AP_APB0_BASE + 0xB000)/*qdec*/ +#define AP_CACHE_BASE (AP_APB0_BASE + 0xC000) +#define AP_SPIF_BASE (AP_APB0_BASE + 0xC800)/*spif*/ +#define AP_KSCAN_BASE (AP_APB0_BASE + 0xD0C0)/*kscan*/ +#define AP_PWM_BASE (AP_APB0_BASE + 0xE000)/*pwm*/ +#define AP_AON_BASE (AP_APB0_BASE + 0xF000)/*aon*/ +#define AP_RTC_BASE (AP_APB0_BASE + 0xF024)/*rtc*/ +#define AP_PCRM_BASE (AP_APB0_BASE + 0xF03c)/*pcrm*/ +#define AP_WAKEUP_BASE (AP_APB0_BASE + 0xF0a0)/*wakeup*/ +#define AP_DMAC_BASE (AP_APB0_BASE + 0x10000)/*dmac*/ +#define ADCC_BASE_ADDR (AP_APB0_BASE + 0x50000)/*adcc*/ + +/*bb_top*/ +/*linklayer*/ + +#define SRAM0_BASE_ADDRESS 0x1FFF0000 +#define SRAM1_BASE_ADDRESS 0x1FFF4000 +#define SRAM2_BASE_ADDRESS 0x1FFF8000 + + +///////////////////////////////////////////////////////////// +#define AP_PCR ((AP_PCR_TypeDef *) AP_PCR_BASE) + +#define AP_TIM1 ((AP_TIM_TypeDef *) AP_TIM1_BASE) +#define AP_TIM2 ((AP_TIM_TypeDef *) AP_TIM2_BASE) +#define AP_TIM3 ((AP_TIM_TypeDef *) AP_TIM3_BASE) +#define AP_TIM4 ((AP_TIM_TypeDef *) AP_TIM4_BASE) +#define AP_TIM5 ((AP_TIM_TypeDef *) AP_TIM5_BASE) +#define AP_TIM6 ((AP_TIM_TypeDef *) AP_TIM6_BASE) +#define AP_TIMS ((AP_TIM_SYS_TypeDef *) AP_TIM_SYS_BASE) + +#define AP_WDT ((AP_WDT_TypeDef *) AP_WDT_BASE) +#define AP_COM ((AP_COM_TypeDef *) AP_COM_BASE) +#define AP_IOMUX ((IOMUX_TypeDef *) AP_IOMUX_BASE) +#define AP_UART0 ((AP_UART_TypeDef *) AP_UART0_BASE) +#define AP_I2C0 ((AP_I2C_TypeDef *) AP_I2C0_BASE) +#define AP_I2C1 ((AP_I2C_TypeDef *) AP_I2C1_BASE) +#define AP_SPI0 ((AP_SSI_TypeDef *) AP_SPI0_BASE) +#define AP_SPI1 ((AP_SSI_TypeDef *) AP_SPI1_BASE) +#define AP_GPIO ((AP_GPIO_TypeDef *) AP_GPIOA_BASE) +#define AP_UART1 ((AP_UART_TypeDef *) AP_UART1_BASE) +#define AP_CACHE ((AP_CACHE_TypeDef *) AP_CACHE_BASE) +#define AP_SPIF ((AP_SPIF_TypeDef *) AP_SPIF_BASE) +#define AP_KSCAN ((AP_KSCAN_TypeDef *) AP_KSCAN_BASE) +#define AP_PWM ((AP_PWM_TypeDef *) AP_PWM_BASE) +#define AP_PWM_CTRL(n) ((AP_PWMCTRL_TypeDef *) (AP_PWM_BASE + 4 + n*12)) +#define AP_AON ((AP_AON_TypeDef *) AP_AON_BASE) +#define AP_RTC ((AP_RTC_TypeDef *) AP_RTC_BASE) +#define AP_PCRM ((AP_PCRM_TypeDef *) AP_PCRM_BASE) +#define AP_WAKEUP ((AP_Wakeup_TypeDef*) AP_WAKEUP_BASE) +#define AP_ADCC ((AP_ADCC_TypeDef *) ADCC_BASE_ADDR) + +#define AP_DMA_CH_CFG(n) ((AP_DMA_CH_TypeDef *) (AP_DMAC_BASE+0x58*n)) +#define AP_DMA_INT ((AP_DMA_INT_TypeDef *) (AP_DMAC_BASE+0x2c0)) +#define AP_DMA_SW_HANDSHAKE ((AP_DMA_SW_HANDSHAKE_TypeDef *) (AP_DMAC_BASE+0x368)) +#define AP_DMA_MISC ((AP_DMA_MISC_TypeDef *) (AP_DMAC_BASE+0x398)) +/* + watchdog enable state,enable or not. +*/ +#define AP_WDT_ENABLE_STATE ((AP_WDT->CR & 0x01))//1:enable 0:disable +#define AP_WDT_FEED do{AP_WDT->CRR = 0x76;}while(0) + +/******************************************************************************/ +/* Peripheral memory map(CP) */ +/******************************************************************************/ +/* Base addresses */ +#define IRQ_PRIO_REALTIME 0 +#define IRQ_PRIO_HIGH 1 +#define IRQ_PRIO_HAL 2 +#define IRQ_PRIO_THREAD 3 +#define IRQ_PRIO_APP 3 + + +#endif diff --git a/src/components/inc/types.h b/src/components/inc/types.h new file mode 100644 index 0000000..990b63f --- /dev/null +++ b/src/components/inc/types.h @@ -0,0 +1,159 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +#ifndef _TYPES_H_ +#define _TYPES_H_ + +#include +#include +typedef signed char int8; //!< Signed 8 bit integer +typedef unsigned char uint8; //!< Unsigned 8 bit integer + +typedef signed short int16; //!< Signed 16 bit integer +typedef unsigned short uint16; //!< Unsigned 16 bit integer + +typedef signed long int32; //!< Signed 32 bit integer +typedef unsigned long uint32; //!< Unsigned 32 bit integer + +typedef uint8 halDataAlign_t; //!< Used for byte alignment + +#ifdef __GCC + #define ALIGN4_U8 _Alignas(4) uint8 + #define ALIGN4_U16 _Alignas(4) uint16 + #define ALIGN4_INT8 _Alignas(4) int8 + #define ALIGN4_INT16 _Alignas(4) int16 +#else + #define ALIGN4_U8 __align(4) uint8 + #define ALIGN4_U16 __align(4) uint16 + #define ALIGN4_INT8 __align(4) int8 + #define ALIGN4_INT16 __align(4) int16 +#endif + +#define BIT(n) (1ul << (n)) + +#define write_reg(addr,data) (*(volatile unsigned int *)(addr)=(unsigned int)(data)) +#define read_reg(addr) (*(volatile unsigned int *)(addr)) + +//bit operations +#define BM_SET(addr,bit) ( *(addr) |= (bit) ) //bit set +#define BM_CLR(addr,bit) ( *(addr) &= ~(bit) ) //bit clear +#define BM_IS_SET(addr,bit) ( *(addr) & (bit) ) //judge bit is set + + + +#ifndef BV + #define BV(n) (1 << (n)) +#endif + +#ifndef BF + #define BF(x,b,s) (((x) & (b)) >> (s)) +#endif + +#ifndef MIN + #define MIN(n,m) (((n) < (m)) ? (n) : (m)) +#endif + +#ifndef MAX + #define MAX(n,m) (((n) < (m)) ? (m) : (n)) +#endif + +#ifndef ABS + #define ABS(n) (((n) < 0) ? -(n) : (n)) +#endif + + +/* takes a byte out of a uint32 : var - uint32, ByteNum - byte to take out (0 - 3) */ +#define BREAK_UINT32( var, ByteNum ) \ + (uint8)((uint32)(((var) >>((ByteNum) * 8)) & 0x00FF)) + +#define BUILD_UINT32(Byte0, Byte1, Byte2, Byte3) \ + ((uint32)((uint32)((Byte0) & 0x00FF) \ + + ((uint32)((Byte1) & 0x00FF) << 8) \ + + ((uint32)((Byte2) & 0x00FF) << 16) \ + + ((uint32)((Byte3) & 0x00FF) << 24))) + +#define BUILD_UINT16(loByte, hiByte) \ + ((uint16)(((loByte) & 0x00FF) + (((hiByte) & 0x00FF) << 8))) + +#define HI_UINT16(a) (((a) >> 8) & 0xFF) +#define LO_UINT16(a) ((a) & 0xFF) + +#define BUILD_UINT8(hiByte, loByte) \ + ((uint8)(((loByte) & 0x0F) + (((hiByte) & 0x0F) << 4))) + + +// Write the 32bit value of 'val' in little endian format to the buffer pointed +// to by pBuf, and increment pBuf by 4 +#define UINT32_TO_BUF_LITTLE_ENDIAN(pBuf,val) \ + do { \ + *(pBuf)++ = (((val) >> 0) & 0xFF); \ + *(pBuf)++ = (((val) >> 8) & 0xFF); \ + *(pBuf)++ = (((val) >> 16) & 0xFF); \ + *(pBuf)++ = (((val) >> 24) & 0xFF); \ + } while (0) + +// Return the 32bit little-endian formatted value pointed to by pBuf, and increment pBuf by 4 +#define BUF_TO_UINT32_LITTLE_ENDIAN(pBuf) (((pBuf) += 4), BUILD_UINT32((pBuf)[-4], (pBuf)[-3], (pBuf)[-2], (pBuf)[-1])) + +#ifndef GET_BIT + #define GET_BIT(DISCS, IDX) (((DISCS)[((IDX) / 8)] & BV((IDX) % 8)) ? TRUE : FALSE) +#endif +#ifndef SET_BIT + #define SET_BIT(DISCS, IDX) (((DISCS)[((IDX) / 8)] |= BV((IDX) % 8))) +#endif +#ifndef CLR_BIT + #define CLR_BIT(DISCS, IDX) (((DISCS)[((IDX) / 8)] &= (BV((IDX) % 8) ^ 0xFF))) +#endif + + +/* ------------------------------------------------------------------------------------------------ + Standard Defines + ------------------------------------------------------------------------------------------------ +*/ +#ifndef TRUE + #define TRUE 1 +#endif + +#ifndef FALSE + #define FALSE 0 +#endif + +#ifndef NULL + #define NULL 0 +#endif + +#define HAL_WAIT_CONDITION(condition) {while(!(condition)){}} + + +#define HAL_WAIT_CONDITION_TIMEOUT(condition, timeout) {\ + volatile int val = 0;\ + while(!(condition)){\ + if(val ++ > timeout)\ + return PPlus_ERR_TIMEOUT;\ + }\ + } + +#define HAL_WAIT_CONDITION_TIMEOUT_WO_RETURN(condition, timeout) {\ + volatile int val = 0;\ + while(!(condition)){\ + if(val ++ > timeout)\ + break;\ + }\ + } + + +typedef struct _comm_evt_t +{ + unsigned int type; + unsigned char* data; + unsigned int len; +} comm_evt_t; + +typedef void (*comm_cb_t)(comm_evt_t* pev); + +#define __ATTR_SECTION_SRAM__ __attribute__((section("_section_sram_code_"))) +#define __ATTR_SECTION_XIP__ __attribute__((section("_section_xip_code_"))) + +#endif + diff --git a/src/components/inc/version.h b/src/components/inc/version.h new file mode 100644 index 0000000..9869a77 --- /dev/null +++ b/src/components/inc/version.h @@ -0,0 +1,25 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file sdk_version.h + @brief + @author + + +*******************************************************************************/ +#ifndef __SDK_VER_H__ +#define __SDK_VER_H__ + +#define __DEF_CHIP_QFN32__ (0x0001) +#define __DEF_CHIP_TSOP16__ (0x0002) +#define SDK_VER_MAJOR 3 +#define SDK_VER_MINOR 1 +#define SDK_VER_REVISION 1 +#define SDK_SUB_CODE 2 +#define SDK_VER_RELEASE_ID ((SDK_VER_MAJOR<<24)|(SDK_VER_MINOR<<16)|(SDK_VER_REVISION<<8)|(SDK_SUB_CODE<<0)) +#define SDK_VER_CHIP __DEF_CHIP_QFN32__ // __DEF_CHIP_TSOP16__ +//#define SDK_VER_TEST_BUILD "" +#endif + diff --git a/src/components/libraries/cliface/cliface.c b/src/components/libraries/cliface/cliface.c new file mode 100644 index 0000000..c1cd4ca --- /dev/null +++ b/src/components/libraries/cliface/cliface.c @@ -0,0 +1,388 @@ +/** + * \file cli.c + * + * This file implements command line interface (CLI) framework. + */ + +/* + * Copyright (C) 2017. Mindtree Ltd. + * All rights reserved. + */ + +/* --------------------------------------------- Header File Inclusion */ +#include "cliface.h" + +//#ifdef HAVE_CLI + +/* --------------------------------------------- Global Definitions */ + +/* --------------------------------------------- Function */ +/** + * \fn CLI_init + * + * \brief Initialize CLI + * + * \Description + * This routine intializes CLI. + * + * \return EM_SUCCESS or an error code indicating reason for failure + * + */ +uint16_t CLI_init + ( + void + ) +{ + return 0; +} + +/** + * \brief Process a command line instruction + * + * \Description + * This routine processes a command line instruction. + * + * \param [in] buffer Buffer containing a command + * \param [in] buffer_len Length of command in buffer + * \param [in] cmd_list Command List + * \param [in] cmd_count Number of command in the list + * + * \return EM_SUCCESS or an error code indicating reason for failure + */ +uint16_t CLI_process_line + ( + /* IN */ uint8_t * buffer, + /* IN */ uint32_t buffer_len, + /* IN */ CLI_COMMAND * cmd_list, + /* IN */ uint32_t cmd_count + ) +{ + uint32_t argc; + uint8_t * argv[CLI_MAX_ARGS]; + + uint8_t * cmd; + uint32_t index; + + /* TBD: Parameter Validation */ + CLI_NULL_CHECK(buffer); + + /* Skip initial white spaces */ + for (; CLI_IS_WHITE_SPACE(*buffer) && (0 != buffer_len); buffer++, buffer_len--); + + /* Check this is not an empty command line */ + if (0 == buffer_len) + { + CLI_ERR( + "[CLI] Empty command line\n"); + + return 0xffff; + } + + /** + * Got the initial command. + * Parse the remaining command line to get the arguments. + */ + argc = 0; + + for (cmd = buffer + 1; cmd < (buffer + buffer_len); cmd++) + { + /** + * If command argument separator is detected, replace with '\0' + * to create each as separate strings. + */ + if (CLI_IS_CMD_SEPARATOR(*cmd)) + { + *cmd = '\0'; + } + /* Check if this is start of a new argument */ + else if ('\0' == (*(cmd - 1))) + { + argv[argc++] = cmd; + } + else + { + /* Nothing to do */ + } + } + + CLI_TRC( + "[CLI] Command %s, Number of arguments %d\n", buffer, argc); + + { + uint8_t ai; + + for (ai = 0; ai < argc; ai++) + { + CLI_TRC( + "Arg [%02X] %s\n", ai, argv[ai]); + } + } + + /* Identified command name */ + cmd = buffer; + + /* Search command and call associated callback */ + for (index = 0; index < cmd_count; index++) + { + if (0 == CLI_STR_COMPARE(buffer, cmd_list[index].cmd)) + { + cmd_list[index].cmd_hdlr(argc, argv); + break; + } + } + + return 0; +} + +/* TODO: Create a separe utility module or move to a common utility module */ +/* Supporting Macros */ +#define IS_SPACE(c) ((' ' == (c)) || ('\t' == (c))) +#define IS_DIGIT(c) (('0' <= (c)) && ('9' >= (c))) +#define IS_UPPER(c) (('A' <= (c)) && ('F' >= (c))) +#define IS_LOWER(c) (('a' <= (c)) && ('f' >= (c))) +#define IS_ALPHA(c) IS_LOWER(c) || IS_UPPER(c) + +/* Convert string to Integer */ +int32_t CLI_strtoi + ( + /* IN */ uint8_t *data, + /* IN */ uint16_t data_length, + /* IN */ uint8_t base + ) +{ + int32_t value; + uint16_t index; + int8_t sign_adj; + uint8_t c; + + c = 0; + + /* Skip Whitespaces */ + for (index = 0; index < data_length; index++) + { + c = data[index]; + + if (IS_SPACE(c)) + { + continue; + } + else + { + break; + } + } + + value = 0; + sign_adj = 1; + + /* Check Sign */ + if ('-' == c) + { + sign_adj = (int8_t)-1; + index++; + } + + /* Not handling spaces after '-' or '0x' etc. */ + for (; index < data_length; index++) + { + c = data[index]; + + /* Check if Digit */ + if (IS_DIGIT(c)) + { + value *= base; + value += (c - '0'); + } + else if (IS_LOWER(c)) + { + value *= base; + value += (c - 'a' + 10); + } + else if (IS_UPPER(c)) + { + value *= base; + value += (c - 'A' + 10); + } + else + { + break; + } + } + + return (sign_adj * value); +} + +/* Convert string to Integer Array */ +uint16_t CLI_strtoarray + ( + /* IN */ uint8_t * data, + /* IN */ uint16_t data_length, + /* OUT */ uint8_t * output_array, + /* IN */ uint16_t output_array_len + ) +{ + int32_t index; + uint8_t c0, c1; + uint8_t base; + uint16_t output_index; + + /* HEX */ + base = 16; + c0 = 0; + c1 = 0; + + /* Fill with Zeros */ + memset(output_array, 0, output_array_len); + + /* Check the length */ + if (data_length > (2 * output_array_len)) + { + return 0xFFFF; + } + + /* Process from end */ + output_index = output_array_len - 1; + for (index = data_length - 1; index >= 0; index -= 2) + { + if (0 != index) + { + c1 = data[index]; + c0 = data[index - 1]; + } + else + { + c1 = data[index]; + c0 = '0'; + } + + /* Check if Digit */ + if (IS_DIGIT(c0)) + { + c0 = (c0 - '0'); + } + else if (IS_LOWER(c0)) + { + c0 = (c0 - 'a' + 10); + } + else if (IS_UPPER(c0)) + { + c0 = (c0 - 'A' + 10); + } + else + { + return 0xFFFF; + } + + /* Check if Digit */ + if (IS_DIGIT(c1)) + { + c1 = (c1 - '0'); + } + else if (IS_LOWER(c1)) + { + c1 = (c1 - 'a' + 10); + } + else if (IS_UPPER(c1)) + { + c1 = (c1 - 'A' + 10); + } + else + { + return 0xFFFF; + } + + output_array[output_index] = c0 * base + c1; + output_index--; + } + + return 0; +} + +/* Convert string to Integer Array in Little Endian Packing */ +uint16_t CLI_strtoarray_le + ( + /* IN */ uint8_t * data, + /* IN */ uint16_t data_length, + /* OUT */ uint8_t * output_array, + /* IN */ uint16_t output_array_len + ) +{ + int32_t index; + uint8_t c0, c1; + uint8_t base; + uint16_t output_index; + + /* HEX */ + base = 16; + c0 = 0; + c1 = 0; + + /* Fill with Zeros */ + memset(output_array, 0, output_array_len); + + /* Check the length */ + if (data_length > (2 * output_array_len)) + { + return 0xFFFF; + } + + /* Process from end */ + output_index = 0; + + for (index = data_length - 1; index >= 0; index -= 2) + { + if (0 != index) + { + c1 = data[index]; + c0 = data[index - 1]; + } + else + { + c1 = data[index]; + c0 = '0'; + } + + /* Check if Digit */ + if (IS_DIGIT(c0)) + { + c0 = (c0 - '0'); + } + else if (IS_LOWER(c0)) + { + c0 = (c0 - 'a' + 10); + } + else if (IS_UPPER(c0)) + { + c0 = (c0 - 'A' + 10); + } + else + { + return 0xFFFF; + } + + /* Check if Digit */ + if (IS_DIGIT(c1)) + { + c1 = (c1 - '0'); + } + else if (IS_LOWER(c1)) + { + c1 = (c1 - 'a' + 10); + } + else if (IS_UPPER(c1)) + { + c1 = (c1 - 'A' + 10); + } + else + { + return 0xFFFF; + } + + output_array[output_index] = c0 * base + c1; + output_index++; + } + + return 0; +} +//#endif /* HAVE_CLI */ + diff --git a/src/components/libraries/cliface/cliface.h b/src/components/libraries/cliface/cliface.h new file mode 100644 index 0000000..159ddd0 --- /dev/null +++ b/src/components/libraries/cliface/cliface.h @@ -0,0 +1,118 @@ + +/** + * \file cliface.h + * + * This file contains definitions for command line interface (CLI) framework. + */ + +/* + * Copyright (C) 2017. Mindtree Ltd. + * All rights reserved. + */ + +#ifndef _H_CLIFACE_ +#define _H_CLIFACE_ + +/* --------------------------------------------- Header File Inclusion */ +#include "mcu.h" +#include +/* --------------------------------------------- Global Definitions */ + + +/* --------------------------------------------- Macros */ + +/* Debug Macros */ +/* TBD: Mapped with debug sub-system */ +#define CLI_ERR(...) /* printf(__VA_ARGS__) */ +#define CLI_TRC(...) /* printf(__VA_ARGS__) */ +#define CLI_INF(...) /* printf(__VA_ARGS__) */ + +#define CLI_STR_COMPARE(s0, s1) strcmp((const char *)(s0), (const char *)(s1)) + +#define CLI_NULL_CHECK(ptr) \ + if (NULL == (ptr)) \ + {\ + CLI_ERR( \ + "[CLI] NULL Pointer\n"); \ + \ + return 0xffff; \ + } + +#define CLI_IS_WHITE_SPACE(ch) ((' ' == (ch)) || ('\t' == (ch))) +#define CLI_IS_CMD_SEPARATOR(ch) ((' ' == (ch)) || ('\t' == (ch)) || ('\r' == (ch)) || ('\n' == (ch))) + +/** TBD: Move to limits/configuration header file */ +#define CLI_MAX_ARGS 16 + +#define CLI_strlen(s) strlen((const char*)s) + +/* --------------------------------------------- Data Types/ Structures */ +/** + * CLI command handler. + * + * CLI will call the handler for the received command. + * + * \param [in] argc Number of arguments. + * \param [in] argv List of arguments. + */ +typedef uint16_t (* CLI_CMD_HANDLER) + ( + uint32_t argc, + uint8_t * argv[] + ) ; + +/** This data structure represents a CLI command */ +typedef struct _cli_command +{ + /** Command name */ + const uint8_t * cmd; + + /* Command description */ + const uint8_t * desc; + + /** Command handler */ + const CLI_CMD_HANDLER cmd_hdlr; + +} CLI_COMMAND; + + +/* --------------------------------------------- Functions */ +uint16_t CLI_init + ( + void + ); + +uint16_t CLI_process_line + ( + /* IN */ uint8_t * buffer, + /* IN */ uint32_t buffer_len, + /* IN */ CLI_COMMAND * cmd_list, + /* IN */ uint32_t cmd_count + ); + +int32_t CLI_strtoi + ( + /* IN */ uint8_t *data, + /* IN */ uint16_t data_length, + /* IN */ uint8_t base + ); + +uint16_t CLI_strtoarray + ( + /* IN */ uint8_t * data, + /* IN */ uint16_t data_length, + /* OUT */ uint8_t * output_array, + /* IN */ uint16_t output_array_len + ); + +uint16_t CLI_strtoarray_le + ( + /* IN */ uint8_t * data, + /* IN */ uint16_t data_length, + /* OUT */ uint8_t * output_array, + /* IN */ uint16_t output_array_len + ); + +#endif /* _H_CLIFACE_ */ + + diff --git a/src/components/libraries/console/phy_console.c b/src/components/libraries/console/phy_console.c new file mode 100644 index 0000000..aef5e9a --- /dev/null +++ b/src/components/libraries/console/phy_console.c @@ -0,0 +1,272 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#include "phy_console.h" +#include "uart.h" +#include "error.h" +#include "OSAL.h" +#include "string.h" +#include "pwrmgr.h" +#include "log.h" + + +typedef enum +{ + CONS_ST_IDLE, + CONS_ST_RX, + CONS_ST_CMD +} cons_state_t; + +typedef struct +{ + cons_state_t state; + uint16_t rx_cnt; + uint8_t rx_buf[CONS_CMD_RXBUF_MAX]; + const cons_cmd_t* cmd_list; + cons_callback_t callback; +} cons_ctx_t; + +cons_ctx_t s_cons_ctx; + + +void console_parse_cmd(void) +{ + uint16_t i,j; + uint16_t cmd_id = 0; + char* param_table[CONS_PARAM_NUM_MAX]; + cons_ctx_t* pctx = &s_cons_ctx; + const cons_cmd_t* cmd_list = pctx->cmd_list; + uint8_t* prx = s_cons_ctx.rx_buf; + char* pcmd = NULL; + char* pparam = NULL; + uint8_t param_num = 0; + + //LOG("\n"); + //for(i = 0; i< pctx->rx_cnt; i++) + // LOG("%x ",prx[i]); + // LOG("\n"); + + //parse "at" + for(i = 1; i< pctx->rx_cnt; i++) + { + if(prx[i-1] == 'a' && prx[i] == 't') + { + i++; + break; + } + } + + if(i == pctx->rx_cnt) + { + LOG("Parse filed, did not found \"at\"\n"); + return; + } + + //parse cmd + { + pcmd = (char*)prx+i; + + for(; i< pctx->rx_cnt; i++) + { + if(prx[i] == ' ' || prx[i] == '\0' ) + { + prx[i] = '\0'; + break; + } + + if(prx[i] < 0x20 || prx[i] > 0x7d) + { + LOG("Parse failed, cmd has illegal character\n"); + return; + } + } + + if(osal_strlen(pcmd) == 0) + { + LOG("Parse failed, cmd is empty\n"); + return; + } + + for(j = 0; jrx_cnt; i++) + { + if(prx[i] == ' ') + { + prx[i] = '\0'; + + if(osal_strlen(pparam) == 0) + { + break; + } + + param_table[param_num] = pparam; + param_num++; + + if(param_num >= CONS_PARAM_NUM_MAX) + break; + + pparam = (char*)prx+i+1; + continue; + } + + if(prx[i] == '\0') + { + if(osal_strlen(pparam) == 0) + { + break; + } + + param_table[param_num] = pparam; + param_num++; + break; + } + + if(prx[i] < 0x20 || prx[i] > 0x7d) + { + LOG("Parse failed, parameter has illegal character\n"); + return; + } + } + + pctx->callback(cmd_id, param_num, param_table); +} + + +void console_sleep_handler(void) +{ + hal_gpio_fmux(P10, Bit_DISABLE); //enable fullmux fuction; enable or disable + hal_gpio_wakeup_set(P10, NEGEDGE); +} + +void console_wakeup_handler(void) +{ + int i; + hal_gpio_write(P14, 0); + hal_gpio_write(P14, 1); + hal_gpio_write(P14, 0); + + for(i = 0; i< 20; i++) + { + if(hal_gpio_read(P10)==0) + { + hal_pwrmgr_lock(MOD_CONSOLE); + break; + } + } + + hal_gpio_write(P14, 0); + hal_gpio_write(P14, 1); + hal_gpio_write(P14, 0); + s_cons_ctx.state = CONS_ST_IDLE; +} + +void console_rx_handler(uart_Evt_t* pev) +{ + cons_ctx_t* pctx = &s_cons_ctx; + uint8_t* prx = s_cons_ctx.rx_buf; + + switch(pev->type) + { + case UART_EVT_TYPE_RX_DATA: + case UART_EVT_TYPE_RX_DATA_TO: + { + uint8_t i; + uint8_t* prx_msg = pev->data; + + //for(i = 0; i< pev->len; i++) + // LOG("%x ",pev->data[i]); + //LOG("\n"); + if(pctx->state == CONS_ST_IDLE) + { + hal_pwrmgr_lock(MOD_CONSOLE); + pctx->state = CONS_ST_RX; + } + + if(pctx->state == CONS_ST_RX) + { + for(i = 0; i< pev->len; i++) + { + if(prx_msg[i] == '\r' ||prx_msg[i] == '\n') + { + prx[pctx->rx_cnt] = 0; + pctx->rx_cnt++; + pctx->state = CONS_ST_CMD; + console_parse_cmd(); + pctx->state = CONS_ST_IDLE; + pctx->rx_cnt = 0; + hal_pwrmgr_unlock(MOD_CONSOLE); + break; + } + + prx[pctx->rx_cnt] = prx_msg[i]; + pctx->rx_cnt++; + } + } + else + { + hal_pwrmgr_unlock(MOD_CONSOLE); + } + + break; + } + + default: + break; + } +} + +int console_init(const cons_cmd_t* cmdlist, cons_callback_t callback) +{ + uart_Cfg_t cfg = + { + .tx_pin = P9, + .rx_pin = P10, + .rts_pin = GPIO_DUMMY, + .cts_pin = GPIO_DUMMY, + .baudrate = 115200, + .use_fifo = TRUE, + .hw_fwctrl = FALSE, + .use_tx_buf = FALSE, + .parity = FALSE, + .evt_handler = console_rx_handler, + }; + + if(callback == NULL) + return PPlus_ERR_INVALID_PARAM; + + hal_pwrmgr_register(MOD_CONSOLE, console_sleep_handler, console_wakeup_handler); + hal_uart_init(cfg,UART0);//uart init + s_cons_ctx.cmd_list = cmdlist; + s_cons_ctx.state = CONS_ST_IDLE; + s_cons_ctx.rx_cnt = 0; + s_cons_ctx.callback = callback; + return PPlus_SUCCESS; +} + diff --git a/src/components/libraries/console/phy_console.h b/src/components/libraries/console/phy_console.h new file mode 100644 index 0000000..d665b3d --- /dev/null +++ b/src/components/libraries/console/phy_console.h @@ -0,0 +1,28 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#ifndef _PHY_CONSOLE_H +#define _PHY_CONSOLE_H + +#include "bus_dev.h" + +#define CONS_CMD_NUM_MAX 32 +#define CONS_CMD_RXBUF_MAX 1024 +#define CONS_PARAM_NUM_MAX 8 + +#define MOD_CONSOLE MOD_USR2 + +typedef void (*cons_callback_t)(uint16_t cmd_id, uint8_t argc, char** argv); + + +typedef struct +{ + uint16_t cmd_id; + char* cmd_name; +} cons_cmd_t; +int console_init(const cons_cmd_t* cmdlist, cons_callback_t callback); + +#endif + diff --git a/src/components/libraries/crc16/crc16.c b/src/components/libraries/crc16/crc16.c new file mode 100644 index 0000000..c0373f3 --- /dev/null +++ b/src/components/libraries/crc16/crc16.c @@ -0,0 +1,45 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/* + crc16 +*/ + +#include "crc16.h" + + + +static uint16_t crc16_byte(uint16_t crc, uint8_t byte) +{ + static const uint16_t crc16_table[16] = + { + 0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, + 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400 + }; + uint16_t temp; + // Compute checksum of lower four bits of a byte. + temp = crc16_table[crc & 0xF]; + crc = (crc >> 4u) & 0x0FFFu; + crc = crc ^ temp ^ crc16_table[byte & 0xF]; + // Now compute checksum of upper four bits of a byte. + temp = crc16_table[crc & 0xF]; + crc = (crc >> 4u) & 0x0FFFu; + crc = crc ^ temp ^ crc16_table[(byte >> 4u) & 0xF]; + return crc; +} + + +uint16_t crc16(uint16_t seed, const volatile void* p_data, uint32_t size) +{ + uint8_t* p_block = (uint8_t*)p_data; + + while (size != 0) + { + seed = crc16_byte(seed, *p_block); + p_block++; + size--; + } + + return seed; +} diff --git a/src/components/libraries/crc16/crc16.h b/src/components/libraries/crc16/crc16.h new file mode 100644 index 0000000..6940b56 --- /dev/null +++ b/src/components/libraries/crc16/crc16.h @@ -0,0 +1,14 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#ifndef _CRC16_H__ +#define _CRC16_H__ + +#include + +uint16_t crc16(uint16_t seed, const volatile void* p_data, uint32_t size); + +#endif // _CRC16_H__ + diff --git a/src/components/libraries/datetime/app_datetime.c b/src/components/libraries/datetime/app_datetime.c new file mode 100644 index 0000000..11f989d --- /dev/null +++ b/src/components/libraries/datetime/app_datetime.c @@ -0,0 +1,227 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#include +#include "OSAL.h" +#include +#include +#include "app_err.h" +#include "app_wrist.h" +#include "app_datetime.h" +#include "types.h" +#include "clock.h" +#include "log.h" + +#ifndef USE_SYS_TICK + #define USE_SYS_TICK FASLE //default use RTC, if system use RC32K as RTC clock source, system tick is usually recommended +#endif + +#if(USE_SYS_TICK) + #define RTC_CNT_RANGE 0x100000000 + #define TM_RATE (1000000/625) +#else + #define RTC_CNT_RANGE 0x1000000 + #define TM_RATE (32768) +#endif +#define DT_INTV_SYNC 60 //sync interval every 60s + + + +//static app_dtm_hdl_t s_evt_hdl = NULL; + +static datetime_cfg_t s_stm_cfg = {0}; + +static const char* const month_str[12] = +{ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" +}; + + +static void app_datetime_adjust_baseline(struct tm* datetm); + +static void print_hex (uint8_t* data, uint16 len) +{ + uint16 i; + + for (i = 0; i < len - 1; i++) + { + LOG("%x",data[i]); + LOG(" "); + } + + LOG("%x",data[i]); +} + +static void dt_timer_start(uint32_t intval_ms) +{ + osal_start_timerEx(AppWrist_TaskID, TIMER_DT_EVT, intval_ms); +} + +void timer_cnt_get(uint32_t* tick) +{ + #if(USE_SYS_TICK) + *tick = hal_systick(); // read current RTC counter + #else + *tick = rtc_get_counter(); // read current RTC counter + #endif +} + + +static void get_default_tm(struct tm* datetm) +{ + int i; + datetime_t dtm; + char dt[20]; + char* pstr = NULL; + LOG(__DATE__); + LOG(__TIME__); + strcpy(dt, __DATE__); + pstr = strtok(dt, " "); + + for(i = 0; i< 12; i++) + { + if(strcmp(dt,month_str[i]) == 0) + { + dtm.month = i+1; + break; + } + } + + pstr = strtok(NULL, " "); + dtm.day = atoi(pstr); + pstr = strtok(NULL, " "); + dtm.year = atoi(pstr); + strcpy(dt, __TIME__); + pstr = strtok(dt, ":"); + dtm.hour = atoi(pstr); + pstr = strtok(NULL, ":"); + dtm.minutes = atoi(pstr); + pstr = strtok(NULL, ":"); + dtm.seconds = atoi(pstr); + DTM2TM(datetm, &dtm); +} + + +static void check_default_datetime(void) +{ + struct tm datetm; + get_default_tm(&datetm); + LOG("check_default_datetime\nTime is %d-%d-%d, %d:%d:%d", + datetm.tm_year+1900, + datetm.tm_mon+1, + datetm.tm_mday, + datetm.tm_hour, + datetm.tm_min, + datetm.tm_sec); + app_datetime_adjust_baseline(&datetm); + return; +} + +static void datetime_print(void) +{ + datetime_t dtm; + app_datetime(&dtm); + LOG("Time is %d-%d-%d, %d:%d:%d\n", dtm.year, dtm.month, dtm.day, dtm.hour, dtm.minutes, dtm.seconds); +} + +void app_datetime_sync_handler(void ) +{ + uint32_t tick= 0; + timer_cnt_get(&tick); + + if(tick < s_stm_cfg.snapshot) + s_stm_cfg.tm_base += RTC_CNT_RANGE; + + s_stm_cfg.snapshot = tick; + dt_timer_start(DATETIME_SYNC_INTERVAL); + datetime_print(); +} + + + +static void app_datetime_adjust_baseline(struct tm* datetm) +{ + uint64_t tmstamp; + uint32_t ticks; + timer_cnt_get(&ticks); + tmstamp = (uint64_t)mktime(datetm); + LOG("%x",(uint32_t)tmstamp); + tmstamp = tmstamp*TM_RATE; + s_stm_cfg.tm_base = tmstamp - ticks; + s_stm_cfg.snapshot = ticks; + LOG("app_datetime_adjust_baseline:\n"); + print_hex((uint8_t*)&s_stm_cfg, sizeof(s_stm_cfg)); + LOG("\n"); +} + + +int app_datetime_set(datetime_t dtm) +{ + struct tm tm; + memset(&tm,0, sizeof(tm)); + DTM2TM(&tm, &dtm); + LOG("\napp_datetime_set:\n"); + LOG("Time is %d-%d-%d, %d:%d:%d\n", dtm.year, dtm.month, dtm.day, dtm.hour, dtm.minutes, dtm.seconds); + app_datetime_adjust_baseline(&tm); + print_hex((uint8_t*)&s_stm_cfg, sizeof(s_stm_cfg)); + LOG("\n"); + return APP_SUCCESS; +} + + + + +int app_datetime_diff(const datetime_t* pdtm_base, const datetime_t* pdtm_cmp) +{ + time_t time_base, time_cmp; + struct tm tm_base, tm_cmp; + DTM2TM(&tm_base, pdtm_base); + DTM2TM(&tm_cmp, pdtm_cmp); + time_base = mktime(&tm_base); + time_cmp = mktime(&tm_cmp); + return (int)difftime(time_base, time_cmp); +} + + +time_t app_datetime_time_t(void) +{ + time_t tm = (time_t)(s_stm_cfg.tm_base / TM_RATE); + return tm; +} + +int app_datetime(datetime_t* pdtm) +{ + struct tm* ptm = NULL; + uint32_t ticks; + time_t tm = (time_t)(s_stm_cfg.tm_base / TM_RATE); + timer_cnt_get(&ticks); + + if(s_stm_cfg.snapshot > ticks) + tm += RTC_CNT_RANGE/TM_RATE; + + tm += ticks/TM_RATE; + ptm = localtime(&tm); + TM2DTM(pdtm, ptm) + return APP_SUCCESS; +} + +void app_datetime_init(void)//app_dtm_hdl_t evt_hdl) +{ + //s_evt_hdl = evt_hdl; + check_default_datetime(); + dt_timer_start(DATETIME_SYNC_INTERVAL); +} + diff --git a/src/components/libraries/datetime/app_datetime.h b/src/components/libraries/datetime/app_datetime.h new file mode 100644 index 0000000..a2f05c1 --- /dev/null +++ b/src/components/libraries/datetime/app_datetime.h @@ -0,0 +1,94 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +#ifndef APP_DATETIME_H +#define APP_DATETIME_H + + +#include "types.h" + + + +#define DATETIME_SYNC_INTERVAL 30*1*1000 //interval is 30s + +#define DTM2TM(tm, dtm) { (tm)->tm_mon = (dtm)->month-1;\ + (tm)->tm_year = (dtm)->year-1900;\ + (tm)->tm_mday = (dtm)->day;\ + (tm)->tm_hour = (dtm)->hour;\ + (tm)->tm_min = (dtm)->minutes;\ + (tm)->tm_sec = (dtm)->seconds;} + + +#define TM2DTM(dtm, tm) { (dtm)->month = (tm)->tm_mon+1;\ + (dtm)->year = (tm)->tm_year+1900;\ + (dtm)->day = (tm)->tm_mday;\ + (dtm)->hour = (tm)->tm_hour;\ + (dtm)->minutes = (tm)->tm_min;\ + (dtm)->seconds = (tm)->tm_sec;} + + +#define BCDTM2DTM(dtm, bcdtm) { (dtm)->year = bcdtm[0] + 2000;\ + (dtm)->month = bcdtm[1];\ + (dtm)->day = bcdtm[2];\ + (dtm)->hour = bcdtm[3];\ + (dtm)->minutes = bcdtm[4];\ + (dtm)->seconds = bcdtm[5];} + +#define DTM2BCDTM(bcdtm, dtm) { bcdtm[0] = (dtm)->year - 2000;\ + bcdtm[1] = (dtm)->month;\ + bcdtm[2] = (dtm)->day;\ + bcdtm[3] = (dtm)->hour;\ + bcdtm[4] = (dtm)->minutes;\ + bcdtm[5] = (dtm)->seconds;} + +#define DTM2U32(u32val, dtm) { uint32 tmp = (dtm)->year; u32val = (tmp << 16);\ + tmp = (dtm)->month; u32val |= (tmp << 8);\ + tmp = (dtm)->day; u32val |= tmp;} + +#define U322DTM(dtm,u32val) { (dtm)->year = (uint16)((u32val)>>16);\ + (dtm)->month = (uint8)(((u32val) >> 8) & 0xff);\ + (dtm)->day = (uint8)((u32val) &0xff);\ + (dtm)->hour = 0; (dtm)->minutes =0; (dtm)->seconds = 0;} + +typedef struct +{ + uint64_t tm_base; + uint32_t snapshot; + uint32_t reserved; //reserved for 4 byte align +} datetime_cfg_t; + + + + +typedef struct +{ + uint8_t seconds; + uint8_t minutes; + uint8_t hour; + uint8_t day; + uint8_t month; + uint16_t year; +} datetime_t; + + +typedef enum +{ + DTM_EV_ALRRM_0 = 1, + DTM_EV_ALRRM_1, + DTM_EV_ALRRM_2, + DTM_EV_ALRRM_3, + DTM_EV_ALRRM_4, +} app_dtm_evt_t; + +//typedef void (*app_dtm_hdl_t)(app_dtm_evt_t ev); + + +void app_datetime_sync_handler(void ); +int app_datetime_diff(const datetime_t* pdtm_base, const datetime_t* pdtm_cmp); +int app_datetime_set(datetime_t dtm); +int app_datetime(datetime_t* pdtm); +void app_datetime_init(void);//app_dtm_hdl_t evt_hdl); + +#endif + diff --git a/src/components/libraries/fs/fs.c b/src/components/libraries/fs/fs.c new file mode 100644 index 0000000..885e67f --- /dev/null +++ b/src/components/libraries/fs/fs.c @@ -0,0 +1,831 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file fs.c + @brief Contains all functions support for spi driver + @version 0.0 + @date 18. Oct. 2017 + @author + + + +*******************************************************************************/ +#include "rom_sym_def.h" +#include "OSAL.h" +#include "fs.h" +#include "flash.h" +#include "error.h" +#include "log.h" + +//#define FS_DBBUG +#ifdef FS_DBBUG + #define FS_LOG LOG +#else + #define FS_LOG(...) +#endif + + +static uint8_t fs_sector_num; +static uint32_t fs_offset_address; + +#define FS_ITEM_LEN_16BYTE 0 +#define FS_ITEM_LEN_32BYTE 1 +#define FS_ITEM_LEN_64BYTE 2 + +#ifndef FS_SETTING + #define FS_SETTING FS_ITEM_LEN_16BYTE +#endif + +#if (FS_SETTING == FS_ITEM_LEN_16BYTE) + #define FS_ITEM_LEN 16 +#elif (FS_SETTING == FS_ITEM_LEN_32BYTE) + #define FS_ITEM_LEN 32 +#elif (FS_SETTING == FS_ITEM_LEN_64BYTE) + #define FS_ITEM_LEN 64 +#else + #error please check your config parameter +#endif + +/* + fs struct: + sector0 + sector_head + file_head(4byte)+file_data + ... + file_head(4byte)+file_data +*/ +//please do not modify the following parameters +#define FS_ITEM_HEAD_LEN 4 +#define FS_ITEM_DATA_LEN (FS_ITEM_LEN - FS_ITEM_HEAD_LEN) +#define FS_SECTOR_ITEM_NUM (4096/FS_ITEM_LEN - 1) +#define FS_SECTOR_NUM_BUFFER_SIZE (312/4) +#define FS_ABSOLUTE_ADDR(offset) (fs.cfg.sector_addr + offset) + +typedef enum +{ + ITEM_DEL = 0x00,//zone is deleted + ITEM_UNUSED = 0x03,//zone is free + ITEM_USED = 0x02,//zone is used + ITEM_RESERVED = 0x01//to be extend +} item_pro; + +typedef enum +{ + ITEM_SF = 0x03,//single frame file + ITEM_MF_F = 0x01,//multiple frame file,first frame + ITEM_MF_C = 0x02,//multiple frame file,continue frame + ITEM_MF_E = 0x00//multiple frame file,end frame +} item_frame; + +typedef enum +{ + FLASH_UNCHECK = 0,//before analysis fs + FLASH_NEW = 1,//new fs,its are 0xFF + FLASH_ORIGINAL_ORDER = 2,//fs has data,its order is the original + FLASH_NEW_ORDER = 3,//fs has data,its order is not the original + FLASH_CONTEXT_ERROR = 4,//fs has data,but data is broken +} FS_FLASH_TYPE; + +/* + file head struct: + len(12bit)+frame(2bit)+pro(2bit)+id(16bit) +*/ +typedef union +{ + struct + { + uint32_t id:16;//file id + uint32_t pro:2;//file property + uint32_t frame:2;//file frame + uint32_t len:12;//file length + } b; + uint32_t reg; +} fs_item_t; + +/* + sector head struct: + sector_addr(one word)+(ff+index+item_len+sector_num)(one word)+(0xffffffff)(one word)~(0xffffffff)(one word) +*/ +typedef struct +{ + uint32_t sector_addr;//fs start address + uint8_t sector_num;//fs sector number + uint8_t item_len;//item length + uint8_t index;//sector index + uint8_t reserved[FS_ITEM_LEN-7]; +} fs_cfg_t; + +typedef struct +{ + fs_cfg_t cfg; + uint8_t current_sector;//free sector index + uint8_t exchange_sector;//exchange sector,only use it when garbage collect + uint16_t offset;//free position in free sector index +} fs_t; + +static fs_t fs; +static bool fs_init_flag = false; + +typedef enum +{ + SEARCH_FREE_ITEM = 0, + SEARCH_APPOINTED_ITEM = 1, + SEARCH_DELETED_ITEMS = 2, +} search_type; + +extern uint32_t __psr(void);//check if in int process + +static void fs_erase_ucds_all_sector(void) +{ + int i; + + for(i=0; i= (fs_offset_address+fs_sector_num*4096)) || ((addr&0x03)>0)) + { + return PPlus_ERR_FS_PARAMETER; + } + + return(hal_flash_write(addr,value,(uint32_t)len)); +} + +static uint32_t fs_spif_read(uint32_t addr,uint8_t* buf,uint32_t len) +{ + if ((addr < fs_offset_address) || (addr >= (fs_offset_address + fs_sector_num*4096)) || (buf == NULL) || (len == 0)) + { + return PPlus_ERR_FS_PARAMETER; + } + + return( hal_flash_read(addr,buf,len) ); +} + +static void check_addr(uint32_t* addr) +{ + if((*addr % 4096) == 0) + { + *addr += sizeof(fs_cfg_t); + + if(*addr >= 4096 *fs_sector_num) + *addr -= 4096 *fs_sector_num; + } +} + +static int fs_search_items(search_type type,uint32_t* para1,uint32_t* para2) +{ + uint8_t m,n; + uint16_t j,g_offset = 1; + uint32_t sector_addr,ab_addr; + fs_item_t i1; + bool from_last_sector = false; + + for(m = 1; m < fs_sector_num; m++) + { + n = (m + fs.exchange_sector) % fs.cfg.sector_num; + + if(g_offset >= FS_SECTOR_ITEM_NUM) + { + g_offset -= FS_SECTOR_ITEM_NUM; + + if(g_offset >= FS_SECTOR_ITEM_NUM) + { + continue; + } + } + + if(SEARCH_FREE_ITEM == type) + fs.current_sector = (m + fs.exchange_sector) % fs.cfg.sector_num; + + sector_addr = n * 4096; + + for(j = 1; j <= FS_SECTOR_ITEM_NUM; j++) + { + if(from_last_sector == true) + { + from_last_sector = false; + j += g_offset; + } + else + { + if(g_offset > 1) + { + if((j - 2 + g_offset) < FS_SECTOR_ITEM_NUM) + { + j = j - 1 + g_offset; + } + else + { + g_offset -= (FS_SECTOR_ITEM_NUM + 2 - j); + from_last_sector = true; + break; + } + } + } + + ab_addr = sector_addr + (j * FS_ITEM_LEN); + fs_spif_read(FS_ABSOLUTE_ADDR(ab_addr),(uint8_t*)&i1,FS_ITEM_HEAD_LEN); + + switch(type) + { + case SEARCH_FREE_ITEM: + { + switch(i1.b.pro) + { + case ITEM_DEL: + case ITEM_USED: + { + if(i1.b.frame == ITEM_MF_F) + g_offset = (i1.b.len/FS_ITEM_DATA_LEN) + ((i1.b.len%FS_ITEM_DATA_LEN)?1:0); + else + g_offset = 1; + } + break; + + case ITEM_UNUSED: + *para1 = ab_addr%4096; + return PPlus_SUCCESS; + + default: + break; + } + } + break; + + case SEARCH_APPOINTED_ITEM: + { + switch(i1.b.pro) + { + case ITEM_DEL: + case ITEM_USED: + if((ITEM_USED == i1.b.pro) && (i1.b.id == (uint16)(*para1))) + { + *para2 = ab_addr; + return PPlus_SUCCESS; + } + else + { + if(i1.b.frame == ITEM_MF_F) + g_offset = (i1.b.len/FS_ITEM_DATA_LEN) + ((i1.b.len%FS_ITEM_DATA_LEN)?1:0); + else + g_offset = 1; + } + + break; + + case ITEM_UNUSED: + return PPlus_ERR_FS_NOT_FIND_ID; + + default: + break; + } + } + break; + + case SEARCH_DELETED_ITEMS: + { + switch(i1.b.pro) + { + case ITEM_DEL: + { + if(i1.b.frame == ITEM_MF_F) + { + g_offset = (i1.b.len/FS_ITEM_DATA_LEN) + ((i1.b.len%FS_ITEM_DATA_LEN)?1:0); + *para1 += g_offset*FS_ITEM_DATA_LEN; + } + else + { + g_offset = 1; + *para1 += FS_ITEM_DATA_LEN; + } + + *para2 += 1; + } + break; + + case ITEM_USED: + { + if(i1.b.frame == ITEM_MF_F) + { + g_offset = (i1.b.len/FS_ITEM_DATA_LEN) + ((i1.b.len%FS_ITEM_DATA_LEN)?1:0); + } + else + { + g_offset = 1; + } + } + break; + + case ITEM_UNUSED: + return PPlus_SUCCESS; + + default: + break; + } + } + break; + + default: + return PPlus_ERR_INVALID_PARAM; + } + } + } + + switch(type) + { + case SEARCH_FREE_ITEM: + return PPlus_ERR_FS_FULL; + + case SEARCH_APPOINTED_ITEM: + return PPlus_ERR_FS_NOT_FIND_ID; + + default: + return PPlus_SUCCESS; + } +} + +static int fs_get_free_item(void) +{ + int ret; + uint32_t posiztion = 0; + + if(fs_init_flag == false) + return PPlus_ERR_FS_UNINITIALIZED; + + ret = fs_search_items(SEARCH_FREE_ITEM,&posiztion,0); + + if(PPlus_SUCCESS == ret) + { + fs.offset = posiztion; + } + else if(PPlus_ERR_FS_FULL == ret) + { + fs.offset = 4096; + } + + return ret; +} + +static int fs_init(void) +{ + uint8_t i = 0,sector_order[FS_SECTOR_NUM_BUFFER_SIZE],ret = PPlus_ERR_FS_UNINITIALIZED; + FS_FLASH_TYPE flash = FLASH_UNCHECK; + fs_cfg_t flash_rd_cfg; + fs.cfg.sector_addr = fs_offset_address; + fs.cfg.sector_num = fs_sector_num;; + fs.cfg.index = 0xff; + fs.cfg.item_len = FS_ITEM_LEN; + osal_memset((fs.cfg.reserved),0xff,(FS_ITEM_LEN-7)*sizeof(uint8_t)); + osal_memset((sector_order),0x00,FS_SECTOR_NUM_BUFFER_SIZE); + FS_LOG("fs_init:\n"); + + for(i = 0; i < fs.cfg.sector_num; i++) + { + fs_spif_read(FS_ABSOLUTE_ADDR(4096*i),(uint8_t*)(&flash_rd_cfg),sizeof(fs_cfg_t)); + FS_LOG("flash_rd_cfg.sector_addr:%x\n",flash_rd_cfg.sector_addr); + FS_LOG("flash_rd_cfg.sector_num:%x\n",flash_rd_cfg.sector_num); + FS_LOG("flash_rd_cfg.item_len:%x\n",flash_rd_cfg.item_len); + FS_LOG("flash_rd_cfg.index:%x\n",flash_rd_cfg.index); + + if((flash_rd_cfg.sector_addr == fs.cfg.sector_addr) && + (flash_rd_cfg.sector_num == fs.cfg.sector_num) && + (flash_rd_cfg.item_len == fs.cfg.item_len)) + { + if(flash_rd_cfg.index < (fs_sector_num - 1)) + { + if(i == flash_rd_cfg.index) + { + flash = FLASH_ORIGINAL_ORDER; + FS_LOG("FLASH_ORIGINAL_ORDER\n"); + } + else + { + flash = FLASH_NEW_ORDER; + FS_LOG("FLASH_NEW_ORDER\n"); + } + + sector_order[i] = flash_rd_cfg.index; + fs.cfg.index = flash_rd_cfg.index; + } + else + { + flash = FLASH_CONTEXT_ERROR; + FS_LOG("FLASH_CONTEXT_ERROR1\n"); + break; + } + } + else if((flash_rd_cfg.sector_addr == 0xffffffff) && + (flash_rd_cfg.sector_num == 0xff) && + (flash_rd_cfg.item_len == 0xff)) + { + sector_order[i] = 0xff; + } + else + { + flash = FLASH_CONTEXT_ERROR; + FS_LOG("FLASH_CONTEXT_ERROR2\n"); + break; + } + } + + if(flash == FLASH_CONTEXT_ERROR) + { + return PPlus_ERR_FS_CONTEXT; + } + + if(fs.cfg.index == 0xff) + flash = FLASH_NEW; + + if(flash == FLASH_NEW) + { + for(i = 0; i < (fs.cfg.sector_num - 1); i++) + { + fs.cfg.index = i; + + if(PPlus_SUCCESS != fs_spif_write((FS_ABSOLUTE_ADDR(4096*i)),(uint8_t*)(&(fs.cfg)),sizeof(fs_cfg_t))) + { + FS_LOG("PPlus_ERR_FS_WRITE_FAILED\n"); + return PPlus_ERR_FS_WRITE_FAILED; + } + } + + fs.current_sector = 0; + fs.exchange_sector = fs.cfg.sector_num - 1; + fs.offset = sizeof(fs_cfg_t); + fs_init_flag = TRUE; + } + else + { + for(i = 0; i < fs.cfg.sector_num; i++) + { + if(sector_order[i] == 0) + break; + } + + if(i < fs.cfg.sector_num) + { + fs.exchange_sector = (i + fs.cfg.sector_num - 1) % fs.cfg.sector_num; + fs_init_flag = TRUE; + ret = fs_get_free_item(); + + if((ret != PPlus_ERR_FS_FULL) && (ret != PPlus_SUCCESS)) + { + FS_LOG("PPlus_ERR_FS_RESERVED_ERROR\n"); + return PPlus_ERR_FS_RESERVED_ERROR; + } + } + } + + FS_LOG("PPlus_SUCCESS\n"); + return PPlus_SUCCESS; +} + +uint32_t hal_fs_get_free_size(void) +{ + uint32_t size = 0; + + if(fs_init_flag == false) + { + //LOG("fs_init_flag = false,free\n"); + return 0; + } + + if(fs.offset < 4096) + { + size = ((fs.exchange_sector + fs.cfg.sector_num - fs.current_sector - 1)%fs.cfg.sector_num)*(4096-sizeof(fs_cfg_t)); + size += (4096 - fs.offset); + size = size*FS_ITEM_DATA_LEN/FS_ITEM_LEN; + } + + return size; +} + +int hal_fs_get_garbage_size(uint32_t* garbage_file_num) +{ + uint32_t garbage_size = 0,garbage_count = 0; + int ret; + + if(fs_init_flag == false) + return PPlus_ERR_FS_UNINITIALIZED; + + ret = fs_search_items(SEARCH_DELETED_ITEMS,&garbage_size,&garbage_count); + + if(PPlus_SUCCESS == ret) + { + if(NULL != garbage_file_num) + *garbage_file_num = garbage_count; + + return garbage_size; + } + + return PPlus_ERR_FATAL; +} + +int hal_fs_item_find_id(uint16_t id,uint32_t* id_addr) +{ + int ret; + uint32_t file_id = 0; + + if(fs_init_flag == false) + return PPlus_ERR_FS_UNINITIALIZED; + + file_id = id & 0xffff; + ret = fs_search_items(SEARCH_APPOINTED_ITEM,&file_id,id_addr); + return ret; +} + +int hal_fs_item_write(uint16_t id,uint8_t* buf,uint16_t len) +{ + uint8_t frame_len,wr_buf[FS_ITEM_LEN]; + uint16_t i,item_len; + uint32_t addr; + fs_item_t i1; + + if(__psr()&0x3f) + { + return PPlus_ERR_FS_IN_INT; + } + + if(fs_init_flag == false) + { + //LOG("fs_init_flag = false,write\n"); + return PPlus_ERR_FS_UNINITIALIZED; + } + + if((buf == NULL) || (len == 0)||(len > 4095)) + return PPlus_ERR_FS_PARAMETER; + + if(len > hal_fs_get_free_size()) + return PPlus_ERR_FS_NOT_ENOUGH_SIZE; + + //if(hal_fs_item_find_id(id,&addr) == PPlus_SUCCESS) + // return PPlus_ERR_FS_EXIST_SAME_ID; + if(hal_fs_item_find_id(id,&addr) == PPlus_SUCCESS) + { + if(PPlus_SUCCESS != hal_fs_item_del(id)) + return PPlus_ERR_FATAL; + } + + item_len = len; + i1.b.len = len; + i1.b.id = id; + i1.b.pro = ITEM_USED; + + if(len <= FS_ITEM_DATA_LEN) + i1.b.frame = ITEM_SF; + + i = 0; + + while(len > 0) + { + if(len > FS_ITEM_DATA_LEN) + { + if(item_len == len) + i1.b.frame = ITEM_MF_F; + else + i1.b.frame = ITEM_MF_C; + + frame_len = FS_ITEM_DATA_LEN; + len -= FS_ITEM_DATA_LEN; + } + else + { + if((i1.b.frame == ITEM_MF_C) || (i1.b.frame == ITEM_MF_F)) + i1.b.frame = ITEM_MF_E; + + frame_len = len; + len = 0; + } + + addr = FS_ABSOLUTE_ADDR((fs.current_sector * 4096) + fs.offset); + osal_memcpy(wr_buf,(uint8_t*)(&i1.reg),FS_ITEM_HEAD_LEN); + osal_memcpy((wr_buf + FS_ITEM_HEAD_LEN),(buf + i),frame_len); + + if(PPlus_SUCCESS != fs_spif_write(addr,wr_buf,(frame_len+FS_ITEM_HEAD_LEN))) + return PPlus_ERR_FS_WRITE_FAILED; + + i += frame_len; + fs.offset += FS_ITEM_LEN; + + if(fs.offset == 4096) + { + if(((fs.current_sector + 1) % fs.cfg.sector_num) != fs.exchange_sector) + { + fs.offset = sizeof(fs_cfg_t); + fs.current_sector = (fs.current_sector + 1) % fs.cfg.sector_num; + } + } + } + + return PPlus_SUCCESS; +} + +int hal_fs_item_read(uint16_t id,uint8_t* buf,uint16_t buf_len,uint16_t* len) +{ + uint8_t rd_len; + uint16_t i = 0,temp_len; + uint32_t addr; + fs_item_t i1; + + if(__psr()&0x3f) + { + return PPlus_ERR_FS_IN_INT; + } + + if(fs_init_flag == false) + return PPlus_ERR_FS_UNINITIALIZED; + + if((buf == NULL) || (buf_len == 0)) + return PPlus_ERR_FS_PARAMETER; + + if(hal_fs_item_find_id(id,&addr) == PPlus_SUCCESS) + { + fs_spif_read(FS_ABSOLUTE_ADDR(addr),(uint8_t*)&i1,FS_ITEM_HEAD_LEN); + + if(len != NULL) + { + *len = i1.b.len; + } + + temp_len = i1.b.len; + + if(buf_len >= i1.b.len) + { + while(temp_len > 0) + { + rd_len = (temp_len >= FS_ITEM_DATA_LEN) ? FS_ITEM_DATA_LEN : temp_len; + fs_spif_read(FS_ABSOLUTE_ADDR(addr + FS_ITEM_HEAD_LEN),(buf + i),rd_len); + temp_len -= rd_len; + addr += FS_ITEM_LEN; + i += rd_len; + check_addr(&addr); + } + + return PPlus_SUCCESS; + } + + return PPlus_ERR_FS_BUFFER_TOO_SMALL; + } + + return PPlus_ERR_FS_NOT_FIND_ID; +} + +int hal_fs_item_del(uint16_t id) +{ + uint16_t i = 0,count = 1; + uint32_t addr = 0; + fs_item_t i1; + + if(__psr()&0x3f) + { + return PPlus_ERR_FS_IN_INT; + } + + if(fs_init_flag == FALSE) + return PPlus_ERR_FS_UNINITIALIZED; + + if(hal_fs_item_find_id(id,&addr) == PPlus_SUCCESS) + { + fs_spif_read(FS_ABSOLUTE_ADDR(addr),(uint8_t*)&i1,FS_ITEM_HEAD_LEN); + count = i1.b.len/FS_ITEM_DATA_LEN + ((i1.b.len % FS_ITEM_DATA_LEN)?1:0); + + for(i = 0; i < count; i++) + { + fs_spif_read(FS_ABSOLUTE_ADDR(addr),(uint8_t*)&i1,FS_ITEM_HEAD_LEN); + i1.b.pro = ITEM_DEL; + + if(PPlus_SUCCESS != fs_spif_write(FS_ABSOLUTE_ADDR(addr),(uint8_t*)(&i1.reg),FS_ITEM_HEAD_LEN)) + return PPlus_ERR_FS_WRITE_FAILED; + + addr += FS_ITEM_LEN; + check_addr(&addr); + } + + return PPlus_SUCCESS; + } + else + { + return PPlus_ERR_FS_NOT_FIND_ID; + } +} + +int hal_fs_garbage_collect(void) +{ + uint8_t i,j,buf[FS_ITEM_DATA_LEN]; + uint8_t from_sector_index = 0,to_sector_index = 0; + uint32_t addr_rd=0,addr_wr=0,addr_erase; + fs_item_t i1; + + if(__psr()&0x3f) + { + return PPlus_ERR_FS_IN_INT; + } + + if(fs_init_flag == FALSE) + return PPlus_ERR_FS_UNINITIALIZED; + + to_sector_index = fs.exchange_sector; + from_sector_index = (fs.exchange_sector + 1) % fs.cfg.sector_num; + addr_wr = 4096*to_sector_index; + + for(i = 0; i < (fs.cfg.sector_num - 1); i++) + { + addr_rd = 4096*((from_sector_index + i) % fs.cfg.sector_num); + addr_erase = addr_rd; + fs.cfg.index = i; + + if(PPlus_SUCCESS != fs_spif_write(FS_ABSOLUTE_ADDR((4096*((to_sector_index + i) % fs.cfg.sector_num))),(uint8_t*)(&(fs.cfg)),sizeof(fs_cfg_t))) + return PPlus_ERR_FS_WRITE_FAILED; + + if(i == 0) + addr_wr += sizeof(fs_cfg_t); + + addr_rd += sizeof(fs_cfg_t); + + for(j = 0; j < FS_SECTOR_ITEM_NUM; j++) + { + fs_spif_read(FS_ABSOLUTE_ADDR(addr_rd),(uint8_t*)&i1,FS_ITEM_HEAD_LEN); + + if(i1.b.pro == ITEM_USED) + { + fs_spif_read(FS_ABSOLUTE_ADDR(addr_rd + FS_ITEM_HEAD_LEN),buf,FS_ITEM_DATA_LEN); + + if(PPlus_SUCCESS != fs_spif_write(FS_ABSOLUTE_ADDR(addr_wr),(uint8_t*)(&i1.reg),FS_ITEM_HEAD_LEN)) + return PPlus_ERR_FS_WRITE_FAILED; + + if(PPlus_SUCCESS != fs_spif_write(FS_ABSOLUTE_ADDR(addr_wr + FS_ITEM_HEAD_LEN),buf,FS_ITEM_DATA_LEN)) + return PPlus_ERR_FS_WRITE_FAILED; + + addr_wr += FS_ITEM_LEN; + check_addr(&addr_wr); + } + else if(i1.b.pro == ITEM_UNUSED) + { + break; + } + + addr_rd += FS_ITEM_LEN; + } + + fs_erase_ucds_one_sector(addr_erase); + } + + return fs_init(); +} + +int hal_fs_format(uint32_t fs_start_address,uint8_t sector_num) +{ + if(__psr()&0x3f) + { + return PPlus_ERR_FS_IN_INT; + } + + fs_init_flag = FALSE; + + if((fs_start_address % 0x1000) || (sector_num < 3)) + { + return PPlus_ERR_INVALID_PARAM; + } + + fs_sector_num = sector_num; + fs_offset_address = fs_start_address; + fs_erase_ucds_all_sector(); + return hal_fs_init(fs_start_address,sector_num); +} + +int hal_fs_init(uint32_t fs_start_address,uint8_t sector_num) +{ + if(fs_init_flag == TRUE) + { + return PPlus_ERR_FS_UNINITIALIZED; + } + + if((fs_start_address % 0x1000) || (sector_num < 2)) + { + return PPlus_ERR_INVALID_PARAM; + } + + fs_sector_num = sector_num; + fs_offset_address = fs_start_address; + return fs_init(); +} + + +bool hal_fs_initialized(void) +{ + return fs_init_flag; +} diff --git a/src/components/libraries/fs/fs.h b/src/components/libraries/fs/fs.h new file mode 100644 index 0000000..a4debb0 --- /dev/null +++ b/src/components/libraries/fs/fs.h @@ -0,0 +1,244 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file fs.h + @brief Contains all functions support for spi driver + @version 0.0 + @date 18. Oct. 2017 + @author + + + +*******************************************************************************/ +#ifndef __FS_H__ +#define __FS_H__ + +#include "types.h" + +/************************************************************************************** + @fn hal_fs_init + + @brief initialize fs. + if fs is new,use fs_start_address and sector_num to config fs. + if fs is not new,read fs every sector head data and check with fs_start_address and sector_num, + if same,the fs is valid,else is invalid. + + input parameters + + @param fs_start_address: + fs zone start address,4Kbyte align. + fs zone should not cover phy code and app code. + + sector_num: + fs zone sector number,one sector = 4Kbyte,its minimal size is 2. + fs zone should not cover phy code and app code. + + output parameters + + @param None. + + @return + PPlus_SUCCESS fs init success. + PPlus_ERR_FS_UNINITIALIZED fs has not been inited. + PPlus_ERR_INVALID_PARAM parameter error,check your parameter. + PPlus_ERR_FS_CONTEXT fs has data but different with your parameter. + PPlus_ERR_FS_WRITE_FAILED flash cannot write. + PPlus_ERR_FS_RESERVED_ERROR reserved error. + **************************************************************************************/ +int hal_fs_init(uint32_t fs_start_address,uint8_t sector_num); + +/************************************************************************************** + @fn hal_fs_item_read + + @brief read a file from fs. + + input parameters + + @param id:file id,it should be unique. + + buf:file buf to be read. + + buf_len:file buf len. + + len:*len is the file length after read from fs. + + output parameters + + @param None. + + @return + PPlus_SUCCESS file write success. + PPlus_ERR_FS_IN_INT write later beyond int processing. + PPlus_ERR_FS_UNINITIALIZED fs has not been inited. + PPlus_ERR_FS_PARAMETER parameter error,check it. + PPlus_ERR_FS_BUFFER_TOO_SMALL buf is too small. + PPlus_ERR_FS_NOT_FIND_ID there is no this file in fs. + **************************************************************************************/ +int hal_fs_item_read(uint16_t id,uint8_t* buf,uint16_t buf_len,uint16_t* len); + +/************************************************************************************** + @fn hal_fs_item_write + + @brief write a file to fs. + + input parameters + + @param id:file id,it should be unique. + + buf:file buf. + + len:file length. + + output parameters + + @param None. + + @return + PPlus_SUCCESS file write success + PPlus_ERR_FS_IN_INT write later beyond int processing + PPlus_ERR_FS_UNINITIALIZED fs has not been inited + PPlus_ERR_FS_PARAMETER parameter error,check it + PPlus_ERR_FS_NOT_ENOUGH_SIZE there is not enouth size to write this file + PPlus_ERR_FATAL there is a same id file,when delete it,occur a error + **************************************************************************************/ +int hal_fs_item_write(uint16_t id,uint8_t* buf,uint16_t len); + +/************************************************************************************** + @fn hal_fs_get_free_size + + @brief get fs free size. + just file data not include file head. + for example,16bytes=4byte+12byte,free size is 12byte. + + input parameters + + @param None. + + output parameters + + @param None. + + @return + free size + **************************************************************************************/ +uint32_t hal_fs_get_free_size(void); + +/************************************************************************************** + @fn hal_fs_get_garbage_size + + @brief get fs garbage size. + some deleted files is in garbage,its size is garbage sise. + only after garbage collect the garbage will be released to free. + just file data not include file head. + for example,16bytes=4byte+12byte,garbage size is 12byte. + + input parameters + + @param None. + + output parameters + + @param garbage_file_num:deleted file number + + @return + garbage size + **************************************************************************************/ +int hal_fs_get_garbage_size(uint32_t* garbage_file_num); +/************************************************************************************** + @fn hal_fs_item_del + + @brief delete a file from fs. + + input parameters + + @param id:file id,it should be unique. + + output parameters + + @param None. + + @return + PPlus_SUCCESS file delete success + PPlus_ERR_FS_IN_INT delete later beyond int processing + PPlus_ERR_FS_UNINITIALIZED fs has not been inited + PPlus_ERR_FS_NOT_FIND_ID not find this file in fs + **************************************************************************************/ +int hal_fs_item_del(uint16_t id); + +/************************************************************************************** + @fn hal_fs_garbage_collect + + @brief release all deleted file zone to free + + input parameters + + @param None. + + output parameters + + @param None. + + @return + PPlus_SUCCESS collect success + PPlus_ERR_FS_IN_INT delete later beyond int processing + PPlus_ERR_FS_UNINITIALIZED fs has not been inited + PPlus_ERR_FS_WRITE_FAILED flash cannot write. + PPlus_ERR_FS_UNINITIALIZED fs has not been inited. + PPlus_ERR_FS_CONTEXT fs has data but different with your parameter. + PPlus_ERR_FS_RESERVED_ERROR reserved error. + **************************************************************************************/ +int hal_fs_garbage_collect(void); + +/************************************************************************************** + @fn hal_fs_format + + @brief format fs.all fs data will be clean. + + input parameters + + @param fs_start_address: + fs zone start address,4Kbyte align. + fs zone should not cover phy code and app code. + + sector_num: + fs zone sector number,one sector = 4Kbyte,its minimal size is 3. + fs zone should not cover phy code and app code. + + output parameters + + @param None. + + @return + PPlus_SUCCESS fs format and init success. + PPlus_ERR_FS_IN_INT delete later beyond int processing + PPlus_ERR_FS_UNINITIALIZED fs has not been inited. + PPlus_ERR_INVALID_PARAM parameter error,check your parameter. + PPlus_ERR_FS_CONTEXT fs has data but different with your parameter. + PPlus_ERR_FS_WRITE_FAILED flash cannot write. + PPlus_ERR_FS_RESERVED_ERROR reserved error. + **************************************************************************************/ +int hal_fs_format(uint32_t fs_start_address,uint8_t sector_num); + +/************************************************************************************** + @fn hal_fs_initialized + + @brief fs has been initialized or not. + if not,fs is disable,please use hal_fs_init to initialize it. + + input parameters + + @param none. + + output parameters + + @param None. + + @return + TRUE + FALSE + **************************************************************************************/ +bool hal_fs_initialized(void); + +#endif diff --git a/src/components/libraries/fs/fs_test.c b/src/components/libraries/fs/fs_test.c new file mode 100644 index 0000000..0d87a40 --- /dev/null +++ b/src/components/libraries/fs/fs_test.c @@ -0,0 +1,1440 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ +#include "rom_sym_def.h" +#include "osal.h" +#include "crc16.h" +#include "fs.h" +#include "error.h" +#include "fs_test.h" +#include "clock.h" +#include "log.h" + +#if (FS_TEST_TYPE == FS_MODULE_TEST) + +#define FTST_MAX_FILE_CNT 256 +#define FTST_MAX_FILE_SIZE 4095 + +typedef struct +{ + uint16_t fid; + uint16_t fsize; + uint16_t fcrc; + uint16_t del_flg;//0: file exist; 1: file deleted +} ftst_t; + +static ftst_t s_fpool[FTST_MAX_FILE_CNT]; +static uint16_t s_ftst_fid_num = 0; +uint8_t s_ftst_buf[4095]; + +static void fstest_init(void) +{ + int i = 0; + osal_memset((void*)s_fpool, 0, sizeof(s_fpool)); + osal_memset(s_ftst_buf, 0, sizeof(s_ftst_buf)); + s_ftst_fid_num = 0; + + for(i = 0; i< FTST_MAX_FILE_CNT; i++) + { + s_fpool[i].fid = 0xffff; + } +} + +uint16_t fstest_gen_new_fid(uint16_t fid_num_limit) +{ + uint16_t id; + uint32_t i; + bool new_flag = false; + + do + { + id = (uint16_t)osal_rand(); + new_flag = true; + + for(i = 0; i< s_ftst_fid_num; i++) + { + if((s_fpool[i].fid == id)&&(s_fpool[i].del_flg == false)) + { + new_flag = false; + break; + } + } + } + while(new_flag == false); + + if(s_ftst_fid_num >= fid_num_limit || s_ftst_fid_num >= FTST_MAX_FILE_CNT) + { + fid_num_limit = fid_num_limit>FTST_MAX_FILE_CNT ? FTST_MAX_FILE_CNT : fid_num_limit; + id = id%s_ftst_fid_num; + return s_fpool[id].fid; + } + + if(id == 0xffff) + id = id/2; + + return id; +} + +static void fstest_gen_fsdata(ftst_t* pftst, uint16_t size_limit, uint16_t fid_num_limit) +{ + uint16_t size; + uint16_t i; + size_limit = size_limit >FTST_MAX_FILE_SIZE?FTST_MAX_FILE_SIZE:size_limit; + size = 1+ osal_rand()%(size_limit-1); + + if(pftst->fid == 0xffff) + { + pftst->fid = fstest_gen_new_fid(fid_num_limit); + } + + for(i = 0; i< size; i++) + { + s_ftst_buf[i] = (uint8_t)(osal_rand()&0xff); + } + + pftst->del_flg = 0; + pftst->fcrc = crc16(0, s_ftst_buf, size); + pftst->fsize = size; +} + + +static uint16_t fstest_save_fsdata(ftst_t* pftst, uint16_t fid_num_limit) +{ + uint16_t i; + fid_num_limit = (fid_num_limit > FTST_MAX_FILE_CNT )? FTST_MAX_FILE_CNT: fid_num_limit; + + for(i = 0; i< fid_num_limit; i++) + { + if(s_fpool[i].fid == pftst->fid) + { + s_fpool[i].del_flg = pftst->del_flg; + s_fpool[i].fcrc = pftst->fcrc; + s_fpool[i].fsize = pftst->fsize; + return i; + } + + if(s_fpool[i].fid == 0xffff) + { + s_fpool[i].fid = pftst->fid; + s_fpool[i].del_flg = pftst->del_flg; + s_fpool[i].fcrc = pftst->fcrc; + s_fpool[i].fsize = pftst->fsize; + s_ftst_fid_num++; + return i; + } + } + + LOG("file count out of test range\n"); + //while(1);;; + return 0xffff; +} + +bool fstest_validate_fsdata(ftst_t* pftst) +{ + int i; + int ret; + uint16_t crc = 0; + ftst_t* pft; + + if(pftst) + { + pft = pftst; + ret = hal_fs_item_read(pft->fid, s_ftst_buf, pft->fsize, NULL); + + if(ret != 0) + { + LOG("ftest_validate_fsdata failed!,fid[0x%x], fsize[%d]\n", pft->fid, pft->fsize); + //while(1);;; + return FALSE; + } + + crc = crc16(0, s_ftst_buf, pft->fsize); + + if(crc != pft->fcrc) + { + LOG("ftest_validate_fsdata CRC error!,fid[0x%x], fsize[%d]\n", pft->fid, pft->fsize); + //while(1);;; + return FALSE; + } + + return TRUE; + } + + for(i = 0; i< s_ftst_fid_num; i++) + { + pft = &(s_fpool[i]); + + if(pft->del_flg) + continue; + + ret = hal_fs_item_read(pft->fid, s_ftst_buf, pft->fsize, NULL); + + if(ret != 0) + { + LOG("ftest_validate_fsdata failed!,fid[0x%x], fsize[%d]\n", pft->fid, pft->fsize); + //hile(1);;; + return FALSE; + } + + crc = crc16(0, s_ftst_buf, pft->fsize); + + if(crc != pft->fcrc) + { + LOG("ftest_validate_fsdata CRC error!,fid[0x%x], fsize[%d]\n", pft->fid, pft->fsize); + //while(1);;; + return FALSE; + } + } + + return TRUE; +} + +int fstest_del(void) +{ + int ret; + uint32_t id_index; + + while(1) + { + id_index = osal_rand()%s_ftst_fid_num; + + if(s_fpool[id_index].del_flg == false) + { + break; + } + } + + ret = hal_fs_item_del(s_fpool[id_index].fid); + + if(ret == PPlus_SUCCESS) + { + s_fpool[id_index].del_flg = true; + return PPlus_SUCCESS; + } + + return PPlus_ERR_FATAL; +} + +void ftcase_simple_write_test(void) +{ + int i; + int iret; + uint16_t index; + char* str_result = "Skip"; + ftst_t ftst_item; + bool error_flag = false; + fstest_init(); + //if(PPlus_ERR_FS_CONTEXT == hal_fs_init(FS_OFFSET_ADDRESS,FS_SECTOR_NUM)) + { + iret = hal_fs_format(FS_OFFSET_ADDRESS,FS_SECTOR_NUM); + + if(iret != PPlus_SUCCESS) + { + LOG("format error\n"); + + while(1); + } + } + str_result = "Success"; + + for(i = 0; i < 20; i++) + { + ftst_item.fid = 0xffff; + fstest_gen_fsdata(&ftst_item, 256, 0xffff);//size_limit fid_num_limit + iret = hal_fs_item_write(ftst_item.fid,s_ftst_buf,ftst_item.fsize); + + if(iret != 0) + { + LOG("fs write error[%d], fid[0x%x], fsize[%d]\n",iret,ftst_item.fid,ftst_item.fsize); + str_result = "FS data validation error"; + error_flag = true; + //while(1);;; + break; + } + + index = fstest_save_fsdata(&ftst_item,256); + + if(index == 0xffff) + { + LOG("fs save error[%d], fid[0x%x], fsize[%d]\n",index, ftst_item.fid, ftst_item.fsize); + str_result = "FS data validation error"; + error_flag = true; + break; + } + + if(fstest_validate_fsdata(NULL) == FALSE) + { + str_result = "FS data validation error"; + error_flag = true; + break; + } + } + + LOG("fstest_simple_write_test %s\n", str_result); + + if(error_flag == true) + { + LOG("fs error!\n"); + + while(1);;; + } +} + + +void ftcase_write_del_test(void) +{ + int i; + int iret; + uint16_t index; + uint32_t garbage_num = 0; + char* str_result = "Skip"; + ftst_t ftst_item; + bool error_flag = false; + fstest_init(); + //if(PPlus_ERR_FS_CONTEXT == hal_fs_init(FS_OFFSET_ADDRESS,FS_SECTOR_NUM)) + { + iret = hal_fs_format(FS_OFFSET_ADDRESS,FS_SECTOR_NUM); + + if(iret != PPlus_SUCCESS) + { + LOG("format error\n"); + + while(1); + } + } + str_result = "Success"; + + for(i=0;; i++) + { + ftst_item.fid = 0xffff; + fstest_gen_fsdata(&ftst_item, 256, 0xfffe); + + if(ftst_item.fsize > hal_fs_get_free_size()) + { + LOG("test end!\n"); + break; + } + + iret = hal_fs_item_write(ftst_item.fid, s_ftst_buf, ftst_item.fsize); + + if(iret != 0) + { + LOG("fs write error[%d], fid[0x%x], fsize[%d]\n", iret,ftst_item.fid, ftst_item.fsize); + str_result = "FS data validation error"; + error_flag = true; + break; + } + + index = fstest_save_fsdata(&ftst_item, 256); + + if(index == 0xffff) + { + LOG("fs save error[%d], fid[0x%x], fsize[%d]\n", iret,ftst_item.fid, ftst_item.fsize); + str_result = "FS data validation error"; + error_flag = true; + break; + } + + if(fstest_validate_fsdata(NULL) == FALSE) + { + str_result = "FS data validation error"; + error_flag = true; + break; + } + + if(((i%8)==0) && (i>0)) + { + iret = fstest_del(); + + if(iret != PPlus_SUCCESS) + { + str_result = "FS del error"; + error_flag = true; + } + } + + if(hal_fs_get_garbage_size(&garbage_num) > 256) + { + iret = hal_fs_garbage_collect(); + + if(iret != PPlus_SUCCESS) + { + str_result = "FS compresss error"; + error_flag = true; + } + else + { + LOG("compress_ok\n"); + } + } + + WaitMs(1); + } + + LOG("ftcase_write_del_test %s\n", str_result); + + if(error_flag == true) + { + LOG("fs error!\n"); + + while(1);;; + } +} + + +void ftcase_write_del_and_ble_enable_test(void) +{ + static int i; + int iret; + uint16_t index; + ftst_t ftst_item; + bool error_flag = false; + static bool firstFlag = true; + uint32_t garbage_num = 0; + + if(firstFlag == true) + { + fstest_init(); + //if(PPlus_ERR_FS_CONTEXT == hal_fs_init(FS_OFFSET_ADDRESS,FS_SECTOR_NUM)) + { + iret = hal_fs_format(FS_OFFSET_ADDRESS,FS_SECTOR_NUM); + + if(iret != PPlus_SUCCESS) + { + LOG("format error\n"); + + while(1); + } + } + firstFlag = false; + i =0; + } + else + { + i++; + } + + { + ftst_item.fid = 0xffff; + fstest_gen_fsdata(&ftst_item, 256, 0xfffe); + + if(ftst_item.fsize > hal_fs_get_free_size()) + { + LOG("\nreinit_and_test:%d %d \n",ftst_item.fsize,hal_fs_get_free_size()); + firstFlag = true; + return; + } + + iret = hal_fs_item_write(ftst_item.fid, s_ftst_buf, ftst_item.fsize); + + if(iret != 0) + { + LOG("fs write error[%d], fid[0x%x], fsize[%d],%d\n", iret,ftst_item.fid, ftst_item.fsize); + iret = hal_fs_item_write(ftst_item.fid, s_ftst_buf, ftst_item.fsize); //to debug + error_flag = true; + + while(1);;; + } + + index = fstest_save_fsdata(&ftst_item, 256); + + if(index == 0xffff) + { + LOG("fs save error[%d], fid[0x%x], fsize[%d]\n", iret,ftst_item.fid, ftst_item.fsize); + error_flag = true; + + while(1);;; + } + + if(fstest_validate_fsdata(NULL) == FALSE) + { + LOG("FS data validation error\n"); + error_flag = true; + + while(1);;; + } + + if(((i%4)==0) && (i>0)) + { + iret = fstest_del(); + + if(iret != PPlus_SUCCESS) + { + LOG("FS del error\n"); + error_flag = true; + + while(1);;; + } + else + { + LOG("."); + } + } + + if(hal_fs_get_garbage_size(&garbage_num) > 1024) + { + iret = hal_fs_garbage_collect(); + + if(iret != PPlus_SUCCESS) + { + LOG("FS compresss error,%d\n",iret); + error_flag = true; + + while(1); + } + else + { + LOG("compress_ok\n"); + } + } + } + + if(error_flag == true) + { + LOG("fs error!\n"); + + while(1);;; + } +} + +#elif (FS_TEST_TYPE == FS_EXAMPLE) + + +#include +#define FS_HOLD {LOG("line:%d\n",__LINE__);while(1);} + +uint8_t id_buf[4095]; +#define FS_ITEM_TEST2 127 +void fs_example(void) +{ + int ret; + uint32_t free_size; + uint16 id = 1,id_len; + uint16 i,file_len; + static uint8_t testCase = 1; + static uint8_t testCycle = 0; + bool errFlag; + uint32_t garbage_num = 0; + + if(testCycle >= 5) + { + LOG("fs example end!\n"); + return; + } + + if(hal_fs_initialized() == FALSE) + { + ret = hal_fs_init(FS_OFFSET_ADDRESS,FS_SECTOR_NUM); + + if(PPlus_SUCCESS != ret) + { + LOG("error:%d\n",ret); + FS_HOLD; + } + } + + osal_memset(id_buf,0x00,4095); + + for(i=0; i<4095; i++) + { + id_buf[i] = i%256; + } + + switch(testCase) + { + case 1://write two files to fs,one is the mix length,one is the max length + { + LOG("\nfs_write................................................\n"); + free_size = hal_fs_get_free_size(); + LOG("free_size:%d\n",free_size); + id = 1; + id_len = 1; + + if(id_len < free_size) + { + ret = hal_fs_item_write(id,id_buf,id_len); + + if(PPlus_SUCCESS != ret) + { + LOG("error:%d\n",ret); + FS_HOLD; + } + else + LOG("write ok\n"); + } + + id = FS_ITEM_TEST2; + id_len = FS_ITEM_TEST2; + + if(id_len < free_size) + { + ret = hal_fs_item_write(id,id_buf,id_len); + + if(PPlus_SUCCESS != ret) + { + LOG("error:%d\n",ret); + FS_HOLD; + } + else + LOG("write ok\n"); + } + + free_size = hal_fs_get_free_size(); + LOG("free_size:%d\n",free_size); + //while(1);;;;; + break; + } + + case 2://read the two files + { + LOG("\nfs_read................................................\n"); + osal_memset(id_buf,0x00,1); + id = 1; + ret = hal_fs_item_read(id,id_buf,1,&file_len); + + if(PPlus_SUCCESS != ret) + { + LOG("error:%d\n",ret); + FS_HOLD; + } + + LOG("id:%d\n",id); + LOG("id len:%d\n",file_len); + LOG("id data:\n"); + errFlag = FALSE; + + for(i=0; i 4) + { + testCase = 1; + testCycle++; + LOG("\nfs test cycle:%d................................................\n",testCycle); + } +} + +#elif (FS_TEST_TYPE == FS_TIMING_TEST) + +#include "flash.h" +#define TOGGLE_GPIO GPIO_P14 +uint8_t id_buf[4095]; +void fs_timing_test(void) +{ + uint8_t testCase = 4,data_wr[4]= {0x12,0x34,0x56,0x78}; + uint16_t i,file_len; + int ret; + uint32_t garbage_size,garbage_num; + hal_gpio_write(TOGGLE_GPIO,1); + WaitMs(1); + testCase = 9; + + switch(testCase) + { + case 0: + hal_gpio_write(TOGGLE_GPIO,0); + hal_flash_erase_sector(0x11005000); + hal_gpio_write(TOGGLE_GPIO,1); + WaitMs(1); + break; + + case 1: + hal_gpio_write(TOGGLE_GPIO,0); + hal_flash_write(0x1100500c,data_wr,4); + hal_gpio_write(TOGGLE_GPIO,1); + WaitMs(1); + break; + + case 2: + hal_gpio_write(TOGGLE_GPIO,0); + osal_memcpy((uint8_t*)id_buf,(uint8_t*)0x11005000,4); + hal_gpio_write(TOGGLE_GPIO,1); + WaitMs(1); + break; + + case 3: + hal_gpio_write(TOGGLE_GPIO,0); + ret = hal_fs_format(0x11005000,3); + hal_gpio_write(TOGGLE_GPIO,1); + WaitMs(1); + + if(ret != PPlus_SUCCESS) + { + LOG("ret:%d",ret); + } + + break; + + case 4: + hal_gpio_write(TOGGLE_GPIO,0); + ret = hal_fs_init(0x11005000,3); + hal_gpio_write(TOGGLE_GPIO,1); + WaitMs(1); + + if(ret != PPlus_SUCCESS) + { + LOG("ret:%d",ret); + } + + ret = hal_fs_item_write(1,id_buf,1); + ret = hal_fs_item_write(2,id_buf,2); + ret = hal_fs_item_write(3,id_buf,3); + ret = hal_fs_item_write(4,id_buf,4); + ret = hal_fs_item_write(5,id_buf,5); + ret = hal_fs_item_write(6,id_buf,6); + ret = hal_fs_item_write(7,id_buf,7); + ret = hal_fs_item_write(8,id_buf,8); + ret = hal_fs_item_write(9,id_buf,9); + ret = hal_fs_item_write(10,id_buf,10); + WaitMs(1); + break; + + case 5: + hal_gpio_write(TOGGLE_GPIO,0); + ret = hal_fs_init(0x11005000,3); + hal_gpio_write(TOGGLE_GPIO,1); + WaitMs(1); + + if(ret != PPlus_SUCCESS) + { + LOG("ret:%d",ret); + } + + break; + + case 6: + LOG("write file\n"); + + for(i=0; i<4095; i++) + id_buf[i] = (i+1)%256; + + ret = hal_fs_format(0x11005000,3); + + if(ret != PPlus_SUCCESS) + { + LOG("ret:%d",ret); + } + + WaitMs(1); + hal_gpio_write(TOGGLE_GPIO,0); + ret = hal_fs_item_write(1,id_buf,1); + hal_gpio_write(TOGGLE_GPIO,1); + WaitMs(5); + hal_gpio_write(TOGGLE_GPIO,0); + ret = hal_fs_item_write(2,id_buf,100); + hal_gpio_write(TOGGLE_GPIO,1); + WaitMs(5); + hal_gpio_write(TOGGLE_GPIO,0); + ret = hal_fs_item_write(3,id_buf,100); + hal_gpio_write(TOGGLE_GPIO,1); + WaitMs(5); + break; + + case 7: + LOG("read file\n"); + ret = hal_fs_init(0x11005000,3); + WaitMs(1); + hal_gpio_write(TOGGLE_GPIO,0); + ret = hal_fs_item_read(1,id_buf,4095,&file_len); + hal_gpio_write(TOGGLE_GPIO,1); + WaitMs(1); + LOG("ret:%d",ret); + hal_gpio_write(TOGGLE_GPIO,0); + ret = hal_fs_item_read(2,id_buf,4095,&file_len); + hal_gpio_write(TOGGLE_GPIO,1); + WaitMs(1); + LOG("ret:%d",ret); + hal_gpio_write(TOGGLE_GPIO,0); + ret = hal_fs_item_read(3,id_buf,4095,&file_len); + hal_gpio_write(TOGGLE_GPIO,1); + WaitMs(1); + LOG("ret:%d",ret); + break; + + case 8: + LOG("del file\n"); + ret = hal_fs_init(0x11005000,3); + WaitMs(1); + hal_gpio_write(TOGGLE_GPIO,0); + ret = hal_fs_item_del(1); + hal_gpio_write(TOGGLE_GPIO,1); + WaitMs(1); + LOG("ret:%d",ret); + hal_gpio_write(TOGGLE_GPIO,0); + ret = hal_fs_item_del(2); + hal_gpio_write(TOGGLE_GPIO,1); + WaitMs(1); + LOG("ret:%d",ret); + hal_gpio_write(TOGGLE_GPIO,0); + ret =hal_fs_item_del(3); + hal_gpio_write(TOGGLE_GPIO,1); + WaitMs(1); + LOG("ret:%d",ret); + break; + + case 9: + LOG("garbage calc and collect\n"); + ret = hal_fs_init(0x11005000,3); + + if(ret != PPlus_SUCCESS) + { + LOG("hal_fs_init error:%d\n",ret); + } + + WaitMs(5); + hal_gpio_write(TOGGLE_GPIO,0); + garbage_size = hal_fs_get_garbage_size(&garbage_num); + hal_gpio_write(TOGGLE_GPIO,1); + LOG("garbage_num:%d garbage_size:%d\n",garbage_num,garbage_size); + WaitMs(5); + hal_gpio_write(TOGGLE_GPIO,0); + ret = hal_fs_garbage_collect(); + hal_gpio_write(TOGGLE_GPIO,1); + + if(ret != PPlus_SUCCESS) + { + LOG("hal_fs_garbage_collect error:%d\n",ret); + } + + WaitMs(5); + break; + + default: + break; + } + + while(1);;; +} + +#elif (FS_TEST_TYPE == FS_XIP_TEST) + +#include "flash.h" + +#define FS_LOG LOG +//#define FS_DBG_EN +/* + test flash api: + int hal_flash_erase_sector(unsigned int addr) + int hal_flash_write(uint32_t addr, uint8_t* data, uint32_t size) + int hal_flash_read(uint32_t addr, uint8_t *data, uint32_t size) + + test config: + #define MIN_WR_SIZE 4 + #define MIN_RD_SIZE 4 +*/ +extern const unsigned char c_data_wr[4096]; +unsigned char c_data_rd[4096]; +#define FS_RET_RRROR(ret) \ + if(ret!= PPlus_SUCCESS) \ + { \ + LOG("err:%d %d",ret,__LINE__); \ + while(1); \ + } + +#define MIN_WR_SIZE 4 +#define MIN_RD_SIZE 4 +/* + erase sector + write 4096 + read 4096 + write 4092 4 + read 4092 4 + ... + write 2048 2048 + read 2048 2048 +*/ +//#define DBG_IO_TOGLE(a,b) do{ for(int i=0;iswporta_dr |= BIT(P11);//output=1 + AP_GPIO->swporta_ddr |= BIT(P11);//set output + AP_GPIO->swporta_dr |= BIT(P14);//output=1 + AP_GPIO->swporta_ddr |= BIT(P14);//set output + AP_GPIO->swporta_dr &= ~BIT(P14); + AP_GPIO->swporta_dr &= ~BIT(P11); + { + ret0 = hal_flash_erase_sector(sector_addr); + } + AP_GPIO->swporta_dr |= BIT(P11); + AP_GPIO->swporta_dr &= ~BIT(P11); + { + ret1 = hal_flash_write(sector_addr,p_wr,4096-wr_data_len); + } + AP_GPIO->swporta_dr |= BIT(P11); + AP_GPIO->swporta_dr &= ~BIT(P11); + { + ret2 = hal_flash_read(sector_addr,p_rd,4096); + } + AP_GPIO->swporta_dr |= BIT(P11); + AP_GPIO->swporta_dr |= BIT(P14); + #ifdef FS_DBG_EN + FS_LOG("xip test end:%d %d %d\n",ret0,ret1,ret2); + #endif + + while(1); + } +} + +#elif (XIP_TEST_TYPE == XIP_FUNCTION) +{ + const uint32_t sector_addr = 0x1103f000; + uint32_t i=0,j=0,run_counter = 0; + uint32_t wr_data_len = 0,rd_data_len = 0; + uint8_t* const p_wr = (uint8_t*)c_data_wr; + uint8_t* const p_rd = (uint8_t*)c_data_rd; + int ret; + #ifdef FS_DBG_EN + FS_LOG("\nc_data_wr:%x\n",(uint32_t*)c_data_wr); + + for(j=0; j<4096; j++) + { + FS_LOG("0x%x,",*(p_wr+j)); + + if((j+1)%0x10==0) + { + FS_LOG("\n"); + } + } + + FS_LOG("\nend\n"); + #endif + + while(1) + { + #ifdef FS_DBG_EN + FS_LOG("wr len:%d rd_len:%d\n",wr_data_len,rd_data_len); + #endif + FS_LOG("erase:"); + hal_flash_erase_sector(sector_addr); + + for(i=sector_addr; i<(sector_addr+4096); i+=MIN_RD_SIZE) + { + ret = hal_flash_read(i,p_rd,MIN_RD_SIZE); + FS_RET_RRROR(ret); + + for(j=0; j<4; j++) + { + if(*(p_rd+j) != 0xFF) + { + FS_LOG("erase! :l:%d 0x%x 0x%x 0x%x\n",__LINE__,i,j,*(p_rd+j)); + + while(1); + } + } + } + + FS_LOG("wr:"); + + for(i=0; i<2; i++) + { + if(i==0) + { + ret = hal_flash_write(sector_addr,p_wr,4096-wr_data_len); + } + else + { + ret = hal_flash_write((sector_addr+4096-wr_data_len),p_wr,wr_data_len); + } + + FS_RET_RRROR(ret); + + if(wr_data_len == 0) + break; + } + + FS_LOG("rd:"); + + for(i=0; i<2; i++) + { + for(j=0; j<4096; j++) + { + c_data_rd[j]=0; + } + + if(i == 0) + { + ret = hal_flash_read(sector_addr,p_rd,4096-rd_data_len); + #ifdef FS_DBG_EN + FS_LOG("\ndbg_start:0x%x %d\n",sector_addr,(4096-rd_data_len)); + + for(j=0; j<4096-rd_data_len; j++) + { + FS_LOG("0x%x,",*(p_rd+j)); + + if((j+1)%0x10==0) + { + FS_LOG("\n"); + } + } + + FS_LOG("\ndbg_end\n"); + #endif + } + else + { + ret = hal_flash_read((sector_addr+4096-rd_data_len),p_rd,rd_data_len); + #ifdef FS_DBG_EN + FS_LOG("\ndbg_start:0x%x %d\n",(sector_addr+4096-rd_data_len),(rd_data_len)); + + for(j=0; j 0) + //if(wr_data_len > 4) + if(wr_data_len > 40) + //if(wr_data_len > 2048)//run_counter=513 + //if(wr_data_len > 4092)//run_counter=1024 + { + FS_LOG("finish,ok\n"); + + while(1);;; + } + } +} + +#endif + +const unsigned char c_data_wr[4096]= +{ + 0xa2,0x9f,0x39,0x21,0xc7,0x69,0x87,0x43,0x4e,0x9c,0x2,0x97,0xb8,0x2f,0x1d,0x1, + 0x24,0x30,0xac,0xec,0x94,0xba,0xd0,0xdc,0x3c,0x9a,0xb6,0xd4,0xeb,0xcc,0xc9,0xc5, + 0x9,0x21,0x78,0xd6,0xb1,0xe8,0x1b,0x7,0xaa,0xa2,0xce,0xa9,0xd6,0xda,0x1b,0x65, + 0xc,0xcc,0xc7,0xbb,0x11,0x8a,0x54,0x6f,0x86,0x79,0x4a,0x6a,0x5d,0x45,0x2c,0x1c, + 0x95,0xb2,0xcd,0xdf,0xe2,0xbf,0x9c,0x53,0x72,0xb5,0xa3,0x9a,0xe6,0x3e,0x6c,0x37, + 0xf0,0xfa,0xf7,0xdc,0xde,0xc6,0x3e,0x8,0xfd,0x4a,0xc4,0x7e,0x11,0xad,0x95,0x8f, + 0x2e,0x31,0x34,0x36,0xc3,0x4c,0xc2,0x2f,0x30,0x4c,0xf5,0x83,0x59,0x38,0xd4,0x54, + 0x33,0xac,0x26,0x50,0xb8,0x8f,0xe3,0x29,0xf6,0x3,0xbf,0x31,0x2,0x5,0xe4,0x87, + 0x96,0xd2,0x8a,0x32,0x28,0x7e,0xa0,0x38,0xf,0x8,0xe8,0x89,0xff,0x9c,0xda,0x30, + 0xe7,0x82,0x41,0x73,0x5a,0x1d,0xdf,0xcf,0x6e,0xa2,0x2d,0x8f,0x83,0xb1,0xba,0x16, + 0xaf,0xe3,0xa0,0x29,0xf0,0x8c,0x21,0x9b,0x7e,0xe3,0x3a,0xca,0xef,0x90,0xc9,0x4f, + 0xec,0xcd,0x24,0x44,0x1f,0x54,0x44,0xd8,0xec,0x57,0x7,0xc8,0x81,0x97,0x63,0x38, + 0xbd,0x74,0xa6,0x3c,0xc5,0x3f,0xd5,0xe5,0x15,0x82,0xf7,0xba,0xe4,0x3e,0x9e,0x99, + 0xb3,0xaa,0x1d,0x79,0xc9,0x25,0xd6,0x30,0xca,0x6c,0x8b,0x1e,0x29,0x2,0xa1,0x31, + 0x73,0xff,0x4e,0x63,0x5b,0x57,0xd7,0xc6,0xa8,0x7,0xd,0xb0,0xa2,0x52,0x44,0xd9, + 0xf,0x46,0x8a,0x81,0x3a,0x7f,0xf7,0x8,0x1f,0x93,0x8b,0xb8,0x9c,0x67,0x86,0xa4, + 0x9b,0xbb,0x16,0xfe,0xf6,0x6f,0xae,0x64,0x94,0xcd,0x90,0x9b,0xcb,0x40,0xd0,0x92, + 0x1e,0x2f,0x5f,0x2,0xc6,0x6d,0x5,0xfa,0x1,0x8f,0x41,0xf5,0xea,0x81,0x7b,0x56, + 0x53,0x85,0xd2,0x28,0x90,0x47,0x24,0xe2,0x59,0xe8,0x8a,0x48,0xd1,0x4a,0x8d,0x8e, + 0x51,0x3b,0x9,0x9f,0xc9,0x30,0x84,0xb9,0x74,0x63,0x63,0x3b,0x26,0x9b,0x60,0x91, + 0xb7,0x18,0xbf,0x10,0x9,0xa0,0x43,0xa6,0x71,0x74,0x9a,0xcf,0x89,0x97,0x6e,0x13, + 0xf5,0x93,0xf5,0xc9,0x39,0xfe,0xf7,0x14,0x61,0x72,0x4b,0x5d,0x69,0x22,0x71,0xb3, + 0xbf,0x68,0xd8,0xde,0xaa,0xd2,0xc5,0x82,0x98,0x38,0x86,0x24,0xd7,0xe4,0x7f,0x7b, + 0xed,0x52,0x2f,0xc6,0x64,0x62,0x23,0x25,0x4a,0x17,0xf8,0x83,0xdc,0x18,0x8a,0xb2, + 0xe0,0x23,0xcd,0x5f,0x34,0x5e,0xa2,0x0,0x5d,0xbc,0xc8,0x11,0x8f,0xd8,0x3c,0x8b, + 0x37,0x11,0x7b,0xbf,0x18,0x60,0x2b,0xdb,0x8c,0x5a,0x3b,0x19,0x2b,0x42,0xb4,0xe3, + 0x96,0x9d,0xe,0xdc,0x50,0x54,0x46,0xc1,0x43,0x41,0xb4,0x68,0x8b,0xa2,0x3,0x6a, + 0xaf,0x4b,0xf,0x85,0x39,0xbb,0x74,0x75,0x11,0xa6,0x58,0x76,0xda,0x8a,0x5c,0x31, + 0xb0,0x6e,0xee,0xb7,0x58,0xd,0xf1,0xf6,0xe0,0x1c,0xb5,0xf2,0x5c,0x92,0xdb,0xee, + 0x32,0x57,0xf2,0x5b,0x16,0xd7,0x97,0xa9,0xce,0xe0,0x14,0xd8,0xc,0x66,0x2a,0xac, + 0xfe,0x42,0xd9,0xd0,0x48,0x2c,0x74,0xfb,0xb0,0x37,0x13,0xe6,0x55,0xbd,0x17,0x51, + 0x6f,0x88,0xa5,0x65,0x3d,0x2f,0x6a,0x34,0x85,0x1d,0x6a,0xe4,0x8,0x46,0xe2,0x27, + 0x11,0x4b,0x47,0x7f,0xd3,0xc6,0x5f,0xbf,0x74,0x80,0xcc,0xde,0x98,0x1a,0xf1,0xd3, + 0xdd,0x1c,0x89,0xc,0xfd,0x15,0xcc,0x64,0x3c,0xf4,0xe,0xf3,0x39,0x1c,0x2c,0xe1, + 0x84,0x5e,0xfe,0x5c,0xe4,0x5d,0x3e,0xc5,0xf1,0xda,0xd3,0xa4,0x66,0x28,0xe,0x78, + 0x9d,0x8e,0x67,0xe0,0x43,0xcb,0x3c,0xd5,0xf1,0x10,0x48,0x63,0xb3,0x76,0xd6,0x22, + 0xd9,0x2a,0xc7,0x7d,0x7f,0xef,0x2e,0xb4,0xb9,0xb,0xff,0x65,0xab,0x90,0x31,0x85, + 0x2d,0x61,0x41,0x21,0xd4,0xdd,0xac,0x94,0xb2,0x9b,0x21,0x1c,0xcd,0xda,0xe2,0x3e, + 0x83,0xf1,0x3,0x4b,0x58,0x17,0x7f,0x92,0xb8,0x2a,0xe,0x79,0xb4,0x4e,0x52,0x46, + 0x8b,0xdd,0xf,0xe5,0x9f,0x4a,0x33,0x82,0x5e,0xf6,0x6d,0xe5,0xe6,0x8d,0x20,0xf5, + 0xdc,0x9f,0xb8,0x89,0x8e,0x32,0x32,0xb3,0x7d,0x57,0x43,0xc2,0xa0,0xf4,0x87,0x2, + 0x1a,0xc9,0x45,0x45,0x73,0xb6,0x49,0x5f,0x13,0xd0,0xa2,0xb8,0x7e,0x3a,0x6c,0x89, + 0x32,0x97,0x38,0x67,0x5f,0x29,0xf3,0x8d,0x76,0x22,0x9d,0x3e,0x29,0x56,0xeb,0x14, + 0x4,0xe,0x7e,0x66,0xde,0xc3,0x82,0x10,0xe1,0xc1,0x4a,0x79,0xf0,0xca,0x9b,0x2b, + 0x9d,0x88,0x40,0xe5,0x8,0xe,0x63,0x2d,0x14,0x88,0x16,0x9f,0x13,0xb,0x8d,0x27, + 0x80,0xee,0xb7,0x3c,0x68,0xd9,0xe8,0xf1,0xb8,0x84,0x23,0x18,0x25,0x30,0x34,0xf0, + 0x8,0x43,0x42,0x3,0x5f,0x8d,0x31,0x1e,0x92,0x7d,0x16,0x98,0x6f,0x77,0xef,0xdb, + 0xee,0x8b,0xca,0xb6,0x37,0x11,0x4d,0xad,0xd3,0x47,0x7f,0xc9,0xab,0x2d,0xd5,0x77, + 0x10,0x12,0x50,0x15,0x41,0x3a,0x8d,0xe6,0xbc,0x2b,0x90,0x76,0x84,0x9c,0xae,0x3b, + 0xe7,0x2,0xf3,0x71,0x1d,0x4c,0x98,0x97,0xfd,0x86,0x46,0xb1,0xd2,0x4f,0x94,0x5e, + 0xfc,0xf4,0x23,0x95,0x1f,0x2e,0xd8,0x22,0x62,0xb2,0xb3,0x7,0xba,0xb7,0xdf,0xe, + 0x28,0xfa,0xc2,0x54,0x21,0xf2,0x19,0x38,0x7b,0x21,0xa1,0xb1,0xd0,0xa7,0xeb,0xb5, + 0xcc,0xae,0xb7,0xaf,0x6b,0x60,0x46,0x3a,0x30,0x4d,0x40,0x91,0xf,0x3a,0x56,0x37, + 0x8a,0x31,0x30,0x77,0xd,0xb0,0x5c,0x30,0x7a,0x54,0x78,0xf7,0x93,0x10,0x1e,0xe9, + 0x2f,0xcf,0x21,0xfa,0x81,0x63,0xfb,0xbc,0x7d,0x3b,0xb3,0x56,0x5e,0x76,0xc2,0x2d, + 0x4,0x21,0x37,0xd4,0xc5,0x4a,0xd6,0xb6,0xec,0x3c,0x5c,0xd3,0x9,0x22,0x53,0xdc, + 0x8,0xb2,0x26,0x66,0x47,0xba,0x68,0xa5,0x19,0xac,0x78,0x79,0x78,0x58,0x72,0x9d, + 0xa5,0x11,0xae,0xdb,0xe,0x3a,0x6e,0x1a,0x5,0xf1,0x60,0x29,0x69,0x51,0xe5,0xb4, + 0x8a,0xdd,0x68,0x3,0x41,0xe7,0xbd,0xba,0x65,0xde,0xd6,0x57,0x35,0xdf,0x42,0x7f, + 0x25,0xcf,0x55,0x19,0x19,0xea,0x99,0xeb,0xe8,0x26,0xbe,0xa4,0xa4,0x4f,0xfd,0xb7, + 0x4e,0x4,0x9d,0x1f,0x68,0x9,0xe6,0x71,0x1d,0x60,0x26,0xf9,0xc4,0xab,0x85,0xcf, + 0xf4,0x32,0x4a,0xb5,0x1,0x4e,0x80,0x7,0x9a,0x55,0x35,0x7b,0x8b,0x2e,0xb3,0xf0, + 0x21,0xb4,0xbc,0x9e,0x48,0x87,0x28,0x41,0xe8,0x8f,0x79,0xfd,0x63,0x65,0x87,0x9a, + 0x45,0xb,0x11,0xca,0xab,0x3e,0x5d,0x8d,0xa0,0x8b,0x2a,0xda,0x9f,0xa4,0xd2,0xb3, + 0xe4,0xcc,0xf8,0x65,0xf6,0x1e,0xd5,0xa0,0x9b,0x40,0xb8,0xb1,0x97,0xd6,0x7f,0xa9, + 0xf8,0x51,0x93,0xcc,0x14,0x4d,0xb8,0x66,0x8e,0x36,0x7,0xcb,0xc5,0x3a,0xd1,0x15, + 0x1b,0x6e,0xeb,0xed,0x62,0xae,0x49,0xe7,0x18,0x50,0x89,0xc0,0x74,0x6e,0xdb,0x2b, + 0x91,0xab,0x78,0x2e,0xc5,0x6a,0x62,0x8a,0x5d,0xff,0x48,0x55,0xa8,0xc2,0x6b,0xdb, + 0x4e,0x4f,0x6a,0xe,0xda,0x2e,0x60,0x51,0x4f,0x2b,0x14,0x28,0x1b,0xc6,0xc9,0x45, + 0xe9,0x42,0x6e,0xb6,0xbc,0x3e,0xdd,0x1b,0x6,0xfb,0x76,0x5,0x9,0x45,0x98,0xdc, + 0xc1,0x4,0xc4,0xec,0x57,0x7d,0x57,0x59,0xc,0x40,0x85,0xa2,0xaa,0xce,0x8f,0x5, + 0x77,0xda,0xe3,0x63,0x4e,0x48,0x55,0x4b,0x6e,0x3f,0x3d,0xfd,0x86,0x65,0x6,0x7a, + 0xf6,0x65,0xc3,0x4f,0x59,0xd1,0xca,0x7b,0xd8,0xc,0x4a,0xb6,0x37,0x5b,0xff,0x60, + 0x3d,0xe4,0x5b,0x10,0x22,0xdb,0x11,0xc2,0x9b,0x47,0xa,0xf2,0x9e,0xa6,0x70,0xc2, + 0x13,0x3,0x66,0x7e,0x0,0xe6,0xc4,0xc8,0x6d,0x7a,0x81,0x63,0x30,0x3b,0x72,0xe2, + 0x46,0xab,0x9f,0x19,0x28,0x44,0x87,0x19,0x96,0xdf,0xee,0xac,0x47,0x4d,0xe8,0x35, + 0x93,0xf,0xda,0x37,0xf7,0x2a,0x6,0xc1,0xca,0x75,0xde,0xcd,0xae,0x7d,0x72,0x9f, + 0x4d,0xa9,0x1f,0x91,0xd6,0x93,0x9c,0xbd,0x5f,0x69,0x9a,0x40,0xb4,0x10,0xf3,0x20, + 0x52,0x49,0x86,0x85,0x65,0x37,0x1a,0xd4,0x3f,0xd8,0xaa,0xff,0x16,0x98,0x8c,0x4e, + 0x68,0x4,0xb1,0x88,0x6b,0x7b,0xa7,0x68,0x18,0x4b,0xba,0x83,0x16,0x7d,0x6c,0x7f, + 0x9a,0x5c,0x87,0x25,0x6e,0x6e,0xf5,0xb2,0x2f,0xea,0x5d,0x15,0x9b,0x45,0xe4,0xb1, + 0xd,0x3f,0x78,0x2f,0x2,0x23,0xb5,0x1a,0xa0,0xf,0x56,0xb2,0x82,0x3d,0x8e,0xfd, + 0xf1,0xc4,0x8e,0xd5,0x5b,0xfe,0xc5,0x8f,0xbd,0x12,0x97,0xa4,0x2,0xf,0x8d,0x26, + 0x93,0x1d,0x76,0xf5,0x39,0x1f,0x52,0x9b,0xe1,0x84,0x14,0x2,0x11,0xa8,0xa8,0xf4, + 0x57,0xcc,0x3b,0xd7,0xf,0xbf,0x10,0xf3,0xa,0xb5,0xcd,0x8f,0xd1,0xe3,0xf5,0x71, + 0xa3,0xd4,0x36,0xa1,0xd2,0xa1,0x6f,0x5c,0x98,0xa1,0x94,0x1d,0x6,0x34,0x43,0xdc, + 0x5f,0x7a,0x9,0x4,0x36,0xe6,0x41,0xa5,0x65,0xf2,0x17,0xc2,0xea,0x74,0x82,0xe6, + 0xf9,0xe6,0xfe,0x84,0xcb,0x84,0x58,0xd2,0x99,0x7e,0xdd,0xba,0x9e,0xe7,0xa2,0x79, + 0x60,0x22,0x81,0xea,0xbe,0xbe,0x76,0xc4,0x76,0xe,0xcd,0x25,0x3,0x44,0xbf,0x72, + 0xa4,0x94,0xb2,0x2d,0xb6,0x13,0xa3,0x45,0x3f,0x7e,0x29,0xf4,0xca,0x43,0xaa,0x2f, + 0x3c,0x9d,0xee,0x2f,0x71,0xb9,0x17,0xd5,0x29,0xd8,0xf1,0xb,0xbf,0xa1,0x87,0xf, + 0x95,0x87,0x64,0x5c,0x8,0xf6,0x11,0xd5,0x46,0x31,0xeb,0x8,0xa0,0x3c,0xb7,0x63, + 0x91,0x2,0x50,0x2b,0x88,0x1c,0x49,0x92,0xcd,0xbb,0xac,0x1f,0xa0,0xe,0xdd,0x35, + 0x95,0xb4,0x88,0x18,0x31,0x3f,0x2c,0x15,0xbe,0xaa,0x53,0xdf,0xb2,0x4,0x1a,0xbd, + 0x6a,0xc7,0x6d,0x96,0x3a,0x29,0x9d,0xc7,0x23,0x5a,0xa0,0xc7,0x9b,0xd1,0x66,0x2, + 0x1f,0x30,0x1,0x53,0xc0,0xc3,0xce,0x8f,0xf5,0xf1,0x75,0xb1,0xc1,0xb2,0xb6,0x84, + 0x96,0x45,0xd4,0xc5,0xf,0x12,0x3f,0x1a,0x97,0xda,0xfd,0xc2,0x50,0xf5,0xbf,0x42, + 0x68,0xab,0x8d,0xf1,0xc8,0x8e,0x62,0x92,0x3f,0x53,0xd8,0x1b,0xdd,0xf,0x97,0x7, + 0x43,0x80,0x47,0xfd,0x7,0x40,0x27,0xbf,0x22,0xba,0xf0,0xb9,0x6e,0x63,0x45,0x98, + 0x5d,0x7,0x63,0xd2,0x5c,0xf9,0x91,0x66,0xe6,0xe6,0xfe,0x8e,0x69,0x40,0xd1,0xa8, + 0x58,0x1d,0x46,0xaf,0xeb,0x54,0xe7,0x34,0x89,0x92,0x96,0x9f,0x2e,0x1b,0xb7,0x4b, + 0xeb,0x84,0xf8,0xc9,0xae,0xa8,0x71,0xc4,0x65,0x90,0x94,0xc4,0x8d,0x70,0x81,0x87, + 0x6c,0x51,0x8d,0xdc,0x20,0xa2,0xae,0x99,0xd6,0x94,0x2b,0x38,0xab,0x88,0xa3,0xea, + 0x89,0x91,0x86,0xb8,0x89,0xef,0xac,0x55,0x92,0xd0,0x3f,0xc5,0x7,0x4e,0xa2,0x72, + 0xc8,0x73,0xf9,0x14,0xd8,0x43,0xf6,0xb0,0x82,0xe8,0x79,0x15,0xbd,0x20,0x25,0xe7, + 0xb2,0x33,0xdc,0x1d,0x73,0x31,0x87,0xfd,0x3c,0xda,0xdd,0xb9,0xc,0x7d,0xd2,0x97, + 0x27,0x21,0xa8,0x21,0xa2,0x55,0x4a,0x14,0xb,0xd,0xc8,0x96,0xf4,0x23,0x93,0xee, + 0xb9,0xd3,0x19,0x8c,0x7a,0xe1,0x1,0x68,0xee,0x5e,0x50,0x8,0xed,0x8a,0x1c,0x2b, + 0xab,0x4d,0xfd,0x7b,0xa,0x3e,0xe5,0x55,0x7,0x67,0x83,0x95,0x9f,0x4b,0x71,0x38, + 0x92,0x5a,0xdc,0xb5,0x21,0xa4,0x19,0xac,0x8a,0x60,0xdf,0x7c,0x1b,0x65,0xf6,0x64, + 0x6f,0x28,0x91,0x2c,0x32,0x59,0xb8,0xac,0x4a,0x38,0x27,0x83,0x58,0xd4,0xd4,0x1d, + 0xcf,0x58,0x14,0x26,0xe3,0x3e,0xf2,0xb3,0x20,0xae,0xf3,0x73,0xcd,0x6f,0x87,0xc7, + 0x78,0x10,0xb8,0x22,0xa4,0x89,0x6c,0x71,0x31,0xec,0x1e,0xe8,0x66,0x81,0x6a,0x6c, + 0xd6,0xcd,0xa3,0x3d,0xe6,0xb4,0x2e,0x93,0x4d,0xd0,0xed,0xf2,0xb1,0x73,0x95,0x4e, + 0x46,0x20,0x68,0x90,0x20,0xfa,0x25,0xf2,0x64,0x23,0xe4,0x9,0x90,0x96,0xc1,0xff, + 0x3c,0x71,0x74,0x23,0xcf,0xd5,0x86,0x32,0xd,0xb9,0x2d,0xe6,0x1d,0x6f,0xd2,0xd0, + 0x7a,0xb,0x62,0x7b,0xc7,0xa2,0xc8,0x6e,0x3e,0x9d,0x3b,0xa1,0xae,0x83,0x7d,0x62, + 0xb,0x43,0x43,0x9c,0x75,0xd5,0xe0,0x2f,0xb8,0x9c,0x58,0x5b,0x82,0x1e,0x20,0x88, + 0x4f,0x66,0x55,0x2b,0x31,0x8,0x3b,0x42,0xb6,0xea,0xec,0x75,0xe0,0xb9,0x2b,0xc5, + 0xec,0xf0,0x3b,0xdc,0x92,0xed,0x2e,0x51,0xf8,0xd6,0x9b,0xfd,0x6,0x47,0x8b,0xcc, + 0x6a,0xb5,0x3f,0x7c,0xba,0xe9,0x17,0x9c,0xb5,0xb7,0x29,0x2d,0xd,0xd0,0x47,0x59, + 0x3e,0x49,0x6b,0x45,0xdf,0xe8,0x25,0x97,0x9e,0x77,0x67,0x55,0xc7,0xec,0x70,0x98, + 0x4b,0xbe,0xad,0x40,0xf,0xd,0x37,0xd1,0xb9,0x97,0x76,0xb2,0xbe,0xb7,0x3a,0x16, + 0x2c,0x33,0xab,0x14,0xd7,0x98,0x5a,0xa0,0x4f,0xa1,0xc4,0xc7,0xea,0x37,0x27,0x32, + 0xb5,0xb4,0x96,0x7e,0x46,0x24,0x6f,0x39,0x8b,0x4f,0x47,0x64,0x3f,0xa6,0x59,0x2e, + 0xac,0xcb,0xd7,0x2f,0xde,0x4f,0xd3,0xbb,0x3c,0x10,0xaf,0xd1,0xf4,0x63,0x5d,0x85, + 0xce,0x4c,0x1c,0x2f,0xb2,0x51,0xf,0xeb,0x9a,0x80,0x53,0x7,0x14,0xb5,0x4f,0x66, + 0xd9,0x92,0xd9,0x37,0x53,0x69,0xae,0x15,0x3e,0x7a,0x7a,0xe9,0xa2,0x8c,0x1d,0xbd, + 0x9e,0x7b,0xf5,0x8,0x5c,0xe6,0xbb,0x90,0xf3,0xfd,0x5b,0xd6,0x8b,0x81,0x2a,0xb2, + 0xc3,0xea,0x70,0x99,0xb2,0xc,0x91,0xd8,0x76,0xc1,0xae,0xe0,0xb5,0x51,0x78,0xd, + 0x41,0xc2,0xdc,0xe2,0xa6,0x4b,0xc9,0xe0,0x59,0xb4,0x2d,0xb1,0x9d,0x84,0x3f,0x23, + 0xe9,0xba,0x17,0x1a,0xb4,0xb7,0x42,0x84,0x6c,0xcc,0x9b,0x80,0xf0,0x92,0x93,0x55, + 0xd0,0xd1,0xcd,0x1e,0x60,0xcb,0xee,0xb3,0x2a,0xf3,0x29,0x4f,0x2c,0x42,0x3d,0x1e, + 0x4e,0x2a,0x88,0xca,0xc1,0x69,0xa9,0xa5,0x7c,0xb8,0x93,0xdd,0x8b,0x4b,0x3d,0x4e, + 0xd0,0xe8,0x1e,0xad,0x50,0xc8,0xe6,0xab,0x68,0xf9,0xcd,0x13,0xb6,0x38,0xfd,0xf9, + 0x50,0xfe,0x43,0x6a,0xbb,0x69,0x59,0x6c,0x85,0xc8,0x5,0x87,0x92,0xd5,0xf3,0x63, + 0x8b,0x4c,0x3f,0x8a,0x52,0xd2,0xda,0x22,0xbb,0x39,0xa,0x40,0xc2,0xcc,0x3d,0x9b, + 0xb6,0x61,0x67,0x6d,0xfb,0x5f,0x20,0x33,0xee,0x61,0x58,0xb2,0xfd,0xea,0x1e,0xd5, + 0x14,0x81,0x21,0x28,0x72,0x38,0xeb,0xde,0x4a,0xab,0xa1,0xd,0xaf,0x90,0x4a,0x51, + 0x3d,0x41,0x9f,0x73,0xaf,0xfb,0x1a,0xbe,0xbc,0x86,0xb0,0xa6,0x1d,0x2a,0x74,0x1e, + 0x20,0xa5,0x1f,0xfb,0xf1,0x19,0x1e,0x22,0xb4,0xd,0xfc,0x38,0xd9,0xb5,0x6d,0xf3, + 0x5c,0xc0,0x47,0x28,0x79,0x65,0x16,0xfa,0x6c,0xc9,0x7f,0x8f,0x31,0x7b,0xd2,0x6a, + 0x77,0x94,0x7a,0x26,0xa4,0x9e,0xff,0x4f,0x3b,0xe0,0x52,0xcf,0xda,0xb3,0xcb,0xef, + 0x11,0xeb,0x5a,0xd1,0x1b,0x66,0xb3,0x7a,0x47,0xfa,0xef,0x43,0x20,0x67,0xcd,0x66, + 0xd2,0xa4,0xee,0x25,0x30,0xd8,0x3f,0x8b,0xb,0xd2,0x79,0xb5,0x64,0xb3,0x8b,0xad, + 0x8,0x7f,0x6b,0x76,0xe0,0x74,0xd5,0xd1,0x17,0xb9,0xc7,0x32,0x36,0xe9,0x78,0xfb, + 0xfe,0xc0,0x6a,0x8e,0x1f,0xd6,0xda,0xbd,0x97,0xa6,0xa1,0x42,0xee,0x89,0x51,0xb, + 0x1b,0xb1,0x36,0x63,0x4f,0xeb,0x9,0x19,0x61,0xdb,0x8a,0xb7,0xf3,0xab,0xec,0x1e, + 0x89,0x87,0xd5,0x3e,0x38,0x3e,0xf3,0xde,0xab,0x43,0xd6,0x9e,0xd3,0x41,0xf5,0x66, + 0xf5,0xbb,0x60,0xbe,0xf0,0x16,0x2b,0xb2,0xaa,0xbb,0xad,0xf7,0x3d,0x9c,0x17,0x67, + 0xe,0x37,0xfd,0x3b,0x22,0xac,0xf5,0x89,0x72,0x49,0x60,0x50,0xb5,0xfc,0xe1,0x46, + 0x54,0xfb,0x6d,0x22,0x0,0x33,0xb7,0x46,0x84,0x92,0x4c,0x93,0xb4,0x20,0xfe,0xf, + 0x25,0x27,0xed,0x10,0x8,0x38,0x7,0x5b,0xca,0xdb,0xc2,0x0,0x5c,0x1,0x68,0x5e, + 0x4a,0x50,0xf3,0xcc,0xe,0x74,0xff,0x3b,0x36,0xc6,0xc3,0xf6,0x55,0x4f,0x82,0xa6, + 0xf8,0x2d,0x60,0xce,0x12,0x13,0xe1,0xcf,0x60,0xd9,0x9,0xf,0x9a,0x14,0xc4,0x16, + 0x17,0xf3,0x8d,0xf3,0xe,0x79,0x7e,0xb4,0xfc,0x5c,0xdf,0x70,0xb4,0x75,0xf3,0xcb, + 0xb8,0xe1,0x43,0x1d,0xba,0x6a,0x79,0xfb,0xbb,0x1a,0x51,0x16,0x1f,0xa1,0x1,0x69, + 0xf,0x10,0x53,0x14,0xad,0xc6,0x22,0x55,0x24,0x7f,0x9,0x5e,0xd3,0x46,0xb,0x48, + 0x4c,0x0,0x50,0x86,0x44,0xe,0xa6,0x28,0x7b,0x6,0xa3,0x42,0x5e,0x8b,0x1b,0x88, + 0x31,0x91,0xf0,0x31,0x39,0x8b,0xbe,0x99,0xc6,0x51,0x8c,0x53,0x7c,0x3a,0xb5,0x5b, + 0x96,0xb1,0x67,0x97,0x15,0xc9,0x71,0x6e,0xb8,0x3d,0x1a,0x12,0x1b,0x15,0x2f,0xc1, + 0xce,0x24,0xec,0x4b,0x54,0xba,0x4a,0xa2,0xda,0x23,0xfb,0x72,0x41,0x99,0xf,0x4f, + 0xd5,0xe4,0x2c,0x50,0x7d,0x27,0xca,0xe3,0xda,0x17,0x20,0x67,0x81,0x64,0x28,0x74, + 0x57,0x1d,0x78,0x97,0xc6,0x1f,0xbf,0x6e,0x87,0x8,0xf0,0xe7,0xa5,0x12,0xe3,0xba, + 0x5c,0x50,0xb8,0x2a,0x6c,0xfc,0x2d,0xb5,0xb3,0x41,0x4d,0xbc,0xcb,0xf9,0x89,0x69, + 0x20,0xf9,0xdf,0xad,0x42,0xba,0xe0,0xaa,0x83,0xf8,0x7f,0xd4,0x48,0x5a,0xca,0x3, + 0x61,0x47,0xa2,0xe2,0xe5,0x53,0x2f,0x74,0x52,0x70,0xa7,0x36,0x31,0x88,0xb3,0x34, + 0xb0,0xfb,0x67,0xd3,0x8e,0x36,0xf7,0x91,0x5b,0x91,0x63,0x22,0xa9,0x9e,0xc9,0xf0, + 0xf9,0xf6,0x93,0x5,0x98,0x4f,0x94,0x50,0xfe,0xdd,0x3,0xab,0xb6,0xd0,0x4,0x0, + 0xab,0x22,0x3d,0x47,0xa9,0x9,0xc,0x18,0x31,0xb6,0xe4,0x67,0x3b,0xa0,0xa8,0x48, + 0xa5,0x12,0x8c,0xf9,0x71,0xb1,0xd1,0x20,0x66,0xa9,0x84,0x51,0x5,0x79,0x99,0xad, + 0x2e,0x51,0xba,0xae,0xe5,0xa7,0xa2,0xde,0x3c,0x4d,0xe8,0x36,0x6c,0x25,0xd7,0x89, + 0x9e,0x1c,0x23,0xda,0xe8,0x99,0xe5,0x3c,0xcb,0x6d,0xef,0x7c,0x3f,0xb2,0x1a,0x7, + 0xc1,0x95,0x3e,0x34,0x2c,0x8b,0xcf,0x6f,0xc2,0x7,0x2f,0xca,0x1f,0xa6,0xf9,0x11, + 0x9c,0x61,0xaa,0x7e,0xda,0x87,0x5b,0x65,0x3a,0x2d,0x20,0xda,0xf8,0x66,0x71,0xeb, + 0x28,0xdb,0x51,0xae,0x74,0x26,0x88,0x66,0xd3,0xb1,0xda,0x31,0x6a,0x51,0x3c,0x43, + 0x7f,0xbc,0x61,0x55,0x2e,0xcf,0xe,0x37,0x23,0x96,0x51,0xa4,0x73,0x3d,0x2a,0x5f, + 0x52,0xd0,0x17,0x70,0x54,0x4d,0x74,0x1b,0xfb,0x6f,0x21,0x58,0x7c,0xba,0x81,0x66, + 0xf9,0x2a,0x37,0xda,0x3f,0x6b,0x42,0x3,0x26,0x15,0x86,0x10,0xd0,0xb8,0x6a,0xcf, + 0xb0,0x9b,0xa4,0x6d,0xeb,0xb8,0x9a,0xf3,0x1f,0x15,0xa7,0xa5,0xc6,0x66,0x2c,0xdb, + 0xb4,0x9a,0x42,0x77,0x97,0x7,0xce,0xfa,0x5,0xb4,0xd1,0x6a,0xcd,0xb2,0x8,0x6a, + 0xc8,0x16,0x3e,0x6d,0x16,0xa4,0x4d,0xb6,0x50,0xbd,0xe1,0xe9,0x92,0x9c,0xed,0x6b, + 0x7f,0x46,0xd5,0x16,0xca,0x70,0x61,0x4b,0xdd,0xc8,0x76,0x27,0x64,0x30,0xa5,0x24, + 0xaf,0x95,0x85,0x80,0x8d,0x79,0xf1,0x1,0x8c,0xa1,0xe7,0xb,0xb5,0x92,0x25,0x3, + 0x1c,0xa4,0x7c,0x42,0x6e,0x2d,0x90,0xfd,0xb6,0xaa,0xd2,0x57,0x51,0xa4,0x7d,0xca, + 0x22,0xf3,0x55,0x5a,0xf2,0xe,0x68,0x7f,0x41,0x50,0x91,0x45,0x75,0xf7,0x42,0x2e, + 0x89,0x6c,0xa5,0x9b,0x5c,0x49,0x31,0xea,0xda,0x74,0xca,0xc0,0x13,0x47,0x54,0x8f, + 0xc7,0xed,0xe9,0xb,0xa,0x9,0xb1,0xc2,0xf1,0xb4,0xf8,0x12,0x94,0x68,0x98,0x4, + 0x21,0x44,0x55,0x66,0x94,0x71,0x36,0x91,0x2d,0x32,0x1d,0xc1,0x45,0xac,0x97,0x11, + 0x2b,0x33,0xe4,0xd3,0x49,0xd,0xa6,0xdf,0x4c,0x34,0x1,0x6e,0xf1,0xbb,0xbe,0xf5, + 0x31,0xe,0x93,0x15,0x95,0x88,0x9e,0x14,0x7,0x1c,0x6b,0x66,0x8,0x1c,0xad,0x51, + 0x14,0xca,0x14,0xfa,0x8b,0x27,0x60,0xd0,0x23,0x57,0xb8,0xcf,0xe0,0x45,0x4c,0x12, + 0xdd,0xea,0xde,0x39,0x1c,0x79,0x7e,0xaa,0x8d,0x91,0x8c,0x19,0x9f,0xba,0x25,0x37, + 0xa3,0xb2,0xab,0x67,0x1a,0xbb,0xec,0x38,0xae,0x6b,0x7,0xe2,0xda,0xbd,0x5b,0x10, + 0xcc,0xb0,0x7a,0xb8,0x4d,0x77,0xfa,0x4,0x87,0x48,0x20,0x86,0x6b,0xeb,0x30,0x48, + 0xf4,0xf7,0x4b,0xa5,0xe1,0x66,0x4d,0x76,0x7f,0xd,0xfc,0x21,0x54,0xa9,0x15,0x61, + 0xa8,0x82,0x6c,0xc3,0x5,0xef,0xea,0xf9,0x65,0x8a,0x72,0xe,0xa3,0x4a,0xb2,0xd5, + 0xd2,0x94,0x2,0x56,0xdd,0x8d,0xb6,0xe,0xef,0xab,0x85,0x79,0xac,0xfa,0xe7,0x5c, + 0xa7,0x35,0x35,0x45,0xb8,0xe0,0x86,0x59,0x94,0x6d,0x55,0x95,0x68,0x4a,0x52,0xae, + 0x65,0xb6,0x24,0xce,0xf7,0x6a,0xc2,0xa6,0xd3,0xdc,0x97,0x22,0x3d,0xc2,0xe4,0x30, + 0x3c,0xc9,0xc8,0x98,0xc3,0xce,0x9,0x38,0x94,0x1,0xdf,0x5d,0xe2,0x22,0xd1,0x77, + 0xed,0xa,0xf2,0x3a,0xe7,0x21,0x47,0x43,0x98,0xcc,0x37,0x5f,0x8a,0x77,0x58,0xa8, + 0x18,0xd,0x27,0x85,0xbf,0x29,0x69,0x92,0x19,0x85,0x23,0x64,0xfe,0x89,0xd3,0x60, + 0x32,0xe,0x38,0xae,0x33,0x27,0x75,0xc1,0x6e,0xe1,0x26,0xfa,0xf0,0x71,0x9,0x81, + 0x3c,0xce,0x8e,0x76,0x73,0xd0,0x55,0x13,0x4a,0x95,0x8e,0x5d,0xf3,0x93,0x1e,0x34, + 0x7f,0xeb,0x21,0xe2,0xb5,0x1d,0x26,0x8e,0xbd,0x97,0xa7,0xa1,0x54,0x6c,0x2,0xcb, + 0xa1,0x2c,0x4b,0xd3,0x1d,0xa1,0xbc,0xc4,0x97,0x44,0x47,0xc8,0xbf,0xe7,0xd7,0x72, + 0x23,0x82,0xeb,0x64,0x2d,0x3d,0x1f,0x15,0x44,0x13,0x9f,0xef,0xb0,0x57,0x44,0xfe, + 0x1c,0xdd,0x7f,0xc,0xe5,0x8f,0x7a,0xb8,0x33,0x82,0x78,0xf8,0x43,0x13,0x82,0x87, + 0xb1,0x5c,0xe8,0x9f,0x78,0xad,0xaa,0x29,0xf5,0x93,0x1f,0x78,0xfa,0xcc,0x20,0x63, + 0x97,0xdb,0x13,0x2d,0xa2,0xea,0xda,0x2,0xce,0x18,0x5e,0xf6,0x3,0xe0,0x63,0x4, + 0xfb,0xb4,0x7,0x5f,0xfc,0xde,0xdd,0x38,0x35,0xcc,0xc4,0x1c,0xcf,0x1f,0x19,0x97, + 0xcc,0x85,0x14,0x3f,0xa6,0xa4,0x85,0x19,0x41,0x8e,0x18,0xde,0x9f,0x48,0x5e,0x9d, + 0xe3,0x85,0x3c,0x25,0xbd,0xc0,0xb5,0xfe,0xb2,0xbd,0x24,0xda,0x15,0x18,0xcc,0x64, + 0x18,0x7f,0xc7,0xa7,0x5a,0xea,0x92,0x6,0xa9,0xa6,0xec,0xf0,0x68,0x85,0x9c,0x6, + 0x46,0x94,0x0,0x4e,0x3b,0x14,0x8d,0x55,0xe7,0x80,0x25,0x90,0xfe,0xd2,0x97,0xe0, + 0x17,0x9d,0x5f,0x8f,0xa5,0x62,0x9a,0x8d,0x3e,0x26,0x6d,0x69,0xc5,0xc0,0xb5,0xf, + 0x2,0xe9,0x9c,0x5f,0x92,0x97,0x2b,0xd4,0xd2,0xc,0x16,0x7,0x93,0xb1,0xeb,0x42, + 0x6f,0xe3,0xd,0x6b,0x49,0x26,0x68,0xd5,0x50,0xea,0x8,0xe7,0x10,0x22,0x5b,0xb8, + 0x21,0x16,0x48,0x52,0x34,0x5f,0xad,0x1c,0x70,0x21,0x38,0xfa,0x5a,0xff,0xb5,0x15, + 0x2,0x5a,0x68,0xdf,0x4b,0x33,0x9c,0xad,0x67,0xa4,0xc7,0x72,0x61,0x2f,0x1c,0xf, + 0x7d,0x18,0xf5,0x7a,0xb3,0x2,0xfb,0xc5,0x58,0xa7,0xa2,0xde,0x75,0xc0,0x5c,0x59, + 0xf2,0x7a,0xe,0xf,0x63,0x56,0x41,0x90,0x88,0xb7,0x40,0x5,0x4f,0x3d,0x51,0xbf, + 0x32,0x92,0x2b,0x9a,0xa5,0x3e,0xeb,0xf2,0xd1,0xdc,0x93,0x9b,0xee,0xaf,0x3,0xcc, + 0xbd,0x7d,0xe8,0x96,0x84,0xda,0xa9,0x60,0x64,0x1e,0x60,0x84,0xe4,0xae,0xa5,0x3d, + 0xa2,0x9b,0x37,0xb7,0x21,0x25,0x65,0x94,0xfe,0xe1,0x4b,0x2f,0x2c,0xfb,0x28,0x3f, + 0xb,0x8e,0x15,0x6d,0xa2,0xfb,0x2b,0xe3,0xdc,0x77,0xf5,0xb4,0xdc,0xf2,0xbf,0x4f, + 0xf4,0x86,0xed,0x1f,0x4f,0xbb,0x2a,0x62,0x66,0x4,0x47,0x6e,0x17,0x9c,0x18,0x52, + 0x4b,0x22,0xd0,0x66,0x4f,0x8d,0xcf,0x95,0x23,0x3a,0x6d,0x80,0x71,0x57,0xb3,0xd7, + 0xfa,0x70,0x0,0x73,0x5f,0x49,0x42,0xa7,0x9d,0x91,0x36,0xd5,0x4f,0x64,0xee,0x23, + 0x38,0xb3,0xe3,0x8c,0x2,0x8,0x79,0x2a,0x7f,0x82,0x2e,0x8f,0xd6,0x36,0x7d,0xa0, + 0x8f,0x3d,0x32,0xd3,0xb9,0xad,0xd2,0xac,0xc2,0xba,0xe9,0xd8,0xdc,0xae,0x4b,0xd5, + 0x1a,0x8b,0x50,0x14,0x59,0x5b,0x72,0x96,0xe4,0xb7,0xe2,0x2,0x3d,0x46,0x12,0x62, + 0xcc,0xd4,0x86,0xb0,0x80,0x30,0x70,0x75,0x94,0x51,0x92,0xb5,0x1a,0x93,0x28,0x9f, + 0xa5,0x80,0x69,0x17,0x3e,0xe7,0x80,0x5f,0x12,0x8d,0x4d,0xb5,0x35,0xb4,0xbf,0xc8, + 0x53,0x96,0x18,0x25,0x89,0xa7,0xe6,0x90,0x2d,0x40,0xcc,0xc6,0x17,0xc9,0xef,0x4e, + 0xd6,0x51,0xa4,0x40,0x7e,0xf,0x3a,0xbb,0x84,0xea,0xc9,0x3b,0xc0,0x86,0xc3,0x70, + 0x48,0x1c,0xd2,0x8d,0x54,0x28,0xa1,0x7,0xbc,0xdf,0x4,0x92,0xe2,0x68,0xd4,0x88, + 0x98,0x2c,0x92,0xaa,0x23,0xa5,0x1f,0x4a,0xf0,0x3b,0x7b,0x41,0xf5,0x9b,0x12,0xbb, + 0x8d,0x3a,0x4c,0x2a,0xb9,0xa5,0xc8,0x8c,0x2,0xfa,0x50,0x37,0x2,0x48,0xbb,0x12, + 0xce,0x22,0x7c,0xba,0x7f,0x58,0x5,0xcb,0x7c,0x11,0x45,0x8e,0x81,0xc2,0x93,0xd0, + 0xdf,0x6d,0xde,0x54,0x98,0x6d,0x9f,0x5a,0x99,0x0,0xe5,0x50,0xef,0x4e,0xa8,0x31, + 0xd1,0x64,0x1a,0x77,0xe9,0xb1,0xcd,0xaf,0xe9,0xfa,0x70,0x76,0xb3,0x78,0x31,0xa3, + 0xf7,0x72,0x59,0x20,0x5b,0xf0,0xbb,0xf,0x47,0xc9,0xa3,0xf4,0x8e,0xa0,0xed,0x95, + 0x3c,0x9a,0x7c,0x44,0x1c,0x2c,0x4b,0x6c,0x2a,0x4c,0xb9,0x8c,0x18,0xc1,0xc4,0x73, + 0x84,0x81,0xe5,0xbb,0x79,0x62,0x50,0xe7,0x86,0x87,0xe4,0x24,0x34,0xc2,0x3f,0x80, + 0xad,0xd4,0x87,0x9e,0xf8,0x6c,0x48,0xc0,0x2f,0xbc,0x89,0x47,0xda,0xaa,0x13,0xfe, + 0x5f,0x1a,0x54,0x88,0x98,0xa8,0x5c,0x42,0x7e,0x35,0x62,0xb6,0xf8,0xde,0x69,0x41, + 0x6b,0x48,0x54,0x8,0x38,0xdd,0x2,0x33,0xe5,0xdd,0x1c,0x5d,0x8e,0x5,0x95,0x6b, + 0x6,0x33,0x54,0x81,0x76,0x39,0xce,0x93,0x4c,0x35,0x7a,0x9b,0x4c,0xa8,0xdb,0x9d, + 0xf0,0xca,0xea,0x1b,0x73,0x2d,0x46,0xcc,0x3f,0xcf,0x72,0x6a,0x9a,0x24,0xbc,0xe9, + 0x29,0x42,0xbc,0xba,0x67,0x30,0x19,0xac,0xa9,0xad,0x3f,0xe8,0x79,0x29,0xa0,0x16, + 0x10,0x61,0xd7,0x83,0x58,0x73,0x25,0x3b,0x63,0x1b,0xea,0xfb,0x90,0xa,0xa,0x5, + 0x85,0x34,0x98,0xde,0xde,0x84,0x23,0x2f,0x91,0xf7,0x23,0x67,0xed,0x2b,0x5d,0x30, + 0xa4,0x8d,0x8b,0x7a,0x77,0x7d,0x62,0xce,0x4a,0x4a,0x84,0x18,0xa7,0x96,0xd8,0x2d, + 0xcc,0xed,0xa0,0xda,0x6b,0xbf,0x2c,0xa1,0x20,0xf4,0x7c,0xeb,0x9b,0x97,0x1d,0xb3, +}; + +#endif diff --git a/src/components/libraries/fs/fs_test.h b/src/components/libraries/fs/fs_test.h new file mode 100644 index 0000000..e87e799 --- /dev/null +++ b/src/components/libraries/fs/fs_test.h @@ -0,0 +1,38 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#ifndef __FS_TEST_H__ +#define __FS_TEST_H__ + +//be care:when assign the fs size,please refer to Flash_Distribution +#define FS_OFFSET_ADDRESS 0x1103c000 //for 256KB Flash +//#define FS_OFFSET_ADDRESS 0x11034000 //for 512KB Flash +#define FS_SECTOR_NUM 2 + + + +#define FS_EXAMPLE 0x01 +#define FS_XIP_TEST 0x02 +//#define FS_MODULE_TEST 0x04 +//#define FS_TIMING_TEST 0x08 + +#define FS_TEST_TYPE FS_EXAMPLE + +#if (FS_TEST_TYPE == FS_EXAMPLE) + void fs_example(void); +#elif (FS_TEST_TYPE == FS_XIP_TEST) + void fs_xip_test(void); +#elif (FS_TEST_TYPE == FS_MODULE_TEST) + void ftcase_simple_write_test(void); + void ftcase_write_del_test(void); + void ftcase_write_del_and_ble_enable_test(void); +#elif (FS_TEST_TYPE == FS_TIMING_TEST) + void fs_timing_test(void); +#else + #error please check your config parameter +#endif + + +#endif diff --git a/src/components/libraries/secure/asm_ecdh_p256/P256-cortex-ecdh.h b/src/components/libraries/secure/asm_ecdh_p256/P256-cortex-ecdh.h new file mode 100644 index 0000000..99454f6 --- /dev/null +++ b/src/components/libraries/secure/asm_ecdh_p256/P256-cortex-ecdh.h @@ -0,0 +1,80 @@ +/* Copyright 2018 Emil Lenngren. Licensed under the BSD 2-clause license. */ + +#ifndef P256_CORTEX_ECDH_H +#define P256_CORTEX_ECDH_H + +#include +#include + +/* + P-256 ECDH implementation + ========================= + + How to use + ---------- + Each part generates a key pair: + uint8_t my_public_point[64], my_private_key[32]; + do { + generate_random_bytes(my_private_key, 32); + } while (!P256_ecdh_keygen(my_public_point, my_private_key)); + The function generate_random_bytes is a placeholder for calling the system's cryptographically secure random generator. + With probability around 1/2^32, the loop will need more than one iteration. + + The public points are then exchanged, and the shared secret is computed: + uint8_t shared_secret[32]; + if (!P256_ecdh_shared_secret(shared_secret, others_public_point, my_private_key)) { + // The other part sent an invalid public point, so abort (it is important to handle this case) + } else { + // The shared_secret is now the same for both parts and may be used for cryptographic purposes + } + A safe alternative if one doesn't want to change the following parts of a protocol if the user sends an invalid key is to replace the + shared secret with the x coordinate of the own public key (same result as if the remote user sent the basepoint as public key) as follows: + uint8_t shared_secret[32]; + if (!P256_ecdh_shared_secret(shared_secret, others_public_point, my_private_key)) { + memcpy(shared_secret, my_public_point, 32); + } + // The shared_secret is now the same for both parts and may be used for cryptographic purposes + + About endianness + ---------------- + All parameters (coordinates, scalars/private keys, shared secret) are represented in little endian byte order. + Other libraries might use big endian convention, so if this should be used against such a library, make sure all 32-byte values exchanged are reversed. + + Security + -------- + The implementation runs in constant time (unless input values are invalid) and uses a constant memory access pattern, + regardless of the scalar/private key in order to protect against side channel attacks. + + Stack usage + ----------- + All functions need 1356 bytes available stack size on Cortex-M0 and 1.5 kB on Cortex-M4. + +*/ + +// Generic point multiplication +// Calculates scalar * point. +// If include_y_in_result == 0, result_point should be an array of size 32 bytes where the resulting x coordinate will be written. +// If include_y_in_result != 0, result_point should be an array of size 64 bytes where the resulting x coordinate concatenated with y will be written. +// Returns true on success and false on invalid input (see the functions below what defines invalid input). +// If false is returned, the result is not written. +bool P256_pointmult(uint8_t* result_point, const uint8_t point[64], const uint8_t scalar[32], bool include_y_in_result); + +// ECDH keygen +// Multiplies the scalar private_key with the curve-defined base point. +// The result should be an array of size 64 bytes where the x coordinate concatenated by the y coordinate will be written. +// Returns true on success and false if the private_key lies outside the allowed range [1..n-1], where n is the curve order. +// If false is returned, the result is not written. (At that point this function can be called again with a new randomized private_key.) +bool P256_ecdh_keygen(uint8_t result_my_public_point[64], const uint8_t private_key[32]); + +// ECDH shared secret +// Multiplies the scalar private_key with the other's public point. +// The result should be an array of size 32 bytes where the x coordinate of the result will be written (y is discarded). +// Returns true on success and false if any of the following occurs: +// - the scalar private_key lies outside the allowed range [1..n-1], where n is the curve order +// - a public point coordinate integer lies outside the allowed range [0..p-1], where p is the prime for the field used by the curve +// - the public point does not lie on the curve +// If false is returned, the result is not written. +// NOTE: the boolean return value MUST be checked in order to avoid different attacks. +bool P256_ecdh_shared_secret(uint8_t result_point_x[32], const uint8_t others_public_point[64], const uint8_t private_key[32]) __attribute__((warn_unused_result)); + +#endif diff --git a/src/components/libraries/secure/asm_ecdh_p256/P256-cortex-m0-ecdh-keil.s b/src/components/libraries/secure/asm_ecdh_p256/P256-cortex-m0-ecdh-keil.s new file mode 100644 index 0000000..2dd1e29 --- /dev/null +++ b/src/components/libraries/secure/asm_ecdh_p256/P256-cortex-m0-ecdh-keil.s @@ -0,0 +1,2954 @@ +; P-256 ECDH +; Author: Emil Lenngren +; Licensed under the BSD 2-clause license. +; The 256x256->512 multiplication/square code is based on public domain µNaCl by Ana Helena Sánchez and Björn Haase (https://munacl.cryptojedi.org/curve25519-cortexm0.shtml) + +; Note on calling conventions: some of the local functions in this file use custom calling conventions. +; Exported symbols use the standard C calling conventions for ARM, which means that r4-r11 and sp are preserved and the other registers are clobbered. + +; Stack usage is 1356 bytes. + +; Settings below for optimizing for speed vs size. +; When optimizing fully for speed, the run time is 4 456 738 cycles and code size is 3708 bytes. +; When optimizing fully for size, the run time is 5 764 182 cycles and code size is 2416 bytes. +; Get the time taken (in seconds) by dividing the number of cycles with the clock frequency (Hz) of the cpu. +; Different optimization levels can be done by setting some to 1 and some to 0. +; Optimizing all settings for size except use_mul_for_sqr and use_smaller_modinv gives a run time of 4 851 527 cycles and code size is 2968 bytes. + + gbla use_mul_for_sqr +use_mul_for_sqr seta 0 ; 1 to enable, 0 to disable (14% slower if enabled but saves 624/460 bytes (depending on use_noninlined_sqr64) of compiled code size) + + gbla use_noninlined_mul64 +use_noninlined_mul64 seta 1 ; 1 to enable, 0 to disable (2.6%/4.0% slower (depending on use_mul_for_sqr) if enabled but saves 308 bytes of compiled code size) + + gbla use_noninlined_sqr64 +use_noninlined_sqr64 seta 1 ; 1 to enable, 0 to disable (2.4% slower if enabled and use_mul_for_sqr=0 but saves 164 bytes of compiled code size) + + gbla use_interpreter +use_interpreter seta 1 ; 1 to enable, 0 to disable (3.6% slower if enabled but saves 268 bytes of compiled code size) + + gbla use_smaller_modinv +use_smaller_modinv seta 0 ; 1 to enable, 0 to disable (3.6% slower if enabled but saves 88 bytes of compiled code size) + + area |.text|,code,readonly + align 2 + + if use_noninlined_mul64 == 1 +; in: (r4,r5) = a[0..1], (r2,r3) = b[0..1] +; out: r0-r3 +; clobbers r4-r9 and lr +P256_mul64 proc + mov r6,r5 + mov r1,r2 + subs r5,r4 + sbcs r0,r0 + eors r5,r0 + subs r5,r0 + subs r1,r3 + sbcs r7,r7 + eors r1,r7 + subs r1,r7 + eors r7,r0 + mov r9,r1 + mov r8,r5 + lsrs r1,r4,#16 + uxth r4,r4 + mov r0,r4 + uxth r5,r2 + lsrs r2,#16 + muls r0,r5,r0;//00 + muls r5,r1,r5;//10 + muls r4,r2,r4;//01 + muls r1,r2,r1;//11 + lsls r2,r4,#16 + lsrs r4,r4,#16 + adds r0,r2 + adcs r1,r4 + lsls r2,r5,#16 + lsrs r4,r5,#16 + adds r0,r2 + adcs r1,r4 + lsrs r4,r6,#16 + uxth r6,r6 + uxth r5,r3 + lsrs r3,r3,#16 + mov r2,r6 + muls r2,r5,r2 + muls r5,r4,r5 + muls r6,r3,r6 + muls r3,r4,r3 + lsls r4,r5,#16 + lsrs r5,r5,#16 + adds r2,r4 + adcs r3,r5 + lsls r4,r6,#16 + lsrs r5,r6,#16 + adds r2,r4 + adcs r3,r5 + eors r6,r6 + adds r2,r1 + adcs r3,r6 + mov r1,r9 + mov r5,r8 + mov r8,r0 + lsrs r0,r1,#16 + uxth r1,r1 + mov r4,r1 + lsrs r6,r5,#16 + uxth r5,r5 + muls r1,r5,r1 + muls r4,r6,r4 + muls r5,r0,r5 + muls r0,r6,r0 + lsls r6,r4,#16 + lsrs r4,#16 + adds r1,r6 + adcs r0,r4 + lsls r6,r5,#16 + lsrs r5,#16 + adds r1,r6 + adcs r0,r5 + eors r1,r7 + eors r0,r7 + eors r4,r4 + asrs r7,r7,#1 + adcs r1,r2 + adcs r2,r0 + adcs r7,r4 + mov r0,r8 + adds r1,r0 + adcs r2,r3 + adcs r3,r7 + bx lr + endp + endif + +; in: *r10 = a, *r11 = b, (r4,r5) = a[0..1], (r2,r3) = b[0..1] +; out: r8,r9,r2-r7 +; clobbers all other registers +P256_mul128 proc + if use_noninlined_mul64 == 1 + push {lr} + frame push {lr} + endif + ;///////MUL128///////////// + ;MUL64 + if use_noninlined_mul64 == 0 + mov r6,r5 + mov r1,r2 + subs r5,r4 + sbcs r0,r0 + eors r5,r0 + subs r5,r0 + subs r1,r3 + sbcs r7,r7 + eors r1,r7 + subs r1,r7 + eors r7,r0 + mov r9,r1 + mov r8,r5 + lsrs r1,r4,#16 + uxth r4,r4 + mov r0,r4 + uxth r5,r2 + lsrs r2,#16 + muls r0,r5,r0;//00 + muls r5,r1,r5;//10 + muls r4,r2,r4;//01 + muls r1,r2,r1;//11 + lsls r2,r4,#16 + lsrs r4,r4,#16 + adds r0,r2 + adcs r1,r4 + lsls r2,r5,#16 + lsrs r4,r5,#16 + adds r0,r2 + adcs r1,r4 + lsrs r4,r6,#16 + uxth r6,r6 + uxth r5,r3 + lsrs r3,r3,#16 + mov r2,r6 + muls r2,r5,r2 + muls r5,r4,r5 + muls r6,r3,r6 + muls r3,r4,r3 + lsls r4,r5,#16 + lsrs r5,r5,#16 + adds r2,r4 + adcs r3,r5 + lsls r4,r6,#16 + lsrs r5,r6,#16 + adds r2,r4 + adcs r3,r5 + eors r6,r6 + adds r2,r1 + adcs r3,r6 + mov r1,r9 + mov r5,r8 + mov r8,r0 + lsrs r0,r1,#16 + uxth r1,r1 + mov r4,r1 + lsrs r6,r5,#16 + uxth r5,r5 + muls r1,r5,r1 + muls r4,r6,r4 + muls r5,r0,r5 + muls r0,r6,r0 + lsls r6,r4,#16 + lsrs r4,#16 + adds r1,r6 + adcs r0,r4 + lsls r6,r5,#16 + lsrs r5,#16 + adds r1,r6 + adcs r0,r5 + eors r1,r7 + eors r0,r7 + eors r4,r4 + asrs r7,r7,#1 + adcs r1,r2 + adcs r2,r0 + adcs r7,r4 + mov r0,r8 + adds r1,r0 + adcs r2,r3 + adcs r3,r7 + else + bl P256_mul64 + endif + push {r0,r1} + frame address sp,8+use_noninlined_mul64*4 + mov r1,r10 + mov r10,r2 + ldm r1,{r0,r1,r4,r5} + mov r2,r4 + mov r7,r5 + subs r2,r0 + sbcs r7,r1 + sbcs r6,r6 + eors r2,r6 + eors r7,r6 + subs r2,r6 + sbcs r7,r6 + push {r2,r7} + frame address sp,16+use_noninlined_mul64*4 + mov r2,r11 + mov r11,r3 + ldm r2,{r0,r1,r2,r3} + subs r0,r2 + sbcs r1,r3 + sbcs r7,r7 + eors r0,r7 + eors r1,r7 + subs r0,r7 + sbcs r1,r7 + eors r7,r6 + mov r12,r7 + push {r0,r1} + frame address sp,24+use_noninlined_mul64*4 + ;MUL64 + if use_noninlined_mul64 == 0 + mov r6,r5 + mov r1,r2 + subs r5,r4 + sbcs r0,r0 + eors r5,r0 + subs r5,r0 + subs r1,r3 + sbcs r7,r7 + eors r1,r7 + subs r1,r7 + eors r7,r0 + mov r9,r1 + mov r8,r5 + lsrs r1,r4,#16 + uxth r4,r4 + mov r0,r4 + uxth r5,r2 + lsrs r2,#16 + muls r0,r5,r0;//00 + muls r5,r1,r5;//10 + muls r4,r2,r4;//01 + muls r1,r2,r1;//11 + lsls r2,r4,#16 + lsrs r4,r4,#16 + adds r0,r2 + adcs r1,r4 + lsls r2,r5,#16 + lsrs r4,r5,#16 + adds r0,r2 + adcs r1,r4 + lsrs r4,r6,#16 + uxth r6,r6 + uxth r5,r3 + lsrs r3,r3,#16 + mov r2,r6 + muls r2,r5,r2 + muls r5,r4,r5 + muls r6,r3,r6 + muls r3,r4,r3 + lsls r4,r5,#16 + lsrs r5,r5,#16 + adds r2,r4 + adcs r3,r5 + lsls r4,r6,#16 + lsrs r5,r6,#16 + adds r2,r4 + adcs r3,r5 + eors r6,r6 + adds r2,r1 + adcs r3,r6 + mov r1,r9 + mov r5,r8 + mov r8,r0 + lsrs r0,r1,#16 + uxth r1,r1 + mov r4,r1 + lsrs r6,r5,#16 + uxth r5,r5 + muls r1,r5,r1 + muls r4,r6,r4 + muls r5,r0,r5 + muls r0,r6,r0 + lsls r6,r4,#16 + lsrs r4,#16 + adds r1,r6 + adcs r0,r4 + lsls r6,r5,#16 + lsrs r5,#16 + adds r1,r6 + adcs r0,r5 + eors r1,r7 + eors r0,r7 + eors r4,r4 + asrs r7,r7,#1 + adcs r1,r2 + adcs r2,r0 + adcs r7,r4 + mov r0,r8 + adds r1,r0 + adcs r2,r3 + adcs r3,r7 + else + bl P256_mul64 + endif + mov r4,r10 + mov r5,r11 + eors r6,r6 + adds r0,r4 + adcs r1,r5 + adcs r2,r6 + adcs r3,r6 + mov r10,r2 + mov r11,r3 + pop {r2-r5} + frame address sp,8+use_noninlined_mul64*4 + push {r0,r1} + frame address sp,16+use_noninlined_mul64*4 + if use_noninlined_mul64 == 0 + mov r6,r5 + mov r1,r2 + subs r5,r4 + sbcs r0,r0 + eors r5,r0 + subs r5,r0 + subs r1,r3 + sbcs r7,r7 + eors r1,r7 + subs r1,r7 + eors r7,r0 + mov r9,r1 + mov r8,r5 + lsrs r1,r4,#16 + uxth r4,r4 + mov r0,r4 + uxth r5,r2 + lsrs r2,#16 + muls r0,r5,r0;//00 + muls r5,r1,r5;//10 + muls r4,r2,r4;//01 + muls r1,r2,r1;//11 + lsls r2,r4,#16 + lsrs r4,r4,#16 + adds r0,r2 + adcs r1,r4 + lsls r2,r5,#16 + lsrs r4,r5,#16 + adds r0,r2 + adcs r1,r4 + lsrs r4,r6,#16 + uxth r6,r6 + uxth r5,r3 + lsrs r3,r3,#16 + mov r2,r6 + muls r2,r5,r2 + muls r5,r4,r5 + muls r6,r3,r6 + muls r3,r4,r3 + lsls r4,r5,#16 + lsrs r5,r5,#16 + adds r2,r4 + adcs r3,r5 + lsls r4,r6,#16 + lsrs r5,r6,#16 + adds r2,r4 + adcs r3,r5 + eors r6,r6 + adds r2,r1 + adcs r3,r6 + mov r1,r9 + mov r5,r8 + mov r8,r0 + lsrs r0,r1,#16 + uxth r1,r1 + mov r4,r1 + lsrs r6,r5,#16 + uxth r5,r5 + muls r1,r5,r1 + muls r4,r6,r4 + muls r5,r0,r5 + muls r0,r6,r0 + lsls r6,r4,#16 + lsrs r4,#16 + adds r1,r6 + adcs r0,r4 + lsls r6,r5,#16 + lsrs r5,#16 + adds r1,r6 + adcs r0,r5 + eors r1,r7 + eors r0,r7 + eors r4,r4 + asrs r7,r7,#1 + adcs r1,r2 + adcs r2,r0 + adcs r7,r4 + mov r0,r8 + adds r1,r0 + adcs r2,r3 + adcs r3,r7 + else + bl P256_mul64 + endif + pop {r4,r5} + frame address sp,8+use_noninlined_mul64*4 + mov r6,r12 + mov r7,r12 + eors r0,r6 + eors r1,r6 + eors r2,r6 + eors r3,r6 + asrs r6,r6,#1 + adcs r0,r4 + adcs r1,r5 + adcs r4,r2 + adcs r5,r3 + eors r2,r2 + adcs r6,r2 ;//0,1 + adcs r7,r2 + pop {r2,r3} + frame address sp,0+use_noninlined_mul64*4 + mov r8,r2 + mov r9,r3 + adds r2,r0 + adcs r3,r1 + mov r0,r10 + mov r1,r11 + adcs r4,r0 + adcs r5,r1 + adcs r6,r0 + adcs r7,r1 + if use_noninlined_mul64 == 1 + pop {pc} + else + bx lr + endif + endp + + if use_mul_for_sqr == 1 +;thumb_func +P256_sqrmod ;label definition + mov r2,r1 + ; fallthrough + endif + +; *r0 = out, *r1 = a, *r2 = b +P256_mulmod proc + push {r0,lr} + frame push {lr} + frame address sp,8 + sub sp,#64 + frame address sp,72 + push {r1-r2} + frame address sp,80 + mov r10,r2 + mov r11,r1 + mov r0,r2 + ldm r0!,{r4,r5} + adds r0,#8 + ldm r1!,{r2,r3} + adds r1,#8 + push {r0,r1} + frame address sp,88 + + bl P256_mul128 + add r0,sp,#24 + stm r0!,{r2,r3} + add r0,sp,#16 + mov r2,r8 + mov r3,r9 + stm r0!,{r2,r3} + + ;pop {r0} ;result+8 + ;stm r0!,{r2,r3} + pop {r1,r2} ;a+16 b+16 + frame address sp,80 + ;push {r0} + push {r4-r7} + frame address sp,96 + mov r10,r1 + mov r11,r2 + ldm r1!,{r4,r5} + ldm r2,{r2,r3} + + bl P256_mul128 + + mov r0,r8 + mov r1,r9 + mov r8,r6 + mov r9,r7 + pop {r6,r7} + frame address sp,88 + adds r0,r6 + adcs r1,r7 + pop {r6,r7} + frame address sp,80 + adcs r2,r6 + adcs r3,r7 + ;pop {r7} ;result+16 + add r7,sp,#24 + stm r7!,{r0-r3} + mov r10,r7 + eors r0,r0 + mov r6,r8 + mov r7,r9 + adcs r4,r0 + adcs r5,r0 + adcs r6,r0 + adcs r7,r0 + pop {r1,r2} ;b a + frame address sp,72 + mov r12,r2 + push {r4-r7} + frame address sp,88 + ldm r1,{r0-r7} + subs r0,r4 + sbcs r1,r5 + sbcs r2,r6 + sbcs r3,r7 + eors r4,r4 + sbcs r4,r4 + eors r0,r4 + eors r1,r4 + eors r2,r4 + eors r3,r4 + subs r0,r4 + sbcs r1,r4 + sbcs r2,r4 + sbcs r3,r4 + mov r6,r12 + mov r12,r4 ;//carry + mov r5,r10 + stm r5!,{r0-r3} + mov r11,r5 + mov r8,r0 + mov r9,r1 + ldm r6,{r0-r7} + subs r4,r0 + sbcs r5,r1 + sbcs r6,r2 + sbcs r7,r3 + eors r0,r0 + sbcs r0,r0 + eors r4,r0 + eors r5,r0 + eors r6,r0 + eors r7,r0 + subs r4,r0 + sbcs r5,r0 + sbcs r6,r0 + sbcs r7,r0 + mov r1,r12 + eors r0,r1 + mov r1,r11 + stm r1!,{r4-r7} + push {r0} + frame address sp,92 + mov r2,r8 + mov r3,r9 + + bl P256_mul128 + + pop {r0} ;//r0,r1 + frame address sp,88 + mov r12,r0 ;//negative + eors r2,r0 + eors r3,r0 + eors r4,r0 + eors r5,r0 + eors r6,r0 + eors r7,r0 + push {r4-r7} + frame address sp,104 + add r1,sp,#32 ;result + ldm r1!,{r4-r7} + ;mov r11,r1 ;//reference + mov r1,r9 + eors r1,r0 + mov r10,r4 + mov r4,r8 + asrs r0,#1 + eors r0,r4 + mov r4,r10 + adcs r0,r4 + adcs r1,r5 + adcs r2,r6 + adcs r3,r7 + eors r4,r4 + adcs r4,r4 + mov r10,r4 ;//carry + ;mov r4,r11 + add r4,sp,#32+16 + ldm r4,{r4-r7} + adds r0,r4 + adcs r1,r5 + adcs r2,r6 + adcs r3,r7 + mov r9,r4 + ;mov r4,r11 + add r4,sp,#32+16 + stm r4!,{r0-r3} + ;mov r11,r4 + pop {r0-r3} + frame address sp,88 + mov r4,r9 + adcs r4,r0 + adcs r5,r1 + adcs r6,r2 + adcs r7,r3 + movs r1,#0 + adcs r1,r1 + mov r0,r10 + mov r10,r1 ;//carry + asrs r0,#1 + pop {r0-r3} + frame address sp,72 + adcs r4,r0 + adcs r5,r1 + adcs r6,r2 + adcs r7,r3 + mov r8,r0 + ;mov r0,r11 + add r0,sp,#32 + stm r0!,{r4-r7} + ;mov r11,r0 + mov r0,r8 + mov r6,r12 + mov r5,r10 + eors r4,r4 + adcs r5,r6 + adcs r6,r4 + adds r0,r5 + adcs r1,r6 + adcs r2,r6 + adcs r3,r6 + ;mov r7,r11 + add r7,sp,#32+16 + stm r7!,{r0-r3} + + ; multiplication done, now reducing + +reduce ;label definition + pop {r0-r7} + frame address sp,40 + adds r3,r0 + adcs r4,r1 + adcs r5,r2 + adcs r6,r0 + mov r8,r2 + mov r9,r3 + mov r10,r4 + mov r11,r5 + mov r12,r6 + adcs r7,r1 + pop {r2-r5} ;8,9,10,11 + frame address sp,24 + adcs r2,r0 ;8+0 + adcs r3,r1 ;9+1 + movs r6,#0 + adcs r4,r6 ;10+#0 + adcs r5,r6 ;11+#0 + adcs r6,r6 ;C + + subs r7,r0 ;7-0 + sbcs r2,r1 ;8-1 + ; r0,r1 dead + mov r0,r8 ;2 + mov r1,r9 ;3 + sbcs r3,r0 ;9-2 + sbcs r4,r1 ;10-3 + movs r0,#0 + sbcs r5,r0 ;11-#0 + sbcs r6,r0 ;C-#0 + + mov r0,r12 ;6 + adds r0,r1 ;6+3 + mov r12,r0 + mov r0,r10 ;4 + adcs r7,r0 ;7+4 + mov lr,r7 + mov r0,r8 ;2 + adcs r2,r0 ;8+2 + adcs r3,r1 ;9+3 + adcs r4,r0 ;10+2 + adcs r5,r1 ;11+3 + movs r7,#0 + adcs r6,r7 ;C+#0 + + ;2-3 are now dead (r8,r9) + ;4 5 6 7 8 9 10 11 C + ;r10 r11 r12 lr r2 r3 r4 r5 r6 + ;r7: 0 + + pop {r0,r1} ;12,13 + frame address sp,16 + + adds r6,r0 ;12+C + adcs r1,r7 ;13+#0 + adcs r7,r7 ;new Carry for 14 + + ;r0 dead + + mov r0,r11 ;5 + adds r2,r0 ;8+5 + mov r8,r2 + mov r2,r12 ;6 + adcs r3,r2 ;9+6 + mov r9,r3 + mov r3,r10 ;4 + adcs r4,r3 ;10+4 + mov r10,r4 + adcs r5,r0 ;11+5 + adcs r6,r3 ;12+4 + adcs r1,r0 ;13+5 + pop {r2,r4} ;14,15 + frame address sp,8 + adcs r2,r7 ;14+C + movs r7,#0 + adcs r4,r7 ;15+#0 + adcs r7,r7 ;new Carry for 16 + + ;4 5 6 7 8 9 10 11 12 13 14 15 C + ;r3 r0 r12 lr r8 r9 r10 r5 r6 r1 r2 r4 r7 + ;r11 is available + + subs r5,r3 ;11-4 + sbcs r6,r0 ;12-5 + mov r3,r12 ;6 + mov r0,lr ;7 + sbcs r1,r3 ;13-6 + sbcs r2,r0 ;14-7 + movs r3,#0 + sbcs r4,r3 ;15-#0 + sbcs r7,r3 ;C-#0 + mov lr,r4 + mov r11,r7 + + mov r4,r10 ;10 + adds r4,r0 ;10+7 + adcs r5,r3 ;11+#0 + mov r7,r12 ;6 + adcs r6,r7 ;12+6 + adcs r1,r0 ;13+7 + adcs r2,r7 ;14+6 + mov r7,lr ;15 + adcs r7,r0 ;15+7 + mov r0,r11 ;C + adcs r0,r3 ;C+#0 + + ; now (T + mN) / R is + ; 8 9 4 5 6 1 2 7 6 (lsb -> msb) + + subs r3,r3 ;set r3 to 0 and C to 1 + mov r10,r0 + mov r0,r8 + adcs r0,r3 + mov r11,r7 + mov r7,r9 + adcs r7,r3 + mov r12,r0 + mov r9,r7 + adcs r4,r3 + sbcs r5,r3 + sbcs r6,r3 + sbcs r1,r3 + movs r3,#1 + sbcs r2,r3 + movs r3,#0 + mov r0,r11 + mov r7,r10 + adcs r0,r3 + sbcs r7,r3 + + ; r12 r9 r4 r5 | r6 r1 r2 r0 + + mov r8,r2 + mov r2,r12 + mov r11,r0 + mov r3,r9 +reduce2 ;label definition + adds r2,r7 + adcs r3,r7 + adcs r4,r7 + movs r0,#0 + adcs r5,r0 + adcs r6,r0 + adcs r1,r0 + pop {r0} + frame address sp,4 + stm r0!,{r2-r6} + movs r5,#1 + ands r5,r7 + mov r2,r8 + mov r3,r11 + adcs r2,r5 + adcs r3,r7 + stm r0!,{r1-r3} + + pop {pc} + + endp + + + if use_mul_for_sqr == 0 + + if use_noninlined_sqr64 == 1 + +P256_sqr64 proc + ; START: sqr 64 Refined Karatsuba + ; Input operands in r4,r5 + ; Result in r0,r1,r2,r3 + ; Clobbers: r4-r6 + ; START: sqr 32 + ; Input operand in r4 + ; Result in r0 ,r1 + ; Clobbers: r2, r3 + uxth r0,r4 + lsrs r1,r4,#16 + mov r2,r0 + muls r2,r1,r2 + muls r0,r0,r0 + muls r1,r1,r1 + lsrs r3,r2,#15 + lsls r2,r2,#17 + adds r0,r2 + adcs r1,r3 + ; End: sqr 32 + ; Result in r0 ,r1 + subs r4,r5 + sbcs r6,r6 + eors r4,r6 + subs r4,r6 + ; START: sqr 32 + ; Input operand in r5 + ; Result in r2 ,r3 + ; Clobbers: r5, r6 + uxth r2,r5 + lsrs r3,r5,#16 + mov r5,r2 + muls r5,r3,r5 + muls r2,r2,r2 + muls r3,r3,r3 + lsrs r6,r5,#15 + lsls r5,r5,#17 + adds r2,r5 + adcs r3,r6 + ; End: sqr 32 + ; Result in r2 ,r3 + movs r6,#0 + adds r2,r1 + adcs r3,r6 + ; START: sqr 32 + ; Input operand in r4 + ; Result in r4 ,r5 + ; Clobbers: r1, r6 + lsrs r5,r4,#16 + uxth r4,r4 + mov r1,r4 + muls r1,r5,r1 + muls r4,r4,r4 + muls r5,r5,r5 + lsrs r6,r1,#15 + lsls r1,r1,#17 + adds r4,r1 + adcs r5,r6 + ; End: sqr 32 + ; Result in r4 ,r5 + mov r1,r2 + subs r1,r4 + sbcs r2,r5 + mov r5,r3 + movs r6,#0 + sbcs r3,r6 + adds r1,r0 + adcs r2,r5 + adcs r3,r6 + ; END: sqr 64 Refined Karatsuba + ; Result in r0,r1,r2,r3 + ; Leaves r6 zero. + bx lr + endp + +P256_sqr128 proc + push {lr} + frame push {lr} + ; sqr 128 Refined Karatsuba + ; Input in r4 ... r7 + ; Result in r0 ... r7 + ; clobbers all registers + mov r0,r4 + mov r1,r5 + subs r0,r6 + sbcs r1,r7 + sbcs r2,r2 + eors r0,r2 + eors r1,r2 + subs r0,r2 + sbcs r1,r2 + mov r8,r0 + mov r9,r1 + mov r10,r6 + + bl P256_sqr64 + + mov r4,r10 + mov r5,r7 + mov r10,r0 + mov r11,r1 + mov r12,r2 + mov r7,r3 + + bl P256_sqr64 + + mov r4,r12 + adds r0,r4 + adcs r1,r7 + adcs r2,r6 + adcs r3,r6 + mov r7,r3 + mov r12,r0 + mov r4,r8 + mov r8,r1 + mov r5,r9 + mov r9,r2 + + bl P256_sqr64 + + mov r4,r12 + mov r5,r8 + mov r6,r9 + subs r4,r0 + sbcs r5,r1 + mov r0,r6 + mov r1,r7 + sbcs r0,r2 + sbcs r1,r3 + movs r2,#0 + sbcs r6,r2 + sbcs r7,r2 + mov r2,r10 + adds r2,r4 + mov r3,r11 + adcs r3,r5 + mov r4,r12 + adcs r4,r0 + mov r5,r8 + adcs r5,r1 + movs r0,#0 + adcs r6,r0 + adcs r7,r0 + mov r0,r10 + mov r1,r11 + ; END: sqr 128 Refined Karatsuba + pop {pc} + endp + else +P256_sqr128 proc + ; sqr 128 Refined Karatsuba + ; Input in r4 ... r7 + ; Result in r0 ... r7 + ; clobbers all registers + mov r0,r4 + mov r1,r5 + subs r0,r6 + sbcs r1,r7 + sbcs r2,r2 + eors r0,r2 + eors r1,r2 + subs r0,r2 + sbcs r1,r2 + mov r8,r0 + mov r9,r1 + mov r10,r6 + ; START: sqr 64 Refined Karatsuba + ; Input operands in r4,r5 + ; Result in r0,r1,r2,r3 + ; Clobbers: r4-r6 + ; START: sqr 32 + ; Input operand in r4 + ; Result in r0 ,r1 + ; Clobbers: r2, r3 + uxth r0,r4 + lsrs r1,r4,#16 + mov r2,r0 + muls r2,r1,r2 + muls r0,r0,r0 + muls r1,r1,r1 + lsrs r3,r2,#15 + lsls r2,r2,#17 + adds r0,r2 + adcs r1,r3 + ; End: sqr 32 + ; Result in r0 ,r1 + subs r4,r5 + sbcs r6,r6 + eors r4,r6 + subs r4,r6 + ; START: sqr 32 + ; Input operand in r5 + ; Result in r2 ,r3 + ; Clobbers: r5, r6 + uxth r2,r5 + lsrs r3,r5,#16 + mov r5,r2 + muls r5,r3,r5 + muls r2,r2,r2 + muls r3,r3,r3 + lsrs r6,r5,#15 + lsls r5,r5,#17 + adds r2,r5 + adcs r3,r6 + ; End: sqr 32 + ; Result in r2 ,r3 + movs r6,#0 + adds r2,r1 + adcs r3,r6 + ; START: sqr 32 + ; Input operand in r4 + ; Result in r4 ,r5 + ; Clobbers: r1, r6 + lsrs r5,r4,#16 + uxth r4,r4 + mov r1,r4 + muls r1,r5,r1 + muls r4,r4,r4 + muls r5,r5,r5 + lsrs r6,r1,#15 + lsls r1,r1,#17 + adds r4,r1 + adcs r5,r6 + ; End: sqr 32 + ; Result in r4 ,r5 + mov r1,r2 + subs r1,r4 + sbcs r2,r5 + mov r5,r3 + movs r6,#0 + sbcs r3,r6 + adds r1,r0 + adcs r2,r5 + adcs r3,r6 + ; END: sqr 64 Refined Karatsuba + ; Result in r0,r1,r2,r3 + ; Leaves r6 zero. + mov r6,r10 + mov r10,r0 + mov r11,r1 + mov r12,r2 + mov r1,r3 + ; START: sqr 64 Refined Karatsuba + ; Input operands in r6,r7 + ; Result in r2,r3,r4,r5 + ; Clobbers: r0,r7,r6 + ; START: sqr 32 + ; Input operand in r6 + ; Result in r2 ,r3 + ; Clobbers: r4, r5 + uxth r2,r6 + lsrs r3,r6,#16 + mov r4,r2 + muls r4,r3,r4 + muls r2,r2,r2 + muls r3,r3,r3 + lsrs r5,r4,#15 + lsls r4,r4,#17 + adds r2,r4 + adcs r3,r5 + ; End: sqr 32 + ; Result in r2 ,r3 + subs r6,r7 + sbcs r4,r4 + eors r6,r4 + subs r6,r4 + ; START: sqr 32 + ; Input operand in r7 + ; Result in r4 ,r5 + ; Clobbers: r0, r7 + uxth r4,r7 + lsrs r5,r7,#16 + mov r0,r4 + muls r0,r5,r0 + muls r4,r4,r4 + muls r5,r5,r5 + lsrs r7,r0,#15 + lsls r0,r0,#17 + adds r4,r0 + adcs r5,r7 + ; End: sqr 32 + ; Result in r4 ,r5 + movs r7,#0 + adds r4,r3 + adcs r5,r7 + ; START: sqr 32 + ; Input operand in r6 + ; Result in r7 ,r0 + ; Clobbers: r6, r3 + uxth r7,r6 + lsrs r0,r6,#16 + mov r6,r7 + muls r6,r0,r6 + muls r7,r7,r7 + muls r0,r0,r0 + lsrs r3,r6,#15 + lsls r6,r6,#17 + adds r7,r6 + adcs r0,r3 + ; End: sqr 32 + ; Result in r7 ,r0 + mov r3,r4 + subs r3,r7 + sbcs r4,r0 + mov r0,r5 + movs r6,#0 + sbcs r5,r6 + adds r3,r2 + adcs r4,r0 + adcs r5,r6 + ; END: sqr 64 Refined Karatsuba + ; Result in r2,r3,r4,r5 + ; Leaves r6 zero. + mov r0,r12 + adds r2,r0 + adcs r3,r1 + adcs r4,r6 + adcs r5,r6 + mov r12,r2 + mov r2,r8 + mov r8,r3 + mov r3,r9 + mov r9,r4 + ; START: sqr 64 Refined Karatsuba + ; Input operands in r2,r3 + ; Result in r6,r7,r0,r1 + ; Clobbers: r2,r3,r4 + ; START: sqr 32 + ; Input operand in r2 + ; Result in r6 ,r7 + ; Clobbers: r0, r1 + uxth r6,r2 + lsrs r7,r2,#16 + mov r0,r6 + muls r0,r7,r0 + muls r6,r6,r6 + muls r7,r7,r7 + lsrs r1,r0,#15 + lsls r0,r0,#17 + adds r6,r0 + adcs r7,r1 + ; End: sqr 32 + ; Result in r6 ,r7 + subs r2,r3 + sbcs r4,r4 + eors r2,r4 + subs r2,r4 + ; START: sqr 32 + ; Input operand in r3 + ; Result in r0 ,r1 + ; Clobbers: r3, r4 + uxth r0,r3 + lsrs r1,r3,#16 + mov r3,r0 + muls r3,r1,r3 + muls r0,r0,r0 + muls r1,r1,r1 + lsrs r4,r3,#15 + lsls r3,r3,#17 + adds r0,r3 + adcs r1,r4 + ; End: sqr 32 + ; Result in r0 ,r1 + movs r4,#0 + adds r0,r7 + adcs r1,r4 + ; START: sqr 32 + ; Input operand in r2 + ; Result in r3 ,r4 + ; Clobbers: r2, r7 + uxth r3,r2 + lsrs r4,r2,#16 + mov r2,r3 + muls r2,r4,r2 + muls r3,r3,r3 + muls r4,r4,r4 + lsrs r7,r2,#15 + lsls r2,r2,#17 + adds r3,r2 + adcs r4,r7 + ; End: sqr 32 + ; Result in r3 ,r4 + mov r7,r0 + subs r7,r3 + sbcs r0,r4 + mov r2,r1 + movs r4,#0 + sbcs r1,r4 + adds r7,r6 + adcs r0,r2 + adcs r1,r4 + ; END: sqr 64 Refined Karatsuba + ; Result in r6,r7,r0,r1 + ; Returns r4 as zero. + mov r2,r12 + mov r3,r8 + mov r4,r9 + subs r2,r6 + sbcs r3,r7 + mov r6,r4 + mov r7,r5 + sbcs r4,r0 + sbcs r5,r1 + movs r0,#0 + sbcs r6,r0 + sbcs r7,r0 + mov r0,r10 + adds r2,r0 + mov r1,r11 + adcs r3,r1 + mov r0,r12 + adcs r4,r0 + mov r0,r8 + adcs r5,r0 + movs r0,#0 + adcs r6,r0 + adcs r7,r0 + mov r0,r10 + ; END: sqr 128 Refined Karatsuba + ; Result in r0 ... r7 + bx lr + endp + + endif + +; ###################### +; ASM Square 256 refined karatsuba: +; ###################### + ; sqr 256 Refined Karatsuba + ; pInput in r1 + ; pResult in r0 +P256_sqrmod proc + push {r0,lr} + frame push {lr} + frame address sp,8 + sub sp,#64 + frame address sp,72 + ;mov lr,sp + push {r1} + frame address sp,76 + ldm r1!,{r4,r5,r6,r7} + + bl P256_sqr128 + + push {r4,r5,r6,r7} + frame address sp,92 + ;mov r4,lr + add r4,sp,#20 + stm r4!,{r0,r1,r2,r3} + ldr r4,[sp,#16] + adds r4,#16 + ldm r4,{r4,r5,r6,r7} + + bl P256_sqr128 + + mov r8,r4 + mov r9,r5 + mov r10,r6 + mov r11,r7 + pop {r4,r5,r6,r7} + frame address sp,76 + adds r0,r4 + adcs r1,r5 + adcs r2,r6 + adcs r3,r7 + mov r4,r8 + mov r5,r9 + mov r6,r10 + mov r7,r11 + mov r8,r0 + movs r0,#0 + adcs r4,r0 + adcs r5,r0 + adcs r6,r0 + adcs r7,r0 + mov r0,r8 + push {r0,r1,r2,r3,r4,r5,r6,r7} + frame address sp,108 + ldr r4,[sp,#32] + ldm r4,{r0,r1,r2,r3,r4,r5,r6,r7} + subs r4,r0 + sbcs r5,r1 + sbcs r6,r2 + sbcs r7,r3 + sbcs r0,r0 + eors r4,r0 + eors r5,r0 + eors r6,r0 + eors r7,r0 + subs r4,r0 + sbcs r5,r0 + sbcs r6,r0 + sbcs r7,r0 + + bl P256_sqr128 + + mvns r0,r0 + mvns r1,r1 + mvns r2,r2 + mvns r3,r3 + mvns r4,r4 + mvns r5,r5 + mvns r6,r6 + mvns r7,r7 + mov r8,r4 + mov r9,r5 + mov r10,r6 + mov r11,r7 + subs r4,r4 + pop {r4,r5,r6,r7} + frame address sp,92 + adcs r0,r4 + adcs r1,r5 + adcs r2,r6 + adcs r3,r7 + mov r12,r4 + ;movs r4,#16 + ;add r4,lr + add r4,sp,#20+16 + stm r4!,{r0,r1,r2,r3} + mov r4,r12 + mov r0,r8 + adcs r0,r4 + mov r8,r0 + mov r1,r9 + adcs r1,r5 + mov r9,r1 + mov r2,r10 + adcs r2,r6 + mov r10,r2 + mov r3,r11 + adcs r3,r7 + mov r11,r3 + movs r0,#0 + adcs r0,r0 + mov r12,r0 + ;mov r0,lr + add r0,sp,#20 + ldm r0,{r0,r1,r2,r3,r4,r5,r6,r7} + adds r0,r4 + adcs r1,r5 + adcs r2,r6 + adcs r3,r7 + ;movs r4,#16 + ;add r4,lr + add r4,sp,#20+16 + stm r4!,{r0,r1,r2,r3} + ;mov lr,r4 + mov r0,r13 + ldm r0!,{r4,r5,r6,r7} + mov r1,r8 + adcs r4,r1 + mov r1,r9 + adcs r5,r1 + mov r1,r10 + adcs r6,r1 + mov r1,r11 + adcs r7,r1 + ;mov r0,lr + add r0,sp,#20+32 + stm r0!,{r4,r5,r6,r7} + pop {r4,r5,r6,r7} + frame address sp,76 + mov r1,r12 + movs r2,#0 + mvns r2,r2 + adcs r1,r2 + asrs r2,r1,#4 + adds r4,r1 + adcs r5,r2 + adcs r6,r2 + adcs r7,r2 + stm r0!,{r4,r5,r6,r7} + add sp,#4 + frame address sp,72 + b reduce + endp + endif + +; *r0 = output, *r1 = a, *r2 = b +P256_addmod proc + push {r0,lr} + frame push {lr} + frame address sp,8 + ldm r1!,{r0,r3,r4} + ldm r2!,{r5,r6,r7} + adds r0,r5 + adcs r3,r6 + adcs r4,r7 + mov r8,r0 + mov r9,r3 + mov r10,r4 + ldm r1!,{r5,r6} + ldm r2!,{r3,r4} + adcs r5,r3 + adcs r6,r4 + ldm r1,{r1,r3,r4} + ldm r2,{r0,r2,r7} + adcs r1,r0 + adcs r3,r2 + adcs r4,r7 + movs r7,#0 + adcs r7,r7 + + subs r0,r0 ;set r0 to 0 and C to 1 + mov r2,r8 + mov r8,r7 + mov r7,r9 + mov r9,r4 + mov r4,r10 + adcs r2,r0 + mov r10,r2 + adcs r7,r0 + mov r11,r7 + adcs r4,r0 + sbcs r5,r0 + sbcs r6,r0 + sbcs r1,r0 + movs r0,#1 + sbcs r3,r0 + movs r0,#0 + mov r2,r9 + adcs r2,r0 + mov r7,r8 + sbcs r7,r0 + + ; r10 r11 r4 r5 | r6 r1 r3 r2 | r7 + + mov r8,r3 + mov r3,r11 + mov r11,r2 + mov r2,r10 + + ; r2 r3 r4 r5 | r6 r1 r8 r11 | r7 + + b reduce2 + + endp + +; *r0 = output, *r1 = a, *r2 = b +P256_submod proc + push {r0,lr} + frame push {lr} + frame address sp,8 + ldm r1!,{r0,r3,r4} + ldm r2!,{r5,r6,r7} + subs r0,r5 + sbcs r3,r6 + sbcs r4,r7 + mov r8,r0 + mov r9,r3 + mov r10,r4 + ldm r1!,{r5,r6} + ldm r2!,{r3,r4} + sbcs r5,r3 + sbcs r6,r4 + ldm r1,{r1,r3,r4} + ldm r2,{r0,r2,r7} + sbcs r1,r0 + sbcs r3,r2 + sbcs r4,r7 + + sbcs r7,r7 + + mov r2,r8 + mov r8,r3 + mov r11,r4 + mov r3,r9 + mov r4,r10 + b reduce2 + + endp + +; in: *r0 = output (8 words) +; out: r0 is preserved +P256_load_1 proc + movs r1,#1 + stm r0!,{r1} + movs r1,#0 + movs r2,#0 + stm r0!,{r1-r2} + stm r0!,{r1-r2} + stm r0!,{r1-r2} + stm r0!,{r1} + subs r0,#32 + bx lr + endp + +; in: *r1 +; out: *r0 +P256_to_montgomery proc + push {r4-r7,lr} + frame push {r4-r7,lr} + adr r2,P256_R2_mod_p + bl P256_mulmod + pop {r4-r7,pc} + endp + + align 4 + ; (2^256)^2 mod p +P256_R2_mod_p + dcd 3 + dcd 0 + dcd 0xffffffff + dcd 0xfffffffb + dcd 0xfffffffe + dcd 0xffffffff + dcd 0xfffffffd + dcd 4 + +; in: *r1 +; out: *r0 +P256_from_montgomery proc + push {r4-r7,lr} + frame push {r4-r7,lr} + movs r2,#0 + movs r3,#0 + push {r2-r3} + frame address sp,28 + push {r2-r3} + frame address sp,36 + push {r2-r3} + frame address sp,44 + movs r2,#1 + push {r2-r3} + frame address sp,52 + mov r2,sp + bl P256_mulmod + add sp,#32 + frame address sp,20 + pop {r4-r7,pc} + endp + +; Elliptic curve operations on the NIST curve P256 + +; Checks if a point is on curve +; in: *r0 = x,y(,scratch) in Montgomery form +; out: r0 = 1 if on curve, otherwise 0 +P256_point_is_on_curve proc + if use_interpreter == 1 + push {r0,lr} + frame push {lr} + frame address sp,8 + adr r2,P256_point_is_on_curve_program + bl P256_interpreter + ldr r0,[sp] + adds r0,#64 + adr r1,P256_b_mont + bl P256_greater_or_equal_than + beq %f0 + adr r0,P256_b_mont + ldr r1,[sp] + adds r1,#64 + bl P256_greater_or_equal_than +0 + pop {r1,pc} + else + push {r0,r4-r7,lr} + frame push {r4-r7,lr} + frame address sp,24 + + ; We verify y^2 - (x^3 - 3x) = b + + ; y^2 + mov r1,r0 + adds r1,#32 + sub sp,#32 + frame address sp,56 + mov r0,sp + bl P256_sqrmod + + ; x^2 + ldr r1,[sp,#32] + sub sp,#32 + frame address sp,88 + mov r0,sp + bl P256_sqrmod + + ; x^3 + mov r0,sp + ldr r1,[sp,#64] + mov r2,sp + bl P256_mulmod + + ; x^3 - 3x + movs r0,#3 +0 + push {r0} + frame address sp,92 + add r0,sp,#4 + add r1,sp,#4 + ldr r2,[sp,#68] + bl P256_submod + pop {r0} + frame address sp,88 + subs r0,#1 + bne %b0 + + ; y^2 - (x^3 - 3x) + mov r0,sp + add r1,sp,#32 + mov r2,sp + bl P256_submod + + ; compare with b + mov r0,sp + adr r1,P256_b_mont + bl P256_greater_or_equal_than + beq %f1 + adr r0,P256_b_mont + mov r1,sp + bl P256_greater_or_equal_than +1 + add sp,#68 + frame address sp,20 + + pop {r4-r7,pc} + endif + + endp + + align 4 +P256_b_mont + dcd 0x29c4bddf + dcd 0xd89cdf62 + dcd 0x78843090 + dcd 0xacf005cd + dcd 0xf7212ed6 + dcd 0xe5a220ab + dcd 0x04874834 + dcd 0xdc30061d + + if use_interpreter == 1 +P256_point_is_on_curve_program + dcw 0x2040 + dcw 0x2130 + dcw 0x1113 + dcw 0x4113 + dcw 0x4113 + dcw 0x4113 + dcw 0x4501 + dcw 0x0000 + endif + +; input: *r0 = value, *r1 = limit +; output: 1 if value >= limit, otherwise 0 +P256_greater_or_equal_than proc + push {r4-r6,lr} + frame push {r4-r6,lr} + subs r5,r5 ; set r5 to 0 and C to 1 + mvns r6,r5 ; set r6 to -1 + movs r2,#8 +0 + ldm r0!,{r3} + ldm r1!,{r4} + sbcs r3,r4 + add r2,r2,r6 + tst r2,r2 + bne %b0 + + adcs r5,r5 + mov r0,r5 + pop {r4-r6,pc} + endp + +; in: *r0 = output location, *r1 = input, *r2 = 0/1, *r3 = m +; if r2 = 0, then *r0 is set to *r1 +; if r2 = 1, then *r0 is set to m - *r1 +; note that *r1 should be in the range [1,m-1] +; out: r0 and r1 will have advanced 32 bytes, r2 will remain as the input +P256_negate_mod_m_if proc + push {r4-r7,lr} + frame push {r4-r7,lr} + movs r4,#1 + rsbs r5,r4,#0 ; r5=-1 + mov r8,r5 + subs r4,r4,r2 ; r4=!r2, C=1 + movs r6,#8 +0 + ldm r1!,{r5} + ldm r3!,{r7} + sbcs r7,r5 + muls r7,r2,r7 + muls r5,r4,r5 + add r7,r7,r5 + stm r0!,{r7} + add r6,r6,r8 + tst r6,r6 + bne %b0 + + pop {r4-r7,pc} + endp + +; copies 8 words +; in: *r0 = result, *r1 = input +; out: *r0 = end of result, *r1 = end of input +P256_copy32 proc + push {r4-r5,lr} + frame push {r4-r5,lr} + ldm r1!,{r2-r5} + stm r0!,{r2-r5} + ldm r1!,{r2-r5} + stm r0!,{r2-r5} + pop {r4-r5,pc} + endp + + +; copies 32 bytes +; in: *r0 = result, *r1 = input +; out: *r0 = end of result, *r1 = end of input +P256_copy32_unaligned proc + movs r2,#32 + add r2,r0 +0 + ldrb r3,[r1] + strb r3,[r0] + adds r1,#1 + adds r0,#1 + cmp r0,r2 + bne %b0 + bx lr + endp + +; Selects one of many values +; *r0 = output, *r1 = table, r2 = index to choose [0..7] +P256_select proc + push {r2,r4-r7,lr} + frame push {r4-r7,lr} + frame address sp,24 + + movs r6,#4 +0 + push {r0,r6} + frame address sp,32 + + movs r7,#0 + mov r8,r7 + mov r9,r7 + mov r10,r7 + mov r11,r7 + mov r12,r7 + mov lr,r7 +1 + ldr r0,[sp,#8] + eors r0,r7 + mrs r0,apsr + lsrs r0,#30 + + ldm r1!,{r2-r4} + muls r2,r0,r2 + muls r3,r0,r3 + muls r4,r0,r4 + add r8,r2 + add r9,r3 + add r10,r4 + ldm r1!,{r2-r4} + muls r2,r0,r2 + muls r3,r0,r3 + muls r4,r0,r4 + add r11,r2 + add r12,r3 + add lr,r4 + + adds r1,#72 + adds r7,#1 + cmp r7,#8 + bne %b1 + + pop {r0,r6} + frame address sp,24 + mov r2,r8 + mov r3,r9 + mov r4,r10 + stm r0!,{r2-r4} + mov r2,r11 + mov r3,r12 + mov r4,lr + stm r0!,{r2-r4} + subs r1,#248 + subs r1,#248 + subs r1,#248 + subs r6,#1 + bne %b0 + + pop {r0,r4-r7,pc} + endp + +; Doubles the point in Jacobian form (integers are in Montgomery form) +; *r0 = out, *r1 = in +P256_double_j proc + if use_interpreter == 1 + adr r2,P256_double_j_prog + b P256_interpreter + else + push {r0,r1,r4-r7,lr} + frame push {r4-r7,lr} + frame address sp,28 + + ; https://eprint.iacr.org/2014/130.pdf, algorithm 10 + + ; t1 = Z1^2 + sub sp,#32 + frame address sp,60 + mov r0,sp + adds r1,#64 + bl P256_sqrmod + + ; Z2 = Y1 * Z1 + ldr r0,[sp,#32] + ldr r1,[sp,#36] + adds r0,#64 + adds r1,#32 + movs r2,#32 + adds r2,r1 + bl P256_mulmod + + ; t2 = X1 + t1 + ldr r1,[sp,#36] + mov r2,sp + sub sp,#32 + frame address sp,92 + mov r0,sp + bl P256_addmod + + ; t1 = X1 - t1 + ldr r1,[sp,#68] + add r2,sp,#32 + mov r0,r2 + bl P256_submod + + ; t1 = t1 * t2 + add r1,sp,#32 + mov r2,sp + mov r0,r1 + bl P256_mulmod + + ; t2 = t1 / 2 + add sp,#32 + frame address sp,60 + mov r7,sp + ldm r7!,{r0-r3} + lsls r6,r0,#31 + asrs r5,r6,#31 + lsrs r6,#31 + movs r4,#0 + adds r0,r5 + adcs r1,r5 + adcs r2,r5 + adcs r3,r4 + push {r0-r3} + frame address sp,76 + ldm r7!,{r0-r3} + adcs r0,r4 + adcs r1,r4 + adcs r2,r6 + adcs r3,r5 + movs r4,#0 + adcs r4,r4 + lsls r7,r4,#31 + lsrs r6,r3,#1 + orrs r7,r6 + lsls r6,r3,#31 + lsrs r5,r2,#1 + orrs r6,r5 + lsls r5,r2,#31 + lsrs r4,r1,#1 + orrs r5,r4 + lsls r4,r1,#31 + lsrs r3,r0,#1 + orrs r4,r3 + lsls r3,r0,#31 + mov r8,r3 + pop {r0-r3} + frame address sp,60 + push {r4-r7} + frame address sp,76 + mov r7,r8 + lsrs r6,r3,#1 + orrs r7,r6 + lsls r6,r3,#31 + lsrs r5,r2,#1 + orrs r6,r5 + lsls r5,r2,#31 + lsrs r4,r1,#1 + orrs r5,r4 + lsls r4,r1,#31 + lsrs r3,r0,#1 + orrs r4,r3 + push {r4-r7} + frame address sp,92 + + ; t1 = t1 + t2 + add r1,sp,#32 + mov r2,sp + mov r0,r1 + bl P256_addmod + + ; t2 = t1^2 + mov r0,sp + add r1,sp,#32 + bl P256_sqrmod + + ; Y2 = Y1^2 + ldr r0,[sp,#64] + ldr r1,[sp,#68] + adds r0,#32 + adds r1,#32 + bl P256_sqrmod + + ; t3 = Y2^2 + ldr r1,[sp,#64] + adds r1,#32 + sub sp,#32 + frame address sp,124 + mov r0,sp + bl P256_sqrmod + + ; Y2 = X1 * Y2 + ldr r0,[sp,#96] + ldr r1,[sp,#100] + adds r0,#32 + mov r2,r0 + bl P256_mulmod + + ; X2 = 2 * Y2 + ldr r0,[sp,#96] + mov r1,r0 + adds r1,#32 + mov r2,r1 + bl P256_addmod + + ; X2 = t2 - X2 + ldr r0,[sp,#96] + add r1,sp,#32 + mov r2,r0 + bl P256_submod + + ; t2 = Y2 - X2 + ldr r2,[sp,#96] + mov r1,r2 + adds r1,#32 + add r0,sp,#32 + bl P256_submod + + ; t1 = t1 * t2 + add r0,sp,#64 + add r1,sp,#64 + add r2,sp,#32 + bl P256_mulmod + + ; Y2 = t1 - t3 + ldr r0,[sp,#96] + adds r0,#32 + add r1,sp,#64 + mov r2,sp + bl P256_submod + + add sp,#104 + frame address sp,20 + + pop {r4-r7,pc} + endif + endp + + +; Adds or subtracts points in Jacobian form (integers are in Montgomery form) +; The first operand is located in *r0, the second in *r1 (may not overlap) +; The result is stored at *r0 +; +; Requirements: +; - no operand is the point at infinity +; - both operand must be different +; - one operand must not be the negation of the other +; If requirements are not met, the returned Z point will be 0 +P256_add_j proc + if use_interpreter == 1 + adr r2,P256_add_j_prog + b P256_interpreter + else + push {r0,r1,r4-r7,lr} + frame push {r4-r7,lr} + frame address sp,28 + + ; Here a variant of + ; https://www.hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-3/addition/add-1998-cmo-2.op3 + ; is used, but rearranged and uses less temporaries. + ; The first operand to the function is both (X3,Y3,Z3) and (X2,Y2,Z2). + ; The second operand to the function is (X1,Y1,Z1) + + ; Z1Z1 = Z1^2 + sub sp,#32 + frame address sp,60 + mov r0,sp + adds r1,#64 + bl P256_sqrmod + + ; U2 = X2*Z1Z1 + ldr r1,[sp,#32] + mov r2,sp + mov r0,r1 + bl P256_mulmod + + ; t1 = Z1*Z1Z1 + ldr r1,[sp,#36] + adds r1,#64 + mov r2,sp + mov r0,sp + bl P256_mulmod + + ; S2 = Y2*t1 + ldr r1,[sp,#32] + adds r1,#32 + mov r2,sp + mov r0,r1 + bl P256_mulmod + + ; Z2Z2 = Z2^2 + sub sp,#32 + frame address sp,92 + mov r0,sp + ldr r1,[sp,#64] + adds r1,#64 + bl P256_sqrmod + + ; U1 = X1*Z2Z2 + ldr r1,[sp,#68] + mov r2,sp + add r0,sp,#32 + bl P256_mulmod + + ; t2 = Z2*Z2Z2 + ldr r1,[sp,#64] + adds r1,#64 + mov r2,sp + mov r0,sp + bl P256_mulmod + + ; S1 = Y1*t2 + ldr r1,[sp,#68] + adds r1,#32 + mov r2,sp + mov r0,sp + bl P256_mulmod + + ; H = U2-U1 + ldr r1,[sp,#64] + add r2,sp,#32 + mov r0,r1 + bl P256_submod + + ; HH = H^2 + ldr r1,[sp,#64] + sub sp,#32 + frame address sp,124 + mov r0,sp + bl P256_sqrmod + + ; Z3 = Z2*H + ldr r2,[sp,#96] + mov r1,r2 + adds r1,#64 + mov r0,r1 + bl P256_mulmod + + ; Z3 = Z1*Z3 + ldr r1,[sp,#100] + adds r1,#64 + ldr r2,[sp,#96] + adds r2,#64 + mov r0,r2 + bl P256_mulmod + + ; HHH = H*HH + ldr r1,[sp,#96] + mov r2,sp + mov r0,r1 + bl P256_mulmod + + ; r = S2-S1 + ldr r1,[sp,#96] + adds r1,#32 + add r2,sp,#32 + mov r0,r1 + bl P256_submod + + ; V = U1*HH + add r1,sp,#64 + mov r2,sp + mov r0,r1 + bl P256_mulmod + + ; t3 = r^2 + ldr r1,[sp,#96] + adds r1,#32 + mov r0,sp + bl P256_sqrmod + + ; t2 = S1*HHH + add r1,sp,#32 + ldr r2,[sp,#96] + add r0,sp,#32 + bl P256_mulmod + + ; X3 = t3-HHH + mov r1,sp + ldr r2,[sp,#96] + mov r0,r2 + bl P256_submod + + ; t3 = 2*V + add r1,sp,#64 + add r2,sp,#64 + mov r0,sp + bl P256_addmod + + ; X3 = X3-t3 + ldr r1,[sp,#96] + mov r2,sp + mov r0,r1 + bl P256_submod + + ; t3 = V-X3 + add r1,sp,#64 + ldr r2,[sp,#96] + mov r0,sp + bl P256_submod + + ; t3 = r*t3 + ldr r1,[sp,#96] + adds r1,#32 + mov r2,sp + mov r0,sp + bl P256_mulmod + + ; Y3 = t3-t2 + mov r1,sp + add r2,sp,#32 + ldr r0,[sp,#96] + adds r0,#32 + bl P256_submod + + add sp,#104 + frame address sp,20 + + pop {r4-r7,pc} + endif + endp + + if use_interpreter == 1 + align 4 +P256_add_j_prog + dcw 0x2080 + dcw 0x1330 + dcw 0x1080 + dcw 0x1440 + dcw 0x2150 + dcw 0x1061 + dcw 0x1151 + dcw 0x1171 + dcw 0x4330 + dcw 0x2230 + dcw 0x1553 + dcw 0x1585 + dcw 0x1332 + dcw 0x4441 + dcw 0x1002 + dcw 0x2240 + dcw 0x1113 + dcw 0x4323 + dcw 0x3200 + dcw 0x4332 + dcw 0x4203 + dcw 0x1242 + dcw 0x4421 + dcw 0x0000 + + align 4 +P256_double_j_prog + dcw 0x2080 + dcw 0x1578 + dcw 0x3160 + dcw 0x4060 + dcw 0x1001 + dcw 0x5100 + dcw 0x3001 + dcw 0x2100 + dcw 0x2470 + dcw 0x2240 + dcw 0x1464 + dcw 0x3344 + dcw 0x4313 + dcw 0x4143 + dcw 0x1001 + dcw 0x4402 + dcw 0x0000 + +; in: *r0 = output, *r1 = input +P256_div2mod proc + mov r9,r0 + mov r7,r1 + ldm r7!,{r0-r3} + lsls r6,r0,#31 + asrs r5,r6,#31 + lsrs r6,#31 + movs r4,#0 + adds r0,r5 + adcs r1,r5 + adcs r2,r5 + adcs r3,r4 + push {r0-r3} + frame address sp,76 + ldm r7!,{r0-r3} + adcs r0,r4 + adcs r1,r4 + adcs r2,r6 + adcs r3,r5 + movs r4,#0 + adcs r4,r4 + lsls r7,r4,#31 + lsrs r6,r3,#1 + orrs r7,r6 + lsls r6,r3,#31 + lsrs r5,r2,#1 + orrs r6,r5 + lsls r5,r2,#31 + lsrs r4,r1,#1 + orrs r5,r4 + lsls r4,r1,#31 + lsrs r3,r0,#1 + orrs r4,r3 + lsls r3,r0,#31 + mov r0,r9 + adds r0,#16 + stm r0!,{r4-r7} + mov r7,r3 + pop {r0-r3} + lsrs r6,r3,#1 + orrs r7,r6 + lsls r6,r3,#31 + lsrs r5,r2,#1 + orrs r6,r5 + lsls r5,r2,#31 + lsrs r4,r1,#1 + orrs r5,r4 + lsls r4,r1,#31 + lsrs r3,r0,#1 + orrs r4,r3 + mov r0,r9 + stm r0!,{r4-r7} + bx lr + endp + +; in: *r0 = op1, *r1 = op2, *r2 = program +; program is an array of 16-bit integers, ending with 0x0000 +; in an opcode, bit 12-15 is function to execute (exit, mul, sqr, add, sub, div2), +; bit 8-11 is dest, bit 4-7 is first operand, bit 0-3 is second operand +; the operand is encoded like this: +; operand 0-2 is temporary variable 0-2 +; operand 3-5 is op1[0], op1[1], op1[2] +; operand 6-8 is op2[0], op2[1], op2[2] +; each variable is 32 bytes +; for a function taking less than two parameters, the extra parameters are ignored +P256_interpreter proc + push {r4-r7,lr} + frame push {r4-r7,lr} + + sub sp,#96 + frame address sp,116 + + movs r3,#32 + mov r4,r1 + adds r5,r1,r3 + adds r6,r5,r3 + push {r4-r6} + frame address sp,128 + mov r4,r0 + adds r5,r0,r3 + adds r6,r5,r3 + push {r4-r6} + frame address sp,140 + add r4,sp,#24 + adds r5,r4,r3 + adds r6,r5,r3 + push {r4-r6} + frame address sp,152 + +0 + movs r4,#0x3c + mov r5,sp + ldrh r3,[r2] + adds r2,#2 + push {r2} + frame address sp,156 + lsls r2,r3,#2 + ands r2,r4 + ldr r2,[r5,r2] + lsrs r1,r3,#2 + ands r1,r4 + ldr r1,[r5,r1] + lsrs r0,r3,#6 + ands r0,r4 + ldr r0,[r5,r0] + adr r5,P256_functions-4 + lsrs r6,r3,#10 + ands r6,r4 + beq %f1 + ldr r6,[r5,r6] + blx r6 + pop {r2} + frame address sp,152 + b %b0 +1 + frame address sp,156 + add sp,#136 + frame address sp,20 + pop {r4-r7,pc} + endp + + align 4 +P256_functions + dcd P256_mulmod ;1 + dcd P256_sqrmod ;2 + dcd P256_addmod ;3 + dcd P256_submod ;4 + dcd P256_div2mod ;5 + + endif + + if use_smaller_modinv == 1 +; in/out: r0-r7 +P256_modinv proc + push {r0-r7,lr} + frame push {r4-r7,lr} + frame address sp,36 + sub sp,#36 + frame address sp,72 + mov r0,sp + bl P256_load_1 + mov r1,r0 + bl P256_to_montgomery + adr r0,P256_p + ldm r0,{r0-r7} + subs r0,#2 + push {r0-r7} + frame address sp,104 + + movs r0,#255 +0 + str r0,[sp,#64] + add r0,sp,#32 + add r1,sp,#32 + bl P256_sqrmod + ldr r0,[sp,#64] + lsrs r1,r0,#3 + add r1,r1,sp + ldrb r1,[r1] + movs r2,#7 + ands r2,r2,r0 + lsrs r1,r2 + movs r2,#1 + tst r1,r2 + beq %f1 + add r0,sp,#32 + add r1,sp,#32 + add r2,sp,#68 + bl P256_mulmod +1 + ldr r0,[sp,#64] + subs r0,#1 + bpl %b0 + + add sp,#32 + frame address sp,72 + pop {r0-r7} + frame address sp,40 + add sp,#36 + frame address sp,4 + pop {pc} + endp + + else + +; in: *r0 = input/output, r1 = count, *r2 = operand for final multiplication +P256_sqrmod_many_and_mulmod proc + push {r0,r2,lr} + frame push {lr} + frame address sp,12 + cmp r1,#0 + beq %f1 +0 + push {r1} + frame address sp,16 + ldr r0,[sp,#4] + mov r1,r0 + bl P256_sqrmod + pop {r1} + frame address sp,12 + subs r1,#1 + bne %b0 +1 + pop {r0,r1} + frame address sp,4 + mov r2,r0 + bl P256_mulmod + pop {pc} + endp + + +; in: *r0 = value in/out +; for modinv, call input a, then if a = A * R % p, then it calculates A^-1 * R % p = (a/R)^-1 * R % p = R^2 / a % p +P256_modinv proc + push {r0,lr} + frame push {lr} + frame address sp,8 + + ldm r0,{r0-r7} + push {r0-r7} + frame address sp,40 + + ; t = a^2*a + ldr r0,[sp,#32] + movs r1,#1 + mov r2,sp + bl P256_sqrmod_many_and_mulmod + ldr r0,[sp,#32] + ldm r0,{r0-r7} + push {r0-r7} + frame address sp,72 + + ; a4_2 = a2_0^(2^2) + + ldr r0,[sp,#64] + mov r1,r0 + bl P256_sqrmod + ldr r0,[sp,#64] + mov r1,r0 + bl P256_sqrmod + ldr r0,[sp,#64] + ldm r0,{r0-r7} + push {r0-r7} + frame address sp,104 + + ; a4_0 = a4_2*a2_0 + ldr r0,[sp,#96] + mov r1,sp + add r2,sp,#32 + bl P256_mulmod + add r0,sp,#32 + ldr r1,[sp,#96] + bl P256_copy32 + + ldr r7,[sp,#96] + movs r4,#0 +0 + adr r2,P256_invtbl + ldrsb r0,[r2,r4] + adds r2,#1 + ldrb r5,[r2,r4] + lsls r6,r0,#2 + bpl %f1 + sub sp,#32 + frame address sp,200 ; not always correct + mov r0,sp + mov r1,r7 + bl P256_copy32 +1 + mov r0,r7 + uxtb r1,r6 + mov r2,r5 + add r2,sp + push {r4,r7} + frame address sp,208 ; not always correct + bl P256_sqrmod_many_and_mulmod + pop {r4,r7} + frame address sp,200 ; not always correct + adds r4,#2 + cmp r4,#22 + bne %b0 + + add sp,#6*32+4 + frame address sp,4 + + pop {pc} + + endp + + align 4 +P256_invtbl + dcb ((8-4)>>2) + dcb 32 + + dcb ((16-8)>>2)+128 + dcb 0 + + dcb (16>>2)+128 + dcb 0 + + dcb (32>>2)+128 + dcb 5*32 + + dcb (192-64)>>2 + dcb 0 + + dcb (224-192)>>2 + dcb 0 + + dcb (240-224)>>2 + dcb 32 + + dcb (248-240)>>2 + dcb 64 + + dcb (252-248)>>2 + dcb 128 + + dcb (256-252)>>2 + dcb 96 + + dcb 0 + dcb 5*32 + + endif + + +; *r0 = output affine montgomery/input jacobian montgomery +P256_jacobian_to_affine proc + push {r0,r4-r7,lr} + frame push {r4-r7,lr} + frame address sp,24 + + adds r0,#64 + ldm r0,{r0-r7} + if use_smaller_modinv == 0 + push {r0-r7} + frame address sp,56 + mov r0,sp + bl P256_modinv + else + bl P256_modinv + push {r0-r7} + frame address sp,56 + endif + + mov r1,sp + sub sp,#32 + frame address sp,88 + mov r0,sp + bl P256_sqrmod + + add r1,sp,#32 + mov r2,sp + mov r0,r1 + bl P256_mulmod + + mov r1,sp + ldr r0,[sp,#64] + mov r2,r0 + bl P256_mulmod + + add r1,sp,#32 + ldr r0,[sp,#64] + adds r0,#32 + mov r2,r0 + bl P256_mulmod + + add sp,#68 + frame address sp,20 + + pop {r4-r7,pc} + endp + +; performs r0 := abs(r0) +P256_abs_int proc + rsbs r2,r0,#0 + asrs r3,r0,#31 + ands r3,r2 + asrs r2,#31 + ands r0,r2 + orrs r0,r0,r3 + bx lr + endp + +; in: *r0 = output, *r1 = point, *r2 = scalar, r3 = include y in result (1/0) +; out: r0 = 1 on success, 0 if invalid point or scalar +P256_pointmult proc + export P256_pointmult + push {r4-r7,lr} + frame push {r4-r7,lr} + mov r4,r8 + mov r5,r9 + mov r6,r10 + mov r7,r11 + push {r0-r1,r4-r7} + frame address sp,44 + frame save {r8-r11},-36 + sub sp,#256 + frame address sp,300 + + lsls r6,r3,#16 + + ; load scalar into an aligned position + add r0,sp,#32 + mov r1,r2 + bl P256_copy32_unaligned + + ; fail if scalar == 0 + mov r0,sp + bl P256_load_1 + add r0,sp,#32 + mov r1,sp + bl P256_greater_or_equal_than + bne %f1 +0 + add sp,#256+8 + frame address sp,36 + b %f10 + frame address sp,300 +1 + ; fail if not (scalar < n) + add r0,sp,#32 + adr r1,P256_order + bl P256_greater_or_equal_than + subs r0,#1 + beq %b0 + + ; select scalar if scalar is odd and -scalar mod n if scalar is even + mov r0,sp + add r1,sp,#32 + ldr r2,[r1] + movs r3,#1 + ands r2,r3 + eors r2,r3 + add r6,r2 ; save original parity of scalar + adr r3,P256_order + bl P256_negate_mod_m_if + + ; stack layout (initially offset 768): + ; 0-767: table of jacobian points P, 3P, 5P, ..., 15P + ; 768-863: current point (in jacobian form) + ; 864-927: scalar rewritten into 4-bit window, each element having an odd signed value + ; 928-1023: extracted selected point from the table + ; 1024-1027: output pointer + ; 1028-1031: input point + + ; rewrite scalar into 4-bit window where every value is odd + add r1,sp,#864-768 + ldr r0,[sp] + lsls r0,#28 + lsrs r0,#28 + movs r2,#1 + mov r4,sp + movs r5,#1 +2 + lsrs r3,r2,#1 + ldrb r3,[r4,r3] + lsls r7,r2,#31 + lsrs r7,#29 + lsrs r3,r7 + lsls r3,#28 + lsrs r3,#28 + movs r7,#1 + ands r7,r3 + eors r7,r5 + lsls r7,#4 + subs r0,r7 + strb r0,[r1] + adds r1,#1 + orrs r3,r5 + mov r0,r3 + adds r2,#1 + cmp r2,#64 + bne %b2 + strb r0,[r1] + + ; load point into an aligned position + ldr r1,[sp,#1028-768] + sub sp,#384 + frame address sp,684 + sub sp,#384 + frame address sp,1068 + mov r0,sp + bl P256_copy32_unaligned + bl P256_copy32_unaligned + + ; fail if not x, y < p + mov r0,sp + adr r1,P256_p + bl P256_greater_or_equal_than + subs r0,#1 + bne %f4 +3 + add sp,#384 + frame address sp,684 + add sp,#384 + frame address sp,300 + b %b0 + frame address sp,1068 +4 + add r0,sp,#32 + adr r1,P256_p + bl P256_greater_or_equal_than + subs r0,#1 + beq %b3 + + ; convert basepoint x, y to montgomery form, + ; and place result as first element in table of Jacobian points + + mov r0,sp + mov r1,sp + bl P256_to_montgomery + add r0,sp,#32 + add r1,sp,#32 + bl P256_to_montgomery + + ; check that the basepoint lies on the curve + mov r0,sp + bl P256_point_is_on_curve + cmp r0,#0 + beq %b3 + + ; load montgomery 1 for Z + add r0,sp,#64 + bl P256_load_1 + mov r1,r0 + bl P256_to_montgomery + + ; temporarily calculate 2P + add r0,sp,#7*96 + mov r1,sp + bl P256_double_j + + ; calculate rest of the table (3P, 5P, ..., 15P) + add r4,sp,#96 + movs r5,#7 +5 + mov r0,r4 + add r1,sp,#7*96 + bl P256_copy32 + bl P256_copy32 + bl P256_copy32 + mov r0,r4 + mov r1,r0 + subs r1,#96 + bl P256_add_j + adds r4,#96 + subs r5,#1 + bne %b5 + + ; select the initial current point based on the first highest 4 scalar bits + add r7,sp,#928 + subs r7,#1 + ldrb r0,[r7] + subs r7,#1 + sxtb r0,r0 + bl P256_abs_int + lsrs r2,r0,#1 + add r0,sp,#768 + mov r1,sp + bl P256_select + + ; main loop iterating from index 62 to 0 of the windowed scalar + add r5,sp,#864 +6 + movs r4,#4 +7 + add r0,sp,#768 + mov r1,r0 + bl P256_double_j + subs r4,#1 + bne %b7 + + ; select the point to add, and then add to the current point + ldrb r0,[r7] + subs r7,#1 + sxtb r0,r0 + lsrs r4,r0,#31 + bl P256_abs_int + lsrs r2,r0,#1 + add r0,sp,#928 + mov r1,sp + bl P256_select + add r0,sp,#960 + mov r1,r0 + mov r2,r4 + adr r3,P256_p + bl P256_negate_mod_m_if + cmp r7,r5 + bge %f8 + ; see note below + add r0,sp,#672 + add r1,sp,#768 + bl P256_double_j +8 + add r0,sp,#768 + add r1,sp,#928 + bl P256_add_j + cmp r7,r5 + bge %b6 + + ; Note: ONLY for the scalars 2 and -2 mod n, the last addition will + ; be an addition where both input values are equal. The addition algorithm + ; fails for such a case (returns Z=0) and we must therefore use the doubling + ; formula. Both values are computed and then the correct value is selected + ; in constant time based on whether the addition formula returned Z=0. + ; Obviously if the scalar (private key) is properly randomized, this would + ; (with extremely high probability), never occur. + mov r0,sp + bl P256_load_1 + add r0,sp,#768+64 + mov r1,sp + bl P256_greater_or_equal_than + adds r2,r0,#6 + add r0,sp,#928 + add r1,sp,#96 + bl P256_select + + add sp,#464 ;928/2 + frame address sp,604 + add sp,#464 + frame address sp,140 + + mov r0,sp + bl P256_jacobian_to_affine + + mov r0,sp + mov r1,sp + bl P256_from_montgomery + add r0,sp,#32 + add r1,sp,#32 + bl P256_from_montgomery + + add r0,sp,#32 + add r1,sp,#32 + uxtb r2,r6 + adr r3,P256_p + bl P256_negate_mod_m_if + + ldr r0,[sp,#96] + mov r1,sp + bl P256_copy32_unaligned + lsrs r6,#16 + beq %f9 + bl P256_copy32_unaligned +9 + + movs r0,#1 + add sp,#96+8 + frame address sp,36 +10 + pop {r4-r7} + frame address sp,20 + mov r8,r4 + mov r9,r5 + mov r10,r6 + mov r11,r7 + pop {r4-r7,pc} + endp + +; in: *r0 = output, *r1 = private key scalar +; out: r0 = 1 on success, 0 if scalar is out of range +P256_ecdh_keygen proc + export P256_ecdh_keygen + mov r2,r1 + adr r1,P256_basepoint + movs r3,#1 + b P256_pointmult + endp + +; in: *r0 = output, *r1 = other's public point, *r2 = private key scalar +; out: r0 = 1 on success, 0 if invalid public point or private key scalar +P256_ecdh_shared_secret proc + export P256_ecdh_shared_secret + movs r3,#0 + b P256_pointmult + endp + + align 4 +P256_p + dcd 0xffffffff + dcd 0xffffffff + dcd 0xffffffff + dcd 0 + dcd 0 + dcd 0 + dcd 1 + dcd 0xffffffff + +P256_order + dcd 0xFC632551 + dcd 0xF3B9CAC2 + dcd 0xA7179E84 + dcd 0xBCE6FAAD + dcd 0xFFFFFFFF + dcd 0xFFFFFFFF + dcd 0 + dcd 0xFFFFFFFF + +P256_basepoint + dcd 0xD898C296 + dcd 0xF4A13945 + dcd 0x2DEB33A0 + dcd 0x77037D81 + dcd 0x63A440F2 + dcd 0xF8BCE6E5 + dcd 0xE12C4247 + dcd 0x6B17D1F2 + dcd 0x37BF51F5 + dcd 0xCBB64068 + dcd 0x6B315ECE + dcd 0x2BCE3357 + dcd 0x7C0F9E16 + dcd 0x8EE7EB4A + dcd 0xFE1A7F9B + dcd 0x4FE342E2 + + end diff --git a/src/components/libraries/tinycrypt-0.2.8/.gitignore b/src/components/libraries/tinycrypt-0.2.8/.gitignore new file mode 100644 index 0000000..c960ccc --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/.gitignore @@ -0,0 +1,5 @@ +*.o +*~ +*.d +*.exe +*.a diff --git a/src/components/libraries/tinycrypt-0.2.8/AUTHORS b/src/components/libraries/tinycrypt-0.2.8/AUTHORS new file mode 100644 index 0000000..0a8e9f8 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/AUTHORS @@ -0,0 +1,15 @@ +Architect: +Rafael Misoczki + +Open Source Maintainer: +Constanza Heath +Rafael Misoczki + +Contributors: +Constanza Heath +Rafael Misoczki +Flavio Santes +Jarkko Sakkinen +Chris Morrison +Marti Bolivar +Colin Ian King diff --git a/src/components/libraries/tinycrypt-0.2.8/LICENSE b/src/components/libraries/tinycrypt-0.2.8/LICENSE new file mode 100644 index 0000000..2e1db51 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/LICENSE @@ -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. + +================================================================================ diff --git a/src/components/libraries/tinycrypt-0.2.8/Makefile b/src/components/libraries/tinycrypt-0.2.8/Makefile new file mode 100644 index 0000000..3c0e42b --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/Makefile @@ -0,0 +1,21 @@ +################################################################################ +# +# Copyright (C) 2017 by Intel Corporation, All Rights Reserved. +# +# Global Makefile. +# See lib/Makefile and tests/Makefile for further configuration. +# +################################################################################ +include config.mk + +all: + $(MAKE) -C lib +ifeq ($(ENABLE_TESTS),true) + $(MAKE) -C tests +endif + +clean: + $(MAKE) -C lib clean + $(MAKE) -C tests clean + $(RM) *~ + diff --git a/src/components/libraries/tinycrypt-0.2.8/README b/src/components/libraries/tinycrypt-0.2.8/README new file mode 100644 index 0000000..fb52c19 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/README @@ -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/ + +================================================================================ + diff --git a/src/components/libraries/tinycrypt-0.2.8/VERSION b/src/components/libraries/tinycrypt-0.2.8/VERSION new file mode 100644 index 0000000..a45be46 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/VERSION @@ -0,0 +1 @@ +0.2.8 diff --git a/src/components/libraries/tinycrypt-0.2.8/config.mk b/src/components/libraries/tinycrypt-0.2.8/config.mk new file mode 100644 index 0000000..a5b9fb7 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/config.mk @@ -0,0 +1,35 @@ +################################################################################ +# +# Copyright (C) 2017 by Intel Corporation, All Rights Reserved. +# +# Global configuration Makefile. Included everywhere. +# +################################################################################ + +# EDIT HERE: +CC:=gcc +CFLAGS:=-Os -std=c99 -Wall -Wextra -D_ISOC99_SOURCE -MMD -I../lib/include/ -I../lib/source/ -I../tests/include/ +vpath %.c ../lib/source/ +ENABLE_TESTS=true + +# override MinGW built-in recipe +%.o: %.c + $(COMPILE.c) $(OUTPUT_OPTION) $< + +ifeq ($(OS),Windows_NT) +DOTEXE:=.exe +endif + +# DO NOT EDIT AFTER THIS POINT: +ifeq ($(ENABLE_TESTS), true) +CFLAGS += -DENABLE_TESTS +else +CFLAGS += -DDISABLE_TESTS +endif + +export CC +export CFLAGS +export VPATH +export ENABLE_TESTS + +################################################################################ diff --git a/src/components/libraries/tinycrypt-0.2.8/documentation/tinycrypt.rst b/src/components/libraries/tinycrypt-0.2.8/documentation/tinycrypt.rst new file mode 100644 index 0000000..356c099 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/documentation/tinycrypt.rst @@ -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 diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/Makefile b/src/components/libraries/tinycrypt-0.2.8/lib/Makefile new file mode 100644 index 0000000..9c4d8e2 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/Makefile @@ -0,0 +1,39 @@ +################################################################################ +# +# Copyright (C) 2017 by Intel Corporation, All Rights Reserved. +# +# Cryptographic Primitives Makefile. +# +################################################################################ + +include ../config.mk + +# Edit the OBJS content to add/remove primitives needed from TinyCrypt library: +OBJS:=aes_decrypt.o \ + aes_encrypt.o \ + cbc_mode.o \ + ctr_mode.o \ + ctr_prng.o \ + hmac.o \ + hmac_prng.o \ + sha256.o \ + ecc.o \ + ecc_dh.o \ + ecc_dsa.o \ + ccm_mode.o \ + cmac_mode.o \ + utils.o + +DEPS:=$(OBJS:.o=.d) + +all: libtinycrypt.a + +libtinycrypt.a: $(OBJS) + $(AR) $(ARFLAGS) $@ $^ + +.PHONY: clean + +clean: + -$(RM) *.exe $(OBJS) $(DEPS) *~ libtinycrypt.a + +-include $(DEPS) diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/aes.h b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/aes.h new file mode 100644 index 0000000..24c95b3 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/aes.h @@ -0,0 +1,131 @@ +/* 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 + +#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__ */ diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/cbc_mode.h b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/cbc_mode.h new file mode 100644 index 0000000..3449c71 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/cbc_mode.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 + +#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__ */ diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ccm_mode.h b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ccm_mode.h new file mode 100644 index 0000000..3709e2c --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ccm_mode.h @@ -0,0 +1,212 @@ +/* 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 +#include + +#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__ */ diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/cmac_mode.h b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/cmac_mode.h new file mode 100644 index 0000000..7c07661 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/cmac_mode.h @@ -0,0 +1,195 @@ +/* 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 + +#include + +#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__ */ diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/constants.h b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/constants.h new file mode 100644 index 0000000..6cf2567 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/constants.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 + +#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__ */ diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ctr_mode.h b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ctr_mode.h new file mode 100644 index 0000000..a39370a --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ctr_mode.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 +#include + +#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__ */ diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ctr_prng.h b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ctr_prng.h new file mode 100644 index 0000000..34725cc --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ctr_prng.h @@ -0,0 +1,167 @@ +/* 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 + +#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__ */ diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ecc.h b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ecc.h new file mode 100644 index 0000000..61e89da --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ecc.h @@ -0,0 +1,547 @@ +/* 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 + +#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__ */ diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ecc_dh.h b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ecc_dh.h new file mode 100644 index 0000000..2e4bd80 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ecc_dh.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 + +#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__ */ diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ecc_dsa.h b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ecc_dsa.h new file mode 100644 index 0000000..57e5cfc --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ecc_dsa.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 + +#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__ */ diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ecc_platform_specific.h b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ecc_platform_specific.h new file mode 100644 index 0000000..fbc0bd4 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/ecc_platform_specific.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_ */ diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/hmac.h b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/hmac.h new file mode 100644 index 0000000..80933d1 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/hmac.h @@ -0,0 +1,140 @@ +/* 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 + +#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 init 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 init +*/ +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__*/ diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/hmac_prng.h b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/hmac_prng.h new file mode 100644 index 0000000..d702667 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/hmac_prng.h @@ -0,0 +1,165 @@ +/* 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 +#include + +#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 + init) + @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__ */ diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/sha256.h b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/sha256.h new file mode 100644 index 0000000..7bde435 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/sha256.h @@ -0,0 +1,130 @@ +/* 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 +#include + +#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__ */ diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/utils.h b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/utils.h new file mode 100644 index 0000000..f054ca8 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/include/tinycrypt/utils.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 +#include + +#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__ */ diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/source/aes_decrypt.c b/src/components/libraries/tinycrypt-0.2.8/lib/source/aes_decrypt.c new file mode 100644 index 0000000..f519e23 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/source/aes_decrypt.c @@ -0,0 +1,185 @@ +/* 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 +#include + +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; +} diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/source/aes_encrypt.c b/src/components/libraries/tinycrypt-0.2.8/lib/source/aes_encrypt.c new file mode 100644 index 0000000..f42c05e --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/source/aes_encrypt.c @@ -0,0 +1,223 @@ +/* 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 +#include + +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; +} diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/source/cbc_mode.c b/src/components/libraries/tinycrypt-0.2.8/lib/source/cbc_mode.c new file mode 100644 index 0000000..6cef3b4 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/source/cbc_mode.c @@ -0,0 +1,121 @@ +/* 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 +#include + +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; +} diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/source/ccm_mode.c b/src/components/libraries/tinycrypt-0.2.8/lib/source/ccm_mode.c new file mode 100644 index 0000000..041590a --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/source/ccm_mode.c @@ -0,0 +1,290 @@ +/* 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 +#include + +#include + +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; + } +} diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/source/cmac_mode.c b/src/components/libraries/tinycrypt-0.2.8/lib/source/cmac_mode.c new file mode 100644 index 0000000..1433524 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/source/cmac_mode.c @@ -0,0 +1,268 @@ +/* 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 +#include +#include + +/* 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; +} diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/source/ctr_mode.c b/src/components/libraries/tinycrypt-0.2.8/lib/source/ctr_mode.c new file mode 100644 index 0000000..1f3487a --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/source/ctr_mode.c @@ -0,0 +1,92 @@ +/* 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 +#include + +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; +} diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/source/ctr_prng.c b/src/components/libraries/tinycrypt-0.2.8/lib/source/ctr_prng.c new file mode 100644 index 0000000..7c05eb0 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/source/ctr_prng.c @@ -0,0 +1,305 @@ +/* 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 +#include +#include + +/* + 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; + } +} + + + + diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/source/ecc.c b/src/components/libraries/tinycrypt-0.2.8/lib/source/ecc.c new file mode 100644 index 0000000..9d95b03 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/source/ecc.c @@ -0,0 +1,993 @@ +/* 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 +#include + +/* 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; +} + + + diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/source/ecc_dh.c b/src/components/libraries/tinycrypt-0.2.8/lib/source/ecc_dh.c new file mode 100644 index 0000000..0cf143f --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/source/ecc_dh.c @@ -0,0 +1,194 @@ +/* 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 +#include +#include + +#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; +} diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/source/ecc_dsa.c b/src/components/libraries/tinycrypt-0.2.8/lib/source/ecc_dsa.c new file mode 100644 index 0000000..ec9047e --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/source/ecc_dsa.c @@ -0,0 +1,307 @@ +/* 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 +#include + +#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); +} + diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/source/ecc_platform_specific.c b/src/components/libraries/tinycrypt-0.2.8/lib/source/ecc_platform_specific.c new file mode 100644 index 0000000..545455d --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/source/ecc_platform_specific.c @@ -0,0 +1,114 @@ +/* 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 +#include +#include + +#include + +#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 */ + diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/source/hmac.c b/src/components/libraries/tinycrypt-0.2.8/lib/source/hmac.c new file mode 100644 index 0000000..de47cfe --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/source/hmac.c @@ -0,0 +1,149 @@ +/* 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 +#include + +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; +} diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/source/hmac_prng.c b/src/components/libraries/tinycrypt-0.2.8/lib/source/hmac_prng.c new file mode 100644 index 0000000..323aaad --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/source/hmac_prng.c @@ -0,0 +1,211 @@ +/* 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 +#include +#include + +/* + 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; +} diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/source/sha256.c b/src/components/libraries/tinycrypt-0.2.8/lib/source/sha256.c new file mode 100644 index 0000000..c0e5b1f --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/source/sha256.c @@ -0,0 +1,248 @@ +/* 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 +#include + +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; +} diff --git a/src/components/libraries/tinycrypt-0.2.8/lib/source/utils.c b/src/components/libraries/tinycrypt-0.2.8/lib/source/utils.c new file mode 100644 index 0000000..3032fbf --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/lib/source/utils.c @@ -0,0 +1,79 @@ +/* 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 + +#include + +#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; +} diff --git a/src/components/libraries/tinycrypt-0.2.8/tests/Makefile b/src/components/libraries/tinycrypt-0.2.8/tests/Makefile new file mode 100644 index 0000000..eff5a88 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/tests/Makefile @@ -0,0 +1,67 @@ +################################################################################ +# +# Copyright (C) 2017 by Intel Corporation, All Rights Reserved. +# +# Tests Makefile. +# +################################################################################ + +include ../config.mk + +TEST_LIB_FILE:=test_ecc_utils.c +TEST_SOURCE:=$(filter-out $(TEST_LIB_FILE), $(wildcard test_*.c)) + +TEST_OBJECTS:=$(TEST_SOURCE:.c=.o) +TEST_DEPS:=$(TEST_SOURCE:.c=.d) +TEST_BINARY:=$(TEST_SOURCE:.c=$(DOTEXE)) + +# Edit the 'all' content to add/remove tests needed from TinyCrypt library: +all: $(TEST_BINARY) + +clean: + -$(RM) $(TEST_BINARY) $(TEST_OBJECTS) $(TEST_DEPS) + -$(RM) *~ *.o *.d + +# Dependencies +test_aes$(DOTEXE): test_aes.o aes_encrypt.o aes_decrypt.o utils.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +test_cbc_mode$(DOTEXE): test_cbc_mode.o cbc_mode.o \ + aes_encrypt.o aes_decrypt.o utils.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +test_ctr_mode$(DOTEXE): test_ctr_mode.o ctr_mode.o \ + aes_encrypt.o utils.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +test_ctr_prng$(DOTEXE): test_ctr_prng.o ctr_prng.o \ + aes_encrypt.o utils.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +test_cmac_mode$(DOTEXE): test_cmac_mode.o aes_encrypt.o utils.o \ + cmac_mode.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +test_ccm_mode$(DOTEXE): test_ccm_mode.o aes_encrypt.o \ + utils.o ccm_mode.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +test_hmac$(DOTEXE): test_hmac.o hmac.o sha256.o utils.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +test_hmac_prng$(DOTEXE): test_hmac_prng.o hmac_prng.o hmac.o \ + sha256.o utils.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +test_sha256$(DOTEXE): test_sha256.o sha256.o utils.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +test_ecc_dh$(DOTEXE): test_ecc_dh.o ecc.o ecc_dh.o test_ecc_utils.o ecc_platform_specific.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +test_ecc_dsa$(DOTEXE): test_ecc_dsa.o ecc.o utils.o ecc_dh.o \ + ecc_dsa.o sha256.o test_ecc_utils.o ecc_platform_specific.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + + +-include $(TEST_DEPS) diff --git a/src/components/libraries/tinycrypt-0.2.8/tests/include/test_ecc_utils.h b/src/components/libraries/tinycrypt-0.2.8/tests/include/test_ecc_utils.h new file mode 100644 index 0000000..1e363f7 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/tests/include/test_ecc_utils.h @@ -0,0 +1,100 @@ +/* test_ecc_utils.h - TinyCrypt interface to common functions for ECC tests */ + +/* 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. + + test_ecc_utils.h -- Interface to common functions for ECC tests. +*/ + +#ifndef __TEST_ECC_UTILS_H__ +#define __TEST_ECC_UTILS_H__ + +#include +#include +#include + +int hex2int (char hex); + + +/* + Convert hex string to byte string + Return number of bytes written to buf, or 0 on error +*/ +int hex2bin(uint8_t* buf, const size_t buflen, const char* hex, + const size_t hexlen); + +/* + Convert hex string to zero-padded nanoECC scalar +*/ +void string2scalar(unsigned int* scalar, unsigned int num_word32, char* str); + + +void print_ecc_scalar(const char* label, const unsigned int* p_vli, + unsigned int num_word32); + +int check_ecc_result(const int num, const char* name, + const unsigned int* expected, + const unsigned int* computed, + const unsigned int num_word32, const bool verbose); + +/* Test ecc_make_keys, and also as keygen part of other tests */ +int keygen_vectors(char** d_vec, char** qx_vec, char** qy_vec, int tests, bool verbose); + +void vli_print_bytes(uint8_t* vli, unsigned int size); + + +int check_code(const int num, const char* name, const int expected, + const int computed, const int verbose); + + +#endif /* __TEST_ECC_UTILS_H__ */ + diff --git a/src/components/libraries/tinycrypt-0.2.8/tests/include/test_utils.h b/src/components/libraries/tinycrypt-0.2.8/tests/include/test_utils.h new file mode 100644 index 0000000..85762c8 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/tests/include/test_utils.h @@ -0,0 +1,129 @@ +/* test_utils.h - TinyCrypt interface to common functions for tests */ + +/* + 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. + + test_utils.h -- Interface to common functions for tests. +*/ + +#ifndef __TEST_UTILS_H__ +#define __TEST_UTILS_H__ + +#include + +#include +#include +#include +#include + +#define PRINT_DATA(fmt, ...) printf(fmt, ##__VA_ARGS__) + +#define PRINT_LINE \ + PRINT_DATA( \ + "============================================================" \ + "=======\n") + + +#define FAIL "FAIL" +#define PASS "PASS" +#define FMT_ERROR "%s - %s@%d. " + +/* TC_ here stands for 'Test Case' not 'TinyCrypt' */ +#define TC_PASS 0 +#define TC_FAIL 1 + +#define TC_ERROR(fmt, ...) \ + do { \ + PRINT_DATA(FMT_ERROR, FAIL, __func__, __LINE__); \ + PRINT_DATA(fmt, ##__VA_ARGS__); \ + } while (0) + +#define TC_PRINT(fmt, ...) PRINT_DATA(fmt, ##__VA_ARGS__) +#define TC_START(name) PRINT_DATA("tc_start() - %s\n", name) +#define TC_END(result, fmt, ...) PRINT_DATA(fmt, ##__VA_ARGS__) + +/* prints result and the function name */ +#define TC_END_RESULT(result) \ + do { \ + PRINT_LINE; \ + TC_END(result, "%s - %s.\n", \ + result == TC_PASS ? PASS : FAIL, __func__); \ + } while (0) + +#define TC_END_REPORT(result) \ + do { \ + PRINT_LINE; \ + TC_END(result, \ + "PROJECT EXECUTION %s\n", \ + result == TC_PASS ? "SUCCESSFUL" : "FAILED"); \ + } while (0) + +static inline void show_str(const char* label, const uint8_t* s, size_t len) +{ + unsigned int i; + TC_PRINT("%s = ", label); + + for (i = 0; i < (unsigned int) len; ++i) + { + TC_PRINT("%02x", s[i]); + } + + TC_PRINT("\n"); +} + +static inline void fatal(unsigned int testnum, const void* expected, size_t expectedlen, + const void* computed, size_t computedlen) +{ + TC_ERROR("\tTest #%d Failed!\n", testnum); + show_str("\t\tExpected", expected, expectedlen); + show_str("\t\tComputed ", computed, computedlen); + TC_PRINT("\n"); +} + +static inline unsigned int check_result(unsigned int testnum, const void* expected, size_t expectedlen, + const void* computed, size_t computedlen) +{ + unsigned int result = TC_PASS; + + if (expectedlen != computedlen) + { + TC_ERROR("The length of the computed buffer (%zu)", computedlen); + TC_ERROR("does not match the expected length (%zu).", expectedlen); + result = TC_FAIL; + } + else if (memcmp(computed, expected, computedlen) != 0) + { + fatal(testnum, expected, expectedlen, computed, computedlen); + result = TC_FAIL; + } + + return result; +} + +#endif /* __TEST_UTILS_H__ */ diff --git a/src/components/libraries/tinycrypt-0.2.8/tests/test_aes.c b/src/components/libraries/tinycrypt-0.2.8/tests/test_aes.c new file mode 100644 index 0000000..c51af10 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/tests/test_aes.c @@ -0,0 +1,2348 @@ +/* test_aes.c - TinyCrypt AES-128 tests (including NIST tests) */ + +/* + 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. +*/ + +/* + DESCRIPTION + This module tests the following AES routines: + + Scenarios tested include: + - AES128 NIST key schedule test + - AES128 NIST encryption test + - AES128 NIST fixed-key and variable-text + - AES128 NIST variable-key and fixed-text +*/ + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define NUM_OF_NIST_KEYS 16 +#define NUM_OF_FIXED_KEYS 128 + + +struct kat_table +{ + uint8_t in[NUM_OF_NIST_KEYS]; + uint8_t out[NUM_OF_NIST_KEYS]; +}; + +/* + NIST test key schedule. +*/ +int test_1(void) +{ + int result = TC_PASS; + const uint8_t nist_key[NUM_OF_NIST_KEYS] = + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }; + const struct tc_aes_key_sched_struct expected = + { + { + 0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x09cf4f3c, + 0xa0fafe17, 0x88542cb1, 0x23a33939, 0x2a6c7605, + 0xf2c295f2, 0x7a96b943, 0x5935807a, 0x7359f67f, + 0x3d80477d, 0x4716fe3e, 0x1e237e44, 0x6d7a883b, + 0xef44a541, 0xa8525b7f, 0xb671253b, 0xdb0bad00, + 0xd4d1c6f8, 0x7c839d87, 0xcaf2b8bc, 0x11f915bc, + 0x6d88a37a, 0x110b3efd, 0xdbf98641, 0xca0093fd, + 0x4e54f70e, 0x5f5fc9f3, 0x84a64fb2, 0x4ea6dc4f, + 0xead27321, 0xb58dbad2, 0x312bf560, 0x7f8d292f, + 0xac7766f3, 0x19fadc21, 0x28d12941, 0x575c006e, + 0xd014f9a8, 0xc9ee2589, 0xe13f0cc8, 0xb6630ca6 + } + }; + struct tc_aes_key_sched_struct s; + TC_PRINT("AES128 %s (NIST key schedule test):\n", __func__); + + if (tc_aes128_set_encrypt_key(&s, nist_key) == 0) + { + TC_ERROR("AES128 test %s (NIST key schedule test) failed.\n", + __func__); + result = TC_FAIL; + goto exitTest1; + } + + result = check_result(1, expected.words, sizeof(expected.words), s.words, + sizeof(s.words)); +exitTest1: + TC_END_RESULT(result); + return result; +} + +/* + NIST test vectors for encryption. +*/ +int test_2(void) +{ + int result = TC_PASS; + const uint8_t nist_key[NUM_OF_NIST_KEYS] = + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }; + const uint8_t nist_input[NUM_OF_NIST_KEYS] = + { + 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, + 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34 + }; + const uint8_t expected[NUM_OF_NIST_KEYS] = + { + 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, + 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32 + }; + struct tc_aes_key_sched_struct s; + uint8_t ciphertext[NUM_OF_NIST_KEYS]; + TC_PRINT("AES128 %s (NIST encryption test):\n", __func__); + (void)tc_aes128_set_encrypt_key(&s, nist_key); + + if (tc_aes_encrypt(ciphertext, nist_input, &s) == 0) + { + TC_ERROR("AES128 %s (NIST encryption test) failed.\n", + __func__); + result = TC_FAIL; + goto exitTest2; + } + + result = check_result(2, expected, sizeof(expected), ciphertext, + sizeof(ciphertext)); +exitTest2: + TC_END_RESULT(result); + return result; +} + +int var_text_test(unsigned int r, const uint8_t* in, const uint8_t* out, + TCAesKeySched_t s) +{ + uint8_t ciphertext[NUM_OF_NIST_KEYS]; + uint8_t decrypted[NUM_OF_NIST_KEYS]; + int result = TC_PASS; + (void)tc_aes_encrypt(ciphertext, in, s); + result = check_result(r, out, NUM_OF_NIST_KEYS, ciphertext, + sizeof(ciphertext)); + + if (result != TC_FAIL) + { + if (tc_aes_decrypt(decrypted, ciphertext, s) == 0) + { + TC_ERROR("aes_decrypt failed\n"); + result = TC_FAIL; + } + else + { + result = check_result(r, in, NUM_OF_NIST_KEYS, + decrypted, sizeof(decrypted)); + } + } + + return result; +} + +/* + All NIST tests with fixed key and variable text. +*/ +int test_3(void) +{ + int result = TC_PASS; + const uint8_t key[NUM_OF_NIST_KEYS] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const struct kat_table kat_tbl[NUM_OF_FIXED_KEYS] = + { + {{ + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x3a, 0xd7, 0x8e, 0x72, 0x6c, 0x1e, 0xc0, 0x2b, + 0x7e, 0xbf, 0xe9, 0x2b, 0x23, 0xd9, 0xec, 0x34 + } + }, + {{ + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xaa, 0xe5, 0x93, 0x9c, 0x8e, 0xfd, 0xf2, 0xf0, + 0x4e, 0x60, 0xb9, 0xfe, 0x71, 0x17, 0xb2, 0xc2 + } + }, + {{ + 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xf0, 0x31, 0xd4, 0xd7, 0x4f, 0x5d, 0xcb, 0xf3, + 0x9d, 0xaa, 0xf8, 0xca, 0x3a, 0xf6, 0xe5, 0x27 + } + }, + {{ + 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x96, 0xd9, 0xfd, 0x5c, 0xc4, 0xf0, 0x74, 0x41, + 0x72, 0x7d, 0xf0, 0xf3, 0x3e, 0x40, 0x1a, 0x36 + } + }, + {{ + 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x30, 0xcc, 0xdb, 0x04, 0x46, 0x46, 0xd7, 0xe1, + 0xf3, 0xcc, 0xea, 0x3d, 0xca, 0x08, 0xb8, 0xc0 + } + }, + {{ + 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x16, 0xae, 0x4c, 0xe5, 0x04, 0x2a, 0x67, 0xee, + 0x8e, 0x17, 0x7b, 0x7c, 0x58, 0x7e, 0xcc, 0x82 + } + }, + {{ + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xb6, 0xda, 0x0b, 0xb1, 0x1a, 0x23, 0x85, 0x5d, + 0x9c, 0x5c, 0xb1, 0xb4, 0xc6, 0x41, 0x2e, 0x0a + } + }, + {{ + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xdb, 0x4f, 0x1a, 0xa5, 0x30, 0x96, 0x7d, 0x67, + 0x32, 0xce, 0x47, 0x15, 0xeb, 0x0e, 0xe2, 0x4b + } + }, + {{ + 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xa8, 0x17, 0x38, 0x25, 0x26, 0x21, 0xdd, 0x18, + 0x0a, 0x34, 0xf3, 0x45, 0x5b, 0x4b, 0xaa, 0x2f + } + }, + {{ + 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x77, 0xe2, 0xb5, 0x08, 0xdb, 0x7f, 0xd8, 0x92, + 0x34, 0xca, 0xf7, 0x93, 0x9e, 0xe5, 0x62, 0x1a + } + }, + {{ + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xb8, 0x49, 0x9c, 0x25, 0x1f, 0x84, 0x42, 0xee, + 0x13, 0xf0, 0x93, 0x3b, 0x68, 0x8f, 0xcd, 0x19 + } + }, + {{ + 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x96, 0x51, 0x35, 0xf8, 0xa8, 0x1f, 0x25, 0xc9, + 0xd6, 0x30, 0xb1, 0x75, 0x02, 0xf6, 0x8e, 0x53 + } + }, + {{ + 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x8b, 0x87, 0x14, 0x5a, 0x01, 0xad, 0x1c, 0x6c, + 0xed, 0xe9, 0x95, 0xea, 0x36, 0x70, 0x45, 0x4f + } + }, + {{ + 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x8e, 0xae, 0x3b, 0x10, 0xa0, 0xc8, 0xca, 0x6d, + 0x1d, 0x3b, 0x0f, 0xa6, 0x1e, 0x56, 0xb0, 0xb2 + } + }, + {{ + 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x64, 0xb4, 0xd6, 0x29, 0x81, 0x0f, 0xda, 0x6b, + 0xaf, 0xdf, 0x08, 0xf3, 0xb0, 0xd8, 0xd2, 0xc5 + } + }, + {{ + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xd7, 0xe5, 0xdb, 0xd3, 0x32, 0x45, 0x95, 0xf8, + 0xfd, 0xc7, 0xd7, 0xc5, 0x71, 0xda, 0x6c, 0x2a + } + }, + {{ + 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xf3, 0xf7, 0x23, 0x75, 0x26, 0x4e, 0x16, 0x7f, + 0xca, 0x9d, 0xe2, 0xc1, 0x52, 0x7d, 0x96, 0x06 + } + }, + {{ + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x8e, 0xe7, 0x9d, 0xd4, 0xf4, 0x01, 0xff, 0x9b, + 0x7e, 0xa9, 0x45, 0xd8, 0x66, 0x66, 0xc1, 0x3b + } + }, + {{ + 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xdd, 0x35, 0xce, 0xa2, 0x79, 0x99, 0x40, 0xb4, + 0x0d, 0xb3, 0xf8, 0x19, 0xcb, 0x94, 0xc0, 0x8b + } + }, + {{ + 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x69, 0x41, 0xcb, 0x6b, 0x3e, 0x08, 0xc2, 0xb7, + 0xaf, 0xa5, 0x81, 0xeb, 0xdd, 0x60, 0x7b, 0x87 + } + }, + {{ + 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x2c, 0x20, 0xf4, 0x39, 0xf6, 0xbb, 0x09, 0x7b, + 0x29, 0xb8, 0xbd, 0x6d, 0x99, 0xaa, 0xd7, 0x99 + } + }, + {{ + 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x62, 0x5d, 0x01, 0xf0, 0x58, 0xe5, 0x65, 0xf7, + 0x7a, 0xe8, 0x63, 0x78, 0xbd, 0x2c, 0x49, 0xb3 + } + }, + {{ + 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xc0, 0xb5, 0xfd, 0x98, 0x19, 0x0e, 0xf4, 0x5f, + 0xbb, 0x43, 0x01, 0x43, 0x8d, 0x09, 0x59, 0x50 + } + }, + {{ + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x13, 0x00, 0x1f, 0xf5, 0xd9, 0x98, 0x06, 0xef, + 0xd2, 0x5d, 0xa3, 0x4f, 0x56, 0xbe, 0x85, 0x4b + } + }, + {{ + 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x3b, 0x59, 0x4c, 0x60, 0xf5, 0xc8, 0x27, 0x7a, + 0x51, 0x13, 0x67, 0x7f, 0x94, 0x20, 0x8d, 0x82 + } + }, + {{ + 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xe9, 0xc0, 0xfc, 0x18, 0x18, 0xe4, 0xaa, 0x46, + 0xbd, 0x2e, 0x39, 0xd6, 0x38, 0xf8, 0x9e, 0x05 + } + }, + {{ + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xf8, 0x02, 0x3e, 0xe9, 0xc3, 0xfd, 0xc4, 0x5a, + 0x01, 0x9b, 0x4e, 0x98, 0x5c, 0x7e, 0x1a, 0x54 + } + }, + {{ + 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x35, 0xf4, 0x01, 0x82, 0xab, 0x46, 0x62, 0xf3, + 0x02, 0x3b, 0xae, 0xc1, 0xee, 0x79, 0x6b, 0x57 + } + }, + {{ + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x3a, 0xeb, 0xba, 0xd7, 0x30, 0x36, 0x49, 0xb4, + 0x19, 0x4a, 0x69, 0x45, 0xc6, 0xcc, 0x36, 0x94 + } + }, + {{ + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xa2, 0x12, 0x4b, 0xea, 0x53, 0xec, 0x28, 0x34, + 0x27, 0x9b, 0xed, 0x7f, 0x7e, 0xb0, 0xf9, 0x38 + } + }, + {{ + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xb9, 0xfb, 0x43, 0x99, 0xfa, 0x4f, 0xac, 0xc7, + 0x30, 0x9e, 0x14, 0xec, 0x98, 0x36, 0x0b, 0x0a + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xc2, 0x62, 0x77, 0x43, 0x74, 0x20, 0xc5, 0xd6, + 0x34, 0xf7, 0x15, 0xae, 0xa8, 0x1a, 0x91, 0x32 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x17, 0x1a, 0x0e, 0x1b, 0x2d, 0xd4, 0x24, 0xf0, + 0xe0, 0x89, 0xaf, 0x2c, 0x4c, 0x10, 0xf3, 0x2f + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x7c, 0xad, 0xbe, 0x40, 0x2d, 0x1b, 0x20, 0x8f, + 0xe7, 0x35, 0xed, 0xce, 0x00, 0xae, 0xe7, 0xce + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x43, 0xb0, 0x2f, 0xf9, 0x29, 0xa1, 0x48, 0x5a, + 0xf6, 0xf5, 0xc6, 0xd6, 0x55, 0x8b, 0xaa, 0x0f + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x09, 0x2f, 0xaa, 0xcc, 0x9b, 0xf4, 0x35, 0x08, + 0xbf, 0x8f, 0xa8, 0x61, 0x3c, 0xa7, 0x5d, 0xea + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xcb, 0x2b, 0xf8, 0x28, 0x0f, 0x3f, 0x97, 0x42, + 0xc7, 0xed, 0x51, 0x3f, 0xe8, 0x02, 0x62, 0x9c + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x21, 0x5a, 0x41, 0xee, 0x44, 0x2f, 0xa9, 0x92, + 0xa6, 0xe3, 0x23, 0x98, 0x6d, 0xed, 0x3f, 0x68 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xf2, 0x1e, 0x99, 0xcf, 0x4f, 0x0f, 0x77, 0xce, + 0xa8, 0x36, 0xe1, 0x1a, 0x2f, 0xe7, 0x5f, 0xb1 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x95, 0xe3, 0xa0, 0xca, 0x90, 0x79, 0xe6, 0x46, + 0x33, 0x1d, 0xf8, 0xb4, 0xe7, 0x0d, 0x2c, 0xd6 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x4a, 0xfe, 0x7f, 0x12, 0x0c, 0xe7, 0x61, 0x3f, + 0x74, 0xfc, 0x12, 0xa0, 0x1a, 0x82, 0x80, 0x73 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x82, 0x7f, 0x00, 0x0e, 0x75, 0xe2, 0xc8, 0xb9, + 0xd4, 0x79, 0xbe, 0xed, 0x91, 0x3f, 0xe6, 0x78 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x35, 0x83, 0x0c, 0x8e, 0x7a, 0xae, 0xfe, 0x2d, + 0x30, 0x31, 0x0e, 0xf3, 0x81, 0xcb, 0xf6, 0x91 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x19, 0x1a, 0xa0, 0xf2, 0xc8, 0x57, 0x01, 0x44, + 0xf3, 0x86, 0x57, 0xea, 0x40, 0x85, 0xeb, 0xe5 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x85, 0x06, 0x2c, 0x2c, 0x90, 0x9f, 0x15, 0xd9, + 0x26, 0x9b, 0x6c, 0x18, 0xce, 0x99, 0xc4, 0xf0 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x67, 0x80, 0x34, 0xdc, 0x9e, 0x41, 0xb5, 0xa5, + 0x60, 0xed, 0x23, 0x9e, 0xea, 0xb1, 0xbc, 0x78 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xc2, 0xf9, 0x3a, 0x4c, 0xe5, 0xab, 0x6d, 0x5d, + 0x56, 0xf1, 0xb9, 0x3c, 0xf1, 0x99, 0x11, 0xc1 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x1c, 0x31, 0x12, 0xbc, 0xb0, 0xc1, 0xdc, 0xc7, + 0x49, 0xd7, 0x99, 0x74, 0x36, 0x91, 0xbf, 0x82 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x00, 0xc5, 0x5b, 0xd7, 0x5c, 0x7f, 0x9c, 0x88, + 0x19, 0x89, 0xd3, 0xec, 0x19, 0x11, 0xc0, 0xd4 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xea, 0x2e, 0x6b, 0x5e, 0xf1, 0x82, 0xb7, 0xdf, + 0xf3, 0x62, 0x9a, 0xbd, 0x6a, 0x12, 0x04, 0x5f + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x22, 0x32, 0x23, 0x27, 0xe0, 0x17, 0x80, 0xb1, + 0x73, 0x97, 0xf2, 0x40, 0x87, 0xf8, 0xcc, 0x6f + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xc9, 0xca, 0xcb, 0x5c, 0xd1, 0x16, 0x92, 0xc3, + 0x73, 0xb2, 0x41, 0x17, 0x68, 0x14, 0x9e, 0xe7 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xa1, 0x8e, 0x3d, 0xbb, 0xca, 0x57, 0x78, 0x60, + 0xda, 0xb6, 0xb8, 0x0d, 0xa3, 0x13, 0x92, 0x56 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x79, 0xb6, 0x1c, 0x37, 0xbf, 0x32, 0x8e, 0xcc, + 0xa8, 0xd7, 0x43, 0x26, 0x5a, 0x3d, 0x42, 0x5c + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xd2, 0xd9, 0x9c, 0x6b, 0xcc, 0x1f, 0x06, 0xfd, + 0xa8, 0xe2, 0x7e, 0x8a, 0xe3, 0xf1, 0xcc, 0xc7 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x1b, 0xfd, 0x4b, 0x91, 0xc7, 0x01, 0xfd, 0x6b, + 0x61, 0xb7, 0xf9, 0x97, 0x82, 0x9d, 0x66, 0x3b + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x11, 0x00, 0x5d, 0x52, 0xf2, 0x5f, 0x16, 0xbd, + 0xc9, 0x54, 0x5a, 0x87, 0x6a, 0x63, 0x49, 0x0a + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x3a, 0x4d, 0x35, 0x4f, 0x02, 0xbb, 0x5a, 0x5e, + 0x47, 0xd3, 0x96, 0x66, 0x86, 0x7f, 0x24, 0x6a + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xd4, 0x51, 0xb8, 0xd6, 0xe1, 0xe1, 0xa0, 0xeb, + 0xb1, 0x55, 0xfb, 0xbf, 0x6e, 0x7b, 0x7d, 0xc3 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x68, 0x98, 0xd4, 0xf4, 0x2f, 0xa7, 0xba, 0x6a, + 0x10, 0xac, 0x05, 0xe8, 0x7b, 0x9f, 0x20, 0x80 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xb6, 0x11, 0x29, 0x5e, 0x73, 0x9c, 0xa7, 0xd9, + 0xb5, 0x0f, 0x8e, 0x4c, 0x0e, 0x75, 0x4a, 0x3f + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x7d, 0x33, 0xfc, 0x7d, 0x8a, 0xbe, 0x3c, 0xa1, + 0x93, 0x67, 0x59, 0xf8, 0xf5, 0xde, 0xaf, 0x20 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x3b, 0x5e, 0x0f, 0x56, 0x6d, 0xc9, 0x6c, 0x29, + 0x8f, 0x0c, 0x12, 0x63, 0x75, 0x39, 0xb2, 0x5c + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xf8, 0x07, 0xc3, 0xe7, 0x98, 0x5f, 0xe0, 0xf5, + 0xa5, 0x0e, 0x2c, 0xdb, 0x25, 0xc5, 0x10, 0x9e + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x41, 0xf9, 0x92, 0xa8, 0x56, 0xfb, 0x27, 0x8b, + 0x38, 0x9a, 0x62, 0xf5, 0xd2, 0x74, 0xd7, 0xe9 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x10, 0xd3, 0xed, 0x7a, 0x6f, 0xe1, 0x5a, 0xb4, + 0xd9, 0x1a, 0xcb, 0xc7, 0xd0, 0x76, 0x7a, 0xb1 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x21, 0xfe, 0xec, 0xd4, 0x5b, 0x2e, 0x67, 0x59, + 0x73, 0xac, 0x33, 0xbf, 0x0c, 0x54, 0x24, 0xfc + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x14, 0x80, 0xcb, 0x39, 0x55, 0xba, 0x62, 0xd0, + 0x9e, 0xea, 0x66, 0x8f, 0x7c, 0x70, 0x88, 0x17 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x66, 0x40, 0x40, 0x33, 0xd6, 0xb7, 0x2b, 0x60, + 0x93, 0x54, 0xd5, 0x49, 0x6e, 0x7e, 0xb5, 0x11 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x1c, 0x31, 0x7a, 0x22, 0x0a, 0x7d, 0x70, 0x0d, + 0xa2, 0xb1, 0xe0, 0x75, 0xb0, 0x02, 0x66, 0xe1 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xab, 0x3b, 0x89, 0x54, 0x22, 0x33, 0xf1, 0x27, + 0x1b, 0xf8, 0xfd, 0x0c, 0x0f, 0x40, 0x35, 0x45 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xd9, 0x3e, 0xae, 0x96, 0x6f, 0xac, 0x46, 0xdc, + 0xa9, 0x27, 0xd6, 0xb1, 0x14, 0xfa, 0x3f, 0x9e + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x1b, 0xde, 0xc5, 0x21, 0x31, 0x65, 0x03, 0xd9, + 0xd5, 0xee, 0x65, 0xdf, 0x3e, 0xa9, 0x4d, 0xdf + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xee, 0xf4, 0x56, 0x43, 0x1d, 0xea, 0x8b, 0x4a, + 0xcf, 0x83, 0xbd, 0xae, 0x37, 0x17, 0xf7, 0x5f + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x06, 0xf2, 0x51, 0x9a, 0x2f, 0xaf, 0xaa, 0x59, + 0x6b, 0xfe, 0xf5, 0xcf, 0xa1, 0x5c, 0x21, 0xb9 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x25, 0x1a, 0x7e, 0xac, 0x7e, 0x2f, 0xe8, 0x09, + 0xe4, 0xaa, 0x8d, 0x0d, 0x70, 0x12, 0x53, 0x1a + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x3b, 0xff, 0xc1, 0x6e, 0x4c, 0x49, 0xb2, 0x68, + 0xa2, 0x0f, 0x8d, 0x96, 0xa6, 0x0b, 0x40, 0x58 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xe8, 0x86, 0xf9, 0x28, 0x19, 0x99, 0xc5, 0xbb, + 0x3b, 0x3e, 0x88, 0x62, 0xe2, 0xf7, 0xc9, 0x88 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x56, 0x3b, 0xf9, 0x0d, 0x61, 0xbe, 0xef, 0x39, + 0xf4, 0x8d, 0xd6, 0x25, 0xfc, 0xef, 0x13, 0x61 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x4d, 0x37, 0xc8, 0x50, 0x64, 0x45, 0x63, 0xc6, + 0x9f, 0xd0, 0xac, 0xd9, 0xa0, 0x49, 0x32, 0x5b + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xb8, 0x7c, 0x92, 0x1b, 0x91, 0x82, 0x9e, 0xf3, + 0xb1, 0x3c, 0xa5, 0x41, 0xee, 0x11, 0x30, 0xa6 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x2e, 0x65, 0xeb, 0x6b, 0x6e, 0xa3, 0x83, 0xe1, + 0x09, 0xac, 0xcc, 0xe8, 0x32, 0x6b, 0x03, 0x93 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x9c, 0xa5, 0x47, 0xf7, 0x43, 0x9e, 0xdc, 0x3e, + 0x25, 0x5c, 0x0f, 0x4d, 0x49, 0xaa, 0x89, 0x90 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xa5, 0xe6, 0x52, 0x61, 0x4c, 0x93, 0x00, 0xf3, + 0x78, 0x16, 0xb1, 0xf9, 0xfd, 0x0c, 0x87, 0xf9 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x14, 0x95, 0x4f, 0x0b, 0x46, 0x97, 0x77, 0x6f, + 0x44, 0x49, 0x4f, 0xe4, 0x58, 0xd8, 0x14, 0xed + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x7c, 0x8d, 0x9a, 0xb6, 0xc2, 0x76, 0x17, 0x23, + 0xfe, 0x42, 0xf8, 0xbb, 0x50, 0x6c, 0xbc, 0xf7 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xdb, 0x7e, 0x19, 0x32, 0x67, 0x9f, 0xdd, 0x99, + 0x74, 0x2a, 0xab, 0x04, 0xaa, 0x0d, 0x5a, 0x80 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x4c, 0x6a, 0x1c, 0x83, 0xe5, 0x68, 0xcd, 0x10, + 0xf2, 0x7c, 0x2d, 0x73, 0xde, 0xd1, 0x9c, 0x28 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00 + }, { + 0x90, 0xec, 0xbe, 0x61, 0x77, 0xe6, 0x74, 0xc9, + 0x8d, 0xe4, 0x12, 0x41, 0x3f, 0x7a, 0xc9, 0x15 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00 + }, { + 0x90, 0x68, 0x4a, 0x2a, 0xc5, 0x5f, 0xe1, 0xec, + 0x2b, 0x8e, 0xbd, 0x56, 0x22, 0x52, 0x0b, 0x73 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00 + }, { + 0x74, 0x72, 0xf9, 0xa7, 0x98, 0x86, 0x07, 0xca, + 0x79, 0x70, 0x77, 0x95, 0x99, 0x10, 0x35, 0xe6 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00 + }, { + 0x56, 0xaf, 0xf0, 0x89, 0x87, 0x8b, 0xf3, 0x35, + 0x2f, 0x8d, 0xf1, 0x72, 0xa3, 0xae, 0x47, 0xd8 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00 + }, { + 0x65, 0xc0, 0x52, 0x6c, 0xbe, 0x40, 0x16, 0x1b, + 0x80, 0x19, 0xa2, 0xa3, 0x17, 0x1a, 0xbd, 0x23 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00 + }, { + 0x37, 0x7b, 0xe0, 0xbe, 0x33, 0xb4, 0xe3, 0xe3, + 0x10, 0xb4, 0xaa, 0xbd, 0xa1, 0x73, 0xf8, 0x4f + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00 + }, { + 0x94, 0x02, 0xe9, 0xaa, 0x6f, 0x69, 0xde, 0x65, + 0x04, 0xda, 0x8d, 0x20, 0xc4, 0xfc, 0xaa, 0x2f + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 + }, { + 0x12, 0x3c, 0x1f, 0x4a, 0xf3, 0x13, 0xad, 0x8c, + 0x2c, 0xe6, 0x48, 0xb2, 0xe7, 0x1f, 0xb6, 0xe1 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00 + }, { + 0x1f, 0xfc, 0x62, 0x6d, 0x30, 0x20, 0x3d, 0xcd, + 0xb0, 0x01, 0x9f, 0xb8, 0x0f, 0x72, 0x6c, 0xf4 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00 + }, { + 0x76, 0xda, 0x1f, 0xbe, 0x3a, 0x50, 0x72, 0x8c, + 0x50, 0xfd, 0x2e, 0x62, 0x1b, 0x5a, 0xd8, 0x85 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00 + }, { + 0x08, 0x2e, 0xb8, 0xbe, 0x35, 0xf4, 0x42, 0xfb, + 0x52, 0x66, 0x8e, 0x16, 0xa5, 0x91, 0xd1, 0xd6 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00 + }, { + 0xe6, 0x56, 0xf9, 0xec, 0xf5, 0xfe, 0x27, 0xec, + 0x3e, 0x4a, 0x73, 0xd0, 0x0c, 0x28, 0x2f, 0xb3 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00 + }, { + 0x2c, 0xa8, 0x20, 0x9d, 0x63, 0x27, 0x4c, 0xd9, + 0xa2, 0x9b, 0xb7, 0x4b, 0xcd, 0x77, 0x68, 0x3a + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00 + }, { + 0x79, 0xbf, 0x5d, 0xce, 0x14, 0xbb, 0x7d, 0xd7, + 0x3a, 0x8e, 0x36, 0x11, 0xde, 0x7c, 0xe0, 0x26 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00 + }, { + 0x3c, 0x84, 0x99, 0x39, 0xa5, 0xd2, 0x93, 0x99, + 0xf3, 0x44, 0xc4, 0xa0, 0xec, 0xa8, 0xa5, 0x76 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 + }, { + 0xed, 0x3c, 0x0a, 0x94, 0xd5, 0x9b, 0xec, 0xe9, + 0x88, 0x35, 0xda, 0x7a, 0xa4, 0xf0, 0x7c, 0xa2 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00 + }, { + 0x63, 0x91, 0x9e, 0xd4, 0xce, 0x10, 0x19, 0x64, + 0x38, 0xb6, 0xad, 0x09, 0xd9, 0x9c, 0xd7, 0x95 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00 + }, { + 0x76, 0x78, 0xf3, 0xa8, 0x33, 0xf1, 0x9f, 0xea, + 0x95, 0xf3, 0xc6, 0x02, 0x9e, 0x2b, 0xc6, 0x10 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00 + }, { + 0x3a, 0xa4, 0x26, 0x83, 0x10, 0x67, 0xd3, 0x6b, + 0x92, 0xbe, 0x7c, 0x5f, 0x81, 0xc1, 0x3c, 0x56 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00 + }, { + 0x92, 0x72, 0xe2, 0xd2, 0xcd, 0xd1, 0x10, 0x50, + 0x99, 0x8c, 0x84, 0x50, 0x77, 0xa3, 0x0e, 0xa0 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00 + }, { + 0x08, 0x8c, 0x4b, 0x53, 0xf5, 0xec, 0x0f, 0xf8, + 0x14, 0xc1, 0x9a, 0xda, 0xe7, 0xf6, 0x24, 0x6c + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00 + }, { + 0x40, 0x10, 0xa5, 0xe4, 0x01, 0xfd, 0xf0, 0xa0, + 0x35, 0x4d, 0xdb, 0xcc, 0x0d, 0x01, 0x2b, 0x17 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00 + }, { + 0xa8, 0x7a, 0x38, 0x57, 0x36, 0xc0, 0xa6, 0x18, + 0x9b, 0xd6, 0x58, 0x9b, 0xd8, 0x44, 0x5a, 0x93 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 + }, { + 0x54, 0x5f, 0x2b, 0x83, 0xd9, 0x61, 0x6d, 0xcc, + 0xf6, 0x0f, 0xa9, 0x83, 0x0e, 0x9c, 0xd2, 0x87 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00 + }, { + 0x4b, 0x70, 0x6f, 0x7f, 0x92, 0x40, 0x63, 0x52, + 0x39, 0x40, 0x37, 0xa6, 0xd4, 0xf4, 0x68, 0x8d + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00 + }, { + 0xb7, 0x97, 0x2b, 0x39, 0x41, 0xc4, 0x4b, 0x90, + 0xaf, 0xa7, 0xb2, 0x64, 0xbf, 0xba, 0x73, 0x87 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00 + }, { + 0x6f, 0x45, 0x73, 0x2c, 0xf1, 0x08, 0x81, 0x54, + 0x6f, 0x0f, 0xd2, 0x38, 0x96, 0xd2, 0xbb, 0x60 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00 + }, { + 0x2e, 0x35, 0x79, 0xca, 0x15, 0xaf, 0x27, 0xf6, + 0x4b, 0x3c, 0x95, 0x5a, 0x5b, 0xfc, 0x30, 0xba + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00 + }, { + 0x34, 0xa2, 0xc5, 0xa9, 0x1a, 0xe2, 0xae, 0xc9, + 0x9b, 0x7d, 0x1b, 0x5f, 0xa6, 0x78, 0x04, 0x47 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00 + }, { + 0xa4, 0xd6, 0x61, 0x6b, 0xd0, 0x4f, 0x87, 0x33, + 0x5b, 0x0e, 0x53, 0x35, 0x12, 0x27, 0xa9, 0xee + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00 + }, { + 0x7f, 0x69, 0x2b, 0x03, 0x94, 0x58, 0x67, 0xd1, + 0x61, 0x79, 0xa8, 0xce, 0xfc, 0x83, 0xea, 0x3f + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 + }, { + 0x3b, 0xd1, 0x41, 0xee, 0x84, 0xa0, 0xe6, 0x41, + 0x4a, 0x26, 0xe7, 0xa4, 0xf2, 0x81, 0xf8, 0xa2 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 + }, { + 0xd1, 0x78, 0x8f, 0x57, 0x2d, 0x98, 0xb2, 0xb1, + 0x6e, 0xc5, 0xd5, 0xf3, 0x92, 0x2b, 0x99, 0xbc + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 + }, { + 0x08, 0x33, 0xff, 0x6f, 0x61, 0xd9, 0x8a, 0x57, + 0xb2, 0x88, 0xe8, 0xc3, 0x58, 0x6b, 0x85, 0xa6 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0 + }, { + 0x85, 0x68, 0x26, 0x17, 0x97, 0xde, 0x17, 0x6b, + 0xf0, 0xb4, 0x3b, 0xec, 0xc6, 0x28, 0x5a, 0xfb + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0 + }, { + 0xf9, 0xb0, 0xfd, 0xa0, 0xc4, 0xa8, 0x98, 0xf5, + 0xb9, 0xe6, 0xf6, 0x61, 0xc4, 0xce, 0x4d, 0x07 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8 + }, { + 0x8a, 0xde, 0x89, 0x59, 0x13, 0x68, 0x5c, 0x67, + 0xc5, 0x26, 0x9f, 0x8a, 0xae, 0x42, 0x98, 0x3e + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc + }, { + 0x39, 0xbd, 0xe6, 0x7d, 0x5c, 0x8e, 0xd8, 0xa8, + 0xb1, 0xc3, 0x7e, 0xb8, 0xfa, 0x9f, 0x5a, 0xc0 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe + }, { + 0x5c, 0x00, 0x5e, 0x72, 0xc1, 0x41, 0x8c, 0x44, + 0xf5, 0x69, 0xf2, 0xea, 0x33, 0xba, 0x54, 0xf3 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }, { + 0x3f, 0x5b, 0x8c, 0xc9, 0xea, 0x85, 0x5a, 0x0a, + 0xfa, 0x73, 0x47, 0xd2, 0x3e, 0x8d, 0x66, 0x4e + } + } + }; + struct tc_aes_key_sched_struct s; + unsigned int i; + TC_PRINT("AES128 %s (NIST fixed-key and variable-text):\n", __func__); + (void)tc_aes128_set_encrypt_key(&s, key); + + for (i = 0; i < 128; ++i) + { + result = var_text_test(i, kat_tbl[i].in, kat_tbl[i].out, &s); + + if (result == TC_FAIL) + { + break; + } + } + + TC_END_RESULT(result); + return result; +} + +int var_key_test(unsigned int r, const uint8_t* in, const uint8_t* out) +{ + int result = TC_PASS; + const uint8_t plaintext[NUM_OF_NIST_KEYS] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + uint8_t ciphertext[NUM_OF_NIST_KEYS]; + struct tc_aes_key_sched_struct s; + (void)tc_aes128_set_encrypt_key(&s, in); + (void)tc_aes_encrypt(ciphertext, plaintext, &s); + result = check_result(r, out, NUM_OF_NIST_KEYS, ciphertext, + sizeof(ciphertext)); + return result; +} + +/* + All NIST tests with variable key and fixed text. +*/ +int test_4(void) +{ + int result = TC_PASS; + const struct kat_table kat_tbl[NUM_OF_FIXED_KEYS] = + { + {{ + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x0e, 0xdd, 0x33, 0xd3, 0xc6, 0x21, 0xe5, 0x46, + 0x45, 0x5b, 0xd8, 0xba, 0x14, 0x18, 0xbe, 0xc8 + } + }, + {{ + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x4b, 0xc3, 0xf8, 0x83, 0x45, 0x0c, 0x11, 0x3c, + 0x64, 0xca, 0x42, 0xe1, 0x11, 0x2a, 0x9e, 0x87 + } + }, + {{ + 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x72, 0xa1, 0xda, 0x77, 0x0f, 0x5d, 0x7a, 0xc4, + 0xc9, 0xef, 0x94, 0xd8, 0x22, 0xaf, 0xfd, 0x97 + } + }, + {{ + 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x97, 0x00, 0x14, 0xd6, 0x34, 0xe2, 0xb7, 0x65, + 0x07, 0x77, 0xe8, 0xe8, 0x4d, 0x03, 0xcc, 0xd8 + } + }, + {{ + 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xf1, 0x7e, 0x79, 0xae, 0xd0, 0xdb, 0x7e, 0x27, + 0x9e, 0x95, 0x5b, 0x5f, 0x49, 0x38, 0x75, 0xa7 + } + }, + {{ + 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x9e, 0xd5, 0xa7, 0x51, 0x36, 0xa9, 0x40, 0xd0, + 0x96, 0x3d, 0xa3, 0x79, 0xdb, 0x4a, 0xf2, 0x6a + } + }, + {{ + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xc4, 0x29, 0x5f, 0x83, 0x46, 0x5c, 0x77, 0x55, + 0xe8, 0xfa, 0x36, 0x4b, 0xac, 0x6a, 0x7e, 0xa5 + } + }, + {{ + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xb1, 0xd7, 0x58, 0x25, 0x6b, 0x28, 0xfd, 0x85, + 0x0a, 0xd4, 0x94, 0x42, 0x08, 0xcf, 0x11, 0x55 + } + }, + {{ + 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x42, 0xff, 0xb3, 0x4c, 0x74, 0x3d, 0xe4, 0xd8, + 0x8c, 0xa3, 0x80, 0x11, 0xc9, 0x90, 0x89, 0x0b + } + }, + {{ + 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x99, 0x58, 0xf0, 0xec, 0xea, 0x8b, 0x21, 0x72, + 0xc0, 0xc1, 0x99, 0x5f, 0x91, 0x82, 0xc0, 0xf3 + } + }, + {{ + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x95, 0x6d, 0x77, 0x98, 0xfa, 0xc2, 0x0f, 0x82, + 0xa8, 0x82, 0x3f, 0x98, 0x4d, 0x06, 0xf7, 0xf5 + } + }, + {{ + 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xa0, 0x1b, 0xf4, 0x4f, 0x2d, 0x16, 0xbe, 0x92, + 0x8c, 0xa4, 0x4a, 0xaf, 0x7b, 0x9b, 0x10, 0x6b + } + }, + {{ + 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xb5, 0xf1, 0xa3, 0x3e, 0x50, 0xd4, 0x0d, 0x10, + 0x37, 0x64, 0xc7, 0x6b, 0xd4, 0xc6, 0xb6, 0xf8 + } + }, + {{ + 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x26, 0x37, 0x05, 0x0c, 0x9f, 0xc0, 0xd4, 0x81, + 0x7e, 0x2d, 0x69, 0xde, 0x87, 0x8a, 0xee, 0x8d + } + }, + {{ + 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x11, 0x3e, 0xcb, 0xe4, 0xa4, 0x53, 0x26, 0x9a, + 0x0d, 0xd2, 0x60, 0x69, 0x46, 0x7f, 0xb5, 0xb5 + } + }, + {{ + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x97, 0xd0, 0x75, 0x4f, 0xe6, 0x8f, 0x11, 0xb9, + 0xe3, 0x75, 0xd0, 0x70, 0xa6, 0x08, 0xc8, 0x84 + } + }, + {{ + 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xc6, 0xa0, 0xb3, 0xe9, 0x98, 0xd0, 0x50, 0x68, + 0xa5, 0x39, 0x97, 0x78, 0x40, 0x52, 0x00, 0xb4 + } + }, + {{ + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xdf, 0x55, 0x6a, 0x33, 0x43, 0x8d, 0xb8, 0x7b, + 0xc4, 0x1b, 0x17, 0x52, 0xc5, 0x5e, 0x5e, 0x49 + } + }, + {{ + 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x90, 0xfb, 0x12, 0x8d, 0x3a, 0x1a, 0xf6, 0xe5, + 0x48, 0x52, 0x1b, 0xb9, 0x62, 0xbf, 0x1f, 0x05 + } + }, + {{ + 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x26, 0x29, 0x8e, 0x9c, 0x1d, 0xb5, 0x17, 0xc2, + 0x15, 0xfa, 0xdf, 0xb7, 0xd2, 0xa8, 0xd6, 0x91 + } + }, + {{ + 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xa6, 0xcb, 0x76, 0x1d, 0x61, 0xf8, 0x29, 0x2d, + 0x0d, 0xf3, 0x93, 0xa2, 0x79, 0xad, 0x03, 0x80 + } + }, + {{ + 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x12, 0xac, 0xd8, 0x9b, 0x13, 0xcd, 0x5f, 0x87, + 0x26, 0xe3, 0x4d, 0x44, 0xfd, 0x48, 0x61, 0x08 + } + }, + {{ + 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x95, 0xb1, 0x70, 0x3f, 0xc5, 0x7b, 0xa0, 0x9f, + 0xe0, 0xc3, 0x58, 0x0f, 0xeb, 0xdd, 0x7e, 0xd4 + } + }, + {{ + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xde, 0x11, 0x72, 0x2d, 0x89, 0x3e, 0x9f, 0x91, + 0x21, 0xc3, 0x81, 0xbe, 0xcc, 0x1d, 0xa5, 0x9a + } + }, + {{ + 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x6d, 0x11, 0x4c, 0xcb, 0x27, 0xbf, 0x39, 0x10, + 0x12, 0xe8, 0x97, 0x4c, 0x54, 0x6d, 0x9b, 0xf2 + } + }, + {{ + 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x5c, 0xe3, 0x7e, 0x17, 0xeb, 0x46, 0x46, 0xec, + 0xfa, 0xc2, 0x9b, 0x9c, 0xc3, 0x8d, 0x93, 0x40 + } + }, + {{ + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x18, 0xc1, 0xb6, 0xe2, 0x15, 0x71, 0x22, 0x05, + 0x6d, 0x02, 0x43, 0xd8, 0xa1, 0x65, 0xcd, 0xdb + } + }, + {{ + 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x99, 0x69, 0x3e, 0x6a, 0x59, 0xd1, 0x36, 0x6c, + 0x74, 0xd8, 0x23, 0x56, 0x2d, 0x7e, 0x14, 0x31 + } + }, + {{ + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x6c, 0x7c, 0x64, 0xdc, 0x84, 0xa8, 0xbb, 0xa7, + 0x58, 0xed, 0x17, 0xeb, 0x02, 0x5a, 0x57, 0xe3 + } + }, + {{ + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xe1, 0x7b, 0xc7, 0x9f, 0x30, 0xea, 0xab, 0x2f, + 0xac, 0x2c, 0xbb, 0xe3, 0x45, 0x8d, 0x68, 0x7a + } + }, + {{ + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x11, 0x14, 0xbc, 0x20, 0x28, 0x00, 0x9b, 0x92, + 0x3f, 0x0b, 0x01, 0x91, 0x5c, 0xe5, 0xe7, 0xc4 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x9c, 0x28, 0x52, 0x4a, 0x16, 0xa1, 0xe1, 0xc1, + 0x45, 0x29, 0x71, 0xca, 0xa8, 0xd1, 0x34, 0x76 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xed, 0x62, 0xe1, 0x63, 0x63, 0x63, 0x83, 0x60, + 0xfd, 0xd6, 0xad, 0x62, 0x11, 0x27, 0x94, 0xf0 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x5a, 0x86, 0x88, 0xf0, 0xb2, 0xa2, 0xc1, 0x62, + 0x24, 0xc1, 0x61, 0x65, 0x8f, 0xfd, 0x40, 0x44 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x23, 0xf7, 0x10, 0x84, 0x2b, 0x9b, 0xb9, 0xc3, + 0x2f, 0x26, 0x64, 0x8c, 0x78, 0x68, 0x07, 0xca + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x44, 0xa9, 0x8b, 0xf1, 0x1e, 0x16, 0x3f, 0x63, + 0x2c, 0x47, 0xec, 0x6a, 0x49, 0x68, 0x3a, 0x89 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x0f, 0x18, 0xaf, 0xf9, 0x42, 0x74, 0x69, 0x6d, + 0x9b, 0x61, 0x84, 0x8b, 0xd5, 0x0a, 0xc5, 0xe5 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x82, 0x40, 0x85, 0x71, 0xc3, 0xe2, 0x42, 0x45, + 0x40, 0x20, 0x7f, 0x83, 0x3b, 0x6d, 0xda, 0x69 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x30, 0x3f, 0xf9, 0x96, 0x94, 0x7f, 0x0c, 0x7d, + 0x1f, 0x43, 0xc8, 0xf3, 0x02, 0x7b, 0x9b, 0x75 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x7d, 0xf4, 0xda, 0xf4, 0xad, 0x29, 0xa3, 0x61, + 0x5a, 0x9b, 0x6e, 0xce, 0x5c, 0x99, 0x51, 0x8a + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xc7, 0x29, 0x54, 0xa4, 0x8d, 0x07, 0x74, 0xdb, + 0x0b, 0x49, 0x71, 0xc5, 0x26, 0x26, 0x04, 0x15 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x1d, 0xf9, 0xb7, 0x61, 0x12, 0xdc, 0x65, 0x31, + 0xe0, 0x7d, 0x2c, 0xfd, 0xa0, 0x44, 0x11, 0xf0 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x8e, 0x4d, 0x8e, 0x69, 0x91, 0x19, 0xe1, 0xfc, + 0x87, 0x54, 0x5a, 0x64, 0x7f, 0xb1, 0xd3, 0x4f + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xe6, 0xc4, 0x80, 0x7a, 0xe1, 0x1f, 0x36, 0xf0, + 0x91, 0xc5, 0x7d, 0x9f, 0xb6, 0x85, 0x48, 0xd1 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x8e, 0xbf, 0x73, 0xaa, 0xd4, 0x9c, 0x82, 0x00, + 0x7f, 0x77, 0xa5, 0xc1, 0xcc, 0xec, 0x6a, 0xb4 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x4f, 0xb2, 0x88, 0xcc, 0x20, 0x40, 0x04, 0x90, + 0x01, 0xd2, 0xc7, 0x58, 0x5a, 0xd1, 0x23, 0xfc + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x04, 0x49, 0x71, 0x10, 0xef, 0xb9, 0xdc, 0xeb, + 0x13, 0xe2, 0xb1, 0x3f, 0xb4, 0x46, 0x55, 0x64 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x75, 0x55, 0x0e, 0x6c, 0xb5, 0xa8, 0x8e, 0x49, + 0x63, 0x4c, 0x9a, 0xb6, 0x9e, 0xda, 0x04, 0x30 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xb6, 0x76, 0x84, 0x73, 0xce, 0x98, 0x43, 0xea, + 0x66, 0xa8, 0x14, 0x05, 0xdd, 0x50, 0xb3, 0x45 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xcb, 0x2f, 0x43, 0x03, 0x83, 0xf9, 0x08, 0x4e, + 0x03, 0xa6, 0x53, 0x57, 0x1e, 0x06, 0x5d, 0xe6 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xff, 0x4e, 0x66, 0xc0, 0x7b, 0xae, 0x3e, 0x79, + 0xfb, 0x7d, 0x21, 0x08, 0x47, 0xa3, 0xb0, 0xba + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x7b, 0x90, 0x78, 0x51, 0x25, 0x50, 0x5f, 0xad, + 0x59, 0xb1, 0x3c, 0x18, 0x6d, 0xd6, 0x6c, 0xe3 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x8b, 0x52, 0x7a, 0x6a, 0xeb, 0xda, 0xec, 0x9e, + 0xae, 0xf8, 0xed, 0xa2, 0xcb, 0x77, 0x83, 0xe5 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x43, 0xfd, 0xaf, 0x53, 0xeb, 0xbc, 0x98, 0x80, + 0xc2, 0x28, 0x61, 0x7d, 0x6a, 0x9b, 0x54, 0x8b + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x53, 0x78, 0x61, 0x04, 0xb9, 0x74, 0x4b, 0x98, + 0xf0, 0x52, 0xc4, 0x6f, 0x1c, 0x85, 0x0d, 0x0b + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xb5, 0xab, 0x30, 0x13, 0xdd, 0x1e, 0x61, 0xdf, + 0x06, 0xcb, 0xaf, 0x34, 0xca, 0x2a, 0xee, 0x78 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x74, 0x70, 0x46, 0x9b, 0xe9, 0x72, 0x30, 0x30, + 0xfd, 0xcc, 0x73, 0xa8, 0xcd, 0x4f, 0xbb, 0x10 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xa3, 0x5a, 0x63, 0xf5, 0x34, 0x3e, 0xbe, 0x9e, + 0xf8, 0x16, 0x7b, 0xcb, 0x48, 0xad, 0x12, 0x2e + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xfd, 0x86, 0x87, 0xf0, 0x75, 0x7a, 0x21, 0x0e, + 0x9f, 0xdf, 0x18, 0x12, 0x04, 0xc3, 0x08, 0x63 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x7a, 0x18, 0x1e, 0x84, 0xbd, 0x54, 0x57, 0xd2, + 0x6a, 0x88, 0xfb, 0xae, 0x96, 0x01, 0x8f, 0xb0 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x65, 0x33, 0x17, 0xb9, 0x36, 0x2b, 0x6f, 0x9b, + 0x9e, 0x1a, 0x58, 0x0e, 0x68, 0xd4, 0x94, 0xb5 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x99, 0x5c, 0x9d, 0xc0, 0xb6, 0x89, 0xf0, 0x3c, + 0x45, 0x86, 0x7b, 0x5f, 0xaa, 0x5c, 0x18, 0xd1 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x77, 0xa4, 0xd9, 0x6d, 0x56, 0xdd, 0xa3, 0x98, + 0xb9, 0xaa, 0xbe, 0xcf, 0xc7, 0x57, 0x29, 0xfd + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x84, 0xbe, 0x19, 0xe0, 0x53, 0x63, 0x5f, 0x09, + 0xf2, 0x66, 0x5e, 0x7b, 0xae, 0x85, 0xb4, 0x2d + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x32, 0xcd, 0x65, 0x28, 0x42, 0x92, 0x6a, 0xea, + 0x4a, 0xa6, 0x13, 0x7b, 0xb2, 0xbe, 0x2b, 0x5e + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x49, 0x3d, 0x4a, 0x4f, 0x38, 0xeb, 0xb3, 0x37, + 0xd1, 0x0a, 0xa8, 0x4e, 0x91, 0x71, 0xa5, 0x54 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xd9, 0xbf, 0xf7, 0xff, 0x45, 0x4b, 0x0e, 0xc5, + 0xa4, 0xa2, 0xa6, 0x95, 0x66, 0xe2, 0xcb, 0x84 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x35, 0x35, 0xd5, 0x65, 0xac, 0xe3, 0xf3, 0x1e, + 0xb2, 0x49, 0xba, 0x2c, 0xc6, 0x76, 0x5d, 0x7a + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xf6, 0x0e, 0x91, 0xfc, 0x32, 0x69, 0xee, 0xcf, + 0x32, 0x31, 0xc6, 0xe9, 0x94, 0x56, 0x97, 0xc6 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xab, 0x69, 0xcf, 0xad, 0xf5, 0x1f, 0x8e, 0x60, + 0x4d, 0x9c, 0xc3, 0x71, 0x82, 0xf6, 0x63, 0x5a + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x78, 0x66, 0x37, 0x3f, 0x24, 0xa0, 0xb6, 0xed, + 0x56, 0xe0, 0xd9, 0x6f, 0xcd, 0xaf, 0xb8, 0x77 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x1e, 0xa4, 0x48, 0xc2, 0xaa, 0xc9, 0x54, 0xf5, + 0xd8, 0x12, 0xe9, 0xd7, 0x84, 0x94, 0x44, 0x6a + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xac, 0xc5, 0x59, 0x9d, 0xd8, 0xac, 0x02, 0x23, + 0x9a, 0x0f, 0xef, 0x4a, 0x36, 0xdd, 0x16, 0x68 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xd8, 0x76, 0x44, 0x68, 0xbb, 0x10, 0x38, 0x28, + 0xcf, 0x7e, 0x14, 0x73, 0xce, 0x89, 0x50, 0x73 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x1b, 0x0d, 0x02, 0x89, 0x36, 0x83, 0xb9, 0xf1, + 0x80, 0x45, 0x8e, 0x4a, 0xa6, 0xb7, 0x39, 0x82 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x96, 0xd9, 0xb0, 0x17, 0xd3, 0x02, 0xdf, 0x41, + 0x0a, 0x93, 0x7d, 0xcd, 0xb8, 0xbb, 0x6e, 0x43 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xef, 0x16, 0x23, 0xcc, 0x44, 0x31, 0x3c, 0xff, + 0x44, 0x0b, 0x15, 0x94, 0xa7, 0xe2, 0x1c, 0xc6 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x28, 0x4c, 0xa2, 0xfa, 0x35, 0x80, 0x7b, 0x8b, + 0x0a, 0xe4, 0xd1, 0x9e, 0x11, 0xd7, 0xdb, 0xd7 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xf2, 0xe9, 0x76, 0x87, 0x57, 0x55, 0xf9, 0x40, + 0x1d, 0x54, 0xf3, 0x6e, 0x2a, 0x23, 0xa5, 0x94 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xec, 0x19, 0x8a, 0x18, 0xe1, 0x0e, 0x53, 0x24, + 0x03, 0xb7, 0xe2, 0x08, 0x87, 0xc8, 0xdd, 0x80 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x54, 0x5d, 0x50, 0xeb, 0xd9, 0x19, 0xe4, 0xa6, + 0x94, 0x9d, 0x96, 0xad, 0x47, 0xe4, 0x6a, 0x80 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xdb, 0xdf, 0xb5, 0x27, 0x06, 0x0e, 0x0a, 0x71, + 0x00, 0x9c, 0x7b, 0xb0, 0xc6, 0x8f, 0x1d, 0x44 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x9c, 0xfa, 0x13, 0x22, 0xea, 0x33, 0xda, 0x21, + 0x73, 0xa0, 0x24, 0xf2, 0xff, 0x0d, 0x89, 0x6d + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x87, 0x85, 0xb1, 0xa7, 0x5b, 0x0f, 0x3b, 0xd9, + 0x58, 0xdc, 0xd0, 0xe2, 0x93, 0x18, 0xc5, 0x21 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x38, 0xf6, 0x7b, 0x9e, 0x98, 0xe4, 0xa9, 0x7b, + 0x6d, 0xf0, 0x30, 0xa9, 0xfc, 0xdd, 0x01, 0x04 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x19, 0x2a, 0xff, 0xfb, 0x2c, 0x88, 0x0e, 0x82, + 0xb0, 0x59, 0x26, 0xd0, 0xfc, 0x6c, 0x44, 0x8b + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x6a, 0x79, 0x80, 0xce, 0x7b, 0x10, 0x5c, 0xf5, + 0x30, 0x95, 0x2d, 0x74, 0xda, 0xaf, 0x79, 0x8c + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xea, 0x36, 0x95, 0xe1, 0x35, 0x1b, 0x9d, 0x68, + 0x58, 0xbd, 0x95, 0x8c, 0xf5, 0x13, 0xef, 0x6c + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00 + }, { + 0x6d, 0xa0, 0x49, 0x0b, 0xa0, 0xba, 0x03, 0x43, + 0xb9, 0x35, 0x68, 0x1d, 0x2c, 0xce, 0x5b, 0xa1 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00 + }, { + 0xf0, 0xea, 0x23, 0xaf, 0x08, 0x53, 0x40, 0x11, + 0xc6, 0x00, 0x09, 0xab, 0x29, 0xad, 0xa2, 0xf1 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00 + }, { + 0xff, 0x13, 0x80, 0x6c, 0xf1, 0x9c, 0xc3, 0x87, + 0x21, 0x55, 0x4d, 0x7c, 0x0f, 0xcd, 0xcd, 0x4b + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00 + }, { + 0x68, 0x38, 0xaf, 0x1f, 0x4f, 0x69, 0xba, 0xe9, + 0xd8, 0x5d, 0xd1, 0x88, 0xdc, 0xdf, 0x06, 0x88 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00 + }, { + 0x36, 0xcf, 0x44, 0xc9, 0x2d, 0x55, 0x0b, 0xfb, + 0x1e, 0xd2, 0x8e, 0xf5, 0x83, 0xdd, 0xf5, 0xd7 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00 + }, { + 0xd0, 0x6e, 0x31, 0x95, 0xb5, 0x37, 0x6f, 0x10, + 0x9d, 0x5c, 0x4e, 0xc6, 0xc5, 0xd6, 0x2c, 0xed + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00 + }, { + 0xc4, 0x40, 0xde, 0x01, 0x4d, 0x3d, 0x61, 0x07, + 0x07, 0x27, 0x9b, 0x13, 0x24, 0x2a, 0x5c, 0x36 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 + }, { + 0xf0, 0xc5, 0xc6, 0xff, 0xa5, 0xe0, 0xbd, 0x3a, + 0x94, 0xc8, 0x8f, 0x6b, 0x6f, 0x7c, 0x16, 0xb9 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00 + }, { + 0x3e, 0x40, 0xc3, 0x90, 0x1c, 0xd7, 0xef, 0xfc, + 0x22, 0xbf, 0xfc, 0x35, 0xde, 0xe0, 0xb4, 0xd9 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00 + }, { + 0xb6, 0x33, 0x05, 0xc7, 0x2b, 0xed, 0xfa, 0xb9, + 0x73, 0x82, 0xc4, 0x06, 0xd0, 0xc4, 0x9b, 0xc6 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00 + }, { + 0x36, 0xbb, 0xaa, 0xb2, 0x2a, 0x6b, 0xd4, 0x92, + 0x5a, 0x99, 0xa2, 0xb4, 0x08, 0xd2, 0xdb, 0xae + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00 + }, { + 0x30, 0x7c, 0x5b, 0x8f, 0xcd, 0x05, 0x33, 0xab, + 0x98, 0xbc, 0x51, 0xe2, 0x7a, 0x6c, 0xe4, 0x61 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00 + }, { + 0x82, 0x9c, 0x04, 0xff, 0x4c, 0x07, 0x51, 0x3c, + 0x0b, 0x3e, 0xf0, 0x5c, 0x03, 0xe3, 0x37, 0xb5 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00 + }, { + 0xf1, 0x7a, 0xf0, 0xe8, 0x95, 0xdd, 0xa5, 0xeb, + 0x98, 0xef, 0xc6, 0x80, 0x66, 0xe8, 0x4c, 0x54 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00 + }, { + 0x27, 0x71, 0x67, 0xf3, 0x81, 0x2a, 0xff, 0xf1, + 0xff, 0xac, 0xb4, 0xa9, 0x34, 0x37, 0x9f, 0xc3 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 + }, { + 0x2c, 0xb1, 0xdc, 0x3a, 0x9c, 0x72, 0x97, 0x2e, + 0x42, 0x5a, 0xe2, 0xef, 0x3e, 0xb5, 0x97, 0xcd + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00 + }, { + 0x36, 0xae, 0xaa, 0x3a, 0x21, 0x3e, 0x96, 0x8d, + 0x4b, 0x5b, 0x67, 0x9d, 0x3a, 0x2c, 0x97, 0xfe + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00 + }, { + 0x92, 0x41, 0xda, 0xca, 0x4f, 0xdd, 0x03, 0x4a, + 0x82, 0x37, 0x2d, 0xb5, 0x0e, 0x1a, 0x0f, 0x3f + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00 + }, { + 0xc1, 0x45, 0x74, 0xd9, 0xcd, 0x00, 0xcf, 0x2b, + 0x5a, 0x7f, 0x77, 0xe5, 0x3c, 0xd5, 0x78, 0x85 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00 + }, { + 0x79, 0x3d, 0xe3, 0x92, 0x36, 0x57, 0x0a, 0xba, + 0x83, 0xab, 0x9b, 0x73, 0x7c, 0xb5, 0x21, 0xc9 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00 + }, { + 0x16, 0x59, 0x1c, 0x0f, 0x27, 0xd6, 0x0e, 0x29, + 0xb8, 0x5a, 0x96, 0xc3, 0x38, 0x61, 0xa7, 0xef + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00 + }, { + 0x44, 0xfb, 0x5c, 0x4d, 0x4f, 0x5c, 0xb7, 0x9b, + 0xe5, 0xc1, 0x74, 0xa3, 0xb1, 0xc9, 0x73, 0x48 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00 + }, { + 0x67, 0x4d, 0x2b, 0x61, 0x63, 0x3d, 0x16, 0x2b, + 0xe5, 0x9d, 0xde, 0x04, 0x22, 0x2f, 0x47, 0x40 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 + }, { + 0xb4, 0x75, 0x0f, 0xf2, 0x63, 0xa6, 0x5e, 0x1f, + 0x9e, 0x92, 0x4c, 0xcf, 0xd9, 0x8f, 0x3e, 0x37 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00 + }, { + 0x62, 0xd0, 0x66, 0x2d, 0x6e, 0xae, 0xdd, 0xed, + 0xeb, 0xae, 0x7f, 0x7e, 0xa3, 0xa4, 0xf6, 0xb6 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00 + }, { + 0x70, 0xc4, 0x6b, 0xb3, 0x06, 0x92, 0xbe, 0x65, + 0x7f, 0x7e, 0xaa, 0x93, 0xeb, 0xad, 0x98, 0x97 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00 + }, { + 0x32, 0x39, 0x94, 0xcf, 0xb9, 0xda, 0x28, 0x5a, + 0x5d, 0x96, 0x42, 0xe1, 0x75, 0x9b, 0x22, 0x4a + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00 + }, { + 0x1d, 0xbf, 0x57, 0x87, 0x7b, 0x7b, 0x17, 0x38, + 0x5c, 0x85, 0xd0, 0xb5, 0x48, 0x51, 0xe3, 0x71 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00 + }, { + 0xdf, 0xa5, 0xc0, 0x97, 0xcd, 0xc1, 0x53, 0x2a, + 0xc0, 0x71, 0xd5, 0x7b, 0x1d, 0x28, 0xd1, 0xbd + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00 + }, { + 0x3a, 0x0c, 0x53, 0xfa, 0x37, 0x31, 0x1f, 0xc1, + 0x0b, 0xd2, 0xa9, 0x98, 0x1f, 0x51, 0x31, 0x74 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00 + }, { + 0xba, 0x4f, 0x97, 0x0c, 0x0a, 0x25, 0xc4, 0x18, + 0x14, 0xbd, 0xae, 0x2e, 0x50, 0x6b, 0xe3, 0xb4 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 + }, { + 0x2d, 0xce, 0x3a, 0xcb, 0x72, 0x7c, 0xd1, 0x3c, + 0xcd, 0x76, 0xd4, 0x25, 0xea, 0x56, 0xe4, 0xf6 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 + }, { + 0x51, 0x60, 0x47, 0x4d, 0x50, 0x4b, 0x9b, 0x3e, + 0xef, 0xb6, 0x8d, 0x35, 0xf2, 0x45, 0xf4, 0xb3 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 + }, { + 0x41, 0xa8, 0xa9, 0x47, 0x76, 0x66, 0x35, 0xde, + 0xc3, 0x75, 0x53, 0xd9, 0xa6, 0xc0, 0xcb, 0xb7 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0 + }, { + 0x25, 0xd6, 0xcf, 0xe6, 0x88, 0x1f, 0x2b, 0xf4, + 0x97, 0xdd, 0x14, 0xcd, 0x4d, 0xdf, 0x44, 0x5b + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0 + }, { + 0x41, 0xc7, 0x8c, 0x13, 0x5e, 0xd9, 0xe9, 0x8c, + 0x09, 0x66, 0x40, 0x64, 0x72, 0x65, 0xda, 0x1e + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8 + }, { + 0x5a, 0x4d, 0x40, 0x4d, 0x89, 0x17, 0xe3, 0x53, + 0xe9, 0x2a, 0x21, 0x07, 0x2c, 0x3b, 0x23, 0x05 + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc + }, { + 0x02, 0xbc, 0x96, 0x84, 0x6b, 0x3f, 0xdc, 0x71, + 0x64, 0x3f, 0x38, 0x4c, 0xd3, 0xcc, 0x3e, 0xaf + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe + }, { + 0x9b, 0xa4, 0xa9, 0x14, 0x3f, 0x4e, 0x5d, 0x40, + 0x48, 0x52, 0x1c, 0x4f, 0x88, 0x77, 0xd8, 0x8e + } + }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }, { + 0xa1, 0xf6, 0x25, 0x8c, 0x87, 0x7d, 0x5f, 0xcd, + 0x89, 0x64, 0x48, 0x45, 0x38, 0xbf, 0xc9, 0x2c + } + } + }; + unsigned int i; + TC_PRINT("AES128 test #4 (NIST variable-key and fixed-text):\n"); + + for (i = 0; i < NUM_OF_FIXED_KEYS; ++i) + { + result = var_key_test(i, kat_tbl[i].in, kat_tbl[i].out); + + if (result == TC_FAIL) + { + break; + } + } + + TC_END_RESULT(result); + return result; +} + +/* + Main task to test AES +*/ +int main(void) +{ + int result = TC_PASS; + TC_START("Performing AES128 tests:"); + result = test_1(); + + if (result == TC_FAIL) /* terminate test */ + { + TC_ERROR("AES128 test #1 (NIST key schedule test) failed.\n"); + goto exitTest; + } + + result = test_2(); + + if (result == TC_FAIL) /* terminate test */ + { + TC_ERROR("AES128 test #2 (NIST encryption test) failed.\n"); + goto exitTest; + } + + result = test_3(); + + if (result == TC_FAIL) /* terminate test */ + { + TC_ERROR("AES128 test #3 (NIST fixed-key and variable-text) " + "failed.\n"); + goto exitTest; + } + + result = test_4(); + + if (result == TC_FAIL) /* terminate test */ + { + TC_ERROR("AES128 test #4 (NIST variable-key and fixed-text) " + "failed.\n"); + goto exitTest; + } + + TC_PRINT("All AES128 tests succeeded!\n"); +exitTest: + TC_END_RESULT(result); + TC_END_REPORT(result); + return result; +} diff --git a/src/components/libraries/tinycrypt-0.2.8/tests/test_cbc_mode.c b/src/components/libraries/tinycrypt-0.2.8/tests/test_cbc_mode.c new file mode 100644 index 0000000..04f2612 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/tests/test_cbc_mode.c @@ -0,0 +1,176 @@ +/* test_cbc_mode.c - TinyCrypt implementation of some AES-CBC tests */ + +/* + 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. +*/ +/* + DESCRIPTION + This module tests the following AES-CBC Mode routines: + + Scenarios tested include: + - AES128 CBC mode encryption SP 800-38a tests +*/ + +#include +#include +#include + +#include +#include +#include + +/* + NIST test vectors from SP 800-38a: + + Block #1 + Plaintext 6bc1bee22e409f96e93d7e117393172a + Input Block 6bc0bce12a459991e134741a7f9e1925 + Output Block 7649abac8119b246cee98e9b12e9197d + Ciphertext 7649abac8119b246cee98e9b12e9197d + Block #2 + Plaintext ae2d8a571e03ac9c9eb76fac45af8e51 + Input Block d86421fb9f1a1eda505ee1375746972c + Output Block 5086cb9b507219ee95db113a917678b2 + Ciphertext 5086cb9b507219ee95db113a917678b2 + Block #3 + Plaintext 30c81c46a35ce411e5fbc1191a0a52ef + Input Block 604ed7ddf32efdff7020d0238b7c2a5d + Output Block 73bed6b8e3c1743b7116e69e22229516 + Ciphertext 73bed6b8e3c1743b7116e69e22229516 + Block #4 + Plaintext f69f2445df4f9b17ad2b417be66c3710 + Input Block 8521f2fd3c8eef2cdc3da7e5c44ea206 + Output Block 3ff1caa1681fac09120eca307586e1a7 + Ciphertext 3ff1caa1681fac09120eca307586e1a7 +*/ +const uint8_t key[16] = +{ + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, + 0x09, 0xcf, 0x4f, 0x3c +}; + +const uint8_t iv[16] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f +}; + +const uint8_t plaintext[64] = +{ + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, + 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, + 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, + 0xe6, 0x6c, 0x37, 0x10 +}; + +const uint8_t ciphertext[80] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, + 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d, 0x50, 0x86, 0xcb, 0x9b, + 0x50, 0x72, 0x19, 0xee, 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2, + 0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, 0x71, 0x16, 0xe6, 0x9e, + 0x22, 0x22, 0x95, 0x16, 0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, + 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7 +}; + +/* + NIST SP 800-38a CBC Test for encryption and decryption. +*/ +int test_1_and_2(void) +{ + struct tc_aes_key_sched_struct a; + uint8_t iv_buffer[16]; + uint8_t encrypted[80]; + uint8_t decrypted[64]; + uint8_t* p; + unsigned int length; + int result = TC_PASS; + (void)tc_aes128_set_encrypt_key(&a, key); + (void)memcpy(iv_buffer, iv, TC_AES_BLOCK_SIZE); + TC_PRINT("CBC test #1 (encryption SP 800-38a tests):\n"); + + if (tc_cbc_mode_encrypt(encrypted, sizeof(plaintext) + TC_AES_BLOCK_SIZE, + plaintext, sizeof(plaintext), iv_buffer, &a) == 0) + { + TC_ERROR("CBC test #1 (encryption SP 800-38a tests) failed in " + "%s.\n", __func__); + result = TC_FAIL; + goto exitTest1; + } + + result = check_result(1, ciphertext, sizeof(encrypted), encrypted, + sizeof(encrypted)); + TC_END_RESULT(result); + TC_PRINT("CBC test #2 (decryption SP 800-38a tests):\n"); + (void)tc_aes128_set_decrypt_key(&a, key); + p = &encrypted[TC_AES_BLOCK_SIZE]; + length = ((unsigned int) sizeof(encrypted)) - TC_AES_BLOCK_SIZE; + + if (tc_cbc_mode_decrypt(decrypted, length - TC_AES_BLOCK_SIZE, p, length, + encrypted, &a) == 0) + { + TC_ERROR("CBC test #2 (decryption SP 800-38a tests) failed in. " + "%s\n", __func__); + result = TC_FAIL; + goto exitTest1; + } + + result = check_result(2, plaintext, sizeof(decrypted), decrypted, + sizeof(decrypted)); +exitTest1: + TC_END_RESULT(result); + return result; +} + +/* + Main task to test AES +*/ +int main(void) +{ + int result = TC_PASS; + TC_START("Performing AES128 tests:"); + TC_PRINT("Performing CBC tests:\n"); + result = test_1_and_2(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("CBC test #1 failed.\n"); + goto exitTest; + } + + TC_PRINT("All CBC tests succeeded!\n"); +exitTest: + TC_END_RESULT(result); + TC_END_REPORT(result); + return result; +} diff --git a/src/components/libraries/tinycrypt-0.2.8/tests/test_ccm_mode.c b/src/components/libraries/tinycrypt-0.2.8/tests/test_ccm_mode.c new file mode 100644 index 0000000..2c9b2df --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/tests/test_ccm_mode.c @@ -0,0 +1,573 @@ +/* test_ccm_mode.c - TinyCrypt AES-CCM tests (RFC 3610 tests) */ + +/* + 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. +*/ + +/* + DESCRIPTION + This module tests the following AES-CCM Mode routines: + + Scenarios tested include: + - AES128 CCM mode encryption RFC 3610 test vector #1 + - AES128 CCM mode encryption RFC 3610 test vector #2 + - AES128 CCM mode encryption RFC 3610 test vector #3 + - AES128 CCM mode encryption RFC 3610 test vector #7 + - AES128 CCM mode encryption RFC 3610 test vector #8 + - AES128 CCM mode encryption RFC 3610 test vector #9 + - AES128 CCM mode encryption No associated data + - AES128 CCM mode encryption No payload data +*/ + +#include +#include +#include + +#include + +#define TC_CCM_MAX_CT_SIZE 50 +#define TC_CCM_MAX_PT_SIZE 25 +#define NUM_NIST_KEYS 16 +#define NONCE_LEN 13 +#define HEADER_LEN 8 +#define M_LEN8 8 +#define M_LEN10 10 +#define DATA_BUF_LEN23 23 +#define DATA_BUF_LEN24 24 +#define DATA_BUF_LEN25 25 +#define EXPECTED_BUF_LEN31 31 +#define EXPECTED_BUF_LEN32 32 +#define EXPECTED_BUF_LEN33 33 +#define EXPECTED_BUF_LEN34 34 +#define EXPECTED_BUF_LEN35 35 + +int do_test(const uint8_t* key, uint8_t* nonce, + size_t nlen, const uint8_t* hdr, + size_t hlen, const uint8_t* data, + size_t dlen, const uint8_t* expected, + size_t elen, const int mlen) +{ + int result = TC_PASS; + uint8_t ciphertext[TC_CCM_MAX_CT_SIZE]; + uint8_t decrypted[TC_CCM_MAX_PT_SIZE]; + struct tc_ccm_mode_struct c; + struct tc_aes_key_sched_struct sched; + tc_aes128_set_encrypt_key(&sched, key); + result = tc_ccm_config(&c, &sched, nonce, nlen, mlen); + + if (result == 0) + { + TC_ERROR("CCM config failed in %s.\n", __func__); + result = TC_FAIL; + goto exitTest1; + } + + result = tc_ccm_generation_encryption(ciphertext, TC_CCM_MAX_CT_SIZE, hdr, + hlen, data, dlen, &c); + + if (result == 0) + { + TC_ERROR("ccm_encrypt failed in %s.\n", __func__); + result = TC_FAIL; + goto exitTest1; + } + + if (memcmp(expected, ciphertext, elen) != 0) + { + TC_ERROR("ccm_encrypt produced wrong ciphertext in %s.\n", + __func__); + show_str("\t\tExpected", expected, elen); + show_str("\t\tComputed", ciphertext, elen); + result = TC_FAIL; + goto exitTest1; + } + + result = tc_ccm_decryption_verification(decrypted, TC_CCM_MAX_PT_SIZE, hdr, + hlen, ciphertext, dlen+mlen, &c); + + if (result == 0) + { + TC_ERROR("ccm_decrypt failed in %s.\n", __func__); + show_str("\t\tExpected", data, dlen); + show_str("\t\tComputed", decrypted, sizeof(decrypted)); + result = TC_FAIL; + goto exitTest1; + } + + result = TC_PASS; +exitTest1: + TC_END_RESULT(result); + return result; +} + +int test_vector_1(void) +{ + int result = TC_PASS; + /* RFC 3610 test vector #1 */ + const uint8_t key[NUM_NIST_KEYS] = + { + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf + }; + uint8_t nonce[NONCE_LEN] = + { + 0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0xa0, + 0xa1, 0xa2, 0xa3, 0xa4, 0xa5 + }; + const uint8_t hdr[HEADER_LEN] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + const uint8_t data[DATA_BUF_LEN23] = + { + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e + }; + const uint8_t expected[EXPECTED_BUF_LEN31] = + { + 0x58, 0x8c, 0x97, 0x9a, 0x61, 0xc6, 0x63, 0xd2, + 0xf0, 0x66, 0xd0, 0xc2, 0xc0, 0xf9, 0x89, 0x80, + 0x6d, 0x5f, 0x6b, 0x61, 0xda, 0xc3, 0x84, 0x17, + 0xe8, 0xd1, 0x2c, 0xfd, 0xf9, 0x26, 0xe0 + }; + uint16_t mlen = M_LEN8; + TC_PRINT("%s: Performing CCM test #1 (RFC 3610 test vector #1):\n", + __func__); + result = do_test(key, nonce, sizeof(nonce), hdr, sizeof(hdr), + data, sizeof(data), expected, sizeof(expected), mlen); + return result; +} + +int test_vector_2(void) +{ + int result = TC_PASS; + /* RFC 3610 test vector #2 */ + const uint8_t key[NUM_NIST_KEYS] = + { + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf + }; + uint8_t nonce[NONCE_LEN] = + { + 0x00, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01, 0xa0, + 0xa1, 0xa2, 0xa3, 0xa4, 0xa5 + }; + const uint8_t hdr[HEADER_LEN] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + const uint8_t data[DATA_BUF_LEN24] = + { + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f + }; + const uint8_t expected[EXPECTED_BUF_LEN32] = + { + 0x72, 0xc9, 0x1a, 0x36, 0xe1, 0x35, 0xf8, 0xcf, + 0x29, 0x1c, 0xa8, 0x94, 0x08, 0x5c, 0x87, 0xe3, + 0xcc, 0x15, 0xc4, 0x39, 0xc9, 0xe4, 0x3a, 0x3b, + 0xa0, 0x91, 0xd5, 0x6e, 0x10, 0x40, 0x09, 0x16 + }; + uint16_t mlen = M_LEN8; + TC_PRINT("%s: Performing CCM test #2 (RFC 3610 test vector #2):\n", + __func__); + result = do_test(key, nonce, sizeof(nonce), hdr, sizeof(hdr), + data, sizeof(data), expected, sizeof(expected), mlen); + return result; +} + +int test_vector_3(void) +{ + int result = TC_PASS; + /* RFC 3610 test vector #3 */ + const uint8_t key[NUM_NIST_KEYS] = + { + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf + }; + uint8_t nonce[NONCE_LEN] = + { + 0x00, 0x00, 0x00, 0x05, 0x04, 0x03, 0x02, 0xa0, + 0xa1, 0xa2, 0xa3, 0xa4, 0xa5 + }; + const uint8_t hdr[HEADER_LEN] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + const uint8_t data[DATA_BUF_LEN25] = + { + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20 + }; + const uint8_t expected[EXPECTED_BUF_LEN33] = + { + 0x51, 0xb1, 0xe5, 0xf4, 0x4a, 0x19, 0x7d, 0x1d, + 0xa4, 0x6b, 0x0f, 0x8e, 0x2d, 0x28, 0x2a, 0xe8, + 0x71, 0xe8, 0x38, 0xbb, 0x64, 0xda, 0x85, 0x96, + 0x57, 0x4a, 0xda, 0xa7, 0x6f, 0xbd, 0x9f, 0xb0, + 0xc5 + }; + uint16_t mlen = M_LEN8; + TC_PRINT("%s: Performing CCM test #3 (RFC 3610 test vector #3):\n", + __func__); + result = do_test(key, nonce, sizeof(nonce), hdr, sizeof(hdr), data, + sizeof(data), expected, sizeof(expected), mlen); + return result; +} + +int test_vector_4(void) +{ + int result = TC_PASS; + /* RFC 3610 test vector #7 */ + const uint8_t key[NUM_NIST_KEYS] = + { + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf + }; + uint8_t nonce[NONCE_LEN] = + { + 0x00, 0x00, 0x00, 0x09, 0x08, 0x07, 0x06, 0xa0, + 0xa1, 0xa2, 0xa3, 0xa4, 0xa5 + }; + const uint8_t hdr[HEADER_LEN] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + const uint8_t data[DATA_BUF_LEN23] = + { + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e + }; + const uint8_t expected[EXPECTED_BUF_LEN33] = + { + 0x01, 0x35, 0xD1, 0xB2, 0xC9, 0x5F, 0x41, 0xD5, + 0xD1, 0xD4, 0xFE, 0xC1, 0x85, 0xD1, 0x66, 0xB8, + 0x09, 0x4E, 0x99, 0x9D, 0xFE, 0xD9, 0x6C, 0x04, + 0x8C, 0x56, 0x60, 0x2C, 0x97, 0xAC, 0xBB, 0x74, + 0x90 + }; + uint16_t mlen = M_LEN10; + TC_PRINT("%s: Performing CCM test #4 (RFC 3610 test vector #7):\n", + __func__); + result = do_test(key, nonce, sizeof(nonce), hdr, sizeof(hdr), + data, sizeof(data), expected, sizeof(expected), mlen); + return result; +} + +int test_vector_5(void) +{ + int result = TC_PASS; + /* RFC 3610 test vector #8 */ + const uint8_t key[NUM_NIST_KEYS] = + { + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF + }; + uint8_t nonce[NONCE_LEN] = + { + 0x00, 0x00, 0x00, 0x0A, 0x09, 0x08, 0x07, 0xA0, + 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 + }; + const uint8_t hdr[HEADER_LEN] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + const uint8_t data[DATA_BUF_LEN24] = + { + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f + }; + const uint8_t expected[EXPECTED_BUF_LEN34] = + { + 0x7B, 0x75, 0x39, 0x9A, 0xC0, 0x83, 0x1D, 0xD2, + 0xF0, 0xBB, 0xD7, 0x58, 0x79, 0xA2, 0xFD, 0x8F, + 0x6C, 0xAE, 0x6B, 0x6C, 0xD9, 0xB7, 0xDB, 0x24, + 0xC1, 0x7B, 0x44, 0x33, 0xF4, 0x34, 0x96, 0x3F, + 0x34, 0xB4 + }; + uint16_t mlen = M_LEN10; + TC_PRINT("%s: Performing CCM test #5 (RFC 3610 test vector #8):\n", + __func__); + result = do_test(key, nonce, sizeof(nonce), hdr, sizeof(hdr), + data, sizeof(data), expected, sizeof(expected), mlen); + return result; +} + +int test_vector_6(void) +{ + int result = TC_PASS; + /* RFC 3610 test vector #9 */ + const uint8_t key[NUM_NIST_KEYS] = + { + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF + }; + uint8_t nonce[NONCE_LEN] = + { + 0x00, 0x00, 0x00, 0x0B, 0x0A, 0x09, 0x08, 0xA0, + 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 + }; + const uint8_t hdr[HEADER_LEN] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + const uint8_t data[DATA_BUF_LEN25] = + { + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20 + }; + const uint8_t expected[EXPECTED_BUF_LEN35] = + { + 0x82, 0x53, 0x1a, 0x60, 0xCC, 0x24, 0x94, 0x5a, + 0x4b, 0x82, 0x79, 0x18, 0x1a, 0xb5, 0xc8, 0x4d, + 0xf2, 0x1c, 0xe7, 0xf9, 0xb7, 0x3f, 0x42, 0xe1, + 0x97, 0xea, 0x9c, 0x07, 0xe5, 0x6b, 0x5e, 0xb1, + 0x7e, 0x5f, 0x4e + }; + uint16_t mlen = M_LEN10; + TC_PRINT("%s: Performing CCM test #6 (RFC 3610 test vector #9):\n", + __func__); + result = do_test(key, nonce, sizeof(nonce), hdr, sizeof(hdr), + data, sizeof(data), expected, sizeof(expected), mlen); + return result; +} + +int test_vector_7(void) +{ + int result = TC_PASS; + /* Test based on RFC 3610 test vector #9 but with no associated data */ + const uint8_t key[NUM_NIST_KEYS] = + { + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF + }; + uint8_t nonce[NONCE_LEN] = + { + 0x00, 0x00, 0x00, 0x0B, 0x0A, 0x09, 0x08, 0xA0, + 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 + }; + uint8_t* hdr = NULL; + uint8_t data[DATA_BUF_LEN25] = + { + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20 + }; + struct tc_ccm_mode_struct c; + struct tc_aes_key_sched_struct sched; + uint8_t decrypted[TC_CCM_MAX_PT_SIZE]; + uint8_t ciphertext[TC_CCM_MAX_CT_SIZE]; + uint16_t mlen = M_LEN10; + TC_PRINT("%s: Performing CCM test #7 (no associated data):\n", + __func__); + tc_aes128_set_encrypt_key(&sched, key); + + if (tc_ccm_config(&c, &sched, nonce, sizeof(nonce), mlen) == 0) + { + TC_ERROR("ccm_config failed in %s.\n", __func__); + result = TC_FAIL; + goto exitTest1; + } + + result = tc_ccm_generation_encryption(ciphertext, TC_CCM_MAX_CT_SIZE, hdr, + 0, data, sizeof(data), &c); + + if (result == 0) + { + TC_ERROR("ccm_encryption failed in %s.\n", __func__); + result = TC_FAIL; + goto exitTest1; + } + + result = tc_ccm_decryption_verification (decrypted, TC_CCM_MAX_PT_SIZE, hdr, + 0, ciphertext, sizeof(data)+mlen, &c); + + if (result == 0) + { + TC_ERROR("ccm_decrypt failed in %s.\n", __func__); + show_str("\t\tExpected", data, sizeof(data)); + show_str("\t\tComputed", decrypted, sizeof(decrypted)); + result = TC_FAIL; + goto exitTest1; + } + + result = TC_PASS; +exitTest1: + TC_END_RESULT(result); + return result; +} + +int test_vector_8(void) +{ + int result = TC_PASS; + /* Test based on RFC 3610 test vector #9 but with no payload data */ + const uint8_t key[NUM_NIST_KEYS] = + { + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF + }; + uint8_t nonce[NONCE_LEN] = + { + 0x00, 0x00, 0x00, 0x0B, 0x0A, 0x09, 0x08, 0xA0, + 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 + }; + const uint8_t hdr[8] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + uint8_t* data = NULL; + struct tc_ccm_mode_struct c; + struct tc_aes_key_sched_struct sched; + uint8_t decrypted[TC_CCM_MAX_PT_SIZE]; + uint8_t ciphertext[TC_CCM_MAX_CT_SIZE]; + uint16_t mlen = M_LEN10; + TC_PRINT("%s: Performing CCM test #8 (no payload data):\n", __func__); + tc_aes128_set_encrypt_key(&sched, key); + + if (tc_ccm_config(&c, &sched, nonce, sizeof(nonce), mlen) == 0) + { + TC_ERROR("CCM config failed in %s.\n", __func__); + result = TC_FAIL; + goto exitTest1; + } + + result = tc_ccm_generation_encryption(ciphertext, TC_CCM_MAX_CT_SIZE, hdr, + sizeof(hdr), data, 0, &c); + + if (result == 0) + { + TC_ERROR("ccm_encrypt failed in %s.\n", __func__); + result = TC_FAIL; + goto exitTest1; + } + + result = tc_ccm_decryption_verification(decrypted, TC_CCM_MAX_PT_SIZE, hdr, + sizeof(hdr), ciphertext, mlen, &c); + + if (result == 0) + { + TC_ERROR("ccm_decrypt failed in %s.\n", __func__); + show_str("\t\tExpected", data, sizeof(data)); + show_str("\t\tComputed", decrypted, sizeof(decrypted)); + result = TC_FAIL; + goto exitTest1; + } + + result = TC_PASS; +exitTest1: + TC_END_RESULT(result); + return result; +} + +/* + Main task to test CCM +*/ +int main(void) +{ + int result = TC_PASS; + TC_START("Performing CCM tests:"); + result = test_vector_1(); + + if (result == TC_FAIL) /* terminate test */ + { + TC_ERROR("CCM test #1 (RFC 3610 test vector #1) failed.\n"); + goto exitTest; + } + + result = test_vector_2(); + + if (result == TC_FAIL) /* terminate test */ + { + TC_ERROR("CCM test #2 failed.\n"); + goto exitTest; + } + + result = test_vector_3(); + + if (result == TC_FAIL) /* terminate test */ + { + TC_ERROR("CCM test #3 failed.\n"); + goto exitTest; + } + + result = test_vector_4(); + + if (result == TC_FAIL) /* terminate test */ + { + TC_ERROR("CCM test #4 failed.\n"); + goto exitTest; + } + + result = test_vector_5(); + + if (result == TC_FAIL) /* terminate test */ + { + TC_ERROR("CCM test #5 failed.\n"); + goto exitTest; + } + + result = test_vector_6(); + + if (result == TC_FAIL) /* terminate test */ + { + TC_ERROR("CCM test #6 failed.\n"); + goto exitTest; + } + + result = test_vector_7(); + + if (result == TC_FAIL) /* terminate test */ + { + TC_ERROR("CCM test #7 failed.\n"); + goto exitTest; + } + + result = test_vector_8(); + + if (result == TC_FAIL) /* terminate test */ + { + TC_ERROR("CCM test #8 (no payload data) failed.\n"); + goto exitTest; + } + + TC_PRINT("All CCM tests succeeded!\n"); +exitTest: + TC_END_RESULT(result); + TC_END_REPORT(result); + return result; +} diff --git a/src/components/libraries/tinycrypt-0.2.8/tests/test_cmac_mode.c b/src/components/libraries/tinycrypt-0.2.8/tests/test_cmac_mode.c new file mode 100644 index 0000000..838eade --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/tests/test_cmac_mode.c @@ -0,0 +1,329 @@ +/* test_cmac_mode.c - TinyCrypt AES-CMAC tests (including SP 800-38B tests) */ + +/* + 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. +*/ +/* + DESCRIPTION + This module tests the following AES-CMAC test (including SP 800-38B): + + Scenarios tested include: + - CMAC test #1 (GF(2^128) double)) + - CMAC test #2 null msg (SP 800-38B test vector #1) + - CMAC test #3 1 block msg (SP 800-38B test vector #2) + - CMAC test #4 320 bit msg (SP 800-38B test vector #3) + - CMAC test #5 512 bit msg (SP 800-38B test vector #4) +*/ + +#include +#include +#include +#include + +#include +#include + +#define BUF_LEN 16 + +static void show(const char* label, const uint8_t* s, size_t slen) +{ + unsigned int i; + TC_PRINT("%s\t", label); + + for (i = 0; i < slen; ++i) + { + TC_PRINT("%02x", s[i]); + } + + TC_PRINT("\n"); +} + +extern void gf_double(uint8_t* out, uint8_t* in); + +static int verify_gf_2_128_double(uint8_t* K1, uint8_t* K2, + struct tc_cmac_struct s) +{ + int result = TC_PASS; + TC_PRINT("Performing CMAC test #1 (GF(2^128) double):\n"); + uint8_t zero[BUF_LEN]; + uint8_t L[BUF_LEN]; + const uint8_t l[BUF_LEN] = + { + 0x7d, 0xf7, 0x6b, 0x0c, 0x1a, 0xb8, 0x99, 0xb3, + 0x3e, 0x42, 0xf0, 0x47, 0xb9, 0x1b, 0x54, 0x6f + }; + const uint8_t k1[BUF_LEN] = + { + 0xfb, 0xee, 0xd6, 0x18, 0x35, 0x71, 0x33, 0x66, + 0x7c, 0x85, 0xe0, 0x8f, 0x72, 0x36, 0xa8, 0xde + }; + const uint8_t k2[BUF_LEN] = + { + 0xf7, 0xdd, 0xac, 0x30, 0x6a, 0xe2, 0x66, 0xcc, + 0xf9, 0x0b, 0xc1, 0x1e, 0xe4, 0x6d, 0x51, 0x3b + }; + (void) memset(zero, '\0', sizeof(zero)); + tc_aes_encrypt(L, zero, s.sched); + + if (memcmp(L, l, BUF_LEN) != 0) + { + TC_ERROR("%s: AES encryption failed\n", __func__); + show("expected L =", l, sizeof(l)); + show("computed L =", L, sizeof(L)); + return TC_FAIL; + } + + gf_double(K1, L); + + if (memcmp(K1, k1, BUF_LEN) != 0) + { + TC_ERROR("%s: gf_2_128_double failed when msb = 0\n", __func__); + show("expected K1 =", k1, sizeof(k1)); + show("computed K1 =", K1, sizeof(k1)); + return TC_FAIL; + } + + gf_double(K2, K1); + + if (memcmp(K2, k2, BUF_LEN) != 0) + { + TC_ERROR("%s: gf_2_128_double failed when msb = 1\n", __func__); + show("expected K2 =", k2, sizeof(k2)); + show("computed K2 =", K2, sizeof(k2)); + return TC_FAIL; + } + + TC_END_RESULT(result); + return result; +} + +static int verify_cmac_null_msg(TCCmacState_t s) +{ + int result = TC_PASS; + TC_PRINT("Performing CMAC test #2 (SP 800-38B test vector #1):\n"); + const uint8_t tag[BUF_LEN] = + { + 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, + 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 + }; + uint8_t Tag[BUF_LEN]; + (void) tc_cmac_init(s); + (void) tc_cmac_update(s, (const uint8_t*) 0, 0); + (void) tc_cmac_final(Tag, s); + + if (memcmp(Tag, tag, BUF_LEN) != 0) + { + TC_ERROR("%s: aes_cmac failed with null msg = 1\n", __func__); + show("expected Tag =", tag, sizeof(tag)); + show("computed Tag =", Tag, sizeof(Tag)); + return TC_FAIL; + } + + TC_END_RESULT(result); + return result; +} + +static int verify_cmac_1_block_msg(TCCmacState_t s) +{ + int result = TC_PASS; + TC_PRINT("Performing CMAC test #3 (SP 800-38B test vector #2):\n"); + const uint8_t msg[BUF_LEN] = + { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a + }; + const uint8_t tag[BUF_LEN] = + { + 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, + 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c + }; + uint8_t Tag[BUF_LEN]; + (void) tc_cmac_init(s); + (void) tc_cmac_update(s, msg, sizeof(msg)); + (void) tc_cmac_final(Tag, s); + + if (memcmp(Tag, tag, BUF_LEN) != 0) + { + TC_ERROR("%s: aes_cmac failed with 1 block msg\n", __func__); + show("aes_cmac failed with 1 block msg =", msg, sizeof(msg)); + show("expected Tag =", tag, sizeof(tag)); + show("computed Tag =", Tag, sizeof(Tag)); + return TC_FAIL; + } + + TC_END_RESULT(result); + return result; +} + +static int verify_cmac_320_bit_msg(TCCmacState_t s) +{ + int result = TC_PASS; + TC_PRINT("Performing CMAC test #4 (SP 800-38B test vector #3):\n"); + const uint8_t msg[40] = + { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11 + }; + const uint8_t tag[BUF_LEN] = + { + 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, + 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27 + }; + uint8_t Tag[BUF_LEN]; + (void) tc_cmac_init(s); + (void) tc_cmac_update(s, msg, sizeof(msg)); + (void) tc_cmac_final(Tag, s); + + if (memcmp(Tag, tag, BUF_LEN) != 0) + { + TC_ERROR("%s: aes_cmac failed with 320 bit msg\n", __func__); + show("aes_cmac failed with 320 bit msg =", msg, sizeof(msg)); + show("expected Tag =", tag, sizeof(tag)); + show("computed Tag =", Tag, sizeof(Tag)); + return TC_FAIL; + } + + TC_END_RESULT(result); + return result; +} + +static int verify_cmac_512_bit_msg(TCCmacState_t s) +{ + int result = TC_PASS; + TC_PRINT("Performing CMAC test #5 (SP 800-38B test vector #4)\n"); + const uint8_t msg[64] = + { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 + }; + const uint8_t tag[BUF_LEN] = + { + 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, + 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe + }; + uint8_t Tag[BUF_LEN]; + (void)tc_cmac_init(s); + (void)tc_cmac_update(s, msg, sizeof(msg)); + (void)tc_cmac_final(Tag, s); + + if (memcmp(Tag, tag, BUF_LEN) != 0) + { + TC_ERROR("%s: aes_cmac failed with 512 bit msg\n", __func__); + show("aes_cmac failed with 512 bit msg =", msg, sizeof(msg)); + show("expected Tag =", tag, sizeof(tag)); + show("computed Tag =", Tag, sizeof(Tag)); + return TC_FAIL; + } + + TC_END_RESULT(result); + return result; +} + +/* + Main task to test CMAC + effects: returns 1 if all tests pass + exceptions: returns a negative value if some test fails +*/ +int main(void) +{ + int result = TC_PASS; + struct tc_cmac_struct state; + struct tc_aes_key_sched_struct sched; + const uint8_t key[BUF_LEN] = + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }; + uint8_t K1[BUF_LEN], K2[BUF_LEN]; + TC_START("Performing CMAC tests:"); + (void) tc_cmac_setup(&state, key, &sched); + result = verify_gf_2_128_double(K1, K2, state); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("CMAC test #1 (128 double) failed.\n"); + goto exitTest; + } + + (void) tc_cmac_setup(&state, key, &sched); + result = verify_cmac_null_msg(&state); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("CMAC test #2 (null msg) failed.\n"); + goto exitTest; + } + + (void) tc_cmac_setup(&state, key, &sched); + result = verify_cmac_1_block_msg(&state); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("CMAC test #3 (1 block msg)failed.\n"); + goto exitTest; + } + + (void) tc_cmac_setup(&state, key, &sched); + result = verify_cmac_320_bit_msg(&state); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("CMAC test #4 (320 bit msg) failed.\n"); + goto exitTest; + } + + (void) tc_cmac_setup(&state, key, &sched); + result = verify_cmac_512_bit_msg(&state); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("CMAC test #5 (512 bit msg)failed.\n"); + goto exitTest; + } + + TC_PRINT("All CMAC tests succeeded!\n"); +exitTest: + TC_END_RESULT(result); + TC_END_REPORT(result); + return result; +} diff --git a/src/components/libraries/tinycrypt-0.2.8/tests/test_ctr_mode.c b/src/components/libraries/tinycrypt-0.2.8/tests/test_ctr_mode.c new file mode 100644 index 0000000..65c1844 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/tests/test_ctr_mode.c @@ -0,0 +1,141 @@ +/* test_ctr_mode.c - TinyCrypt implementation of some AES-CTR tests */ + +/* + 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. +*/ + +/* + DESCRIPTION + This module tests the following AES-CTR Mode routines: + + Scenarios tested include: + - AES128 CTR mode encryption SP 800-38a tests +*/ + +#include +#include +#include +#include + +#include +#include +#include + +/* + NIST SP 800-38a CTR Test for encryption and decryption. +*/ +unsigned int test_1_and_2(void) +{ + const uint8_t key[16] = + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, + 0x09, 0xcf, 0x4f, 0x3c + }; + uint8_t ctr[16] = + { + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, + 0xfc, 0xfd, 0xfe, 0xff + }; + const uint8_t plaintext[64] = + { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, + 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, + 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, + 0xe6, 0x6c, 0x37, 0x10 + }; + const uint8_t ciphertext[80] = + { + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, + 0xfc, 0xfd, 0xfe, 0xff, 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, + 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce, 0x98, 0x06, 0xf6, 0x6b, + 0x79, 0x70, 0xfd, 0xff, 0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff, + 0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e, 0x5b, 0x4f, 0x09, 0x02, + 0x0d, 0xb0, 0x3e, 0xab, 0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1, + 0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee + }; + struct tc_aes_key_sched_struct sched; + uint8_t out[80]; + uint8_t decrypted[64]; + unsigned int result = TC_PASS; + TC_PRINT("CTR test #1 (encryption SP 800-38a tests):\n"); + (void)tc_aes128_set_encrypt_key(&sched, key); + (void)memcpy(out, ctr, sizeof(ctr)); + + if (tc_ctr_mode(&out[TC_AES_BLOCK_SIZE], sizeof(plaintext), plaintext, + sizeof(plaintext), ctr, &sched) == 0) + { + TC_ERROR("CTR test #1 (encryption SP 800-38a tests) failed in %s.\n", __func__); + result = TC_FAIL; + goto exitTest1; + } + + result = check_result(1, ciphertext, sizeof(out), out, sizeof(out)); + TC_END_RESULT(result); + TC_PRINT("CTR test #2 (decryption SP 800-38a tests):\n"); + (void) memcpy(ctr, out, sizeof(ctr)); + + if (tc_ctr_mode(decrypted, sizeof(decrypted), &out[TC_AES_BLOCK_SIZE], + sizeof(decrypted), ctr, &sched) == 0) + { + TC_ERROR("CTR test #2 (decryption SP 800-38a tests) failed in %s.\n", __func__); + result = TC_FAIL; + goto exitTest1; + } + + result = check_result(2, plaintext, sizeof(plaintext), + decrypted, sizeof(plaintext)); +exitTest1: + TC_END_RESULT(result); + return result; +} + +/* + Main task to test AES +*/ + +int main(void) +{ + unsigned int result = TC_PASS; + TC_START("Performing AES128-CTR mode tests:"); + TC_PRINT("Performing CTR tests:\n"); + result = test_1_and_2(); + + if (result == TC_FAIL) /* terminate test */ + { + TC_ERROR("CBC test #1 failed.\n"); + goto exitTest; + } + + TC_PRINT("All CTR tests succeeded!\n"); +exitTest: + TC_END_RESULT(result); + TC_END_REPORT(result); +} diff --git a/src/components/libraries/tinycrypt-0.2.8/tests/test_ctr_prng.c b/src/components/libraries/tinycrypt-0.2.8/tests/test_ctr_prng.c new file mode 100644 index 0000000..5d54278 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/tests/test_ctr_prng.c @@ -0,0 +1,628 @@ +/* test_ctr_prng.c - TinyCrypt implementation of some CTR-PRNG tests */ + +/* + 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 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. +*/ + +/* + DESCRIPTION + This module tests the CTR-PRNG routines +*/ + +#include +#include +#include +#include + + +#include +#include +#include + +/* utility function to convert hex character representation to their nibble (4 bit) values */ +static uint8_t nibbleFromChar(char c) +{ + if(c >= '0' && c <= '9') return c - '0'; + + if(c >= 'a' && c <= 'f') return c - 'a' + 10U; + + if(c >= 'A' && c <= 'F') return c - 'A' + 10U; + + return 255U; +} + +/* + Convert a string of characters representing a hex buffer into a series of + bytes of that real value +*/ +uint8_t* hexStringToBytes(char* inhex) +{ + uint8_t* retval; + uint8_t* p; + int len, i; + len = strlen(inhex) / 2; + retval = (uint8_t*)malloc(len+1); + + for(i=0, p = (uint8_t*) inhex; i +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +int ecdh_vectors(char** qx_vec, char** qy_vec, char** d_vec, char** z_vec, + int tests, int verbose) +{ + unsigned int pub[2*NUM_ECC_WORDS]; + unsigned int prv[NUM_ECC_WORDS]; + unsigned int z[NUM_ECC_WORDS]; + unsigned int result = TC_PASS; + int rc; + unsigned int exp_z[NUM_ECC_WORDS]; + const struct uECC_Curve_t* curve = uECC_secp256r1(); + + for (int i = 0; i < tests; i++) + { + string2scalar(pub + NUM_ECC_WORDS, NUM_ECC_WORDS, qx_vec[i]); + string2scalar(pub, NUM_ECC_WORDS, qy_vec[i]); + string2scalar(exp_z, NUM_ECC_WORDS, z_vec[i]); + string2scalar(prv, NUM_ECC_WORDS, d_vec[i]); + uint8_t pub_bytes[2*NUM_ECC_BYTES]; + uECC_vli_nativeToBytes(pub_bytes, 2*NUM_ECC_BYTES, pub); + uint8_t private_bytes[NUM_ECC_BYTES]; + uECC_vli_nativeToBytes(private_bytes, NUM_ECC_BYTES, prv); + uint8_t z_bytes[NUM_ECC_BYTES]; + uECC_vli_nativeToBytes(z_bytes, NUM_ECC_BYTES, exp_z); + rc = uECC_shared_secret(pub_bytes, private_bytes, z_bytes, curve); + + if (rc == TC_CRYPTO_FAIL) + { + TC_ERROR("ECDH failure, exit.\n"); + result = TC_FAIL; + return result;; + } + + uECC_vli_bytesToNative(z, z_bytes, NUM_ECC_BYTES); + result = check_ecc_result(i, "Z", exp_z, z, NUM_ECC_WORDS, verbose); + + if (result == TC_FAIL) + { + return result; + } + } + + return result; +} + +int cavp_ecdh(bool verbose) +{ + unsigned int result = TC_PASS; + /* + P-256 + */ + char* d[] = + { + "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534", + "38f65d6dce47676044d58ce5139582d568f64bb16098d179dbab07741dd5caf5", + "1accfaf1b97712b85a6f54b148985a1bdc4c9bec0bd258cad4b3d603f49f32c8", + "207c43a79bfee03db6f4b944f53d2fb76cc49ef1c9c4d34d51b6c65c4db6932d", + "59137e38152350b195c9718d39673d519838055ad908dd4757152fd8255c09bf", + "f5f8e0174610a661277979b58ce5c90fee6c9b3bb346a90a7196255e40b132ef", + "3b589af7db03459c23068b64f63f28d3c3c6bc25b5bf76ac05f35482888b5190", + "d8bf929a20ea7436b2461b541a11c80e61d826c0a4c9d322b31dd54e7f58b9c8", + "0f9883ba0ef32ee75ded0d8bda39a5146a29f1f2507b3bd458dbea0b2bb05b4d", + "2beedb04b05c6988f6a67500bb813faf2cae0d580c9253b6339e4a3337bb6c08", + "77c15dcf44610e41696bab758943eff1409333e4d5a11bbe72c8f6c395e9f848", + "42a83b985011d12303db1a800f2610f74aa71cdf19c67d54ce6c9ed951e9093e", + "ceed35507b5c93ead5989119b9ba342cfe38e6e638ba6eea343a55475de2800b", + "43e0e9d95af4dc36483cdd1968d2b7eeb8611fcce77f3a4e7d059ae43e509604", + "b2f3600df3368ef8a0bb85ab22f41fc0e5f4fdd54be8167a5c3cd4b08db04903", + "4002534307f8b62a9bf67ff641ddc60fef593b17c3341239e95bdb3e579bfdc8", + "4dfa12defc60319021b681b3ff84a10a511958c850939ed45635934ba4979147", + "1331f6d874a4ed3bc4a2c6e9c74331d3039796314beee3b7152fcdba5556304e", + "dd5e9f70ae740073ca0204df60763fb6036c45709bf4a7bb4e671412fad65da3", + "5ae026cfc060d55600717e55b8a12e116d1d0df34af831979057607c2d9c2f76", + "b601ac425d5dbf9e1735c5e2d5bdb79ca98b3d5be4a2cfd6f2273f150e064d9d", + "fefb1dda1845312b5fce6b81b2be205af2f3a274f5a212f66c0d9fc33d7ae535", + "334ae0c4693d23935a7e8e043ebbde21e168a7cba3fa507c9be41d7681e049ce", + "2c4bde40214fcc3bfc47d4cf434b629acbe9157f8fd0282540331de7942cf09d", + "85a268f9d7772f990c36b42b0a331adc92b5941de0b862d5d89a347cbf8faab0", + }; + char* x[] = + { + "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287", + "809f04289c64348c01515eb03d5ce7ac1a8cb9498f5caa50197e58d43a86a7ae", + "a2339c12d4a03c33546de533268b4ad667debf458b464d77443636440ee7fec3", + "df3989b9fa55495719b3cf46dccd28b5153f7808191dd518eff0c3cff2b705ed", + "41192d2813e79561e6a1d6f53c8bc1a433a199c835e141b05a74a97b0faeb922", + "33e82092a0f1fb38f5649d5867fba28b503172b7035574bf8e5b7100a3052792", + "6a9e0c3f916e4e315c91147be571686d90464e8bf981d34a90b6353bca6eeba7", + "a9c0acade55c2a73ead1a86fb0a9713223c82475791cd0e210b046412ce224bb", + "94e94f16a98255fff2b9ac0c9598aac35487b3232d3231bd93b7db7df36f9eb9", + "e099bf2a4d557460b5544430bbf6da11004d127cb5d67f64ab07c94fcdf5274f", + "f75a5fe56bda34f3c1396296626ef012dc07e4825838778a645c8248cff01658", + "2db4540d50230756158abf61d9835712b6486c74312183ccefcaef2797b7674d", + "cd94fc9497e8990750309e9a8534fd114b0a6e54da89c4796101897041d14ecb", + "15b9e467af4d290c417402e040426fe4cf236bae72baa392ed89780dfccdb471", + "49c503ba6c4fa605182e186b5e81113f075bc11dcfd51c932fb21e951eee2fa1", + "19b38de39fdd2f70f7091631a4f75d1993740ba9429162c2a45312401636b29c", + "2c91c61f33adfe9311c942fdbff6ba47020feff416b7bb63cec13faf9b099954", + "a28a2edf58025668f724aaf83a50956b7ac1cfbbff79b08c3bf87dfd2828d767", + "a2ef857a081f9d6eb206a81c4cf78a802bdf598ae380c8886ecd85fdc1ed7644", + "ccd8a2d86bc92f2e01bce4d6922cf7fe1626aed044685e95e2eebd464505f01f", + "c188ffc8947f7301fb7b53e36746097c2134bf9cc981ba74b4e9c4361f595e4e", + "317e1020ff53fccef18bf47bb7f2dd7707fb7b7a7578e04f35b3beed222a0eb6", + "45fb02b2ceb9d7c79d9c2fa93e9c7967c2fa4df5789f9640b24264b1e524fcb1", + "a19ef7bff98ada781842fbfc51a47aff39b5935a1c7d9625c8d323d511c92de6", + "356c5a444c049a52fee0adeb7e5d82ae5aa83030bfff31bbf8ce2096cf161c4b", + }; + char* y[] = + { + "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac", + "b29d84e811197f25eba8f5194092cb6ff440e26d4421011372461f579271cda3", + "ef48a3ab26e20220bcda2c1851076839dae88eae962869a497bf73cb66faf536", + "422294ff46003429d739a33206c8752552c8ba54a270defc06e221e0feaf6ac4", + "1af98cc45e98a7e041b01cf35f462b7562281351c8ebf3ffa02e33a0722a1328", + "f2cf6b601e0a05945e335550bf648d782f46186c772c0f20d3cd0d6b8ca14b2f", + "40f9bead39c2f2bcc2602f75b8a73ec7bdffcbcead159d0174c6c4d3c5357f05", + "f6de0afa20e93e078467c053d241903edad734c6b403ba758c2b5ff04c9d4229", + "d8049a43579cfa90b8093a94416cbefbf93386f15b3f6e190b6e3455fedfe69a", + "d9c50dbe70d714edb5e221f4e020610eeb6270517e688ca64fb0e98c7ef8c1c5", + "33bbdf1b1772d8059df568b061f3f1122f28a8d819167c97be448e3dc3fb0c3c", + "62f57f314e3f3495dc4e099012f5e0ba71770f9660a1eada54104cdfde77243e", + "c3def4b5fe04faee0a11932229fff563637bfdee0e79c6deeaf449f85401c5c4", + "cdf4e9170fb904302b8fd93a820ba8cc7ed4efd3a6f2d6b05b80b2ff2aee4e77", + "8af706ff0922d87b3f0c5e4e31d8b259aeb260a9269643ed520a13bb25da5924", + "09aed7232b28e060941741b6828bcdfa2bc49cc844f3773611504f82a390a5ae", + "6cab31b06419e5221fca014fb84ec870622a1b12bab5ae43682aa7ea73ea08d0", + "dfa7bfffd4c766b86abeaf5c99b6e50cb9ccc9d9d00b7ffc7804b0491b67bc03", + "563c4c20419f07bc17d0539fade1855e34839515b892c0f5d26561f97fa04d1a", + "e9ddd583a9635a667777d5b8a8f31b0f79eba12c75023410b54b8567dddc0f38", + "bf7d2f2056e72421ef393f0c0f2b0e00130e3cac4abbcc00286168e85ec55051", + "09420ce5a19d77c6fe1ee587e6a49fbaf8f280e8df033d75403302e5a27db2ae", + "5c6e8ecf1f7d3023893b7b1ca1e4d178972ee2a230757ddc564ffe37f5c5a321", + "e9c184df75c955e02e02e400ffe45f78f339e1afe6d056fb3245f4700ce606ef", + "57d128de8b2a57a094d1a001e572173f96e8866ae352bf29cddaf92fc85b2f92", + }; + char* Z[] = + { + "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b", + "057d636096cb80b67a8c038c890e887d1adfa4195e9b3ce241c8a778c59cda67", + "2d457b78b4614132477618a5b077965ec90730a8c81a1c75d6d4ec68005d67ec", + "96441259534b80f6aee3d287a6bb17b5094dd4277d9e294f8fe73e48bf2a0024", + "19d44c8d63e8e8dd12c22a87b8cd4ece27acdde04dbf47f7f27537a6999a8e62", + "664e45d5bba4ac931cd65d52017e4be9b19a515f669bea4703542a2c525cd3d3", + "ca342daa50dc09d61be7c196c85e60a80c5cb04931746820be548cdde055679d", + "35aa9b52536a461bfde4e85fc756be928c7de97923f0416c7a3ac8f88b3d4489", + "605c16178a9bc875dcbff54d63fe00df699c03e8a888e9e94dfbab90b25f39b4", + "f96e40a1b72840854bb62bc13c40cc2795e373d4e715980b261476835a092e0b", + "8388fa79c4babdca02a8e8a34f9e43554976e420a4ad273c81b26e4228e9d3a3", + "72877cea33ccc4715038d4bcbdfe0e43f42a9e2c0c3b017fc2370f4b9acbda4a", + "e4e7408d85ff0e0e9c838003f28cdbd5247cdce31f32f62494b70e5f1bc36307", + "ed56bcf695b734142c24ecb1fc1bb64d08f175eb243a31f37b3d9bb4407f3b96", + "bc5c7055089fc9d6c89f83c1ea1ada879d9934b2ea28fcf4e4a7e984b28ad2cf", + "9a4e8e657f6b0e097f47954a63c75d74fcba71a30d83651e3e5a91aa7ccd8343", + "3ca1fc7ad858fb1a6aba232542f3e2a749ffc7203a2374a3f3d3267f1fc97b78", + "1aaabe7ee6e4a6fa732291202433a237df1b49bc53866bfbe00db96a0f58224f", + "430e6a4fba4449d700d2733e557f66a3bf3d50517c1271b1ddae1161b7ac798c", + "1ce9e6740529499f98d1f1d71329147a33df1d05e4765b539b11cf615d6974d3", + "4690e3743c07d643f1bc183636ab2a9cb936a60a802113c49bb1b3f2d0661660", + "30c2261bd0004e61feda2c16aa5e21ffa8d7e7f7dbf6ec379a43b48e4b36aeb0", + "2adae4a138a239dcd93c243a3803c3e4cf96e37fe14e6a9b717be9599959b11c", + "2e277ec30f5ea07d6ce513149b9479b96e07f4b6913b1b5c11305c1444a1bc0b", + "1e51373bd2c6044c129c436e742a55be2a668a85ae08441b6756445df5493857", + }; + TC_PRINT("Test #1: ECDH"); + TC_PRINT("NIST-p256\n"); + result = ecdh_vectors(x, y, d, Z, 25, verbose); + + if(result == TC_FAIL) + { + goto exitTest1; + } + +exitTest1: + TC_END_RESULT(result); + return result; +} + +int cavp_keygen(bool verbose) +{ + unsigned int result = TC_PASS; + /* + [P-256, B.4.2 Key Pair Generation by Testing Candidates] + */ + char* d[] = + { + "c9806898a0334916c860748880a541f093b579a9b1f32934d86c363c39800357", + "710735c8388f48c684a97bd66751cc5f5a122d6b9a96a2dbe73662f78217446d", + "78d5d8b7b3e2c16b3e37e7e63becd8ceff61e2ce618757f514620ada8a11f6e4", + "2a61a0703860585fe17420c244e1de5a6ac8c25146b208ef88ad51ae34c8cb8c", + "01b965b45ff386f28c121c077f1d7b2710acc6b0cb58d8662d549391dcf5a883", + "fac92c13d374c53a085376fe4101618e1e181b5a63816a84a0648f3bdc24e519", + "f257a192dde44227b3568008ff73bcf599a5c45b32ab523b5b21ca582fef5a0a", + "add67e57c42a3d28708f0235eb86885a4ea68e0d8cfd76eb46134c596522abfd", + "4494860fd2c805c5c0d277e58f802cff6d731f76314eb1554142a637a9bc5538", + "d40b07b1ea7b86d4709ef9dc634c61229feb71abd63dc7fc85ef46711a87b210", + }; + char* x[] = + { + "d0720dc691aa80096ba32fed1cb97c2b620690d06de0317b8618d5ce65eb728f", + "f6836a8add91cb182d8d258dda6680690eb724a66dc3bb60d2322565c39e4ab9", + "76711126cbb2af4f6a5fe5665dad4c88d27b6cb018879e03e54f779f203a854e", + "e1aa7196ceeac088aaddeeba037abb18f67e1b55c0a5c4e71ec70ad666fcddc8", + "1f038c5422e88eec9e88b815e8f6b3e50852333fc423134348fc7d79ef8e8a10", + "7258f2ab96fc84ef6ccb33e308cd392d8b568ea635730ceb4ebd72fa870583b9", + "d2e01411817b5512b79bbbe14d606040a4c90deb09e827d25b9f2fc068997872", + "55bed2d9c029b7f230bde934c7124ed52b1330856f13cbac65a746f9175f85d7", + "5190277a0c14d8a3d289292f8a544ce6ea9183200e51aec08440e0c1a463a4e4", + "fbcea7c2827e0e8085d7707b23a3728823ea6f4878b24747fb4fd2842d406c73", + }; + char* y[] = + { + "9681b517b1cda17d0d83d335d9c4a8a9a9b0b1b3c7106d8f3c72bc5093dc275f", + "1f837aa32864870cb8e8d0ac2ff31f824e7beddc4bb7ad72c173ad974b289dc2", + "a26df39960ab5248fd3620fd018398e788bd89a3cea509b352452b69811e6856", + "d7d35bdce6dedc5de98a7ecb27a9cd066a08f586a733b59f5a2cdb54f971d5c8", + "43a047cb20e94b4ffb361ef68952b004c0700b2962e0c0635a70269bc789b849", + "489807ca55bdc29ca5c8fe69b94f227b0345cccdbe89975e75d385cc2f6bb1e2", + "503f138f8bab1df2c4507ff663a1fdf7f710e7adb8e7841eaa902703e314e793", + "32805e311d583b4e007c40668185e85323948e21912b6b0d2cda8557389ae7b0", + "ecd98514821bd5aaf3419ab79b71780569470e4fed3da3c1353b28fe137f36eb", + "2393c85f1f710c5afc115a39ba7e18abe03f19c9d4bb3d47d19468b818efa535", + }; + TC_PRINT("Test #2: ECC KeyGen "); + TC_PRINT("NIST-p256\n"); + result = keygen_vectors(d, x, y, 10, verbose); + + if(result == TC_FAIL) + { + goto exitTest1; + } + +exitTest1: + TC_END_RESULT(result); + return result; +} + +/* Test ecc_make_keys, and also as keygen part of other tests */ +int pkv_vectors(char** qx_vec, char** qy_vec, char** res_vec, int tests, + bool verbose) +{ + unsigned int pub[2 * NUM_ECC_WORDS]; + uint8_t _public[2 * NUM_ECC_BYTES]; + int rc; + int exp_rc; + char tmp; + unsigned int result = TC_PASS; + const struct uECC_Curve_t* curve = uECC_secp256r1(); + + for (int i = 0; i < tests; i++) + { + if (2 != sscanf(res_vec[i], "%c (%d ", &tmp, &exp_rc)) + { + TC_ERROR("Error: failed to parse CAVP response.\n"); + result = TC_FAIL; + goto exitTest1; + } + + if (strlen(qx_vec[i]) > 2 * NUM_ECC_BYTES || + strlen(qy_vec[i]) > 2 * NUM_ECC_BYTES) + { + /* invalid input to ECC digit conversion (string2native()) */ + rc = -2; + } + else + { + string2scalar(pub, NUM_ECC_WORDS, qx_vec[i]); + string2scalar(pub + NUM_ECC_WORDS, NUM_ECC_WORDS, qy_vec[i]); + uECC_vli_nativeToBytes(_public, NUM_ECC_BYTES, pub); + uECC_vli_nativeToBytes(_public + NUM_ECC_BYTES, NUM_ECC_BYTES, pub+NUM_ECC_WORDS); + rc = uECC_valid_public_key(_public, curve); + } + + /* + map to CAVP error codes + 0 => 0 - success + -1 => ? - (x,y) = (0,0) (not covered) + -2 => 1 - out of bounds (pubverify or ecc import) + -3 => 2 - not on curve + -4 => ? - public key is the group generator + */ + + if (rc == -3) rc = 2; + + if (rc == -2) rc = 1; + + result = check_code(i, res_vec[i], exp_rc, rc, verbose); + + if(result == TC_FAIL) + { + goto exitTest1; + } + } + +exitTest1: + TC_END_RESULT(result); + return result; +} + +int cavp_pkv(bool verbose) +{ + /* + [P-256] + */ + char* x[] = + { + "e0f7449c5588f24492c338f2bc8f7865f755b958d48edb0f2d0056e50c3fd5b7", + "d17c446237d9df87266ba3a91ff27f45abfdcb77bfd83536e92903efb861a9a9", + "17875397ae87369365656d490e8ce956911bd97607f2aff41b56f6f3a61989826", + "f2d1c0dc0852c3d8a2a2500a23a44813ccce1ac4e58444175b440469ffc12273", + "10b0ca230fff7c04768f4b3d5c75fa9f6c539bea644dffbec5dc796a213061b58", + "2c1052f25360a15062d204a056274e93cbe8fc4c4e9b9561134ad5c15ce525da", + "a40d077a87dae157d93dcccf3fe3aca9c6479a75aa2669509d2ef05c7de6782f", + "2633d398a3807b1895548adbb0ea2495ef4b930f91054891030817df87d4ac0a", + "14bf57f76c260b51ec6bbc72dbd49f02a56eaed070b774dc4bad75a54653c3d56", + "2fa74931ae816b426f484180e517f5050c92decfc8daf756cd91f54d51b302f1", + "f8c6dd3181a76aa0e36c2790bba47041acbe7b1e473ff71eee39a824dc595ff0", + "7a81a7e0b015252928d8b36e4ca37e92fdc328eb25c774b4f872693028c4be38", + }; + char* y[] = + { + "86d7e9255d0f4b6f44fa2cd6f8ba3c0aa828321d6d8cc430ca6284ce1d5b43a0", + "1eabb6a349ce2cd447d777b6739c5fc066add2002d2029052c408d0701066231c", + "980a3c4f61b9692633fbba5ef04c9cb546dd05cdec9fa8428b8849670e2fba92", + "32bfe992831b305d8c37b9672df5d29fcb5c29b4a40534683e3ace23d24647dd", + "f5edf37c11052b75f771b7f9fa050e353e464221fec916684ed45b6fead38205", + "ced9783713a8a2a09eff366987639c625753295d9a85d0f5325e32dedbcada0b", + "503d86b87d743ba20804fd7e7884aa017414a7b5b5963e0d46e3a9611419ddf3", + "d6b2f738e3873cc8364a2d364038ce7d0798bb092e3dd77cbdae7c263ba618d2", + "7a231a23bf8b3aa31d9600d888a0678677a30e573decd3dc56b33f365cc11236", + "5b994346137988c58c14ae2152ac2f6ad96d97decb33099bd8a0210114cd1141", + "9c965f227f281b3072b95b8daf29e88b35284f3574462e268e529bbdc50e9e52", + "08862f7335147261e7b1c3d055f9a316e4cab7daf99cc09d1c647f5dd6e7d5bb", + }; + char* Result[] = + { + "P (0 )", "F (1 - Q_x or Q_y out of range)", + "F (1 - Q_x or Q_y out of range)", "F (2 - Point not on curve)", + "F (1 - Q_x or Q_y out of range)", "P (0 )", + "F (2 - Point not on curve)", "P (0 )", + "F (1 - Q_x or Q_y out of range)", "P (0 )", + "F (2 - Point not on curve)", "F (2 - Point not on curve)", + }; + TC_PRINT("Test #3: PubKeyVerify "); + TC_PRINT("NIST-p256-SHA2-256\n"); + return pkv_vectors(x, y, Result, 12, verbose); +} + +int montecarlo_ecdh(int num_tests, bool verbose) +{ + int i; + uint8_t private1[NUM_ECC_BYTES] = {0}; + uint8_t private2[NUM_ECC_BYTES] = {0}; + uint8_t public1[2*NUM_ECC_BYTES] = {0}; + uint8_t public2[2*NUM_ECC_BYTES] = {0}; + uint8_t secret1[NUM_ECC_BYTES] = {0}; + uint8_t secret2[NUM_ECC_BYTES] = {0}; + unsigned int result = TC_PASS; + const struct uECC_Curve_t* curve = uECC_secp256r1(); + TC_PRINT("Test #4: Monte Carlo (%d Randomized EC-DH key-exchange) ", num_tests); + TC_PRINT("NIST-p256\n "); + + for (i = 0; i < num_tests; ++i) + { + if (verbose) + { + TC_PRINT("."); + fflush(stdout); + } + + if (!uECC_make_key(public1, private1, curve) || + !uECC_make_key(public2, private2, curve)) + { + TC_ERROR("uECC_make_key() failed\n"); + result = TC_FAIL; + goto exitTest1; + } + + if (!uECC_shared_secret(public2, private1, secret1, curve)) + { + TC_ERROR("shared_secret() failed (1)\n"); + result = TC_FAIL; + goto exitTest1;; + } + + if (!uECC_shared_secret(public1, private2, secret2, curve)) + { + TC_ERROR("shared_secret() failed (2)\n"); + result = TC_FAIL; + goto exitTest1; + } + + if (memcmp(secret1, secret2, sizeof(secret1)) != 0) + { + TC_PRINT("Shared secrets are not identical!\n"); + TC_PRINT("Private key 1 = "); + vli_print_bytes(private1, 32); + TC_PRINT("\nPrivate key 2 = "); + vli_print_bytes(private2, 32); + TC_PRINT("\nPublic key 1 = "); + vli_print_bytes(public1, 64); + TC_PRINT("\nPublic key 2 = "); + vli_print_bytes(public2, 64); + TC_PRINT("\nShared secret 1 = "); + vli_print_bytes(secret1, 32); + TC_PRINT("\nShared secret 2 = "); + vli_print_bytes(secret2, 32); + TC_PRINT("\n"); + } + } + + TC_PRINT("\n"); +exitTest1: + TC_END_RESULT(result); + return result; +} + +int main() +{ + unsigned int result = TC_PASS; + TC_START("Performing ECC-DH tests:"); + /* Setup of the Cryptographically Secure PRNG. */ + uECC_set_rng(&default_CSPRNG); + bool verbose = true; + TC_PRINT("Performing cavp_ecdh test:\n"); + result = cavp_ecdh(verbose); + + if (result == TC_FAIL) /* terminate test */ + { + TC_ERROR("cavp_ecdh test failed.\n"); + goto exitTest; + } + + TC_PRINT("Performing cavp_keygen test:\n"); + result = cavp_keygen(verbose); + + if (result == TC_FAIL) /* terminate test */ + { + TC_ERROR("cavp_keygen test failed.\n"); + goto exitTest; + } + + TC_PRINT("Performing cavp_pkv test:\n"); + result = cavp_pkv(verbose); + + if (result == TC_FAIL) /* terminate test */ + { + TC_ERROR("cavp_pkv failed.\n"); + goto exitTest; + } + + TC_PRINT("Performing montecarlo_ecdh test:\n"); + result = montecarlo_ecdh(10, verbose); + + if (result == TC_FAIL) /* terminate test */ + { + TC_ERROR("montecarlo_ecdh test failed.\n"); + goto exitTest; + } + + TC_PRINT("All EC-DH tests succeeded!\n"); +exitTest: + TC_END_RESULT(result); + TC_END_REPORT(result); +} diff --git a/src/components/libraries/tinycrypt-0.2.8/tests/test_ecc_dsa.c b/src/components/libraries/tinycrypt-0.2.8/tests/test_ecc_dsa.c new file mode 100644 index 0000000..1c6636c --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/tests/test_ecc_dsa.c @@ -0,0 +1,682 @@ +/* test_ecc_ecdsa.c - TinyCrypt implementation of some EC-DSA tests */ + +/* 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. + + test_ecc_ecdsa.c -- Implementation of some EC-DSA tests + +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +/* Maximum size of message to be signed. */ +#define BUF_SIZE 256 + +int sign_vectors(TCSha256State_t hash, char** d_vec, char** k_vec, + char** msg_vec, char** qx_vec, char** qy_vec, char** r_vec, + char** s_vec, int tests, bool verbose) +{ + unsigned int k[NUM_ECC_WORDS]; + unsigned int private[NUM_ECC_WORDS]; + uint8_t private_bytes[NUM_ECC_BYTES]; + unsigned int sig[2 * NUM_ECC_WORDS]; + uint8_t sig_bytes[2 * NUM_ECC_BYTES]; + unsigned int digest[TC_SHA256_DIGEST_SIZE / 4]; + uint8_t digest_bytes[TC_SHA256_DIGEST_SIZE]; + unsigned int result = TC_PASS; + /* expected outputs (converted input vectors) */ + unsigned int exp_r[NUM_ECC_WORDS]; + unsigned int exp_s[NUM_ECC_WORDS]; + uint8_t msg[BUF_SIZE]; + size_t msglen; + + for (int i = 0; i < tests; i++) + { + /* use keygen test to generate and validate pubkey */ + keygen_vectors(d_vec+i, qx_vec+i, qy_vec+i, 1, false); + string2scalar(private, NUM_ECC_WORDS, d_vec[i]); + uECC_vli_nativeToBytes(private_bytes, NUM_ECC_BYTES, private); + /* validate ECDSA: hash message, sign digest, check r+s */ + memset(k, 0, NUM_ECC_BYTES); + string2scalar(k, NUM_ECC_WORDS, k_vec[i]); + string2scalar(exp_r, NUM_ECC_WORDS, r_vec[i]); + string2scalar(exp_s, NUM_ECC_WORDS, s_vec[i]); + msglen = hex2bin(msg, BUF_SIZE, msg_vec[i], strlen(msg_vec[i])); + + if (msglen == false) + { + TC_ERROR("failed to import message!\n"); + result = TC_FAIL; + goto exitTest1; + } + + tc_sha256_init(hash); + tc_sha256_update(hash, msg, msglen); + tc_sha256_final(digest_bytes, hash); + /* if digest larger than ECC scalar, drop the end + if digest smaller than ECC scalar, zero-pad front */ + int hash_dwords = TC_SHA256_DIGEST_SIZE / 4; + + if (NUM_ECC_WORDS < hash_dwords) + { + hash_dwords = NUM_ECC_WORDS; + } + + memset(digest, 0, NUM_ECC_BYTES - 4 * hash_dwords); + uECC_vli_bytesToNative(digest + (NUM_ECC_WORDS-hash_dwords), + digest_bytes, TC_SHA256_DIGEST_SIZE); + + if (uECC_sign_with_k(private_bytes, digest_bytes, + sizeof(digest_bytes), k, sig_bytes, uECC_secp256r1()) == 0) + { + TC_ERROR("ECDSA_sign failed!\n"); + result = TC_FAIL; + goto exitTest1; + } + + uECC_vli_bytesToNative(sig, sig_bytes, NUM_ECC_BYTES); + uECC_vli_bytesToNative(sig + NUM_ECC_WORDS, sig_bytes+NUM_ECC_BYTES, NUM_ECC_BYTES); + result = check_ecc_result(i, "sig.r", exp_r, sig, NUM_ECC_WORDS, verbose); + + if(result == TC_FAIL) + { + goto exitTest1; + } + + result = check_ecc_result(i, "sig.s", exp_s, sig + NUM_ECC_WORDS, NUM_ECC_WORDS, verbose); + + if(result == TC_FAIL) + { + goto exitTest1; + } + } + +exitTest1: + TC_END_RESULT(result); + return result; +} + +int cavp_sign(bool verbose) +{ + /* + [P-256,SHA-256] + */ + char* d[] = + { + "519b423d715f8b581f4fa8ee59f4771a5b44c8130b4e3eacca54a56dda72b464", + "0f56db78ca460b055c500064824bed999a25aaf48ebb519ac201537b85479813", + "e283871239837e13b95f789e6e1af63bf61c918c992e62bca040d64cad1fc2ef", + "a3d2d3b7596f6592ce98b4bfe10d41837f10027a90d7bb75349490018cf72d07", + "53a0e8a8fe93db01e7ae94e1a9882a102ebd079b3a535827d583626c272d280d", + "4af107e8e2194c830ffb712a65511bc9186a133007855b49ab4b3833aefc4a1d", + "78dfaa09f1076850b3e206e477494cddcfb822aaa0128475053592c48ebaf4ab", + "80e692e3eb9fcd8c7d44e7de9f7a5952686407f90025a1d87e52c7096a62618a", + "5e666c0db0214c3b627a8e48541cc84a8b6fd15f300da4dff5d18aec6c55b881", + "f73f455271c877c4d5334627e37c278f68d143014b0a05aa62f308b2101c5308", + "b20d705d9bd7c2b8dc60393a5357f632990e599a0975573ac67fd89b49187906", + "d4234bebfbc821050341a37e1240efe5e33763cbbb2ef76a1c79e24724e5a5e7", + "b58f5211dff440626bb56d0ad483193d606cf21f36d9830543327292f4d25d8c", + "54c066711cdb061eda07e5275f7e95a9962c6764b84f6f1f3ab5a588e0a2afb1", + "34fa4682bf6cb5b16783adcd18f0e6879b92185f76d7c920409f904f522db4b1", + }; + char* k[] = + { + "94a1bbb14b906a61a280f245f9e93c7f3b4a6247824f5d33b9670787642a68de", + "6d3e71882c3b83b156bb14e0ab184aa9fb728068d3ae9fac421187ae0b2f34c6", + "ad5e887eb2b380b8d8280ad6e5ff8a60f4d26243e0124c2f31a297b5d0835de2", + "24fc90e1da13f17ef9fe84cc96b9471ed1aaac17e3a4bae33a115df4e5834f18", + "5d833e8d24cc7a402d7ee7ec852a3587cddeb48358cea71b0bedb8fabe84e0c4", + "e18f96f84dfa2fd3cdfaec9159d4c338cd54ad314134f0b31e20591fc238d0ab", + "295544dbb2da3da170741c9b2c6551d40af7ed4e891445f11a02b66a5c258a77", + "7c80fd66d62cc076cef2d030c17c0a69c99611549cb32c4ff662475adbe84b22", + "2e7625a48874d86c9e467f890aaa7cd6ebdf71c0102bfdcfa24565d6af3fdce9", + "62f8665fd6e26b3fa069e85281777a9b1f0dfd2c0b9f54a086d0c109ff9fd615", + "72b656f6b35b9ccbc712c9f1f3b1a14cbbebaec41c4bca8da18f492a062d6f6f", + "d926fe10f1bfd9855610f4f5a3d666b1a149344057e35537373372ead8b1a778", + "e158bf4a2d19a99149d9cdb879294ccb7aaeae03d75ddd616ef8ae51a6dc1071", + "646fe933e96c3b8f9f507498e907fdd201f08478d0202c752a7c2cfebf4d061a", + "a6f463ee72c9492bc792fe98163112837aebd07bab7a84aaed05be64db3086f4", + }; + char* Msg[] = + { + "5905238877c77421f73e43ee3da6f2d9e2ccad5fc942dcec0cbd25482935faaf416983fe16" + "5b1a045ee2bcd2e6dca3bdf46c4310a7461f9a37960ca672d3feb5473e253605fb1ddfd280" + "65b53cb5858a8ad28175bf9bd386a5e471ea7a65c17cc934a9d791e91491eb3754d0379979" + "0fe2d308d16146d5c9b0d0debd97d79ce8", + "c35e2f092553c55772926bdbe87c9796827d17024dbb9233a545366e2e5987dd344deb72df" + "987144b8c6c43bc41b654b94cc856e16b96d7a821c8ec039b503e3d86728c494a967d83011" + "a0e090b5d54cd47f4e366c0912bc808fbb2ea96efac88fb3ebec9342738e225f7c7c2b011c" + "e375b56621a20642b4d36e060db4524af1", + "3c054e333a94259c36af09ab5b4ff9beb3492f8d5b4282d16801daccb29f70fe61a0b37ffe" + "f5c04cd1b70e85b1f549a1c4dc672985e50f43ea037efa9964f096b5f62f7ffdf8d6bfb2cc" + "859558f5a393cb949dbd48f269343b5263dcdb9c556eca074f2e98e6d94c2c29a677afaf80" + "6edf79b15a3fcd46e7067b7669f83188ee", + "0989122410d522af64ceb07da2c865219046b4c3d9d99b01278c07ff63eaf1039cb787ae9e" + "2dd46436cc0415f280c562bebb83a23e639e476a02ec8cff7ea06cd12c86dcc3adefbf1a9e" + "9a9b6646c7599ec631b0da9a60debeb9b3e19324977f3b4f36892c8a38671c8e1cc8e50fcd" + "50f9e51deaf98272f9266fc702e4e57c30", + "dc66e39f9bbfd9865318531ffe9207f934fa615a5b285708a5e9c46b7775150e818d7f24d2" + "a123df3672fff2094e3fd3df6fbe259e3989dd5edfcccbe7d45e26a775a5c4329a084f057c" + "42c13f3248e3fd6f0c76678f890f513c32292dd306eaa84a59abe34b16cb5e38d0e885525d" + "10336ca443e1682aa04a7af832b0eee4e7", + "600974e7d8c5508e2c1aab0783ad0d7c4494ab2b4da265c2fe496421c4df238b0be25f2565" + "9157c8a225fb03953607f7df996acfd402f147e37aee2f1693e3bf1c35eab3ae360a2bd91d" + "04622ea47f83d863d2dfecb618e8b8bdc39e17d15d672eee03bb4ce2cc5cf6b217e5faf3f3" + "36fdd87d972d3a8b8a593ba85955cc9d71", + "dfa6cb9b39adda6c74cc8b2a8b53a12c499ab9dee01b4123642b4f11af336a91a5c9ce0520" + "eb2395a6190ecbf6169c4cba81941de8e76c9c908eb843b98ce95e0da29c5d4388040264e0" + "5e07030a577cc5d176387154eabae2af52a83e85c61c7c61da930c9b19e45d7e34c8516dc3" + "c238fddd6e450a77455d534c48a152010b", + "51d2547cbff92431174aa7fc7302139519d98071c755ff1c92e4694b58587ea560f72f32fc" + "6dd4dee7d22bb7387381d0256e2862d0644cdf2c277c5d740fa089830eb52bf79d1e75b859" + "6ecf0ea58a0b9df61e0c9754bfcd62efab6ea1bd216bf181c5593da79f10135a9bc6e164f1" + "854bc8859734341aad237ba29a81a3fc8b", + "558c2ac13026402bad4a0a83ebc9468e50f7ffab06d6f981e5db1d082098065bcff6f21a7a" + "74558b1e8612914b8b5a0aa28ed5b574c36ac4ea5868432a62bb8ef0695d27c1e3ceaf75c7" + "b251c65ddb268696f07c16d2767973d85beb443f211e6445e7fe5d46f0dce70d58a4cd9fe7" + "0688c035688ea8c6baec65a5fc7e2c93e8", + "4d55c99ef6bd54621662c3d110c3cb627c03d6311393b264ab97b90a4b15214a5593ba2510" + "a53d63fb34be251facb697c973e11b665cb7920f1684b0031b4dd370cb927ca7168b0bf8ad" + "285e05e9e31e34bc24024739fdc10b78586f29eff94412034e3b606ed850ec2c1900e8e681" + "51fc4aee5adebb066eb6da4eaa5681378e", + "f8248ad47d97c18c984f1f5c10950dc1404713c56b6ea397e01e6dd925e903b4fadfe2c9e8" + "77169e71ce3c7fe5ce70ee4255d9cdc26f6943bf48687874de64f6cf30a012512e787b8805" + "9bbf561162bdcc23a3742c835ac144cc14167b1bd6727e940540a9c99f3cbb41fb1dcb00d7" + "6dda04995847c657f4c19d303eb09eb48a", + "3b6ee2425940b3d240d35b97b6dcd61ed3423d8e71a0ada35d47b322d17b35ea0472f35edd" + "1d252f87b8b65ef4b716669fc9ac28b00d34a9d66ad118c9d94e7f46d0b4f6c2b2d339fd6b" + "cd351241a387cc82609057048c12c4ec3d85c661975c45b300cb96930d89370a327c98b67d" + "efaa89497aa8ef994c77f1130f752f94a4", + "c5204b81ec0a4df5b7e9fda3dc245f98082ae7f4efe81998dcaa286bd4507ca840a53d21b0" + "1e904f55e38f78c3757d5a5a4a44b1d5d4e480be3afb5b394a5d2840af42b1b4083d40afbf" + "e22d702f370d32dbfd392e128ea4724d66a3701da41ae2f03bb4d91bb946c7969404cb544f" + "71eb7a49eb4c4ec55799bda1eb545143a7", + "72e81fe221fb402148d8b7ab03549f1180bcc03d41ca59d7653801f0ba853add1f6d29edd7" + "f9abc621b2d548f8dbf8979bd16608d2d8fc3260b4ebc0dd42482481d548c7075711b57596" + "49c41f439fad69954956c9326841ea6492956829f9e0dc789f73633b40f6ac77bcae6dfc79" + "30cfe89e526d1684365c5b0be2437fdb01", + "21188c3edd5de088dacc1076b9e1bcecd79de1003c2414c3866173054dc82dde85169baa77" + "993adb20c269f60a5226111828578bcc7c29e6e8d2dae81806152c8ba0c6ada1986a1983eb" + "eec1473a73a04795b6319d48662d40881c1723a706f516fe75300f92408aa1dc6ae4288d20" + "46f23c1aa2e54b7fb6448a0da922bd7f34", + }; + char* Qx[] = + { + "1ccbe91c075fc7f4f033bfa248db8fccd3565de94bbfb12f3c59ff46c271bf83", + "e266ddfdc12668db30d4ca3e8f7749432c416044f2d2b8c10bf3d4012aeffa8a", + "74ccd8a62fba0e667c50929a53f78c21b8ff0c3c737b0b40b1750b2302b0bde8", + "322f80371bf6e044bc49391d97c1714ab87f990b949bc178cb7c43b7c22d89e1", + "1bcec4570e1ec2436596b8ded58f60c3b1ebc6a403bc5543040ba82963057244", + "a32e50be3dae2c8ba3f5e4bdae14cf7645420d425ead94036c22dd6c4fc59e00", + "8bcfe2a721ca6d753968f564ec4315be4857e28bef1908f61a366b1f03c97479", + "a88bc8430279c8c0400a77d751f26c0abc93e5de4ad9a4166357952fe041e767", + "1bc487570f040dc94196c9befe8ab2b6de77208b1f38bdaae28f9645c4d2bc3a", + "b8188bd68701fc396dab53125d4d28ea33a91daf6d21485f4770f6ea8c565dde", + "51f99d2d52d4a6e734484a018b7ca2f895c2929b6754a3a03224d07ae61166ce", + "8fb287f0202ad57ae841aea35f29b2e1d53e196d0ddd9aec24813d64c0922fb7", + "68229b48c2fe19d3db034e4c15077eb7471a66031f28a980821873915298ba76", + "0a7dbb8bf50cb605eb2268b081f26d6b08e012f952c4b70a5a1e6e7d46af98bb", + "105d22d9c626520faca13e7ced382dcbe93498315f00cc0ac39c4821d0d73737", + }; + char* Qy[] = + { + "ce4014c68811f9a21a1fdb2c0e6113e06db7ca93b7404e78dc7ccd5ca89a4ca9", + "bfa86404a2e9ffe67d47c587ef7a97a7f456b863b4d02cfc6928973ab5b1cb39", + "29074e21f3a0ef88b9efdf10d06aa4c295cc1671f758ca0e4cd108803d0f2614", + "3c15d54a5cc6b9f09de8457e873eb3deb1fceb54b0b295da6050294fae7fd999", + "8af62a4c683f096b28558320737bf83b9959a46ad2521004ef74cf85e67494e1", + "d623bf641160c289d6742c6257ae6ba574446dd1d0e74db3aaa80900b78d4ae9", + "0f67576a30b8e20d4232d8530b52fb4c89cbc589ede291e499ddd15fe870ab96", + "2d365a1eef25ead579cc9a069b6abc1b16b81c35f18785ce26a10ba6d1381185", + "ec81602abd8345e71867c8210313737865b8aa186851e1b48eaca140320f5d8f", + "423f058810f277f8fe076f6db56e9285a1bf2c2a1dae145095edd9c04970bc4a", + "4737da963c6ef7247fb88d19f9b0c667cac7fe12837fdab88c66f10d3c14cad1", + "1f6daff1aa2dd2d6d3741623eecb5e7b612997a1039aab2e5cf2de969cfea573", + "303e8ee3742a893f78b810991da697083dd8f11128c47651c27a56740a80c24c", + "f26dd7d799930062480849962ccf5004edcfd307c044f4e8f667c9baa834eeae", + "6c47f3cbbfa97dfcebe16270b8c7d5d3a5900b888c42520d751e8faf3b401ef4", + }; + char* R[] = + { + "f3ac8061b514795b8843e3d6629527ed2afd6b1f6a555a7acabb5e6f79c8c2ac", + "976d3a4e9d23326dc0baa9fa560b7c4e53f42864f508483a6473b6a11079b2db", + "35fb60f5ca0f3ca08542fb3cc641c8263a2cab7a90ee6a5e1583fac2bb6f6bd1", + "d7c562370af617b581c84a2468cc8bd50bb1cbf322de41b7887ce07c0e5884ca", + "18caaf7b663507a8bcd992b836dec9dc5703c080af5e51dfa3a9a7c387182604", + "8524c5024e2d9a73bde8c72d9129f57873bbad0ed05215a372a84fdbc78f2e68", + "c5a186d72df452015480f7f338970bfe825087f05c0088d95305f87aacc9b254", + "9d0c6afb6df3bced455b459cc21387e14929392664bb8741a3693a1795ca6902", + "2f9e2b4e9f747c657f705bffd124ee178bbc5391c86d056717b140c153570fd9", + "1cc628533d0004b2b20e7f4baad0b8bb5e0673db159bbccf92491aef61fc9620", + "9886ae46c1415c3bc959e82b760ad760aab66885a84e620aa339fdf102465c42", + "490efd106be11fc365c7467eb89b8d39e15d65175356775deab211163c2504cb", + "e67a9717ccf96841489d6541f4f6adb12d17b59a6bef847b6183b8fcf16a32eb", + "b53ce4da1aa7c0dc77a1896ab716b921499aed78df725b1504aba1597ba0c64b", + "542c40a18140a6266d6f0286e24e9a7bad7650e72ef0e2131e629c076d962663", + }; + char* S[] = + { + "8bf77819ca05a6b2786c76262bf7371cef97b218e96f175a3ccdda2acc058903", + "1b766e9ceb71ba6c01dcd46e0af462cd4cfa652ae5017d4555b8eeefe36e1932", + "ee59d81bc9db1055cc0ed97b159d8784af04e98511d0a9a407b99bb292572e96", + "b46d9f2d8c4bf83546ff178f1d78937c008d64e8ecc5cbb825cb21d94d670d89", + "77c68928ac3b88d985fb43fb615fb7ff45c18ba5c81af796c613dfa98352d29c", + "d18c2caf3b1072f87064ec5e8953f51301cada03469c640244760328eb5a05cb", + "84a58f9e9d9e735344b316b1aa1ab5185665b85147dc82d92e969d7bee31ca30", + "d7f9ddd191f1f412869429209ee3814c75c72fa46a9cccf804a2f5cc0b7e739f", + "f5413bfd85949da8d83de83ab0d19b2986613e224d1901d76919de23ccd03199", + "880e0bbf82a8cf818ed46ba03cf0fc6c898e36fca36cc7fdb1d2db7503634430", + "2bf3a80bc04faa35ebecc0f4864ac02d349f6f126e0f988501b8d3075409a26c", + "644300fc0da4d40fb8c6ead510d14f0bd4e1321a469e9c0a581464c7186b7aa7", + "9ae6ba6d637706849a6a9fc388cf0232d85c26ea0d1fe7437adb48de58364333", + "d7c246dc7ad0e67700c373edcfdd1c0a0495fc954549ad579df6ed1438840851", + "4f7f65305e24a6bbb5cff714ba8f5a2cee5bdc89ba8d75dcbf21966ce38eb66f", + }; + struct tc_sha256_state_struct sha256_ctx; + TC_PRINT("Test #1: ECDSAsign "); + TC_PRINT("NIST-p256, SHA2-256\n"); + return sign_vectors(&sha256_ctx, d, k, Msg, Qx, Qy, R, S, 15, verbose); +} + +int vrfy_vectors(TCSha256State_t hash, char** msg_vec, char** qx_vec, char** qy_vec, + char** r_vec, char** s_vec, char** res_vec, int tests, bool verbose) +{ + const struct uECC_Curve_t* curve = uECC_secp256r1(); + unsigned int pub[2 * NUM_ECC_WORDS]; + uint8_t pub_bytes[2 * NUM_ECC_BYTES]; + unsigned int sig[2 * NUM_ECC_WORDS]; + uint8_t sig_bytes[2 * NUM_ECC_BYTES]; + uint8_t digest_bytes[TC_SHA256_DIGEST_SIZE]; + unsigned int digest[TC_SHA256_DIGEST_SIZE / 4]; + unsigned int result = TC_PASS; + int rc; + int exp_rc; + char tmp; + uint8_t msg[BUF_SIZE]; + size_t msglen; + + for (int i = 0; i < tests; i++) + { + string2scalar(pub, NUM_ECC_WORDS, qx_vec[i]); + string2scalar(pub + NUM_ECC_WORDS, NUM_ECC_WORDS, qy_vec[i]); + string2scalar(sig, NUM_ECC_WORDS, r_vec[i]); + string2scalar(sig + NUM_ECC_WORDS, NUM_ECC_WORDS, s_vec[i]); + + if (2 != sscanf(res_vec[i], "%c (%d ", &tmp, &exp_rc)) + { + TC_ERROR("Error: failed to parse CAVP response.\n"); + result = TC_FAIL; + goto exitTest1; + } + + /* validate ECDSA: hash message, verify r+s */ + msglen = hex2bin(msg, BUF_SIZE, msg_vec[i], strlen(msg_vec[i])); + + if (msglen == false) + { + TC_ERROR("failed to import message!\n"); + result = TC_FAIL; + goto exitTest1; + } + + tc_sha256_init(hash); + tc_sha256_update(hash, msg, msglen); + tc_sha256_final(digest_bytes, hash); + /* if digest larger than ECC scalar, drop the end + if digest smaller than ECC scalar, zero-pad front */ + int hash_dwords = TC_SHA256_DIGEST_SIZE / 4; + + if (NUM_ECC_WORDS < hash_dwords) + { + hash_dwords = NUM_ECC_WORDS; + } + + memset(digest, 0, NUM_ECC_BYTES - 4 * hash_dwords); + uECC_vli_bytesToNative(digest + (NUM_ECC_WORDS-hash_dwords), digest_bytes, + TC_SHA256_DIGEST_SIZE); + uECC_vli_nativeToBytes(pub_bytes, NUM_ECC_BYTES, pub); + uECC_vli_nativeToBytes(pub_bytes + NUM_ECC_BYTES, NUM_ECC_BYTES, + pub + NUM_ECC_WORDS); + + /* adapt return codes to match CAVP error: */ + if (0 != uECC_valid_public_key(pub_bytes, curve)) + { + /* error 4 - Q changed */ + rc = 4; + } + else + { + uECC_vli_nativeToBytes(sig_bytes, NUM_ECC_BYTES, sig); + uECC_vli_nativeToBytes(sig_bytes + NUM_ECC_BYTES, NUM_ECC_BYTES, + sig + NUM_ECC_WORDS); + rc = uECC_verify(pub_bytes, digest_bytes, sizeof(digest_bytes), sig_bytes, + uECC_secp256r1()); + /* CAVP expects 0 for success, others for fail */ + rc = !rc; + + if (exp_rc != 0 && rc != 0) + { + /* mimic CAVP code on errors. */ + rc = exp_rc; + } + } + + result = check_code(i, res_vec[i], exp_rc, rc, verbose); + + if(result == TC_FAIL) + { + goto exitTest1; + } + } + +exitTest1: + TC_END_RESULT(result); + return result; +} + +int cavp_verify(bool verbose) +{ + /* + [P-256,SHA-256] + */ + char* Msg[] = + { + "e4796db5f785f207aa30d311693b3702821dff1168fd2e04c0836825aefd850d9aa60326d8" + "8cde1a23c7745351392ca2288d632c264f197d05cd424a30336c19fd09bb229654f0222fcb" + "881a4b35c290a093ac159ce13409111ff0358411133c24f5b8e2090d6db6558afc36f06ca1" + "f6ef779785adba68db27a409859fc4c4a0", + "069a6e6b93dfee6df6ef6997cd80dd2182c36653cef10c655d524585655462d683877f95ec" + "c6d6c81623d8fac4e900ed0019964094e7de91f1481989ae1873004565789cbf5dc56c62ae" + "dc63f62f3b894c9c6f7788c8ecaadc9bd0e81ad91b2b3569ea12260e93924fdddd3972af52" + "73198f5efda0746219475017557616170e", + "df04a346cf4d0e331a6db78cca2d456d31b0a000aa51441defdb97bbeb20b94d8d746429a3" + "93ba88840d661615e07def615a342abedfa4ce912e562af714959896858af817317a840dcf" + "f85a057bb91a3c2bf90105500362754a6dd321cdd86128cfc5f04667b57aa78c112411e42d" + "a304f1012d48cd6a7052d7de44ebcc01de", + "e1130af6a38ccb412a9c8d13e15dbfc9e69a16385af3c3f1e5da954fd5e7c45fd75e2b8c36" + "699228e92840c0562fbf3772f07e17f1add56588dd45f7450e1217ad239922dd9c32695dc7" + "1ff2424ca0dec1321aa47064a044b7fe3c2b97d03ce470a592304c5ef21eed9f93da56bb23" + "2d1eeb0035f9bf0dfafdcc4606272b20a3", + "73c5f6a67456ae48209b5f85d1e7de7758bf235300c6ae2bdceb1dcb27a7730fb68c950b7f" + "cada0ecc4661d3578230f225a875e69aaa17f1e71c6be5c831f22663bac63d0c7a9635edb0" + "043ff8c6f26470f02a7bc56556f1437f06dfa27b487a6c4290d8bad38d4879b334e341ba09" + "2dde4e4ae694a9c09302e2dbf443581c08", + "666036d9b4a2426ed6585a4e0fd931a8761451d29ab04bd7dc6d0c5b9e38e6c2b263ff6cb8" + "37bd04399de3d757c6c7005f6d7a987063cf6d7e8cb38a4bf0d74a282572bd01d0f41e3fd0" + "66e3021575f0fa04f27b700d5b7ddddf50965993c3f9c7118ed78888da7cb221849b326059" + "2b8e632d7c51e935a0ceae15207bedd548", + "7e80436bce57339ce8da1b5660149a20240b146d108deef3ec5da4ae256f8f894edcbbc57b" + "34ce37089c0daa17f0c46cd82b5a1599314fd79d2fd2f446bd5a25b8e32fcf05b76d644573" + "a6df4ad1dfea707b479d97237a346f1ec632ea5660efb57e8717a8628d7f82af50a4e84b11" + "f21bdff6839196a880ae20b2a0918d58cd", + "1669bfb657fdc62c3ddd63269787fc1c969f1850fb04c933dda063ef74a56ce13e3a649700" + "820f0061efabf849a85d474326c8a541d99830eea8131eaea584f22d88c353965dabcdc4bf" + "6b55949fd529507dfb803ab6b480cd73ca0ba00ca19c438849e2cea262a1c57d8f81cd257f" + "b58e19dec7904da97d8386e87b84948169", + "3fe60dd9ad6caccf5a6f583b3ae65953563446c4510b70da115ffaa0ba04c076115c7043ab" + "8733403cd69c7d14c212c655c07b43a7c71b9a4cffe22c2684788ec6870dc2013f269172c8" + "22256f9e7cc674791bf2d8486c0f5684283e1649576efc982ede17c7b74b214754d70402fb" + "4bb45ad086cf2cf76b3d63f7fce39ac970", + "983a71b9994d95e876d84d28946a041f8f0a3f544cfcc055496580f1dfd4e312a2ad418fe6" + "9dbc61db230cc0c0ed97e360abab7d6ff4b81ee970a7e97466acfd9644f828ffec538abc38" + "3d0e92326d1c88c55e1f46a668a039beaa1be631a89129938c00a81a3ae46d4aecbf9707f7" + "64dbaccea3ef7665e4c4307fa0b0a3075c", + "4a8c071ac4fd0d52faa407b0fe5dab759f7394a5832127f2a3498f34aac287339e043b4ffa" + "79528faf199dc917f7b066ad65505dab0e11e6948515052ce20cfdb892ffb8aa9bf3f1aa5b" + "e30a5bbe85823bddf70b39fd7ebd4a93a2f75472c1d4f606247a9821f1a8c45a6cb80545de" + "2e0c6c0174e2392088c754e9c8443eb5af", + "0a3a12c3084c865daf1d302c78215d39bfe0b8bf28272b3c0b74beb4b7409db0718239de70" + "0785581514321c6440a4bbaea4c76fa47401e151e68cb6c29017f0bce4631290af5ea5e2bf" + "3ed742ae110b04ade83a5dbd7358f29a85938e23d87ac8233072b79c94670ff0959f9c7f45" + "17862ff829452096c78f5f2e9a7e4e9216", + "785d07a3c54f63dca11f5d1a5f496ee2c2f9288e55007e666c78b007d95cc28581dce51f49" + "0b30fa73dc9e2d45d075d7e3a95fb8a9e1465ad191904124160b7c60fa720ef4ef1c5d2998" + "f40570ae2a870ef3e894c2bc617d8a1dc85c3c55774928c38789b4e661349d3f84d2441a3b" + "856a76949b9f1f80bc161648a1cad5588e", + "76f987ec5448dd72219bd30bf6b66b0775c80b394851a43ff1f537f140a6e7229ef8cd72ad" + "58b1d2d20298539d6347dd5598812bc65323aceaf05228f738b5ad3e8d9fe4100fd767c2f0" + "98c77cb99c2992843ba3eed91d32444f3b6db6cd212dd4e5609548f4bb62812a920f6e2bf1" + "581be1ebeebdd06ec4e971862cc42055ca", + "60cd64b2cd2be6c33859b94875120361a24085f3765cb8b2bf11e026fa9d8855dbe435acf7" + "882e84f3c7857f96e2baab4d9afe4588e4a82e17a78827bfdb5ddbd1c211fbc2e6d884cddd" + "7cb9d90d5bf4a7311b83f352508033812c776a0e00c003c7e0d628e50736c7512df0acfa9f" + "2320bd102229f46495ae6d0857cc452a84", + }; + char* Qx[] = + { + "87f8f2b218f49845f6f10eec3877136269f5c1a54736dbdf69f89940cad41555", + "5cf02a00d205bdfee2016f7421807fc38ae69e6b7ccd064ee689fc1a94a9f7d2", + "2ddfd145767883ffbb0ac003ab4a44346d08fa2570b3120dcce94562422244cb", + "e424dc61d4bb3cb7ef4344a7f8957a0c5134e16f7a67c074f82e6e12f49abf3c", + "e0fc6a6f50e1c57475673ee54e3a57f9a49f3328e743bf52f335e3eeaa3d2864", + "a849bef575cac3c6920fbce675c3b787136209f855de19ffe2e8d29b31a5ad86", + "3dfb6f40f2471b29b77fdccba72d37c21bba019efa40c1c8f91ec405d7dcc5df", + "69b7667056e1e11d6caf6e45643f8b21e7a4bebda463c7fdbc13bc98efbd0214", + "bf02cbcf6d8cc26e91766d8af0b164fc5968535e84c158eb3bc4e2d79c3cc682", + "224a4d65b958f6d6afb2904863efd2a734b31798884801fcab5a590f4d6da9de", + "43691c7795a57ead8c5c68536fe934538d46f12889680a9cb6d055a066228369", + "9157dbfcf8cf385f5bb1568ad5c6e2a8652ba6dfc63bc1753edf5268cb7eb596", + "072b10c081a4c1713a294f248aef850e297991aca47fa96a7470abe3b8acfdda", + "09308ea5bfad6e5adf408634b3d5ce9240d35442f7fe116452aaec0d25be8c24", + "2d98ea01f754d34bbc3003df5050200abf445ec728556d7ed7d5c54c55552b6d", + }; + char* Qy[] = + { + "e15f369036f49842fac7a86c8a2b0557609776814448b8f5e84aa9f4395205e9", + "ec530ce3cc5c9d1af463f264d685afe2b4db4b5828d7e61b748930f3ce622a85", + "5f70c7d11ac2b7a435ccfbbae02c3df1ea6b532cc0e9db74f93fffca7c6f9a64", + "970eed7aa2bc48651545949de1dddaf0127e5965ac85d1243d6f60e7dfaee927", + "7f59d689c91e463607d9194d99faf316e25432870816dde63f5d4b373f12f22a", + "bf5fe4f7858f9b805bd8dcc05ad5e7fb889de2f822f3d8b41694e6c55c16b471", + "f22f953f1e395a52ead7f3ae3fc47451b438117b1e04d613bc8555b7d6e6d1bb", + "d3f9b12eb46c7c6fda0da3fc85bc1fd831557f9abc902a3be3cb3e8be7d1aa2f", + "069ba6cb06b49d60812066afa16ecf7b51352f2c03bd93ec220822b1f3dfba03", + "178d51fddada62806f097aa615d33b8f2404e6b1479f5fd4859d595734d6d2b9", + "f8790110b3c3b281aa1eae037d4f1234aff587d903d93ba3af225c27ddc9ccac", + "972570f4313d47fc96f7c02d5594d77d46f91e949808825b3d31f029e8296405", + "9581145cca04a0fb94cedce752c8f0370861916d2a94e7c647c5373ce6a4c8f5", + "f40c93e023ef494b1c3079b2d10ef67f3170740495ce2cc57f8ee4b0618b8ee5", + "9b52672742d637a32add056dfd6d8792f2a33c2e69dafabea09b960bc61e230a", + }; + char* R[] = + { + "d19ff48b324915576416097d2544f7cbdf8768b1454ad20e0baac50e211f23b0", + "dc23d130c6117fb5751201455e99f36f59aba1a6a21cf2d0e7481a97451d6693", + "9913111cff6f20c5bf453a99cd2c2019a4e749a49724a08774d14e4c113edda8", + "bf96b99aa49c705c910be33142017c642ff540c76349b9dab72f981fd9347f4f", + "1d75830cd36f4c9aa181b2c4221e87f176b7f05b7c87824e82e396c88315c407", + "25acc3aa9d9e84c7abf08f73fa4195acc506491d6fc37cb9074528a7db87b9d6", + "548886278e5ec26bed811dbb72db1e154b6f17be70deb1b210107decb1ec2a5a", + "288f7a1cd391842cce21f00e6f15471c04dc182fe4b14d92dc18910879799790", + "f5acb06c59c2b4927fb852faa07faf4b1852bbb5d06840935e849c4d293d1bad", + "87b93ee2fecfda54deb8dff8e426f3c72c8864991f8ec2b3205bb3b416de93d2", + "8acd62e8c262fa50dd9840480969f4ef70f218ebf8ef9584f199031132c6b1ce", + "dfaea6f297fa320b707866125c2a7d5d515b51a503bee817de9faa343cc48eeb", + "09f5483eccec80f9d104815a1be9cc1a8e5b12b6eb482a65c6907b7480cf4f19", + "5cc8aa7c35743ec0c23dde88dabd5e4fcd0192d2116f6926fef788cddb754e73", + "06108e525f845d0155bf60193222b3219c98e3d49424c2fb2a0987f825c17959", + }; + char* Result[] = + { + "F (3 - S changed)", "F (2 - R changed)", "F (4 - Q changed)", + "P (0 )", "P (0 )", "F (2 - R changed)", + "F (4 - Q changed)", "F (1 - Message changed)", "F (3 - S changed)", + "F (2 - R changed)", "F (3 - S changed)", "F (1 - Message changed)", + "F (4 - Q changed)", "F (1 - Message changed)", "P (0 )", + }; + char* S[] = + { + "a3e81e59311cdfff2d4784949f7a2cb50ba6c3a91fa54710568e61aca3e847c6", + "d6ce7708c18dbf35d4f8aa7240922dc6823f2e7058cbc1484fcad1599db5018c", + "9467cd4cd21ecb56b0cab0a9a453b43386845459127a952421f5c6382866c5cc", + "17c55095819089c2e03b9cd415abdf12444e323075d98f31920b9e0f57ec871c", + "cb2acb01dac96efc53a32d4a0d85d0c2e48955214783ecf50a4f0414a319c05a", + "9b21d5b5259ed3f2ef07dfec6cc90d3a37855d1ce122a85ba6a333f307d31537", + "e93bfebd2f14f3d827ca32b464be6e69187f5edbd52def4f96599c37d58eee75", + "247b3c4e89a3bcadfea73c7bfd361def43715fa382b8c3edf4ae15d6e55e9979", + "049dab79c89cc02f1484c437f523e080a75f134917fda752f2d5ca397addfe5d", + "4044a24df85be0cc76f21a4430b75b8e77b932a87f51e4eccbc45c263ebf8f66", + "cfca7ed3d4347fb2a29e526b43c348ae1ce6c60d44f3191b6d8ea3a2d9c92154", + "8f780ad713f9c3e5a4f7fa4c519833dfefc6a7432389b1e4af463961f09764f2", + "a4f90e560c5e4eb8696cb276e5165b6a9d486345dedfb094a76e8442d026378d", + "9c9c045ebaa1b828c32f82ace0d18daebf5e156eb7cbfdc1eff4399a8a900ae7", + "62b5cdd591e5b507e560167ba8f6f7cda74673eb315680cb89ccbc4eec477dce", + }; + struct tc_sha256_state_struct sha256_ctx; + printf("Test #2: ECDSAvrfy "); + printf("NIST-p256, SHA2-256\n"); + return vrfy_vectors(&sha256_ctx, Msg, Qx, Qy, R, S, Result, 15, verbose); +} + +int montecarlo_signverify(int num_tests, bool verbose) +{ + printf("Test #3: Monte Carlo (%d Randomized EC-DSA signatures) ", num_tests); + printf("NIST-p256, SHA2-256\n "); + int i; + uint8_t private[NUM_ECC_BYTES]; + uint8_t public[2*NUM_ECC_BYTES]; + uint8_t hash[NUM_ECC_BYTES]; + unsigned int hash_words[NUM_ECC_WORDS]; + uint8_t sig[2*NUM_ECC_BYTES]; + const struct uECC_Curve_t* curve = uECC_secp256r1(); + + for (i = 0; i < num_tests; ++i) + { + if (verbose) + { + TC_PRINT("."); + fflush(stdout); + } + + uECC_generate_random_int(hash_words, curve->n, BITS_TO_WORDS(curve->num_n_bits)); + uECC_vli_nativeToBytes(hash, NUM_ECC_BYTES, hash_words); + + if (!uECC_make_key(public, private, curve)) + { + TC_ERROR("uECC_make_key() failed\n"); + return TC_FAIL; + } + + if (!uECC_sign(private, hash, sizeof(hash), sig, curve)) + { + TC_ERROR("uECC_sign() failed\n"); + return TC_FAIL; + } + + if (!uECC_verify(public, hash, sizeof(hash), sig, curve)) + { + TC_ERROR("uECC_verify() failed\n"); + return TC_FAIL; + } + + if (verbose) + { + fflush(stdout); + printf("."); + } + } + + TC_PRINT("\n"); + return TC_PASS; +} + +int main() +{ + unsigned int result = TC_PASS; + TC_START("Performing ECC-DSA tests:"); + /* Setup of the Cryptographically Secure PRNG. */ + uECC_set_rng(&default_CSPRNG); + bool verbose = true; + TC_PRINT("Performing cavp_sign test:\n"); + result = cavp_sign(verbose); + + if (result == TC_FAIL) /* terminate test */ + { + TC_ERROR("cavp_sign test failed.\n"); + goto exitTest; + } + + TC_PRINT("Performing cavp_verify test:\n"); + result = cavp_verify(verbose); + + if (result == TC_FAIL) + { + TC_ERROR("cavp_verify test failed.\n"); + goto exitTest; + } + + TC_PRINT("Performing montecarlo_signverify test:\n"); + result = montecarlo_signverify(10, verbose); + + if (result == TC_FAIL) + { + TC_ERROR("montecarlo_signverify test failed.\n"); + goto exitTest; + } + + TC_PRINT("\nAll ECC-DSA tests succeeded.\n"); +exitTest: + TC_END_RESULT(result); + TC_END_REPORT(result); +} diff --git a/src/components/libraries/tinycrypt-0.2.8/tests/test_ecc_utils.c b/src/components/libraries/tinycrypt-0.2.8/tests/test_ecc_utils.c new file mode 100644 index 0000000..627dc2b --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/tests/test_ecc_utils.c @@ -0,0 +1,287 @@ +/* test_ecc_utils.c - TinyCrypt common functions for ECC tests */ + +/* 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. + + test_ecc_utils.c -- Implementation of some common functions for ECC tests. + +*/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +int hex2int (char hex) +{ + uint8_t dec; + + if ('0' <= hex && hex <= '9') dec = hex - '0'; + else if ('a' <= hex && hex <= 'f') dec = hex - 'a' + 10; + else if ('A' <= hex && hex <= 'F') dec = hex - 'A' + 10; + else return -1; + + return dec; +} + +/* + Convert hex string to byte string + Return number of bytes written to buf, or 0 on error +*/ +int hex2bin(uint8_t* buf, const size_t buflen, const char* hex, + const size_t hexlen) +{ + int dec; + + if (buflen < hexlen / 2 + hexlen % 2) + { + return false; + } + + /* if hexlen is uneven, insert leading zero nibble */ + if (hexlen % 2) + { + dec = hex2int(hex[0]); + + if (dec == -1) + return false; + + buf[0] = dec; + buf++; + hex++; + } + + /* regular hex conversion */ + for (size_t i = 0; i < hexlen / 2; i++) + { + dec = hex2int(hex[2 * i]); + + if (dec == -1) + { + return false; + } + + buf[i] = dec << 4; + dec = hex2int(hex[ 2 * i + 1]); + + if (dec == -1) + { + return false; + } + + buf[i] += dec; + } + + return hexlen / 2 + hexlen % 2; +} + +/* + Convert hex string to zero-padded nanoECC scalar +*/ +void string2scalar(unsigned int* scalar, unsigned int num_word32, char* str) +{ + unsigned int num_bytes = 4 * num_word32; + uint8_t tmp[num_bytes]; + size_t hexlen = strlen(str); + int padding; + + if (0 > (padding = 2 * num_bytes - strlen(str))) + { + printf("Error: 2 * num_bytes(%d) < strlen(hex) (%zu)\n", + 2 * num_bytes, strlen(str)); + exit(-1); + } + + memset(tmp, 0, padding / 2); + + if (false == hex2bin(tmp + padding / 2, num_bytes, str, hexlen)) + { + exit(-1); + } + + uECC_vli_bytesToNative(scalar, tmp, num_bytes); +} + +void vli_print_bytes(uint8_t* vli, unsigned int size) +{ + for(unsigned i = 0; i < size; ++i) + { + printf("%02X ", (unsigned)vli[i]); + } +} + +void print_ecc_scalar(const char* label, const unsigned int* p_vli, + unsigned int num_word32) +{ + unsigned int i; + + if (label) + { + printf("%s = { ", label); + } + + for(i = 0; i < num_word32 - 1; ++i) + { + printf("0x%08lX, ", (unsigned long)p_vli[i]); + } + + printf("0x%08lX", (unsigned long)p_vli[i]); + + if (label) + { + printf(" };\n"); + } +} + +int check_ecc_result(const int num, const char* name, + const unsigned int* expected, + const unsigned int* computed, + const unsigned int num_word32, const bool verbose) +{ + uint32_t num_bytes = 4 * num_word32; + + if (memcmp(computed, expected, num_bytes)) + { + TC_PRINT("\n Vector #%02d check %s - FAILURE:\n\n", num, name); + print_ecc_scalar("Expected", expected, num_word32); + print_ecc_scalar("Computed", computed, num_word32); + TC_PRINT("\n"); + return TC_FAIL; + } + + if (verbose) + { + TC_PRINT(" Vector #%02d check %s - success\n", num, name); + } + + return TC_PASS; +} + +int check_code(const int num, const char* name, const int expected, + const int computed, const int verbose) +{ + if (expected != computed) + { + TC_ERROR("\n Vector #%02d check %s - FAILURE:\n", num, name); + TC_ERROR("\n Expected: %d, computed: %d\n\n", expected, computed); + return TC_FAIL; + } + + if (verbose) + { + TC_PRINT(" Vector #%02d check %s - success (%d=%d)\n", num, name, + expected, computed); + } + + return TC_PASS; +} + +/* Test ecc_make_keys, and also as keygen part of other tests */ +int keygen_vectors(char** d_vec, char** qx_vec, char** qy_vec, int tests, + bool verbose) +{ + unsigned int pub[2 * NUM_ECC_WORDS]; + unsigned int d[NUM_ECC_WORDS]; + unsigned int prv[NUM_ECC_WORDS]; + unsigned int result = TC_PASS; + /* expected outputs (converted input vectors) */ + unsigned int exp_pub[2 * NUM_ECC_WORDS]; + unsigned int exp_prv[NUM_ECC_WORDS]; + + for (int i = 0; i < tests; i++) + { + string2scalar(exp_prv, NUM_ECC_WORDS, d_vec[i]); + string2scalar(exp_pub, NUM_ECC_WORDS, qx_vec[i]); + string2scalar(exp_pub + NUM_ECC_WORDS, NUM_ECC_WORDS, qy_vec[i]); + /* + Feed prvkey vector as padded random seed into ecc_make_key. + Internal mod-reduction will be zero-op and generate correct prv/pub + */ + memset(d, 0, NUM_ECC_WORDS); + string2scalar(d, NUM_ECC_WORDS, d_vec[i]); + uint8_t pub_bytes[2*NUM_ECC_BYTES]; + uint8_t prv_bytes[NUM_ECC_BYTES]; + uECC_make_key_with_d(pub_bytes, prv_bytes, d, uECC_secp256r1()); + uECC_vli_bytesToNative(prv, prv_bytes, NUM_ECC_BYTES); + uECC_vli_bytesToNative(pub, pub_bytes, NUM_ECC_BYTES); + uECC_vli_bytesToNative(pub + NUM_ECC_WORDS, pub_bytes + NUM_ECC_BYTES, NUM_ECC_BYTES); + /* validate correctness of vector conversion and make_key() */ + result = check_ecc_result(i, "prv ", exp_prv, prv, NUM_ECC_WORDS, verbose); + + if (result == TC_FAIL) + { + return result; + } + + result = check_ecc_result(i, "pub.x", exp_pub, pub, NUM_ECC_WORDS, verbose); + + if (result == TC_FAIL) + { + return result; + } + + result = check_ecc_result(i, "pub.y", exp_pub + NUM_ECC_WORDS, pub + NUM_ECC_WORDS, NUM_ECC_WORDS, verbose); + + if (result == TC_FAIL) + { + return result; + } + } + + return result; +} diff --git a/src/components/libraries/tinycrypt-0.2.8/tests/test_hmac.c b/src/components/libraries/tinycrypt-0.2.8/tests/test_hmac.c new file mode 100644 index 0000000..1423fe6 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/tests/test_hmac.c @@ -0,0 +1,383 @@ +/* test_hmac.c - TinyCrypt implementation of some HMAC tests */ + +/* + 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. +*/ + +/* + DESCRIPTION + This module tests the following HMAC routines: + + Scenarios tested include: + - HMAC tests (RFC 4231 test vectors) +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include + +unsigned int do_hmac_test(TCHmacState_t h, unsigned int testnum, const uint8_t* data, + size_t datalen, const uint8_t* expected, + size_t expectedlen) +{ + uint8_t digest[32]; + unsigned int result = TC_PASS; + (void)tc_hmac_init(h); + (void)tc_hmac_update(h, data, datalen); + (void)tc_hmac_final(digest, TC_SHA256_DIGEST_SIZE, h); + result = check_result(testnum, expected, expectedlen, + digest, sizeof(digest)); + return result; +} + +/* + NIST test vectors for encryption. +*/ +unsigned int test_1(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("HMAC %s:\n", __func__); + const uint8_t key[20] = + { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b + }; + const uint8_t data[8] = + { + 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 + }; + const uint8_t expected[32] = + { + 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, + 0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, + 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7 + }; + struct tc_hmac_state_struct h; + (void)memset(&h, 0x00, sizeof(h)); + (void)tc_hmac_set_key(&h, key, sizeof(key)); + result = do_hmac_test(&h, 1, data, sizeof(data),expected, + sizeof(expected)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_2(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("HMAC %s:\n", __func__); + const uint8_t key[4] = + { + 0x4a, 0x65, 0x66, 0x65 + }; + const uint8_t data[28] = + { + 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, 0x79, 0x61, 0x20, 0x77, + 0x61, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68, + 0x69, 0x6e, 0x67, 0x3f + }; + const uint8_t expected[32] = + { + 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24, 0x26, + 0x08, 0x95, 0x75, 0xc7, 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, + 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43 + }; + struct tc_hmac_state_struct h; + (void)memset(&h, 0x00, sizeof(h)); + (void)tc_hmac_set_key(&h, key, sizeof(key)); + result = do_hmac_test(&h, 2, data, sizeof(data), expected, + sizeof(expected)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_3(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("HMAC %s:\n", __func__); + const uint8_t key[20] = + { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa + }; + const uint8_t data[50] = + { + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd + }; + const uint8_t expected[32] = + { + 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8, 0xeb, + 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22, + 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe + }; + struct tc_hmac_state_struct h; + (void)memset(&h, 0x00, sizeof(h)); + (void)tc_hmac_set_key(&h, key, sizeof(key)); + result = do_hmac_test(&h, 3, data, sizeof(data), expected, + sizeof(expected)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_4(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("HMAC %s:\n", __func__); + const uint8_t key[25] = + { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19 + }; + const uint8_t data[50] = + { + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd + }; + const uint8_t expected[32] = + { + 0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, 0xa4, 0xcc, 0x81, 0x98, + 0x99, 0xf2, 0x08, 0x3a, 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07, + 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b + }; + struct tc_hmac_state_struct h; + (void)memset(&h, 0x00, sizeof(h)); + (void)tc_hmac_set_key(&h, key, sizeof(key)); + result = do_hmac_test(&h, 4, data, sizeof(data), expected, + sizeof(expected)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_5(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("HMAC %s:\n", __func__); + const uint8_t key[20] = + { + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c + }; + const uint8_t data[20] = + { + 0x54, 0x65, 0x73, 0x74, 0x20, 0x57, 0x69, 0x74, 0x68, 0x20, 0x54, 0x72, + 0x75, 0x6e, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e + }; + const uint8_t expected[32] = + { + 0xa3, 0xb6, 0x16, 0x74, 0x73, 0x10, 0x0e, 0xe0, 0x6e, 0x0c, 0x79, 0x6c, + 0x29, 0x55, 0x55, 0x2b, 0xfa, 0x6f, 0x7c, 0x0a, 0x6a, 0x8a, 0xef, 0x8b, + 0x93, 0xf8, 0x60, 0xaa, 0xb0, 0xcd, 0x20, 0xc5 + }; + struct tc_hmac_state_struct h; + (void)memset(&h, 0x00, sizeof(h)); + (void)tc_hmac_set_key(&h, key, sizeof(key)); + result = do_hmac_test(&h, 5, data, sizeof(data), expected, + sizeof(expected)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_6(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("HMAC %s:\n", __func__); + const uint8_t key[131] = + { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa + }; + const uint8_t data[54] = + { + 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x4c, + 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, 0x65, 0x20, 0x4b, 0x65, + 0x79, 0x20, 0x2d, 0x20, 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79, + 0x20, 0x46, 0x69, 0x72, 0x73, 0x74 + }; + const uint8_t expected[32] = + { + 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa, + 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, + 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54 + }; + struct tc_hmac_state_struct h; + (void)memset(&h, 0x00, sizeof(h)); + (void)tc_hmac_set_key(&h, key, sizeof(key)); + result = do_hmac_test(&h, 6, data, sizeof(data), expected, + sizeof(expected)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_7(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("HMAC %s:\n", __func__); + const uint8_t key[131] = + { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa + }; + const uint8_t data[152] = + { + 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x65, + 0x73, 0x74, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c, + 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65, + 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x6c, 0x61, 0x72, 0x67, + 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65, + 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x68, 0x61, 0x73, + 0x68, 0x65, 0x64, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62, + 0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x62, 0x79, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c, + 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e + }; + const uint8_t expected[32] = + { + 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f, 0xbc, + 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, + 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2 + }; + struct tc_hmac_state_struct h; + (void)memset(&h, 0x00, sizeof(h)); + (void)tc_hmac_set_key(&h, key, sizeof(key)); + result = do_hmac_test(&h, 7, data, sizeof(data), expected, + sizeof(expected)); + TC_END_RESULT(result); + return result; +} + +/* + Main task to test AES +*/ +int main(void) +{ + unsigned int result = TC_PASS; + TC_START("Performing HMAC tests (RFC4231 test vectors):"); + result = test_1(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("HMAC test #1 failed.\n"); + goto exitTest; + } + + result = test_2(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("HMAC test #2 failed.\n"); + goto exitTest; + } + + result = test_3(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("HMAC test #3 failed.\n"); + goto exitTest; + } + + result = test_4(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("HMAC test #4 failed.\n"); + goto exitTest; + } + + result = test_5(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("HMAC test #5 failed.\n"); + goto exitTest; + } + + result = test_6(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("HMAC #6 test failed.\n"); + goto exitTest; + } + + result = test_7(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("HMAC test #7 failed.\n"); + goto exitTest; + } + + TC_PRINT("All HMAC tests succeeded!\n"); +exitTest: + TC_END_RESULT(result); + TC_END_REPORT(result); +} diff --git a/src/components/libraries/tinycrypt-0.2.8/tests/test_hmac_prng.c b/src/components/libraries/tinycrypt-0.2.8/tests/test_hmac_prng.c new file mode 100644 index 0000000..0ef05eb --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/tests/test_hmac_prng.c @@ -0,0 +1,140 @@ +/* test_hmac_prng.c - TinyCrypt implementation of some HMAC-PRNG tests */ + +/* + 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. +*/ + +/* + DESCRIPTION + This module tests the following PRNG routines: + + Scenarios tested include: + - HMAC-PRNG init + - HMAC-PRNG reseed + - HMAC-PRNG generate) +*/ + +#include +#include +#include + +#include +#include +#include + +#define TC_DEBUG_MODE 0 + +#ifdef TC_DEBUG_MODE +void show(const char* label, const uint8_t* s, size_t len) +{ + unsigned int i; + printf ("%s = ", label); + + for (i = 0; i < (unsigned int) len; ++i) + { + printf ("%02x", s[i]); + } + + printf ("\n"); +} + +void printBinaryFile(const uint8_t* s, unsigned int slen) +{ + FILE* write_ptr; + write_ptr = fopen("pseudo-random-data.bin","wb"); + fwrite(s, slen, 1, write_ptr); +} +#endif + +/* + Main task to test AES +*/ +int main(void) +{ + uint8_t seed[128]; + struct tc_hmac_prng_struct h; + unsigned int size = (1 << 19); + uint8_t random[size]; + unsigned int i; + unsigned int result = TC_PASS; + TC_START("Performing HMAC-PRNG tests:"); + TC_PRINT("HMAC-PRNG test#1 (init, reseed, generate):\n"); + + /* Fake seed (replace by a a truly random seed): */ + for (i = 0; i < (unsigned int) sizeof(seed); ++i) + { + seed[i] = i; + } + + /* Fake personalization and additional_input (replace by appropriate + values): + e.g.: hostname+timestamp */ + uint8_t* personalization = (uint8_t*) "HOSTNAME"; + uint8_t* additional_input = (uint8_t*) "additional input"; + TC_PRINT("HMAC-PRNG test#1 (init):\n"); + + if (tc_hmac_prng_init(&h, personalization, + sizeof(personalization)) == 0) + { + TC_ERROR("HMAC-PRNG initialization failed.\n"); + result = TC_FAIL; + goto exitTest; + } + + TC_END_RESULT(result); + TC_PRINT("HMAC-PRNG test#1 (reseed):\n"); + + if (tc_hmac_prng_reseed(&h, seed, sizeof(seed), additional_input, + sizeof(additional_input)) == 0) + { + TC_ERROR("HMAC-PRNG reseed failed.\n"); + result = TC_FAIL; + goto exitTest; + } + + TC_END_RESULT(result); + TC_PRINT("HMAC-PRNG test#1 (generate):\n"); + + if (tc_hmac_prng_generate(random, size, &h) < 1) + { + TC_ERROR("HMAC-PRNG generate failed.\n"); + result = TC_FAIL; + goto exitTest; + } + + TC_END_RESULT(result); + #ifdef TC_DEBUG_MODE + printBinaryFile(random, size); + show ("Pseudo-random data", random, size); + #endif + TC_PRINT("All HMAC tests succeeded!\n"); +exitTest: + TC_END_RESULT(result); + TC_END_REPORT(result); +} diff --git a/src/components/libraries/tinycrypt-0.2.8/tests/test_sha256.c b/src/components/libraries/tinycrypt-0.2.8/tests/test_sha256.c new file mode 100644 index 0000000..cf9f9a9 --- /dev/null +++ b/src/components/libraries/tinycrypt-0.2.8/tests/test_sha256.c @@ -0,0 +1,532 @@ +/* test_sha256.c - TinyCrypt implementation of some SHA-256 tests */ + +/* + 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. +*/ + +/* + DESCRIPTION + This module tests the following SHA256 routines: + + Scenarios tested include: + - NIST SHA256 test vectors +*/ + +#include +#include +#include + +#include +#include +#include +#include + +/* + NIST SHA256 test vector 1. +*/ +unsigned int test_1(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #1:\n"); + const uint8_t expected[32] = + { + 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, + 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad + }; + const char* m = "abc"; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + (void)tc_sha256_init(&s); + tc_sha256_update(&s, (const uint8_t*) m, strlen(m)); + (void)tc_sha256_final(digest, &s); + result = check_result(1, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +/* + NIST SHA256 test vector 2. +*/ +unsigned int test_2(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #2:\n"); + const uint8_t expected[32] = + { + 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, + 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, + 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 + }; + const char* m = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + (void)tc_sha256_init(&s); + tc_sha256_update(&s, (const uint8_t*) m, strlen(m)); + (void) tc_sha256_final(digest, &s); + result = check_result(2, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_3(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #3:\n"); + const uint8_t expected[32] = + { + 0x68, 0x32, 0x57, 0x20, 0xaa, 0xbd, 0x7c, 0x82, 0xf3, 0x0f, 0x55, 0x4b, + 0x31, 0x3d, 0x05, 0x70, 0xc9, 0x5a, 0xcc, 0xbb, 0x7d, 0xc4, 0xb5, 0xaa, + 0xe1, 0x12, 0x04, 0xc0, 0x8f, 0xfe, 0x73, 0x2b + }; + const uint8_t m[1] = { 0xbd }; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + (void)tc_sha256_init(&s); + tc_sha256_update(&s, m, sizeof(m)); + (void)tc_sha256_final(digest, &s); + result = check_result(3, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_4(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #4:\n"); + const uint8_t expected[32] = + { + 0x7a, 0xbc, 0x22, 0xc0, 0xae, 0x5a, 0xf2, 0x6c, 0xe9, 0x3d, 0xbb, 0x94, + 0x43, 0x3a, 0x0e, 0x0b, 0x2e, 0x11, 0x9d, 0x01, 0x4f, 0x8e, 0x7f, 0x65, + 0xbd, 0x56, 0xc6, 0x1c, 0xcc, 0xcd, 0x95, 0x04 + }; + const uint8_t m[4] = { 0xc9, 0x8c, 0x8e, 0x55 }; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + (void)tc_sha256_init(&s); + tc_sha256_update(&s, m, sizeof(m)); + (void)tc_sha256_final(digest, &s); + result = check_result(4, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_5(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #5:\n"); + const uint8_t expected[32] = + { + 0x02, 0x77, 0x94, 0x66, 0xcd, 0xec, 0x16, 0x38, 0x11, 0xd0, 0x78, 0x81, + 0x5c, 0x63, 0x3f, 0x21, 0x90, 0x14, 0x13, 0x08, 0x14, 0x49, 0x00, 0x2f, + 0x24, 0xaa, 0x3e, 0x80, 0xf0, 0xb8, 0x8e, 0xf7 + }; + uint8_t m[55]; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + (void)memset(m, 0x00, sizeof(m)); + (void)tc_sha256_init(&s); + tc_sha256_update(&s, m, sizeof(m)); + (void)tc_sha256_final(digest, &s); + result = check_result(5, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_6(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #6:\n"); + const uint8_t expected[32] = + { + 0xd4, 0x81, 0x7a, 0xa5, 0x49, 0x76, 0x28, 0xe7, 0xc7, 0x7e, 0x6b, 0x60, + 0x61, 0x07, 0x04, 0x2b, 0xbb, 0xa3, 0x13, 0x08, 0x88, 0xc5, 0xf4, 0x7a, + 0x37, 0x5e, 0x61, 0x79, 0xbe, 0x78, 0x9f, 0xbb + }; + uint8_t m[56]; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + (void)memset(m, 0x00, sizeof(m)); + (void)tc_sha256_init(&s); + tc_sha256_update(&s, m, sizeof(m)); + (void)tc_sha256_final(digest, &s); + result = check_result(6, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_7(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #7:\n"); + const uint8_t expected[32] = + { + 0x65, 0xa1, 0x6c, 0xb7, 0x86, 0x13, 0x35, 0xd5, 0xac, 0xe3, 0xc6, 0x07, + 0x18, 0xb5, 0x05, 0x2e, 0x44, 0x66, 0x07, 0x26, 0xda, 0x4c, 0xd1, 0x3b, + 0xb7, 0x45, 0x38, 0x1b, 0x23, 0x5a, 0x17, 0x85 + }; + uint8_t m[57]; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + (void)memset(m, 0x00, sizeof(m)); + (void)tc_sha256_init(&s); + tc_sha256_update(&s, m, sizeof(m)); + (void)tc_sha256_final(digest, &s); + result = check_result(7, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_8(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #8:\n"); + const uint8_t expected[32] = + { + 0xf5, 0xa5, 0xfd, 0x42, 0xd1, 0x6a, 0x20, 0x30, 0x27, 0x98, 0xef, 0x6e, + 0xd3, 0x09, 0x97, 0x9b, 0x43, 0x00, 0x3d, 0x23, 0x20, 0xd9, 0xf0, 0xe8, + 0xea, 0x98, 0x31, 0xa9, 0x27, 0x59, 0xfb, 0x4b + }; + uint8_t m[64]; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + (void)memset(m, 0x00, sizeof(m)); + (void)tc_sha256_init(&s); + tc_sha256_update(&s, m, sizeof(m)); + (void)tc_sha256_final(digest, &s); + result = check_result(8, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_9(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #9:\n"); + const uint8_t expected[32] = + { + 0x54, 0x1b, 0x3e, 0x9d, 0xaa, 0x09, 0xb2, 0x0b, 0xf8, 0x5f, 0xa2, 0x73, + 0xe5, 0xcb, 0xd3, 0xe8, 0x01, 0x85, 0xaa, 0x4e, 0xc2, 0x98, 0xe7, 0x65, + 0xdb, 0x87, 0x74, 0x2b, 0x70, 0x13, 0x8a, 0x53 + }; + uint8_t m[1000]; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + (void)memset(m, 0x00, sizeof(m)); + (void)tc_sha256_init(&s); + tc_sha256_update(&s, m, sizeof(m)); + (void)tc_sha256_final(digest, &s); + result = check_result(9, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_10(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #10:\n"); + const uint8_t expected[32] = + { + 0xc2, 0xe6, 0x86, 0x82, 0x34, 0x89, 0xce, 0xd2, 0x01, 0x7f, 0x60, 0x59, + 0xb8, 0xb2, 0x39, 0x31, 0x8b, 0x63, 0x64, 0xf6, 0xdc, 0xd8, 0x35, 0xd0, + 0xa5, 0x19, 0x10, 0x5a, 0x1e, 0xad, 0xd6, 0xe4 + }; + uint8_t m[1000]; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + (void)memset(m, 0x41, sizeof(m)); + (void)tc_sha256_init(&s); + tc_sha256_update(&s, m, sizeof(m)); + (void)tc_sha256_final(digest, &s); + result = check_result(10, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_11(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #11:\n"); + const uint8_t expected[32] = + { + 0xf4, 0xd6, 0x2d, 0xde, 0xc0, 0xf3, 0xdd, 0x90, 0xea, 0x13, 0x80, 0xfa, + 0x16, 0xa5, 0xff, 0x8d, 0xc4, 0xc5, 0x4b, 0x21, 0x74, 0x06, 0x50, 0xf2, + 0x4a, 0xfc, 0x41, 0x20, 0x90, 0x35, 0x52, 0xb0 + }; + uint8_t m[1005]; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + (void)memset(m, 0x55, sizeof(m)); + (void)tc_sha256_init(&s); + tc_sha256_update(&s, m, sizeof(m)); + (void)tc_sha256_final(digest, &s); + result = check_result(11, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_12(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #12:\n"); + const uint8_t expected[32] = + { + 0xd2, 0x97, 0x51, 0xf2, 0x64, 0x9b, 0x32, 0xff, 0x57, 0x2b, 0x5e, 0x0a, + 0x9f, 0x54, 0x1e, 0xa6, 0x60, 0xa5, 0x0f, 0x94, 0xff, 0x0b, 0xee, 0xdf, + 0xb0, 0xb6, 0x92, 0xb9, 0x24, 0xcc, 0x80, 0x25 + }; + uint8_t m[1000]; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + unsigned int i; + (void)memset(m, 0x00, sizeof(m)); + (void)tc_sha256_init(&s); + + for (i = 0; i < 1000; ++i) + { + tc_sha256_update(&s, m, sizeof(m)); + } + + (void)tc_sha256_final(digest, &s); + result = check_result(12, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_13(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #13:\n"); + const uint8_t expected[32] = + { + 0x15, 0xa1, 0x86, 0x8c, 0x12, 0xcc, 0x53, 0x95, 0x1e, 0x18, 0x23, 0x44, + 0x27, 0x74, 0x47, 0xcd, 0x09, 0x79, 0x53, 0x6b, 0xad, 0xcc, 0x51, 0x2a, + 0xd2, 0x4c, 0x67, 0xe9, 0xb2, 0xd4, 0xf3, 0xdd + }; + uint8_t m[32768]; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + unsigned int i; + (void)memset(m, 0x5a, sizeof(m)); + (void)tc_sha256_init(&s); + + for (i = 0; i < 16384; ++i) + { + tc_sha256_update(&s, m, sizeof(m)); + } + + (void)tc_sha256_final(digest, &s); + result = check_result(13, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_14(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #14:\n"); + const uint8_t expected[32] = + { + 0x46, 0x1c, 0x19, 0xa9, 0x3b, 0xd4, 0x34, 0x4f, 0x92, 0x15, 0xf5, 0xec, + 0x64, 0x35, 0x70, 0x90, 0x34, 0x2b, 0xc6, 0x6b, 0x15, 0xa1, 0x48, 0x31, + 0x7d, 0x27, 0x6e, 0x31, 0xcb, 0xc2, 0x0b, 0x53 + }; + uint8_t m[32768]; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + unsigned int i; + (void)memset(m, 0x00, sizeof(m)); + (void) tc_sha256_init(&s); + + for (i = 0; i < 33280; ++i) + { + tc_sha256_update(&s, m, sizeof(m)); + } + + (void) tc_sha256_final(digest, &s); + result = check_result(14, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +/* + Main task to test AES +*/ + +int main(void) +{ + unsigned int result = TC_PASS; + TC_START("Performing SHA256 tests (NIST tests vectors):"); + result = test_1(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("SHA256 test #1 failed.\n"); + goto exitTest; + } + + result = test_2(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("SHA256 test #2 failed.\n"); + goto exitTest; + } + + result = test_3(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("SHA256 test #3 failed.\n"); + goto exitTest; + } + + result = test_4(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("SHA256 test #4 failed.\n"); + goto exitTest; + } + + result = test_5(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("SHA256 test #5 failed.\n"); + goto exitTest; + } + + result = test_6(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("SHA256 test #6 failed.\n"); + goto exitTest; + } + + result = test_7(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("SHA256 test #7 failed.\n"); + goto exitTest; + } + + result = test_8(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("SHA256 test #8 failed.\n"); + goto exitTest; + } + + result = test_9(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("SHA256 test #9 failed.\n"); + goto exitTest; + } + + result = test_10(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("SHA256 test #10 failed.\n"); + goto exitTest; + } + + result = test_11(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("SHA256 test #11 failed.\n"); + goto exitTest; + } + + result = test_12(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("SHA256 test #12 failed.\n"); + goto exitTest; + } + + /* memory and computation intensive test cases: */ + result = test_13(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("SHA256 test #13 failed.\n"); + goto exitTest; + } + + result = test_14(); + + if (result == TC_FAIL) + { + /* terminate test */ + TC_ERROR("SHA256 test #14 failed.\n"); + goto exitTest; + } + + TC_PRINT("All SHA256 tests succeeded!\n"); +exitTest: + TC_END_RESULT(result); + TC_END_REPORT(result); +} + diff --git a/src/components/osal/include/OSAL.h b/src/components/osal/include/OSAL.h new file mode 100644 index 0000000..295a4c2 --- /dev/null +++ b/src/components/osal/include/OSAL.h @@ -0,0 +1,270 @@ +/****************************************************************************** + Filename: OSAL.h + Revised: + Revision: +******************************************************************************/ + +#ifndef OSAL_H +#define OSAL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +#include "comdef.h" +#include "OSAL_Memory.h" +#include "OSAL_Timers.h" + +/********************************************************************* + MACROS +*/ +#if ( UINT_MAX == 65535 ) /* 8-bit and 16-bit devices */ +#define osal_offsetof(type, member) ((uint16) &(((type *) 0)->member)) +#else /* 32-bit devices */ +#define osal_offsetof(type, member) ((uint32) &(((type *) 0)->member)) +#endif + +#define OSAL_MSG_NEXT(msg_ptr) ((osal_msg_hdr_t *) (msg_ptr) - 1)->next + +#define OSAL_MSG_Q_INIT(q_ptr) *(q_ptr) = NULL + +#define OSAL_MSG_Q_EMPTY(q_ptr) (*(q_ptr) == NULL) + +#define OSAL_MSG_Q_HEAD(q_ptr) (*(q_ptr)) + +#define OSAL_MSG_LEN(msg_ptr) ((osal_msg_hdr_t *) (msg_ptr) - 1)->len + +#define OSAL_MSG_ID(msg_ptr) ((osal_msg_hdr_t *) (msg_ptr) - 1)->dest_id + +/********************************************************************* + CONSTANTS +*/ + +/*** Interrupts ***/ +#define INTS_ALL 0xFF + +/********************************************************************* + TYPEDEFS +*/ +typedef struct +{ + void* next; + uint16 len; + uint8 dest_id; +} osal_msg_hdr_t; + +typedef struct +{ + uint8 event; + uint8 status; +} osal_event_hdr_t; + +typedef void* osal_msg_q_t; + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + FUNCTIONS +*/ + +/*** Message Management ***/ + +/* + Task Message Allocation +*/ +extern uint8* osal_msg_allocate(uint16 len ); + +/* + Task Message Deallocation +*/ +extern uint8 osal_msg_deallocate( uint8* msg_ptr ); + +/* + Send a Task Message +*/ +extern uint8 osal_msg_send( uint8 destination_task, uint8* msg_ptr ); + +/* + Push a Task Message to head of queue +*/ +extern uint8 osal_msg_push_front( uint8 destination_task, uint8* msg_ptr ); + +/* + Receive a Task Message +*/ +extern uint8* osal_msg_receive( uint8 task_id ); + +/* + Find in place a matching Task Message / Event. +*/ +extern osal_event_hdr_t* osal_msg_find(uint8 task_id, uint8 event); + +/* + Enqueue a Task Message +*/ +extern void osal_msg_enqueue( osal_msg_q_t* q_ptr, void* msg_ptr ); + +/* + Enqueue a Task Message Up to Max +*/ +extern uint8 osal_msg_enqueue_max( osal_msg_q_t* q_ptr, void* msg_ptr, uint8 max ); + +/* + Dequeue a Task Message +*/ +extern void* osal_msg_dequeue( osal_msg_q_t* q_ptr ); + +/* + Push a Task Message to head of queue +*/ +extern void osal_msg_push( osal_msg_q_t* q_ptr, void* msg_ptr ); + +/* + Extract and remove a Task Message from queue +*/ +extern void osal_msg_extract( osal_msg_q_t* q_ptr, void* msg_ptr, void* prev_ptr ); + + +/*** Task Synchronization ***/ + +/* + Set a Task Event +*/ +extern uint8 osal_set_event( uint8 task_id, uint16 event_flag ); + + +/* + Clear a Task Event +*/ +extern uint8 osal_clear_event( uint8 task_id, uint16 event_flag ); + + +/*** Interrupt Management ***/ + +/* + Register Interrupt Service Routine (ISR) +*/ +extern uint8 osal_isr_register( uint8 interrupt_id, void (*isr_ptr)( uint8* ) ); + +/* + Enable Interrupt +*/ +extern uint8 osal_int_enable( uint8 interrupt_id ); + +/* + Disable Interrupt +*/ +extern uint8 osal_int_disable( uint8 interrupt_id ); + + +/*** Task Management ***/ + +/* + Initialize the Task System +*/ +extern uint8 osal_init_system( void ); + +/* + System Processing Loop +*/ +#if defined (ZBIT) +extern __declspec(dllexport) void osal_start_system( void ); +#else +extern void osal_start_system( void ); +#endif + +/* + One Pass Throu the OSAL Processing Loop +*/ +extern void osal_run_system( void ); + +/* + Get the active task ID +*/ +extern uint8 osal_self( void ); + + +/*** Helper Functions ***/ + +/* + String Length +*/ +extern int osal_strlen( char* pString ); + +/* + Memory copy +*/ +extern void* osal_memcpy( void*, const void GENERIC*, unsigned int ); + +/* + Memory Duplicate - allocates and copies +*/ +extern void* osal_memdup( const void GENERIC* src, unsigned int len ); + +/* + Reverse Memory copy +*/ +extern void* osal_revmemcpy( void*, const void GENERIC*, unsigned int ); + +/* + Memory compare +*/ +extern uint8 osal_memcmp( const void GENERIC* src1, const void GENERIC* src2, unsigned int len ); + +/* + Memory set +*/ +extern void* osal_memset( void* dest, uint8 value, int len ); + +/* + Build a uint16 out of 2 bytes (0 then 1). +*/ +extern uint16 osal_build_uint16( uint8* swapped ); + +/* + Build a uint32 out of sequential bytes. +*/ +extern uint32 osal_build_uint32( uint8* swapped, uint8 len ); + +/* + Convert long to ascii string +*/ +#if !defined ( ZBIT ) && !defined ( ZBIT2 ) && !defined (UBIT) +extern uint8* _ltoa( uint32 l, uint8* buf, uint8 radix ); +#endif + +/* + Random number generator +*/ +extern uint16 osal_rand( void ); + +/* + Buffer an uint32 value - LSB first. +*/ +extern uint8* osal_buffer_uint32( uint8* buf, uint32 val ); + +/* + Buffer an uint24 value - LSB first +*/ +extern uint8* osal_buffer_uint24( uint8* buf, uint24 val ); + +/* + Is all of the array elements set to a value? +*/ +extern uint8 osal_isbufset( uint8* buf, uint8 val, uint8 len ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* OSAL_H */ diff --git a/src/components/osal/include/OSAL_Clock.h b/src/components/osal/include/OSAL_Clock.h new file mode 100644 index 0000000..d1d900a --- /dev/null +++ b/src/components/osal/include/OSAL_Clock.h @@ -0,0 +1,111 @@ +/****************************************************************************** + Filename: OSAL_Clock.h + Revised: + Revision: + + Description: OSAL Clock definition and manipulation functions. + + + +******************************************************************************/ + +#ifndef OSAL_CLOCK_H +#define OSAL_CLOCK_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + MACROS +*/ + +#define IsLeapYear(yr) (!((yr) % 400) || (((yr) % 100) && !((yr) % 4))) + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +// number of seconds since 0 hrs, 0 minutes, 0 seconds, on the +// 1st of January 2000 UTC +typedef unsigned int UTCTime; // to confirm , int is 32bits long + +// To be used with +typedef struct +{ + uint8 seconds; // 0-59 + uint8 minutes; // 0-59 + uint8 hour; // 0-23 + uint8 day; // 0-30 + uint8 month; // 0-11 + uint16 year; // 2000+ +} UTCTimeStruct; + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + FUNCTIONS +*/ + +/* + Updates the OSAL clock and Timers from the MAC 320us timer tick. +*/ +extern void osalTimeUpdate( void ); + +/* + Set the new time. This will only set the seconds portion + of time and doesn't change the factional second counter. + newTime - number of seconds since 0 hrs, 0 minutes, + 0 seconds, on the 1st of January 2000 UTC +*/ +extern void osal_setClock( UTCTime newTime ); + +/* + Gets the current time. This will only return the seconds + portion of time and doesn't include the factional second counter. + returns: number of seconds since 0 hrs, 0 minutes, + 0 seconds, on the 1st of January 2000 UTC +*/ +extern UTCTime osal_getClock( void ); + +/* + Converts UTCTime to UTCTimeStruct + + secTime - number of seconds since 0 hrs, 0 minutes, + 0 seconds, on the 1st of January 2000 UTC + tm - pointer to breakdown struct +*/ +extern void osal_ConvertUTCTime( UTCTimeStruct* tm, UTCTime secTime ); + +/* + Converts UTCTimeStruct to UTCTime (seconds since 00:00:00 01/01/2000) + + tm - pointer to UTC time struct +*/ +extern UTCTime osal_ConvertUTCSecs( UTCTimeStruct* tm ); + +/* + Update/Adjust the osal clock and timers + Msec - elapsed time in milli seconds +*/ +extern void osalAdjustTimer( uint32 Msec ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* OSAL_CLOCK_H */ diff --git a/src/components/osal/include/OSAL_Memory.h b/src/components/osal/include/OSAL_Memory.h new file mode 100644 index 0000000..6e0440a --- /dev/null +++ b/src/components/osal/include/OSAL_Memory.h @@ -0,0 +1,126 @@ +/************************************************************************************************** + Filename: OSAL_Memory.h + Revised: + Revision: + + Description: This module defines the OSAL memory control functions. + + + +**************************************************************************************************/ + +#ifndef OSAL_MEMORY_H +#define OSAL_MEMORY_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ +#include "comdef.h" + +/********************************************************************* + CONSTANTS +*/ + +#if !defined ( OSALMEM_METRICS ) +#define OSALMEM_METRICS FALSE +#endif + +/********************************************************************* + MACROS +*/ + +//#define osal_stack_used() OnBoard_stack_used() + +/********************************************************************* + TYPEDEFS +*/ + +typedef struct +{ + // The 15 LSB's of 'val' indicate the total item size, including the header, in 8-bit bytes. + unsigned short len : 15; // unsigned short len : 15; + // The 1 MSB of 'val' is used as a boolean to indicate in-use or freed. + unsigned short inUse : 1; // unsigned short inUse : 1; +} osalMemHdrHdr_t; + +typedef union +{ + /* Dummy variable so compiler forces structure to alignment of largest element while not wasting + space on targets when the halDataAlign_t is smaller than a UINT16. + */ + halDataAlign_t alignDummy; + uint32 val; // uint16 // TODO: maybe due to 4 byte alignment requirement in M0, this union should be 4 byte, change from uint16 to uint32, investigate more later - 04-25 + osalMemHdrHdr_t hdr; +} osalMemHdr_t; + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + FUNCTIONS +*/ + +/* + Initialize memory manager. +*/ +void osal_mem_init( void ); + +/* + Setup efficient search for the first free block of heap. +*/ +void osal_mem_kick( void ); + +/* + Allocate a block of memory. +*/ +void* osal_mem_alloc( uint16 size ); + +/* + Free a block of memory. +*/ +void osal_mem_free( void* ptr ); + + +// ====== A2 metal change add +/* + Set osal memory buffer +*/ +void osal_mem_set_heap(osalMemHdr_t* hdr, uint32 size); + +#if ( OSALMEM_METRICS ) +/* + Return the maximum number of blocks ever allocated at once. +*/ +uint16 osal_heap_block_max( void ); + +/* + Return the current number of blocks now allocated. +*/ +uint16 osal_heap_block_cnt( void ); + +/* + Return the current number of free blocks. +*/ +uint16 osal_heap_block_free( void ); + +/* + Return the current number of bytes allocated. +*/ +uint16 osal_heap_mem_used( void ); +#endif + + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef OSAL_MEMORY_H */ diff --git a/src/components/osal/include/OSAL_Nv.h b/src/components/osal/include/OSAL_Nv.h new file mode 100644 index 0000000..a70ddb1 --- /dev/null +++ b/src/components/osal/include/OSAL_Nv.h @@ -0,0 +1,83 @@ +/************************************************************************************************** + Filename: OSAL_Nv.h + Revised: + Revision: + + Description: This module defines the OSAL nv control functions. + + + +**************************************************************************************************/ + +#ifndef OSAL_NV_H +#define OSAL_NV_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +#include "hal_types.h" + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + FUNCTIONS +*/ + +/* + Initialize NV service +*/ +extern void osal_nv_init( void* p ); + +/* + Initialize an item in NV +*/ +extern uint8 osal_nv_item_init( uint16 id, uint16 len, void* buf ); + +/* + Read an NV attribute +*/ +extern uint8 osal_nv_read( uint16 id, uint16 offset, uint16 len, void* buf ); + +/* + Write an NV attribute +*/ +extern uint8 osal_nv_write( uint16 id, uint16 offset, uint16 len, void* buf ); + +/* + Get the length of an NV item. +*/ +extern uint16 osal_nv_item_len( uint16 id ); + +/* + Delete an NV item. +*/ +extern uint8 osal_nv_delete( uint16 id, uint16 len ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* OSAL_NV.H */ diff --git a/src/components/osal/include/OSAL_PwrMgr.h b/src/components/osal/include/OSAL_PwrMgr.h new file mode 100644 index 0000000..18d08f1 --- /dev/null +++ b/src/components/osal/include/OSAL_PwrMgr.h @@ -0,0 +1,112 @@ +/************************************************************************************************** + Filename: OSAL_PwrMgr.h + Revised: + Revision: + + Description: This file contains the OSAL Power Management API. + + + **************************************************************************************************/ + +#ifndef OSAL_PWRMGR_H +#define OSAL_PWRMGR_H + +#include "comdef.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/* These attributes define sleep beheaver. The attributes can be changed + for each sleep cycle or when the device characteristic change. +*/ +typedef struct +{ + uint16 pwrmgr_task_state; + uint16 pwrmgr_next_timeout; + uint16 accumulated_sleep_time; + uint8 pwrmgr_device; +} pwrmgr_attribute_t; + +/* With PWRMGR_ALWAYS_ON selection, there is no power savings and the + device is most likely on mains power. The PWRMGR_BATTERY selection allows + the HAL sleep manager to enter SLEEP LITE state or SLEEP DEEP state. +*/ +#define PWRMGR_ALWAYS_ON 0 +#define PWRMGR_BATTERY 1 + +/* The PWRMGR_CONSERVE selection turns power savings on, all tasks have to + agree. The PWRMGR_HOLD selection turns power savings off. +*/ +#define PWRMGR_CONSERVE 0 +#define PWRMGR_HOLD 1 + + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/* This global variable stores the power management attributes. +*/ +extern pwrmgr_attribute_t pwrmgr_attribute; + +/********************************************************************* + FUNCTIONS +*/ + +/* + Initialize the power management system. + This function is called from OSAL. + +*/ +extern void osal_pwrmgr_init( void ); + +/* + This function is called by each task to state whether or not this + task wants to conserve power. The task will call this function to + vote whether it wants the OSAL to conserve power or it wants to + hold off on the power savings. By default, when a task is created, + its own power state is set to conserve. If the task always wants + to converse power, it doesn't need to call this function at all. + It is important for the task that changed the power manager task + state to PWRMGR_HOLD to switch back to PWRMGR_CONSERVE when the + hold period ends. +*/ +extern uint8 osal_pwrmgr_task_state( uint8 task_id, uint8 state ); + +/* + This function is called on power-up, whenever the device characteristic + change (ex. Battery backed coordinator). This function works with the timer + to set HAL's power manager sleep state when power saving is entered. + This function should be called form HAL initialization. After power up + initialization, it should only be called from NWK or ZDO. +*/ +extern void osal_pwrmgr_device( uint8 pwrmgr_device ); + +/* + This function is called from the main OSAL loop when there are + no events scheduled and shouldn't be called from anywhere else. +*/ +extern void osal_pwrmgr_powerconserve( void ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* OSAL_PWRMGR_H */ diff --git a/src/components/osal/include/OSAL_Tasks.h b/src/components/osal/include/OSAL_Tasks.h new file mode 100644 index 0000000..2eb50da --- /dev/null +++ b/src/components/osal/include/OSAL_Tasks.h @@ -0,0 +1,65 @@ +/************************************************************************************************** + Filename: OSAL_Tasks.h + Revised: + Revision: + + Description: This file contains the OSAL Task definition and manipulation functions. + + +**************************************************************************************************/ + +#ifndef OSAL_TASKS_H +#define OSAL_TASKS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ +#define TASK_NO_TASK 0xFF + +/********************************************************************* + TYPEDEFS +*/ + +/* + Event handler function prototype +*/ +typedef unsigned short (*pTaskEventHandlerFn)( unsigned char task_id, unsigned short event ); + +/********************************************************************* + GLOBAL VARIABLES +*/ + +extern const pTaskEventHandlerFn tasksArr[]; +extern const uint8 tasksCnt; +extern uint16* tasksEvents; + +/********************************************************************* + FUNCTIONS +*/ + +/* + Call each of the tasks initailization functions. +*/ +extern void osalInitTasks( void ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* OSAL_TASKS_H */ diff --git a/src/components/osal/include/OSAL_Timers.h b/src/components/osal/include/OSAL_Timers.h new file mode 100644 index 0000000..1b20b13 --- /dev/null +++ b/src/components/osal/include/OSAL_Timers.h @@ -0,0 +1,138 @@ +/************************************************************************************************** + Filename: OSAL_Timers.h + Revised: + Revision: + + Description: This file contains the OSAL Timer definition and manipulation functions. + + + +**************************************************************************************************/ + +#ifndef OSAL_TIMERS_H +#define OSAL_TIMERS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS + the unit is chosen such that the 320us tick equivalent can fit in + 32 bits. +*/ +#define OSAL_TIMERS_MAX_TIMEOUT 0x28f5c28e /* unit is ms*/ + + +/********************************************************************* + TYPEDEFS +*/ +typedef union +{ + uint32 time32; + uint16 time16[2]; + uint8 time8[4]; +} osalTime_t; + +typedef struct +{ + void* next; + osalTime_t timeout; + uint16 event_flag; + uint8 task_id; + uint32 reloadTimeout; +} osalTimerRec_t; + + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + FUNCTIONS +*/ + +/* + Initialization for the OSAL Timer System. +*/ + +extern osalTimerRec_t* osalFindTimer( uint8 task_id, uint16 event_flag ); + +extern void osalTimerInit( void ); + +/* + Set a Timer +*/ +extern uint8 osal_start_timerEx( uint8 task_id, uint16 event_id, uint32 timeout_value ); + +/* + Set a timer that reloads itself. +*/ +extern uint8 osal_start_reload_timer( uint8 taskID, uint16 event_id, uint32 timeout_value ); + +/* + Stop a Timer +*/ +extern uint8 osal_stop_timerEx( uint8 task_id, uint16 event_id ); + +/* + Get the tick count of a Timer. +*/ +extern uint32 osal_get_timeoutEx( uint8 task_id, uint16 event_id ); + +/* + Simulated Timer Interrupt Service Routine +*/ + +extern void osal_timer_ISR( void ); + +/* + Adjust timer tables +*/ +extern void osal_adjust_timers( void ); + +/* + Update timer tables +*/ +extern void osalTimerUpdate( uint32 updateTime ); + +/* + Count active timers +*/ +extern uint8 osal_timer_num_active( void ); + +/* + Set the hardware timer interrupts for sleep mode. + These functions should only be called in OSAL_PwrMgr.c +*/ +extern void osal_sleep_timers( void ); +extern void osal_unsleep_timers( void ); + +/* + Read the system clock - returns milliseconds +*/ +extern uint32 osal_GetSystemClock( void ); + +/* + Get the next OSAL timer expiration. + This function should only be called in OSAL_PwrMgr.c +*/ +extern uint32 osal_next_timeout( void ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* OSAL_TIMERS_H */ diff --git a/src/components/osal/include/comdef.h b/src/components/osal/include/comdef.h new file mode 100644 index 0000000..c5c0c37 --- /dev/null +++ b/src/components/osal/include/comdef.h @@ -0,0 +1,129 @@ +/************************************************************************************************** + Filename: comdef.h + Revised: + Revision: + + Description: Type definitions and macros. + + + +**************************************************************************************************/ + +#ifndef COMDEF_H +#define COMDEF_H + +#ifdef __cplusplus +extern "C" +{ +#endif + + + +/********************************************************************* + INCLUDES +*/ + +/* HAL */ + +#include "types.h" + + +/********************************************************************* + Lint Keywords +*/ +#define VOID (void) + +#define NULL_OK +#define INP +#define OUTP +#define UNUSED +#define ONLY +#define READONLY +#define SHARED +#define KEEP +#define RELAX + + + + +/********************************************************************* + CONSTANTS +*/ + +#ifndef false +#define false 0 +#endif + +#ifndef true +#define true 1 +#endif + +#ifndef CONST +#define CONST const +#endif + +#ifndef GENERIC +#define GENERIC +#endif + +/*** Generic Status Return Values ***/ +#define SUCCESS 0x00 +#define FAILURE 0x01 +#define INVALIDPARAMETER 0x02 +#define INVALID_TASK 0x03 +#define MSG_BUFFER_NOT_AVAIL 0x04 +#define INVALID_MSG_POINTER 0x05 +#define INVALID_EVENT_ID 0x06 +#define INVALID_INTERRUPT_ID 0x07 +#define NO_TIMER_AVAIL 0x08 +#define NV_ITEM_UNINIT 0x09 +#define NV_OPER_FAILED 0x0A +#define INVALID_MEM_SIZE 0x0B +#define NV_BAD_ITEM_LEN 0x0C + +/********************************************************************* + TYPEDEFS +*/ + +// Generic Status return +typedef uint8 Status_t; + +// Data types +typedef int32 int24; +typedef uint32 uint24; + +/********************************************************************* + Global System Events +*/ + +#define SYS_EVENT_MSG 0x8000 // A message is waiting event + +/********************************************************************* + Global Generic System Messages +*/ + +#define KEY_CHANGE 0xC0 // Key Events + +// OSAL System Message IDs/Events Reserved for applications (user applications) +// 0xE0 – 0xFC + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + FUNCTIONS +*/ + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* COMDEF_H */ diff --git a/src/components/osal/include/osal_bufmgr.h b/src/components/osal/include/osal_bufmgr.h new file mode 100644 index 0000000..089f825 --- /dev/null +++ b/src/components/osal/include/osal_bufmgr.h @@ -0,0 +1,80 @@ +/************************************************************************************************** + Filename: osal_bufmgr.h + Revised: + Revision: + + Description: This file contains the buffer management definitions. + + + +**************************************************************************************************/ + +#ifndef OSAL_BUFMGR_H +#define OSAL_BUFMGR_H + +#include "comdef.h" +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + CONSTANTS +*/ + + +/********************************************************************* + VARIABLES +*/ + + +/********************************************************************* + MACROS +*/ + + +/********************************************************************* + TYPEDEFS +*/ + + +/********************************************************************* + VARIABLES +*/ + +/********************************************************************* + FUNCTIONS +*/ + +/* + Allocate a block of memory. +*/ +extern void* osal_bm_alloc( uint16 size ); + +/* + Add or remove header space for the payload pointer. +*/ +extern void* osal_bm_adjust_header( void* payload_ptr, int16 size ); + +/* + Add or remove tail space for the payload pointer. +*/ +extern void* osal_bm_adjust_tail( void* payload_ptr, int16 size ); + +/* + Free a block of memory. +*/ +extern void osal_bm_free( void* payload_ptr ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* OSAL_BUFMGR_H */ diff --git a/src/components/osal/include/osal_cbtimer.h b/src/components/osal/include/osal_cbtimer.h new file mode 100644 index 0000000..bfc16e4 --- /dev/null +++ b/src/components/osal/include/osal_cbtimer.h @@ -0,0 +1,102 @@ +/************************************************************************************************** + Filename: osal_cbtimer.h + Revised: + Revision: + + Description: This file contains the Callback Timer definitions. + + + **************************************************************************************************/ + +#ifndef OSAL_CBTIMER_H +#define OSAL_CBTIMER_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + CONSTANTS +*/ +// Invalid timer id +#define INVALID_TIMER_ID 0xFF + +// Timed out timer +#define TIMEOUT_TIMER_ID 0xFE + +/********************************************************************* + VARIABLES +*/ + +/********************************************************************* + MACROS +*/ +#define OSAL_CBTIMER_NUM_TASKS 1 // set by HZF, align to TI project setting +#if ( OSAL_CBTIMER_NUM_TASKS == 0 ) +#error "Callback Timer module shouldn't be included (no callback timer is needed)!" +#elif ( OSAL_CBTIMER_NUM_TASKS == 1 ) +#define OSAL_CBTIMER_PROCESS_EVENT( a ) ( a ) +#elif ( OSAL_CBTIMER_NUM_TASKS == 2 ) +#define OSAL_CBTIMER_PROCESS_EVENT( a ) ( a ), ( a ) +#else +#error "Maximum of 2 callback timer tasks are supported! Modify it here." +#endif + +/********************************************************************* + TYPEDEFS +*/ + +// Callback Timer function prototype. Callback function will be called +// when the associated timer expires. +// +// pData - pointer to data registered with timer +// +typedef void (*pfnCbTimer_t)( uint8* pData ); + +/********************************************************************* + VARIABLES +*/ + +/********************************************************************* + FUNCTIONS +*/ + +/* + Callback Timer task initialization function. +*/ +extern void osal_CbTimerInit( uint8 taskId ); + +/* + Callback Timer task event processing function. +*/ +extern uint16 osal_CbTimerProcessEvent( uint8 taskId, uint16 events ); + +/* + Function to start a timer to expire in n mSecs. +*/ +extern Status_t osal_CbTimerStart( pfnCbTimer_t pfnCbTimer, uint8* pData, + uint32 timeout, uint8* pTimerId ); + +/* + Function to update a timer that has already been started. +*/ +extern Status_t osal_CbTimerUpdate( uint8 timerId, uint32 timeout ); + +/* + Function to stop a timer that has already been started. +*/ +extern Status_t osal_CbTimerStop( uint8 timerId ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* OSAL_CBTIMER_H */ diff --git a/src/components/osal/include/osal_snv.h b/src/components/osal/include/osal_snv.h new file mode 100644 index 0000000..0168d63 --- /dev/null +++ b/src/components/osal/include/osal_snv.h @@ -0,0 +1,110 @@ +/************************************************************************************************** + Filename: OSAL_snv.h + Revised: + Revision: + + Description: This module defines the OSAL snv control functions. + + + +**************************************************************************************************/ +#ifndef OSAL_SNV_H +#define OSAL_SNV_H + +#include "comdef.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +//#include "hal_types.h" + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + TYPEDEFS +*/ +#ifdef OSAL_SNV_UINT16_ID +typedef uint16 osalSnvId_t; +typedef uint16 osalSnvLen_t; +#else +typedef uint8 osalSnvId_t; +typedef uint8 osalSnvLen_t; +#endif + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + FUNCTIONS +*/ + +/********************************************************************* + @fn osal_snv_init + + @brief Initialize NV service. + + @return SUCCESS if initialization succeeds. FAILURE, otherwise. +*/ +extern uint8 osal_snv_init( void ); + +/********************************************************************* + @fn osal_snv_read + + @brief Read data from NV. + + @param id - Valid NV item Id. + @param len - Length of data to read. + @param *pBuf - Data is read into this buffer. + + @return SUCCESS if successful. + Otherwise, NV_OPER_FAILED for failure. +*/ +extern uint8 osal_snv_read( osalSnvId_t id, osalSnvLen_t len, void* pBuf); + +/********************************************************************* + @fn osal_snv_write + + @brief Write a data item to NV. + + @param id - Valid NV item Id. + @param len - Length of data to write. + @param *pBuf - Data to write. + + @return SUCCESS if successful, NV_OPER_FAILED if failed. +*/ +extern uint8 osal_snv_write( osalSnvId_t id, osalSnvLen_t len, void* pBuf); + +/********************************************************************* + @fn osal_snv_compact + + @brief Compacts NV if its usage has reached a specific threshold. + + @param threshold - compaction threshold + + @return SUCCESS if successful, + NV_OPER_FAILED if failed, or + INVALIDPARAMETER if threshold invalid. +*/ +extern uint8 osal_snv_compact( uint8 threshold ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* OSAL_SNV.H */ diff --git a/src/components/osal/snv/osal_snv.c b/src/components/osal/snv/osal_snv.c new file mode 100644 index 0000000..0d087f8 --- /dev/null +++ b/src/components/osal/snv/osal_snv.c @@ -0,0 +1,113 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#include +#include "OSAL.h" +#include "flash.h" +#include "error.h" +#include "osal_snv.h" +#include "log.h" + +#ifndef USE_FS + #define USE_FS 1 +#endif +#ifdef USE_FS + #include "fs.h" +#endif + + +#if (USE_FS == 0) +#define NVM_BASE_ADDR 0x1103C000 //16K bytes + + +uint8 osal_snv_init( void ) +{ + return PPlus_ERR_FATAL; +} + +uint8 osal_snv_read( osalSnvId_t id, osalSnvLen_t len, void* pBuf) +{ + (void)(id); + (void)(len); + (void)(pBuf); + return PPlus_ERR_FATAL; +} + +uint8 osal_snv_write( osalSnvId_t id, osalSnvLen_t len, void* pBuf) +{ + (void)(id); + (void)(len); + (void)(pBuf); + return PPlus_ERR_FATAL; +} + +uint8 osal_snv_compact( uint8 threshold ) +{ + return SUCCESS; +} + +#else + +uint8 osal_snv_init( void ) +{ + if(!hal_fs_initialized()) + return NV_OPER_FAILED; + + return SUCCESS; +} + +uint8 osal_snv_read( osalSnvId_t id, osalSnvLen_t len, void* pBuf) +{ + int ret; + // LOG("osal_snv_read:%x\n",id); + ret = hal_fs_item_read((uint16_t)id,(uint8_t*) pBuf, (uint16_t)len,NULL); + + if(ret != PPlus_SUCCESS) + { + // LOG("rd_ret:%d\n",ret); + return NV_OPER_FAILED; + } + + // LOG_DUMP_BYTE(pBuf, len); + return SUCCESS; +} + +uint8 osal_snv_write( osalSnvId_t id, osalSnvLen_t len, void* pBuf) +{ + int ret = PPlus_SUCCESS; + // LOG("osal_snv_write:%x,%d\n",id,len); + // LOG_DUMP_BYTE(pBuf, len); + + if(hal_fs_get_free_size() < len+32) + { + if(hal_fs_get_garbage_size(NULL) > len+32) + { + hal_fs_garbage_collect(); + } + else + { + return NV_OPER_FAILED; + } + } + + ret = hal_fs_item_write((uint16_t) id, (uint8_t*) pBuf, (uint16_t) len); + + if(ret !=0) + { + // LOG("wr_ret:%d\n",ret); + return NV_OPER_FAILED; + } + + //LOG("Success\n"); + return SUCCESS; +} + +uint8 osal_snv_compact( uint8 threshold ) +{ + return 0; +} + +#endif + diff --git a/src/components/profiles/AudioProfile/AudioGATTprofile.c b/src/components/profiles/AudioProfile/AudioGATTprofile.c new file mode 100644 index 0000000..4d0376c --- /dev/null +++ b/src/components/profiles/AudioProfile/AudioGATTprofile.c @@ -0,0 +1,664 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: AudioGATTprofile.c + Revised: + Revision: + + Description: This file contains the Simple GATT profile sample GATT service + profile for use with the BLE sample application. + + +**************************************************************************************************/ + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "linkdb.h" +#include "att.h" +#include "gatt.h" +#include "gatt_uuid.h" +#include "gattservapp.h" +#include "gapbondmgr.h" + +#include "AudioGATTprofile.h" + +#include "log.h" +//#include "common.h" +#include "peripheral.h" + +#include "hidkbd.h" + + + + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +#define SERVAPP_NUM_ATTR_SUPPORTED 8 + +/********************************************************************* + TYPEDEFS +*/ + +#define AUDIO_BASE_UUID_128( uuid ) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, \ + 0x00, 0x40, 0x51, 0x04, LO_UINT16( uuid ), HI_UINT16( uuid ), 0x00, 0xF0 + +/********************************************************************* + GLOBAL VARIABLES +*/ + + +uint8 char1Tx_length=0; +uint8 char2Tx_length=0; + +// Audio GATT Profile Service UUID: 0xFF01 + +CONST uint8 AudioProfileServUUID[ATT_UUID_SIZE] = +{ + AUDIO_BASE_UUID_128(AUDIOPROFILE_SERV_UUID) +}; + +// Characteristic 1 UUID: 0xFFF1 +CONST uint8 AudioProfilechar1UUID[ATT_UUID_SIZE] = +{ + AUDIO_BASE_UUID_128(AUDIOPROFILE_CHAR1_UUID) +}; + +// Characteristic 2 UUID: 0xFFF2 +CONST uint8 AudioProfilechar2UUID[ATT_UUID_SIZE] = +{ + AUDIO_BASE_UUID_128(AUDIOPROFILE_CHAR2_UUID) +}; + + + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +static AudioProfileCBs_t* AudioProfile_AppCBs = NULL; + +/********************************************************************* + Profile Attributes - variables +*/ + +// Simple Profile Service attribute +static CONST gattAttrType_t AudioProfileService = { ATT_UUID_SIZE, AudioProfileServUUID }; + + +// Audio Profile Characteristic 1 Properties +static uint8 AudioProfileChar1Props = GATT_PROP_NOTIFY|GATT_PROP_READ; + +// Characteristic 1 Value +uint8 AudioProfileChar1[AUDIOPROFILE_CHAR1_LEN]; + +// Audio Profile Characteristic 1 Configuration Each client has its own +// instantiation of the Client Characteristic Configuration. Reads of the +// Client Characteristic Configuration only shows the configuration for +// that client and writes only affect the configuration of that client. +static gattCharCfg_t AudioProfileChar1Config[GATT_MAX_NUM_CONN]; + + +// Audio Profile Characteristic 2 User Description +//static uint8 AudioProfileChar1UserDesp[] = "RX CHAR\0"; + + + +// Audio Profile Characteristic 1 Properties +static uint8 AudioProfileChar2Props = GATT_PROP_NOTIFY|GATT_PROP_READ; + +// Characteristic 1 Value +uint8 AudioProfileChar2[AUDIOPROFILE_CHAR2_LEN]; + +// Audio Profile Characteristic 1 User Description +//static uint8 AudioProfileChar2UserDesp[] = "TX CHAR\0"; + +// Audio Profile Characteristic 1 Configuration Each client has its own +// instantiation of the Client Characteristic Configuration. Reads of the +// Client Characteristic Configuration only shows the configuration for +// that client and writes only affect the configuration of that client. +static gattCharCfg_t AudioProfileChar2Config[GATT_MAX_NUM_CONN]; + + +/********************************************************************* + Profile Attributes - Table +*/ + +static gattAttribute_t AudioProfileAttrTbl[] = +{ + // =========== Simple Profile Service + { + { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */ + GATT_PERMIT_READ, /* permissions */ + 0, /* handle */ + (uint8*)& AudioProfileService /* pValue */ + }, + + // ---------------------------------------------------------------------- + // Characteristic 1 Declaration, + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &AudioProfileChar1Props + }, + + // Characteristic Value 1 + { + { ATT_UUID_SIZE, AudioProfilechar1UUID }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8*)& AudioProfileChar1 + }, + + // Characteristic 1 User Description, this field is optional +// { +// { ATT_BT_UUID_SIZE, charUserDescUUID }, +// GATT_PERMIT_READ, +// 0, +// AudioProfileChar1UserDesp +// }, + + // Characteristic 1 configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8*)AudioProfileChar1Config + }, + + // ---------------------------------------------------------------------- + // Characteristic 2 Declaration, + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &AudioProfileChar2Props + }, + + // Characteristic Value 2 + { + { ATT_UUID_SIZE, AudioProfilechar2UUID }, + GATT_PERMIT_READ, + 0, + AudioProfileChar2 + }, + + // Characteristic 2 configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8*)AudioProfileChar2Config + }, + + // Characteristic 2 User Description + // { +// { ATT_BT_UUID_SIZE, charUserDescUUID }, +// GATT_PERMIT_READ, +// 0, +// AudioProfileChar2UserDesp +// }, + + +}; + + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static uint8 AudioProfile_ReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ); +static bStatus_t AudioProfile_WriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ); + +static void AudioProfile_HandleConnStatusCB( uint16 connHandle, uint8 changeType ); + + +/********************************************************************* + PROFILE CALLBACKS +*/ +// Audio Profile Service Callbacks +CONST gattServiceCBs_t AudioProfileCBs = +{ + AudioProfile_ReadAttrCB, // Read callback function pointer + AudioProfile_WriteAttrCB, // Write callback function pointer + NULL // Authorization callback function pointer +}; + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/********************************************************************* + @fn AudioProfile_AddService + + @brief Initializes the Simple Profile service by registering + GATT attributes with the GATT server. + + @param services - services to add. This is a bit map and can + contain more than one service. + + @return Success or Failure +*/ +bStatus_t AudioProfile_AddService( uint32 services ) +{ + uint8 status = SUCCESS; + // Initialize Client Characteristic Configuration attributes + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, AudioProfileChar1Config ); + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, AudioProfileChar2Config ); + // Register with Link DB to receive link status change callback + VOID linkDB_Register(AudioProfile_HandleConnStatusCB ); + + if ( services & AUDIOPROFILE_SERVICE ) + { + // Register GATT attribute list and CBs with GATT Server App + status = GATTServApp_RegisterService( AudioProfileAttrTbl, + GATT_NUM_ATTRS( AudioProfileAttrTbl ), + &AudioProfileCBs ); + } + + return ( status ); +} + + +/********************************************************************* + @fn AudioProfile_RegisterAppCBs + + @brief Registers the application callback function. Only call + this function once. + + @param callbacks - pointer to application callbacks. + + @return SUCCESS or bleAlreadyInRequestedMode +*/ +bStatus_t AudioProfile_RegisterAppCBs( AudioProfileCBs_t* appCallbacks ) +{ + if ( appCallbacks ) + { + AudioProfile_AppCBs = appCallbacks; + return ( SUCCESS ); + } + else + { + return ( bleAlreadyInRequestedMode ); + } +} + +/********************************************************************* + @fn AudioProfile_SetParameter + + @brief Set a Simple Profile parameter. + + @param param - Profile parameter ID + @param len - length of data to right + @param value - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t AudioProfile_SetParameter( uint8 param, uint8 len, void* value ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case AUDIOPROFILE_CHAR1: + if ( len >0) + { + VOID osal_memcpy( AudioProfileChar1, value, len ); + char1Tx_length=len; + ret=GATTServApp_ProcessCharCfg( AudioProfileChar1Config, AudioProfileChar1, FALSE, + AudioProfileAttrTbl, GATT_NUM_ATTRS( AudioProfileAttrTbl ), + INVALID_TASK_ID ); + + if(ret!=SUCCESS) + { + // LOG("Notify_error:%d\n\r",ret); + } + } + else + { + ret = bleInvalidRange; + } + + break; + + case AUDIOPROFILE_CHAR2: + if ( len >0) + { + VOID osal_memcpy( AudioProfileChar2, value, len ); + char2Tx_length=len; + ret=GATTServApp_ProcessCharCfg( AudioProfileChar2Config, AudioProfileChar2, FALSE, + AudioProfileAttrTbl, GATT_NUM_ATTRS( AudioProfileAttrTbl ), + INVALID_TASK_ID ); + + if(ret!=SUCCESS) + { + // LOG("Notify_error:%d\nr",ret); + } + } + else + { + ret = bleInvalidRange; + } + + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn AudioProfile_GetParameter + + @brief Get a Audio Profile parameter. + + @param param - Profile parameter ID + @param value - pointer to data to put. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t AudioProfile_GetParameter( uint8 param, void* value ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn AudioProfile_ReadAttrCB + + @brief Read an attribute. + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be read + @param pLen - length of data to be read + @param offset - offset of the first octet to be read + @param maxLen - maximum length of data to be read + + @return Success or Failure +*/ +static uint8 AudioProfile_ReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ) +{ + bStatus_t status = SUCCESS; + + // If attribute permissions require authorization to read, return error + if ( gattPermitAuthorRead( pAttr->permissions ) ) + { + // Insufficient authorization + return ( ATT_ERR_INSUFFICIENT_AUTHOR ); + } + + // Make sure it's not a blob operation (no attributes in the profile are long) + if ( offset > 0 ) + { + return ( ATT_ERR_ATTR_NOT_LONG ); + } + + if ( pAttr->type.len == ATT_BT_UUID_SIZE||pAttr->type.len == ATT_UUID_SIZE ) + { + AudioProfile_Read(connHandle,pAttr,pValue,pLen,offset,maxLen); + } + + return ( status ); +} + +/********************************************************************* + @fn AudioProfile_WriteAttrCB + + @brief Validate attribute data prior to a write operation + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be written + @param len - length of data + @param offset - offset of the first octet to be written + + @return Success or Failure +*/ +static bStatus_t AudioProfile_WriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ) +{ + bStatus_t status = SUCCESS; + uint8 notifyApp = 0xFF; + + // If attribute permissions require authorization to write, return error + if ( gattPermitAuthorWrite( pAttr->permissions ) ) + { + // Insufficient authorization + return ( ATT_ERR_INSUFFICIENT_AUTHOR ); + } + + if ( pAttr->type.len == ATT_BT_UUID_SIZE ) + { + // 16-bit UUID + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + switch ( uuid ) + { + case GATT_CLIENT_CHAR_CFG_UUID: + status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len, + offset, GATT_CLIENT_CFG_NOTIFY ); + + if ( status == SUCCESS ) + { + // uint16 charCfg = BUILD_UINT16( pValue[0], pValue[1] ); + if(pAttr->handle==AudioProfileAttrTbl[3].handle) + { + LOG("audio start cmd enable\n\r"); + } + else if(pAttr->handle==AudioProfileAttrTbl[6].handle) + { + LOG("audio data transf enable\n\r"); + // if(charCfg==0x0001) + //osal_start_timerEx(hidKbdTaskId, HID_KEY_TEST_EVT, 8000); + } + } + + break; + + default: + // Should never get here! (characteristics 2 and 4 do not have write permissions) + status = ATT_ERR_ATTR_NOT_FOUND; + break; + } + } + else + { + // 128-bit UUID + status = ATT_ERR_INVALID_HANDLE; + } + + // If a charactersitic value changed then callback function to notify application of change + if ( (notifyApp != 0xFF ) && AudioProfile_AppCBs && AudioProfile_AppCBs->pfnAudioProfileChange ) + { + AudioProfile_AppCBs->pfnAudioProfileChange( notifyApp ); + } + + return ( status ); +} + +/********************************************************************* + @fn AudioProfile_HandleConnStatusCB + + @brief Audio Profile link status change handler function. + + @param connHandle - connection handle + @param changeType - type of change + + @return none +*/ +static void AudioProfile_HandleConnStatusCB( uint16 connHandle, uint8 changeType ) +{ + // Make sure this is not loopback connection + if ( connHandle != LOOPBACK_CONNHANDLE ) + { + // Reset Client Char Config if connection has dropped + if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) || + ( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && + ( !linkDB_Up( connHandle ) ) ) ) + { + GATTServApp_InitCharCfg( connHandle, AudioProfileChar1Config ); + GATTServApp_InitCharCfg( connHandle, AudioProfileChar2Config ); + } + } +} + +bStatus_t AudioProfile_Notify( uint8 param, uint8 len, void* value ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case AUDIOPROFILE_CHAR2: + VOID osal_memcpy( AudioProfileChar2, value, len ); + GATTServApp_ProcessCharCfg( AudioProfileChar2Config, AudioProfileChar2, FALSE, + AudioProfileAttrTbl, GATT_NUM_ATTRS( AudioProfileAttrTbl ), + INVALID_TASK_ID ); + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +bStatus_t AudioProfile_Write( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint8 len, uint16 offset ) +{ + bStatus_t status = SUCCESS; + // 16-bit UUID + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + switch(uuid) + { + case AUDIOPROFILE_CHAR1_UUID: + if ( offset != 0 ) + { + status = ATT_ERR_ATTR_NOT_LONG; + } + + if ( status == SUCCESS ) + { + uint8* pCurValue = (uint8*)pAttr->pValue; + VOID osal_memcpy( pCurValue, pValue, len ); + //rxdata_process(pCurValue,len); + } + + break; + + case GATT_CLIENT_CHAR_CFG_UUID: + status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len, + offset, GATT_CLIENT_CFG_NOTIFY ); + break; + + default: + status = ATT_ERR_ATTR_NOT_FOUND; + break; + } + + return status; +} + +bStatus_t AudioProfile_Read( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ) +{ + bStatus_t status = SUCCESS; + + if(pAttr->type.len == ATT_BT_UUID_SIZE) + { + // 16-bit UUID + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + LOG("16 uuid:%X\n\r",uuid); + + switch ( uuid ) + { + case AUDIOPROFILE_CHAR1_UUID: + *pLen = char1Tx_length; + VOID osal_memcpy( pValue, pAttr->pValue, *pLen ); + break; + + case AUDIOPROFILE_CHAR2_UUID: + *pLen=char2Tx_length; + VOID osal_memcpy( pValue, pAttr->pValue, *pLen ); + break; + + default: + // Should never get here! (characteristics 3 and 4 do not have read permissions) + *pLen = 0; + status = ATT_ERR_ATTR_NOT_FOUND; + LOG("uuid not find\n\r"); + break; + } + } + else + { + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[12], pAttr->type.uuid[13]); + + //LOG("128 uuid:%X\n\r",uuid); + switch ( uuid ) + { + case AUDIOPROFILE_CHAR1_UUID: + *pLen = char1Tx_length; + VOID osal_memcpy( pValue, pAttr->pValue, *pLen ); + break; + + case AUDIOPROFILE_CHAR2_UUID: + *pLen=char2Tx_length; + VOID osal_memcpy( pValue, pAttr->pValue, *pLen ); + break; + + default: + // Should never get here! (characteristics 3 and 4 do not have read permissions) + *pLen = 0; + status = ATT_ERR_ATTR_NOT_FOUND; + LOG("uuid not find\n\r"); + break; + } + } + + return status; +} + + +/********************************************************************* +*********************************************************************/ diff --git a/src/components/profiles/AudioProfile/AudioGATTprofile.h b/src/components/profiles/AudioProfile/AudioGATTprofile.h new file mode 100644 index 0000000..de17a89 --- /dev/null +++ b/src/components/profiles/AudioProfile/AudioGATTprofile.h @@ -0,0 +1,143 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: AudioGATTprofile.h + Revised: + Revision: + + Description: This file contains the Simple GATT profile definitions and + prototypes. + + **************************************************************************************************/ + +#ifndef AUDIOGATTPROFILE_H +#define AUDIOGATTPROFILE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + CONSTANTS +*/ + +// Profile Parameters +#define AUDIOPROFILE_CHAR1 0 // RW uint8 - Profile Characteristic 1 value +#define AUDIOPROFILE_CHAR2 1 // RW uint8 - Profile Characteristic 2 value + + + +//product id +#define PRODUCT_ID 0x0046 + +// AUDIO Profile Service UUID +#define AUDIOPROFILE_SERV_UUID 0xB000 + + +// Key Pressed UUID +#define AUDIOPROFILE_CHAR1_UUID 0xB001 +#define AUDIOPROFILE_CHAR2_UUID 0xB002 + + +// AUDIO Keys Profile Services bit fields +#define AUDIOPROFILE_SERVICE 0x00000001 + +#define AUDIOPROFILE_CHAR1_LEN 20 +#define AUDIOPROFILE_CHAR2_LEN 20 +// Length of Characteristic 5 in bytes +#define AUDIOPROFILE_CHAR5_LEN 5 + + +/********************************************************************* + TYPEDEFS +*/ + + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + Profile Callbacks +*/ + +// Callback when a characteristic value has changed +typedef void (*AudioProfileChange_t)( uint8 paramID ); + +typedef struct +{ + AudioProfileChange_t pfnAudioProfileChange; // Called when characteristic value changes +} AudioProfileCBs_t; + + + +/********************************************************************* + API FUNCTIONS +*/ + + +/* + AudioProfile_AddService- Initializes the Audio GATT Profile service by registering + GATT attributes with the GATT server. + + @param services - services to add. This is a bit map and can + contain more than one service. +*/ + +extern bStatus_t AudioProfile_AddService( uint32 services ); + +/* + AudioProfile_RegisterAppCBs - Registers the application callback function. + Only call this function once. + + appCallbacks - pointer to application callbacks. +*/ +extern bStatus_t AudioProfile_RegisterAppCBs( AudioProfileCBs_t* appCallbacks ); + +/* + AudioProfile_SetParameter - Set a Audio GATT Profile parameter. + + param - Profile parameter ID + len - length of data to right + value - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). +*/ +extern bStatus_t AudioProfile_SetParameter( uint8 param, uint8 len, void* value ); + +/* + AudioProfile_GetParameter - Get a Audio GATT Profile parameter. + + param - Profile parameter ID + value - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). +*/ +extern bStatus_t AudioProfile_GetParameter( uint8 param, void* value ); + +extern bStatus_t AudioProfile_Notify( uint8 param, uint8 len, void* value ); + +extern bStatus_t AudioProfile_Read( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ); + +extern bStatus_t AudioProfile_Write( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint8 len, uint16 offset ); + + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* SIMPLEGATTPROFILE_H */ diff --git a/src/components/profiles/Batt/battservice.c b/src/components/profiles/Batt/battservice.c new file mode 100644 index 0000000..b78c92f --- /dev/null +++ b/src/components/profiles/Batt/battservice.c @@ -0,0 +1,369 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "types.h" +#include "OSAL.h" +#include "linkdb.h" +#include "att.h" +#include "gatt.h" +#include "gatt_uuid.h" +#include "gatt_profile_uuid.h" +#include "gattservapp.h" +#include "peripheral.h" +#include "hiddev.h" + +#include "battservice.h" +#include "sensor.h" +/********************************************************************* + MACROS +*/ +#define USE_HID_BATT 0 +/********************************************************************* + CONSTANTS +*/ + +#define BATT_LEVEL_VALUE_IDX 2 // Position of battery level in attribute array +#define BATT_LEVEL_VALUE_CCCD_IDX 3 // Position of battery level CCCD in attribute array + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ +// Battery service +CONST uint8 battServUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(BATT_SERV_UUID), HI_UINT16(BATT_SERV_UUID) +}; + +// Battery level characteristic +CONST uint8 battLevelUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(BATT_LEVEL_UUID), HI_UINT16(BATT_LEVEL_UUID) +}; + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +// Application callback +static battServiceCB_t battServiceCB; + +/********************************************************************* + Profile Attributes - variables +*/ + +// Battery Service attribute +static CONST gattAttrType_t battService = { ATT_BT_UUID_SIZE, battServUUID }; + +// Battery level characteristic +static uint8 battLevelProps = GATT_PROP_READ | GATT_PROP_NOTIFY; + +static gattCharCfg_t battLevelClientCharCfg[GATT_MAX_NUM_CONN]; + +#if USE_HID_BATT +// HID Report Reference characteristic descriptor, battery level +static uint8 hidReportRefBattLevel[HID_REPORT_REF_LEN] = +{ HID_RPT_ID_BATT_LEVEL_IN, HID_REPORT_TYPE_INPUT }; +#endif + +/********************************************************************* + Profile Attributes - Table +*/ + +static gattAttribute_t battAttrTbl[] = +{ + // Battery Service + { + { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */ + GATT_PERMIT_READ, /* permissions */ + 0, /* handle */ + (uint8*)& battService /* pValue */ + }, + + // Battery Level Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &battLevelProps + }, + + // Battery Level Value + { + { ATT_BT_UUID_SIZE, battLevelUUID }, + GATT_PERMIT_READ, + 0, + &measured_data.battery + }, + + // Battery Level Client Characteristic Configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8*)& battLevelClientCharCfg + }, + + // HID Report Reference characteristic descriptor, batter level input +#if USE_HID_BATT + { + { ATT_BT_UUID_SIZE, reportRefUUID }, + GATT_PERMIT_READ, + 0, + hidReportRefBattLevel + }, +#endif +#ifdef HID_VOICE_SPEC + + // Characteristic Presentation format + { + { ATT_BT_UUID_SIZE, charFormatUUID }, + GATT_PERMIT_READ, + 0, + (uint8_t*)& battLevelPresentation + }, +#endif +}; + + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static uint8 battReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ); +static bStatus_t battWriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ); +static void battNotifyCB( linkDBItem_t* pLinkItem ); +//static void battNotifyLevel( void ); + +/********************************************************************* + PROFILE CALLBACKS +*/ +// Battery Service Callbacks +CONST gattServiceCBs_t battCBs = +{ + battReadAttrCB, // Read callback function pointer + battWriteAttrCB, // Write callback function pointer + NULL // Authorization callback function pointer +}; + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/********************************************************************* + @fn Batt_AddService + + @brief Initializes the Battery Service by registering + GATT attributes with the GATT server. + + @return Success or Failure +*/ +bStatus_t Batt_AddService( void ) +{ + uint8 status = SUCCESS; + // Initialize Client Characteristic Configuration attributes + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, battLevelClientCharCfg ); + // Register GATT attribute list and CBs with GATT Server App + status = GATTServApp_RegisterService( battAttrTbl, + GATT_NUM_ATTRS( battAttrTbl ), + &battCBs ); + return ( status ); +} + +/********************************************************************* + @fn Batt_Register + + @brief Register a callback function with the Battery Service. + + @param pfnServiceCB - Callback function. + + @return None. +*/ +extern void Batt_Register( battServiceCB_t pfnServiceCB ) +{ + battServiceCB = pfnServiceCB; +} + +/********************************************************************* + @fn battReadAttrCB + + @brief Read an attribute. + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be read + @param pLen - length of data to be read + @param offset - offset of the first octet to be read + @param maxLen - maximum length of data to be read + + @return Success or Failure +*/ +static uint8 battReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ) +{ + bStatus_t status = SUCCESS; + + // Make sure it's not a blob operation (no attributes in the profile are long) + if ( offset > 0 ) + { + return ( ATT_ERR_ATTR_NOT_LONG ); + } + + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1] ); + + // Measure battery level if reading level + if ( uuid == BATT_LEVEL_UUID ) + { + *pLen = 1; + pValue[0] = measured_data.battery; + } +#if USE_HID_BATT + else if ( uuid == GATT_REPORT_REF_UUID ) + { + *pLen = HID_REPORT_REF_LEN; + osal_memcpy( pValue, pAttr->pValue, HID_REPORT_REF_LEN ); + } +#endif + else + { + status = ATT_ERR_ATTR_NOT_FOUND; + } + + return ( status ); +} + +/********************************************************************* + @fn battWriteAttrCB + + @brief Validate attribute data prior to a write operation + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be written + @param len - length of data + @param offset - offset of the first octet to be written + + @return Success or Failure +*/ +static bStatus_t battWriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ) +{ + bStatus_t status = SUCCESS; + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + switch ( uuid ) + { + case GATT_CLIENT_CHAR_CFG_UUID: + status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len, + offset, GATT_CLIENT_CFG_NOTIFY ); + + if ( status == SUCCESS ) + { + uint16 charCfg = BUILD_UINT16( pValue[0], pValue[1] ); + + if ( battServiceCB ) + { + (*battServiceCB)( (charCfg == GATT_CFG_NO_OPERATION) ? + BATT_LEVEL_NOTI_DISABLED : + BATT_LEVEL_NOTI_ENABLED); + } + } + + break; + + default: + status = ATT_ERR_ATTR_NOT_FOUND; + break; + } + + return ( status ); +} + +/********************************************************************* + @fn battNotifyCB + + @brief Send a notification of the level state characteristic. + + @param connHandle - linkDB item + + @return None. +*/ +static void battNotifyCB( linkDBItem_t* pLinkItem ) +{ + if ( pLinkItem->stateFlags & LINK_CONNECTED ) + { + uint16 value = GATTServApp_ReadCharCfg( pLinkItem->connectionHandle, + battLevelClientCharCfg ); + + if ( value & GATT_CLIENT_CFG_NOTIFY ) + { + attHandleValueNoti_t noti; + noti.handle = battAttrTbl[BATT_LEVEL_VALUE_IDX].handle; + noti.len = 1; + noti.value[0] = measured_data.battery; + GATT_Notification( pLinkItem->connectionHandle, ¬i, FALSE ); + } + } +} + +/********************************************************************* + @fn battNotifyLevelState + + @brief Send a notification of the battery level state + characteristic if a connection is established. + + @return None. +*/ +void BattNotifyLevel( void ) +{ + // Execute linkDB callback to send notification + linkDB_PerformFunc( battNotifyCB ); +} + +/********************************************************************* + @fn Batt_HandleConnStatusCB + + @brief Battery Service link status change handler function. + + @param connHandle - connection handle + @param changeType - type of change + + @return none +*/ +void Batt_HandleConnStatusCB( uint16 connHandle, uint8 changeType ) +{ + // Make sure this is not loopback connection + if ( connHandle != LOOPBACK_CONNHANDLE ) + { + // Reset Client Char Config if connection has dropped + if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) || + ( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && + ( !linkDB_Up( connHandle ) ) ) ) + { + GATTServApp_InitCharCfg( connHandle, battLevelClientCharCfg ); + } + } +} + + +/********************************************************************* +*********************************************************************/ diff --git a/src/components/profiles/Batt/battservice.h b/src/components/profiles/Batt/battservice.h new file mode 100644 index 0000000..4d93f77 --- /dev/null +++ b/src/components/profiles/Batt/battservice.h @@ -0,0 +1,182 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#ifndef BATTSERVICE_H +#define BATTSERVICE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + CONSTANTS +*/ + +// Battery Service Get/Set Parameters +#define BATT_PARAM_LEVEL 0 +#define BATT_PARAM_CRITICAL_LEVEL 1 +#define BATT_PARAM_SERVICE_HANDLE 2 +#define BATT_PARAM_BATT_LEVEL_IN_REPORT 3 + +// Callback events +#define BATT_LEVEL_NOTI_ENABLED 1 +#define BATT_LEVEL_NOTI_DISABLED 2 + +// HID Report IDs for the service +#define HID_RPT_ID_BATT_LEVEL_IN 4 // Battery Level input report ID + +#ifdef HID_VOICE_SPEC +#define GATT_DESC_LENGTH_UUID 0x3111 // Used with Unit percent +#endif + + +/********************************************************************* + TYPEDEFS +*/ + +// Battery Service callback function +typedef void (*battServiceCB_t)(uint8 event); + +// Battery measure HW setup function +typedef void (*battServiceSetupCB_t)(void); + +// Battery measure percentage calculation function +typedef uint8 (*battServiceCalcCB_t)(uint16 adcVal); + +// Battery measure HW teardown function +typedef void (*battServiceTeardownCB_t)(void); + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + Profile Callbacks +*/ + + +/********************************************************************* + API FUNCTIONS +*/ + +/********************************************************************* + @fn Batt_AddService + + @brief Initializes the Battery service by registering + GATT attributes with the GATT server. + + @return Success or Failure +*/ +extern bStatus_t Batt_AddService( void ); + +/********************************************************************* + @fn Batt_Register + + @brief Register a callback function with the Battery Service. + + @param pfnServiceCB - Callback function. + + @return None. +*/ +extern void Batt_Register( battServiceCB_t pfnServiceCB ); + +/********************************************************************* + @fn Batt_SetParameter + + @brief Set a Battery Service parameter. + + @param param - Profile parameter ID + @param len - length of data to right + @param value - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +extern bStatus_t Batt_SetParameter( uint8 param, uint8 len, void* value ); + +/********************************************************************* + @fn Batt_GetParameter + + @brief Get a Battery parameter. + + @param param - Profile parameter ID + @param value - pointer to data to get. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +extern bStatus_t Batt_GetParameter( uint8 param, void* value ); + +/********************************************************************* + @fn Batt_MeasLevel + + @brief Measure the battery level and update the battery + level value in the service characteristics. If + the battery level-state characteristic is configured + for notification and the battery level has changed + since the last measurement, then a notification + will be sent. + + @return Success or Failure +*/ +extern bStatus_t Batt_MeasLevel( void ); + +/********************************************************************* + @fn Batt_Setup + + @brief Set up which ADC source is to be used. Defaults to VDD/3. + + @param adc_ch - ADC Channel, e.g. HAL_ADC_CHN_AIN6 + @param minVal - max battery level + @param maxVal - min battery level + @param sCB - HW setup callback + @param tCB - HW tear down callback + @param cCB - percentage calculation callback + + @return none. +*/ +extern void Batt_Setup( uint8 adc_ch, uint16 minVal, uint16 maxVal, + battServiceSetupCB_t sCB, battServiceTeardownCB_t tCB, + battServiceCalcCB_t cCB ); + +/********************************************************************* + @fn Batt_HandleConnStatusCB + + @brief Battery Service link status change handler function. + + @param connHandle - connection handle + @param changeType - type of change + + @return none +*/ +void Batt_HandleConnStatusCB( uint16 connHandle, uint8 changeType ); + +/********************************************************************* + @fn battNotifyLevelState + + @brief Send a notification of the battery level state + characteristic if a connection is established. + + @return None. +*/ +void BattNotifyLevel( void ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* BATTSERVICE_H */ diff --git a/src/components/profiles/Batt/hiddev.h b/src/components/profiles/Batt/hiddev.h new file mode 100644 index 0000000..2b32fc1 --- /dev/null +++ b/src/components/profiles/Batt/hiddev.h @@ -0,0 +1,301 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + + +#ifndef HIDDEV_H +#define HIDDEV_H + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +// HID Device Parameters +#define HIDDEV_ERASE_ALLBONDS 0 // Erase all of the bonded devices. Write Only. No Size. + +// HID read/write operation +#define HID_DEV_OPER_WRITE 0 // Write operation +#define HID_DEV_OPER_READ 1 // Read operation +#define HID_DEV_OPER_ENABLE 2 // Notification enabled for report ID +#define HID_DEV_OPER_DISABLE 3 // Notifications disabled for report ID + +// HID callback events +#define HID_DEV_SUSPEND_EVT 0 // HID suspend +#define HID_DEV_EXIT_SUSPEND_EVT 1 // HID exit suspend +#define HID_DEV_SET_BOOT_EVT 2 // HID set boot mode +#define HID_DEV_SET_REPORT_EVT 3 // HID set report mode + +/* HID Report type */ +#define HID_REPORT_TYPE_INPUT 1 +#define HID_REPORT_TYPE_OUTPUT 2 +#define HID_REPORT_TYPE_FEATURE 3 + +/* HID information flags */ +#define HID_FLAGS_REMOTE_WAKE 0x01 // RemoteWake +#define HID_FLAGS_NORMALLY_CONNECTABLE 0x02 // NormallyConnectable + +/* Control point commands */ +#define HID_CMD_SUSPEND 0x00 // Suspend +#define HID_CMD_EXIT_SUSPEND 0x01 // Exit Suspend + +/* HID protocol mode values */ +#define HID_PROTOCOL_MODE_BOOT 0x00 // Boot Protocol Mode +#define HID_PROTOCOL_MODE_REPORT 0x01 // Report Protocol Mode + +/* Attribute value lengths */ +#define HID_PROTOCOL_MODE_LEN 1 // HID Protocol Mode +#define HID_INFORMATION_LEN 4 // HID Information +#define HID_REPORT_REF_LEN 2 // HID Report Reference Descriptor +#define HID_EXT_REPORT_REF_LEN 2 // External Report Reference Descriptor + +// HID Keyboard/Keypad Usage IDs (subset of the codes available in the USB HID Usage Tables spec) +#define HID_KEYBOARD_RESERVED 0 // 0x00 - No event inidicated +#define HID_KEYBOARD_A 4 // 0x04 - Keyboard a and A +#define HID_KEYBOARD_B 5 // 0x05 - Keyboard b and B +#define HID_KEYBOARD_C 6 // 0x06 - Keyboard c and C +#define HID_KEYBOARD_D 7 // 0x07 - Keyboard d and D +#define HID_KEYBOARD_E 8 // 0x08 - Keyboard e and E +#define HID_KEYBOARD_F 9 // 0x09 - Keyboard f and F +#define HID_KEYBOARD_G 10 // 0x0A - Keyboard g and G +#define HID_KEYBOARD_H 11 // 0x0B - Keyboard h and H +#define HID_KEYBOARD_I 12 // 0x0C - Keyboard i and I +#define HID_KEYBOARD_J 13 // 0x0D - Keyboard j and J +#define HID_KEYBOARD_K 14 // 0x0E - Keyboard k and K +#define HID_KEYBOARD_L 15 // 0x0F - Keyboard l and L +#define HID_KEYBOARD_M 16 // 0x10 - Keyboard m and M +#define HID_KEYBOARD_N 17 // 0x11 - Keyboard n and N +#define HID_KEYBOARD_O 18 // 0x12 - Keyboard o and O +#define HID_KEYBOARD_P 19 // 0x13 - Keyboard p and p +#define HID_KEYBOARD_Q 20 // 0x14 - Keyboard q and Q +#define HID_KEYBOARD_R 21 // 0x15 - Keyboard r and R +#define HID_KEYBOARD_S 22 // 0x16 - Keyboard s and S +#define HID_KEYBOARD_T 23 // 0x17 - Keyboard t and T +#define HID_KEYBOARD_U 24 // 0x18 - Keyboard u and U +#define HID_KEYBOARD_V 25 // 0x19 - Keyboard v and V +#define HID_KEYBOARD_W 26 // 0x1A - Keyboard w and W +#define HID_KEYBOARD_X 27 // 0x1B - Keyboard x and X +#define HID_KEYBOARD_Y 28 // 0x1C - Keyboard y and Y +#define HID_KEYBOARD_Z 29 // 0x1D - Keyboard z and Z +#define HID_KEYBOARD_1 30 // 0x1E - Keyboard 1 and ! +#define HID_KEYBOARD_2 31 // 0x1F - Keyboard 2 and @ +#define HID_KEYBOARD_3 32 // 0x20 - Keyboard 3 and # +#define HID_KEYBOARD_4 33 // 0x21 - Keyboard 4 and % +#define HID_KEYBOARD_5 34 // 0x22 - Keyboard 5 and % +#define HID_KEYBOARD_6 35 // 0x23 - Keyboard 6 and ^ +#define HID_KEYBOARD_7 36 // 0x24 - Keyboard 7 and & +#define HID_KEYBOARD_8 37 // 0x25 - Keyboard 8 and * +#define HID_KEYBOARD_9 38 // 0x26 - Keyboard 9 and ( +#define HID_KEYBOARD_0 39 // 0x27 - Keyboard 0 and ) +#define HID_KEYBOARD_RETURN 40 // 0x28 - Keyboard Return (ENTER) +#define HID_KEYBOARD_ESCAPE 41 // 0x29 - Keyboard ESCAPE +#define HID_KEYBOARD_DELETE 42 // 0x2A - Keyboard DELETE (Backspace) +#define HID_KEYBOARD_TAB 43 // 0x2B - Keyboard Tab +#define HID_KEYBOARD_SPACEBAR 44 // 0x2C - Keyboard Spacebar +#define HID_KEYBOARD_MINUS 45 // 0x2D - Keyboard - and (underscore) +#define HID_KEYBOARD_EQUAL 46 // 0x2E - Keyboard = and + +#define HID_KEYBOARD_LEFT_BRKT 47 // 0x2F - Keyboard [ and { +#define HID_KEYBOARD_RIGHT_BRKT 48 // 0x30 - Keyboard ] and } +#define HID_KEYBOARD_BACK_SLASH 49 // 0x31 - Keyboard \ and | +#define HID_KEYBOARD_SEMI_COLON 51 // 0x33 - Keyboard ; and : +#define HID_KEYBOARD_SGL_QUOTE 52 // 0x34 - Keyboard ' and " +#define HID_KEYBOARD_GRV_ACCENT 53 // 0x35 - Keyboard Grave Accent and Tilde +#define HID_KEYBOARD_COMMA 54 // 0x36 - Keyboard , and < +#define HID_KEYBOARD_DOT 55 // 0x37 - Keyboard . and > +#define HID_KEYBOARD_FWD_SLASH 56 // 0x38 - Keyboard / and ? +#define HID_KEYBOARD_CAPS_LOCK 57 // 0x39 - Keyboard Caps Lock +#define HID_KEYBOARD_F1 58 // 0x3A - Keyboard F1 +#define HID_KEYBOARD_F2 59 // 0x3B - Keyboard F2 +#define HID_KEYBOARD_F3 60 // 0x3C - Keyboard F3 +#define HID_KEYBOARD_F4 61 // 0x3D - Keyboard F4 +#define HID_KEYBOARD_F5 62 // 0x3E - Keyboard F5 +#define HID_KEYBOARD_F6 63 // 0x3F - Keyboard F6 +#define HID_KEYBOARD_F7 64 // 0x40 - Keyboard F7 +#define HID_KEYBOARD_F8 65 // 0x41 - Keyboard F8 +#define HID_KEYBOARD_F9 66 // 0x42 - Keyboard F9 +#define HID_KEYBOARD_F10 67 // 0x43 - Keyboard F10 +#define HID_KEYBOARD_F11 68 // 0x44 - Keyboard F11 +#define HID_KEYBOARD_F12 69 // 0x45 - Keyboard F12 +#define HID_KEYBOARD_PRNT_SCREEN 70 // 0x46 - Keyboard Print Screen +#define HID_KEYBOARD_SCROLL_LOCK 71 // 0x47 - Keyboard Scroll Lock +#define HID_KEYBOARD_PAUSE 72 // 0x48 - Keyboard Pause +#define HID_KEYBOARD_INSERT 73 // 0x49 - Keyboard Insert +#define HID_KEYBOARD_HOME 74 // 0x4A - Keyboard Home +#define HID_KEYBOARD_PAGE_UP 75 // 0x4B - Keyboard PageUp +#define HID_KEYBOARD_DELETE_FWD 76 // 0x4C - Keyboard Delete Forward +#define HID_KEYBOARD_END 77 // 0x4D - Keyboard End +#define HID_KEYBOARD_PAGE_DOWN 78 // 0x4E - Keyboard PageDown +#define HID_KEYBOARD_RIGHT_ARROW 79 // 0x4F - Keyboard RightArrow +#define HID_KEYBOARD_LEFT_ARROW 80 // 0x50 - Keyboard LeftArrow +#define HID_KEYBOARD_DOWN_ARROW 81 // 0x51 - Keyboard DownArrow +#define HID_KEYBOARD_UP_ARROW 82 // 0x52 - Keyboard UpArrow +#define HID_KEYBPAD_NUM_LOCK 83 // 0x53 - Keypad Num Lock and Clear +#define HID_KEYBPAD_DIVIDE 84 // 0x54 - Keypad / +#define HID_KEYBOARD_MULTIPLY 85 // 0x55 - Keypad * +#define HID_KEYBOARD_SUBTRACT 86 // 0x56 - Keypad - +#define HID_KEYBPAD_ADD 87 // 0x57 - Keypad + +#define HID_KEYBPAD_ENTER 88 // 0x58 - Keypad ENTER +#define HID_KEYBPAD_1 89 // 0x59 - Keypad 1 and End +#define HID_KEYBPAD_2 90 // 0x5A - Keypad 2 and Down Arrow +#define HID_KEYBPAD_3 91 // 0x5B - Keypad 3 and PageDn +#define HID_KEYBPAD_4 92 // 0x5C - Keypad 4 and Lfet Arrow +#define HID_KEYBPAD_5 93 // 0x5D - Keypad 5 +#define HID_KEYBPAD_6 94 // 0x5E - Keypad 6 and Right Arrow +#define HID_KEYBPAD_7 95 // 0x5F - Keypad 7 and Home +#define HID_KEYBPAD_8 96 // 0x60 - Keypad 8 and Up Arrow +#define HID_KEYBPAD_9 97 // 0x61 - Keypad 9 and PageUp +#define HID_KEYBPAD_0 98 // 0x62 - Keypad 0 and Insert +#define HID_KEYBPAD_DOT 99 // 0x63 - Keypad . and Delete +#define HID_KEYBOARD_MUTE 127 // 0x7F - Keyboard Mute +#define HID_KEYBOARD_VOLUME_UP 128 // 0x80 - Keyboard Volume up +#define HID_KEYBOARD_VOLUME_DOWN 129 // 0x81 - Keyboard Volume down +#define HID_KEYBOARD_LEFT_CTRL 224 // 0xE0 - Keyboard LeftContorl +#define HID_KEYBOARD_LEFT_SHIFT 225 // 0xE1 - Keyboard LeftShift +#define HID_KEYBOARD_LEFT_ALT 226 // 0xE2 - Keyboard LeftAlt +#define HID_KEYBOARD_LEFT_GUI 227 // 0xE3 - Keyboard LeftGUI +#define HID_KEYBOARD_RIGHT_CTRL 228 // 0xE4 - Keyboard LeftContorl +#define HID_KEYBOARD_RIGHT_SHIFT 229 // 0xE5 - Keyboard LeftShift +#define HID_KEYBOARD_RIGHT_ALT 230 // 0xE6 - Keyboard LeftAlt +#define HID_KEYBOARD_RIGHT_GUI 231 // 0xE7 - Keyboard RightGUI + +#define HID_MOUSE_BUTTON_LEFT 253 +#define HID_MOUSE_BUTTON_MIDDLE 254 +#define HID_MOUSE_BUTTON_RIGHT 255 + +// HID Consumer Usage IDs (subset of the codes available in the USB HID Usage Tables spec) +#define HID_CONSUMER_POWER 48 // 0x30 - Power +#define HID_CONSUMER_RESET 49 // 0x31 - Reset +#define HID_CONSUMER_SLEEP 50 // 0x32 - Sleep + +#define HID_CONSUMER_MENU 64 // 0x40 - Menu +#define HID_CONSUMER_SELECTION 128 // 0x80 - Selection +#define HID_CONSUMER_ASSIGN_SEL 129 // 0x81 - Assign Selection +#define HID_CONSUMER_MODE_STEP 130 // 0x82 - Mode Step +#define HID_CONSUMER_RECALL_LAST 131 // 0x83 - Recall Last +#define HID_CONSUMER_QUIT 148 // 0x94 - Quit +#define HID_CONSUMER_HELP 149 // 0x95 - Help +#define HID_CONSUMER_CHANNEL_UP 156 // 0x9C - Channel Increment +#define HID_CONSUMER_CHANNEL_DOWN 157 // 0x9D - Channel Decrement + +#define HID_CONSUMER_PLAY 176 // 0xB0 - Play +#define HID_CONSUMER_PAUSE 177 // 0xB1 - Pause +#define HID_CONSUMER_RECORD 178 // 0xB2 - Record +#define HID_CONSUMER_FAST_FORWARD 179 // 0xB3 - Fast Forward +#define HID_CONSUMER_REWIND 180 // 0xB4 - Rewind +#define HID_CONSUMER_SCAN_NEXT_TRK 181 // 0xB5 - Scan Next Track +#define HID_CONSUMER_SCAN_PREV_TRK 182 // 0xB6 - Scan Previous Track +#define HID_CONSUMER_STOP 183 // 0xB7 - Stop +#define HID_CONSUMER_EJECT 184 // 0xB8 - Eject +#define HID_CONSUMER_RANDOM_PLAY 185 // 0xB9 - Random Play +#define HID_CONSUMER_SELECT_DISC 186 // 0xBA - Select Disk +#define HID_CONSUMER_ENTER_DISC 187 // 0xBB - Enter Disc +#define HID_CONSUMER_REPEAT 188 // 0xBC - Repeat +#define HID_CONSUMER_STOP_EJECT 204 // 0xCC - Stop/Eject +#define HID_CONSUMER_PLAY_PAUSE 205 // 0xCD - Play/Pause +#define HID_CONSUMER_PLAY_SKIP 206 // 0xCE - Play/Skip + +#define HID_CONSUMER_VOLUME 224 // 0xE0 - Volume +#define HID_CONSUMER_BALANCE 225 // 0xE1 - Balance +#define HID_CONSUMER_MUTE 226 // 0xE2 - Mute +#define HID_CONSUMER_BASS 227 // 0xE3 - Bass +#define HID_CONSUMER_VOLUME_UP 233 // 0xE9 - Volume Increment +#define HID_CONSUMER_VOLUME_DOWN 234 // 0xEA - Volume Decrement + +/********************************************************************* + TYPEDEFS +*/ + +// HID report mapping table +typedef struct +{ + uint16 handle; // Handle of report characteristic + uint16 cccdHandle; // Handle of CCCD for report characteristic + uint8 id; // Report ID + uint8 type; // Report type + uint8 mode; // Protocol mode (report or boot) +} hidRptMap_t; + +// HID dev configuration structure +typedef struct +{ + uint32 idleTimeout; // Idle timeout in milliseconds + uint8 hidFlags; // HID feature flags + +} hidDevCfg_t; + +/********************************************************************* + Global Variables +*/ + +// These variables are defined in the service .c file that uses HID Dev + +// HID report map length +extern uint16 hidReportMapLen; + +// HID protocol mode +extern uint8 hidProtocolMode; + +/********************************************************************* + Profile Callbacks +*/ + +// HID Report callback +typedef uint8 (*hidDevReportCB_t)( uint8 id, uint8 type, uint16 uuid, + uint8 oper, uint16* pLen, uint8* pData ); + +// HID event callback +typedef void (*hidDevEvtCB_t)( uint8 evt ); + +// HID passcode callback +typedef void (*hidDevPasscodeCB_t)( uint8* deviceAddr, uint16 connectionHandle, + uint8 uiInputs, uint8 uiOutputs ); + +typedef struct +{ + hidDevReportCB_t reportCB; + hidDevEvtCB_t evtCB; + hidDevPasscodeCB_t passcodeCB; +} hidDevCB_t; + + +extern void hidDevGapStateCB( gaprole_States_t newState ); +extern void hidDevPairStateCB( uint16 connHandle, uint8 state, uint8 status ); +extern void hidDevPasscodeCB( uint8* deviceAddr, uint16 connectionHandle, + uint8 uiInputs, uint8 uiOutputs ); +extern void HidDev_Init( uint8 task_id ); +extern uint16 HidDev_ProcessEvent( uint8 task_id, uint16 events ); +extern void HidDev_Register( hidDevCfg_t* pCfg, hidDevCB_t* pCBs ); +extern void HidDev_RegisterReports( uint8 numReports, hidRptMap_t* pRpt ); +extern void HidDev_Report( uint8 id, uint8 type, uint8 len, uint8* pData ); +extern void HidDev_Close( void ); +extern bStatus_t HidDev_SetParameter( uint8 param, uint8 len, void* pValue ); +extern bStatus_t HidDev_GetParameter( uint8 param, void* pValue ); +extern void HidDev_PasscodeRsp( uint8 status, uint32 passcode ); +extern bStatus_t HidDev_ReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, + uint8 maxLen); +extern bStatus_t HidDev_WriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* HIDDEV_H */ diff --git a/src/components/profiles/DevInfo/devinfoservice.c b/src/components/profiles/DevInfo/devinfoservice.c new file mode 100644 index 0000000..03149c9 --- /dev/null +++ b/src/components/profiles/DevInfo/devinfoservice.c @@ -0,0 +1,589 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: devinfoservice.c + Revised: $Date $ + Revision: $Revision $ + + Description: This file contains the Device Information service. + + + **************************************************************************************************/ + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "linkdb.h" +#include "att.h" +#include "gatt.h" +#include "gatt_uuid.h" +#include "gatt_profile_uuid.h" +#include "gattservapp.h" + +#include "devinfoservice.h" + +/********************************************************************* + MACROS +*/ +#define SYSTEM_ID_ENABLE 0 +#define MODEL_NUMBER_STR_ENABLE 1 +#define SERIAL_NUMBER_STR_ENABLE 1 +#define FIRMWARE_REVISION_ENABLE 1 +#define HARDWARE_REVISION_ENABLE 1 +#define SOFTWARE_REVISION_ENABLE 1 +#define MANUFACTURE_NAME_STR_ENABLE 1 +#define IEEE_DATA_ENABLE 0 +#define PNP_ID_ENABLE 0 + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ +// Device information service +CONST uint8 devInfoServUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(DEVINFO_SERV_UUID), HI_UINT16(DEVINFO_SERV_UUID) +}; + +// System ID +CONST uint8 devInfoSystemIdUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(SYSTEM_ID_UUID), HI_UINT16(SYSTEM_ID_UUID) +}; + +// Model Number String +CONST uint8 devInfoModelNumberUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(MODEL_NUMBER_UUID), HI_UINT16(MODEL_NUMBER_UUID) +}; + +// Serial Number String +CONST uint8 devInfoSerialNumberUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(SERIAL_NUMBER_UUID), HI_UINT16(SERIAL_NUMBER_UUID) +}; + +// Firmware Revision String +CONST uint8 devInfoFirmwareRevUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(FIRMWARE_REV_UUID), HI_UINT16(FIRMWARE_REV_UUID) +}; + +// Hardware Revision String +CONST uint8 devInfoHardwareRevUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(HARDWARE_REV_UUID), HI_UINT16(HARDWARE_REV_UUID) +}; + +// Software Revision String +CONST uint8 devInfoSoftwareRevUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(SOFTWARE_REV_UUID), HI_UINT16(SOFTWARE_REV_UUID) +}; + +// Manufacturer Name String +CONST uint8 devInfoMfrNameUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(MANUFACTURER_NAME_UUID), HI_UINT16(MANUFACTURER_NAME_UUID) +}; + +// IEEE 11073-20601 Regulatory Certification Data List +CONST uint8 devInfo11073CertUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(IEEE_11073_CERT_DATA_UUID), HI_UINT16(IEEE_11073_CERT_DATA_UUID) +}; + +// PnP ID +CONST uint8 devInfoPnpIdUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(PNP_ID_UUID), HI_UINT16(PNP_ID_UUID) +}; + + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +/********************************************************************* + Profile Attributes - variables +*/ + +// Device Information Service attribute +static CONST gattAttrType_t devInfoService = { ATT_BT_UUID_SIZE, devInfoServUUID }; + +#if SYSTEM_ID_ENABLE +// System ID characteristic +static uint8 devInfoSystemIdProps = GATT_PROP_READ; +static uint8 devInfoSystemId[DEVINFO_SYSTEM_ID_LEN] = {0, 0, 0, 0, 0, 0, 0, 0}; +#endif + +#if MODEL_NUMBER_STR_ENABLE +// Model Number String characteristic +static uint8 devInfoModelNumberProps = GATT_PROP_READ; +static const uint8 devInfoModelNumber[] = "THB2"; +#endif + +#if SERIAL_NUMBER_STR_ENABLE +// Serial Number String characteristic +static uint8 devInfoSerialNumberProps = GATT_PROP_READ; +static const uint8 devInfoSerialNumber[] = "0001"; +#endif + +#if FIRMWARE_REVISION_ENABLE +// Firmware Revision String characteristic +static uint8 devInfoFirmwareRevProps = GATT_PROP_READ; +static const uint8 devInfoFirmwareRev[] = "github.com/pvvx"; +#endif + +#if HARDWARE_REVISION_ENABLE +// Hardware Revision String characteristic +static uint8 devInfoHardwareRevProps = GATT_PROP_READ; +static const uint8 devInfoHardwareRev[] = "0.1"; +#endif + +#if SOFTWARE_REVISION_ENABLE +// Software Revision String characteristic +static uint8 devInfoSoftwareRevProps = GATT_PROP_READ; +static const uint8 devInfoSoftwareRev[] = "V0.2"; +#endif + +#if MANUFACTURE_NAME_STR_ENABLE +// Manufacturer Name String characteristic +static uint8 devInfoMfrNameProps = GATT_PROP_READ; +static const uint8 devInfoMfrName[] = "Tuya"; +#endif + +#if IEEE_DATA_ENABLE +// IEEE 11073-20601 Regulatory Certification Data List characteristic +static uint8 devInfo11073CertProps = GATT_PROP_READ; +static const uint8 devInfo11073Cert[] = +{ + DEVINFO_11073_BODY_EXP, // authoritative body type + 0x00, // authoritative body structure type + // authoritative body data follows below: + 'e', 'x', 'p', 'e', 'r', 'i', 'm', 'e', 'n', 't', 'a', 'l' +}; +#endif + +#if PNP_ID_ENABLE +// System ID characteristic +static uint8 devInfoPnpIdProps = GATT_PROP_READ; +static uint8 devInfoPnpId[DEVINFO_PNP_ID_LEN] = +{ + 1, // Vendor ID source (1=Bluetooth SIG) + LO_UINT16(0x0f0f), HI_UINT16(0x0f0f), // Vendor ID + LO_UINT16(0x0000), HI_UINT16(0x0000), // Product ID (vendor-specific) + LO_UINT16(0x0110), HI_UINT16(0x0110) // Product version (JJ.M.N) +}; +#endif + +/********************************************************************* + Profile Attributes - Table +*/ + +static gattAttribute_t devInfoAttrTbl[] = +{ + /* type */ /* permissions */ /* handle */ /* pValue */ + // Device Information Service + {{ ATT_BT_UUID_SIZE, primaryServiceUUID }, GATT_PERMIT_READ, 0, (uint8 *)&devInfoService }, + +#if SYSTEM_ID_ENABLE + // System ID Declaration + {{ ATT_BT_UUID_SIZE, characterUUID }, GATT_PERMIT_READ, 0, &devInfoSystemIdProps }, + // System ID Value + {{ ATT_BT_UUID_SIZE, devInfoSystemIdUUID }, GATT_PERMIT_READ, 0, (uint8 *) devInfoSystemId }, +#endif + +#if MODEL_NUMBER_STR_ENABLE + // Model Number String Declaration + {{ ATT_BT_UUID_SIZE, characterUUID }, GATT_PERMIT_READ, 0, &devInfoModelNumberProps }, + // Model Number Value + {{ ATT_BT_UUID_SIZE, devInfoModelNumberUUID }, GATT_PERMIT_READ, 0, (uint8 *) devInfoModelNumber }, +#endif + +#if SERIAL_NUMBER_STR_ENABLE + // Serial Number String Declaration + {{ ATT_BT_UUID_SIZE, characterUUID }, GATT_PERMIT_READ, 0, &devInfoSerialNumberProps }, + // Serial Number Value + {{ ATT_BT_UUID_SIZE, devInfoSerialNumberUUID }, GATT_PERMIT_READ, 0, (uint8 *) devInfoSerialNumber }, +#endif + +#if FIRMWARE_REVISION_ENABLE + // Firmware Revision String Declaration + {{ ATT_BT_UUID_SIZE, characterUUID }, GATT_PERMIT_READ, 0, &devInfoFirmwareRevProps }, + // Firmware Revision Value + {{ ATT_BT_UUID_SIZE, devInfoFirmwareRevUUID }, GATT_PERMIT_READ, 0, (uint8 *) devInfoFirmwareRev }, +#endif + +#if HARDWARE_REVISION_ENABLE + // Hardware Revision String Declaration + {{ ATT_BT_UUID_SIZE, characterUUID }, GATT_PERMIT_READ, 0, &devInfoHardwareRevProps }, + // Hardware Revision Value + {{ ATT_BT_UUID_SIZE, devInfoHardwareRevUUID }, GATT_PERMIT_READ, 0, (uint8 *) devInfoHardwareRev }, +#endif + +#if SOFTWARE_REVISION_ENABLE + // Software Revision String Declaration + {{ ATT_BT_UUID_SIZE, characterUUID }, GATT_PERMIT_READ, 0, &devInfoSoftwareRevProps }, + // Software Revision Value + {{ ATT_BT_UUID_SIZE, devInfoSoftwareRevUUID }, GATT_PERMIT_READ, 0, (uint8 *) devInfoSoftwareRev }, +#endif + +#if MANUFACTURE_NAME_STR_ENABLE + // Manufacturer Name String Declaration + {{ ATT_BT_UUID_SIZE, characterUUID }, GATT_PERMIT_READ, 0, &devInfoMfrNameProps }, + // Manufacturer Name Value + {{ ATT_BT_UUID_SIZE, devInfoMfrNameUUID }, GATT_PERMIT_READ, 0, (uint8 *) devInfoMfrName }, +#endif + +#if IEEE_DATA_ENABLE + // IEEE 11073-20601 Regulatory Certification Data List Declaration + {{ ATT_BT_UUID_SIZE, characterUUID }, GATT_PERMIT_READ, 0, &devInfo11073CertProps }, + // IEEE 11073-20601 Regulatory Certification Data List Value + {{ ATT_BT_UUID_SIZE, devInfo11073CertUUID }, GATT_PERMIT_READ, 0, (uint8 *) devInfo11073Cert }, +#endif + +#if PNP_ID_ENABLE + // PnP ID Declaration + {{ ATT_BT_UUID_SIZE, characterUUID }, GATT_PERMIT_READ, 0, &devInfoPnpIdProps }, + // PnP ID Value + {{ ATT_BT_UUID_SIZE, devInfoPnpIdUUID }, GATT_PERMIT_READ, 0, (uint8 *) devInfoPnpId }, +#endif +}; + + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static uint8 devInfo_ReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ); + +/********************************************************************* + PROFILE CALLBACKS +*/ +// Device Info Service Callbacks +CONST gattServiceCBs_t devInfoCBs = +{ + devInfo_ReadAttrCB, // Read callback function pointer + NULL, // Write callback function pointer + NULL // Authorization callback function pointer +}; + +/********************************************************************* + NETWORK LAYER CALLBACKS +*/ + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/********************************************************************* + @fn DevInfo_AddService + + @brief Initializes the Device Information service by registering + GATT attributes with the GATT server. + + @return Success or Failure +*/ +bStatus_t DevInfo_AddService( void ) +{ + // Register GATT attribute list and CBs with GATT Server App + return GATTServApp_RegisterService( devInfoAttrTbl, + GATT_NUM_ATTRS( devInfoAttrTbl ), + &devInfoCBs ); +} + +/********************************************************************* + @fn DevInfo_SetParameter + + @brief Set a Device Information parameter. + + @param param - Profile parameter ID + @param len - length of data to write + @param value - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t DevInfo_SetParameter( uint8 param, uint8 len, void* value ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + #if SYSTEM_ID_ENABLE + case DEVINFO_SYSTEM_ID: + osal_memcpy(devInfoSystemId, value, len); + break; + #endif + + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn DevInfo_GetParameter + + @brief Get a Device Information parameter. + + @param param - Profile parameter ID + @param value - pointer to data to get. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t DevInfo_GetParameter( uint8 param, void* value ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + #if SYSTEM_ID_ENABLE + case DEVINFO_SYSTEM_ID: + osal_memcpy(value, devInfoSystemId, sizeof(devInfoSystemId)); + break; + #endif + + #if MODEL_NUMBER_STR_ENABLE + case DEVINFO_MODEL_NUMBER: + osal_memcpy(value, devInfoModelNumber, sizeof(devInfoModelNumber)); + break; + #endif + + #if SERIAL_NUMBER_STR_ENABLE + case DEVINFO_SERIAL_NUMBER: + osal_memcpy(value, devInfoSerialNumber, sizeof(devInfoSerialNumber)); + break; + #endif + + #if FIRMWARE_REVISION_ENABLE + case DEVINFO_FIRMWARE_REV: + osal_memcpy(value, devInfoFirmwareRev, sizeof(devInfoFirmwareRev)); + break; + #endif + + #if HARDWARE_REVISION_ENABLE + case DEVINFO_HARDWARE_REV: + osal_memcpy(value, devInfoHardwareRev, sizeof(devInfoHardwareRev)); + break; + #endif + + #if SOFTWARE_REVISION_ENABLE + case DEVINFO_SOFTWARE_REV: + osal_memcpy(value, devInfoSoftwareRev, sizeof(devInfoSoftwareRev)); + break; + #endif + + #if MANUFACTURE_NAME_STR_ENABLE + case DEVINFO_MANUFACTURER_NAME: + osal_memcpy(value, devInfoMfrName, sizeof(devInfoMfrName)); + break; + #endif + + #if IEEE_DATA_ENABLE + case DEVINFO_11073_CERT_DATA: + osal_memcpy(value, devInfo11073Cert, sizeof(devInfo11073Cert)); + break; + #endif + + #if PNP_ID_ENABLE + case DEVINFO_PNP_ID: + osal_memcpy(value, devInfoPnpId, sizeof(devInfoPnpId)); + break; + #endif + + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn devInfo_ReadAttrCB + + @brief Read an attribute. + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be read + @param pLen - length of data to be read + @param offset - offset of the first octet to be read + @param maxLen - maximum length of data to be read + + @return Success or Failure +*/ +static uint8 devInfo_ReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ) +{ + bStatus_t status = SUCCESS; + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + switch (uuid) + { + #if SYSTEM_ID_ENABLE + case SYSTEM_ID_UUID: + // verify offset + if (offset >= sizeof(devInfoSystemId)){ + status = ATT_ERR_INVALID_OFFSET; + }else{ + // determine read length + *pLen = MIN(maxLen, (sizeof(devInfoSystemId) - offset)); + // copy data + osal_memcpy(pValue, &devInfoSystemId[offset], *pLen); + } + break; + #endif + + #if MODEL_NUMBER_STR_ENABLE + case MODEL_NUMBER_UUID: + // verify offset + if (offset >= (sizeof(devInfoModelNumber) - 1)){ + status = ATT_ERR_INVALID_OFFSET; + }else{ + // determine read length (exclude null terminating character) + *pLen = MIN(maxLen, ((sizeof(devInfoModelNumber) - 1) - offset)); + // copy data + osal_memcpy(pValue, &devInfoModelNumber[offset], *pLen); + } + break; + #endif + + #if SERIAL_NUMBER_STR_ENABLE + case SERIAL_NUMBER_UUID: + // verify offset + if (offset >= (sizeof(devInfoSerialNumber) - 1)){ + status = ATT_ERR_INVALID_OFFSET; + }else{ + // determine read length (exclude null terminating character) + *pLen = MIN(maxLen, ((sizeof(devInfoSerialNumber) - 1) - offset)); + // copy data + osal_memcpy(pValue, &devInfoSerialNumber[offset], *pLen); + } + break; + #endif + + #if FIRMWARE_REVISION_ENABLE + case FIRMWARE_REV_UUID: + // verify offset + if (offset >= (sizeof(devInfoFirmwareRev) - 1)){ + status = ATT_ERR_INVALID_OFFSET; + }else{ + // determine read length (exclude null terminating character) + *pLen = MIN(maxLen, ((sizeof(devInfoFirmwareRev) - 1) - offset)); + // copy data + osal_memcpy(pValue, &devInfoFirmwareRev[offset], *pLen); + } + break; + #endif + + #if HARDWARE_REVISION_ENABLE + case HARDWARE_REV_UUID: + // verify offset + if (offset >= (sizeof(devInfoHardwareRev) - 1)){ + status = ATT_ERR_INVALID_OFFSET; + }else{ + // determine read length (exclude null terminating character) + *pLen = MIN(maxLen, ((sizeof(devInfoHardwareRev) - 1) - offset)); + // copy data + osal_memcpy(pValue, &devInfoHardwareRev[offset], *pLen); + } + break; + #endif + + #if SOFTWARE_REVISION_ENABLE + case SOFTWARE_REV_UUID: + // verify offset + if (offset >= (sizeof(devInfoSoftwareRev) - 1)){ + status = ATT_ERR_INVALID_OFFSET; + }else{ + // determine read length (exclude null terminating character) + *pLen = MIN(maxLen, ((sizeof(devInfoSoftwareRev) - 1) - offset)); + // copy data + osal_memcpy(pValue, &devInfoSoftwareRev[offset], *pLen); + } + break; + #endif + + #if MANUFACTURE_NAME_STR_ENABLE + case MANUFACTURER_NAME_UUID: + // verify offset + if (offset >= (sizeof(devInfoMfrName) - 1)){ + status = ATT_ERR_INVALID_OFFSET; + }else{ + // determine read length (exclude null terminating character) + *pLen = MIN(maxLen, ((sizeof(devInfoMfrName) - 1) - offset)); + // copy data + osal_memcpy(pValue, &devInfoMfrName[offset], *pLen); + } + break; + #endif + + #if IEEE_DATA_ENABLE + case IEEE_11073_CERT_DATA_UUID: + // verify offset + if (offset >= sizeof(devInfo11073Cert)){ + status = ATT_ERR_INVALID_OFFSET; + }else{ + // determine read length + *pLen = MIN(maxLen, (sizeof(devInfo11073Cert) - offset)); + // copy data + osal_memcpy(pValue, &devInfo11073Cert[offset], *pLen); + } + break; + #endif + + #if PNP_ID_ENABLE + case PNP_ID_UUID: + // verify offset + if (offset >= sizeof(devInfoPnpId)){ + status = ATT_ERR_INVALID_OFFSET; + }else{ + // determine read length + *pLen = MIN(maxLen, (sizeof(devInfoPnpId) - offset)); + // copy data + osal_memcpy(pValue, &devInfoPnpId[offset], *pLen); + } + break; + #endif + + default: + *pLen = 0; + status = ATT_ERR_ATTR_NOT_FOUND; + break; + } + + return ( status ); +} + + +/********************************************************************* +*********************************************************************/ diff --git a/src/components/profiles/DevInfo/devinfoservice.h b/src/components/profiles/DevInfo/devinfoservice.h new file mode 100644 index 0000000..7fba6cf --- /dev/null +++ b/src/components/profiles/DevInfo/devinfoservice.h @@ -0,0 +1,115 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: devinfoservice.h + Revised: $Date $ + Revision: $Revision $ + + Description: This file contains the Device Information service definitions and + prototypes. + + + +**************************************************************************************************/ + +#ifndef DEVINFOSERVICE_H +#define DEVINFOSERVICE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + CONSTANTS +*/ + +// Device Information Service Parameters +#define DEVINFO_SYSTEM_ID 0 +#define DEVINFO_MODEL_NUMBER 1 +#define DEVINFO_SERIAL_NUMBER 2 +#define DEVINFO_FIRMWARE_REV 3 +#define DEVINFO_HARDWARE_REV 4 +#define DEVINFO_SOFTWARE_REV 5 +#define DEVINFO_MANUFACTURER_NAME 6 +#define DEVINFO_11073_CERT_DATA 7 +#define DEVINFO_PNP_ID 8 + +// IEEE 11073 authoritative body values +#define DEVINFO_11073_BODY_EMPTY 0 +#define DEVINFO_11073_BODY_IEEE 1 +#define DEVINFO_11073_BODY_CONTINUA 2 +#define DEVINFO_11073_BODY_EXP 254 + +// System ID length +#define DEVINFO_SYSTEM_ID_LEN 8 + +// PnP ID length +#define DEVINFO_PNP_ID_LEN 7 + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + Profile Callbacks +*/ + + +/********************************************************************* + API FUNCTIONS +*/ + +/* + DevInfo_AddService- Initializes the Device Information service by registering + GATT attributes with the GATT server. + +*/ + +extern bStatus_t DevInfo_AddService( void ); + +/********************************************************************* + @fn DevInfo_SetParameter + + @brief Set a Device Information parameter. + + @param param - Profile parameter ID + @param len - length of data to right + @param value - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t DevInfo_SetParameter( uint8 param, uint8 len, void* value ); + +/* + DevInfo_GetParameter - Get a Device Information parameter. + + param - Profile parameter ID + value - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). +*/ +extern bStatus_t DevInfo_GetParameter( uint8 param, void* value ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* DEVINFOSERVICE_H */ diff --git a/src/components/profiles/GATT/gattservapp.c b/src/components/profiles/GATT/gattservapp.c new file mode 100644 index 0000000..8262a74 --- /dev/null +++ b/src/components/profiles/GATT/gattservapp.c @@ -0,0 +1,2519 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************* + Filename: gattservapp.c + Revised: + Revision: + + Description: This file contains the GATT Server Application. + + + +**************************************************************************************************/ + +#if ( HOST_CONFIG & ( CENTRAL_CFG | PERIPHERAL_CFG ) ) + +/******************************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "linkdb.h" + +#include "gatt.h" +#include "gatt_uuid.h" +#include "gattservapp.h" + + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +// Structure to keep Prepare Write Requests for each Client +typedef struct +{ + uint16 connHandle; // connection message was received on + attPrepareWriteReq_t* pPrepareWriteQ; // Prepare Write Request queue +} prepareWrites_t; + +// GATT Structure to keep CBs information for each service being registered +typedef struct +{ + uint16 handle; // Service handle - assigned internally by GATT Server + CONST gattServiceCBs_t* pCBs; // Service callback function pointers +} gattServiceCBsInfo_t; + +// Service callbacks list item +typedef struct _serviceCBsList +{ + struct _serviceCBsList* next; // pointer to next service callbacks record + gattServiceCBsInfo_t serviceInfo; // service handle/callbacks +} serviceCBsList_t; + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ +extern l2capSegmentBuff_t l2capSegmentPkt; +/********************************************************************* + LOCAL VARIABLES +*/ +uint8 GATTServApp_TaskID; // Task ID for internal task/event processing + +uint8 appTaskID = INVALID_TASK_ID; // The task ID of an app/profile that +// wants GATT Server event messages + +// Server Prepare Write table (one entry per each physical link) +static prepareWrites_t prepareWritesTbl[MAX_NUM_LL_CONN]; + +// Maximum number of attributes that Server can prepare for writing per Client +static uint8 maxNumPrepareWrites = 0; +#ifdef PREPARE_QUEUE_STATIC + static attPrepareWriteReq_t prepareQueue[MAX_NUM_LL_CONN*GATT_MAX_NUM_PREPARE_WRITES]; +#endif +// Callbacks for services +static serviceCBsList_t* serviceCBsList = NULL; + +// Globals to be used for processing an incoming request +//static uint8 attrLen; +static uint16 attrLen; +static uint8 attrValue[ATT_MTU_SIZE-1]; +static attMsg_t rsp; + +/*** Defined GATT Attributes ***/ + +// GATT Service attribute +static CONST gattAttrType_t gattService = { ATT_BT_UUID_SIZE, gattServiceUUID }; + +#ifndef HID_VOICE_SPEC + // Service Changed Characteristic Properties + static uint8 serviceChangedCharProps = GATT_PROP_INDICATE; +#endif + +// Service Changed attribute (hidden). Set the affected Attribute Handle range +// to 0x0001 to 0xFFFF to indicate to the client to rediscover the entire set +// of Attribute Handles on the server. + +// Client Characteristic configuration. Each client has its own instantiation +// of the Client Characteristic Configuration. Reads of the Client Characteristic +// Configuration only shows the configuration for that client and writes only +// affect the configuration of that client. +static gattCharCfg_t indCharCfg[GATT_MAX_NUM_CONN]; + +#if defined ( TESTMODES ) + static uint16 paramValue = 0; +#endif + +/********************************************************************* + Profile Attributes - Table +*/ + +// GATT Attribute Table +static gattAttribute_t gattAttrTbl[] = +{ + // Generic Attribute Profile + { + { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */ + GATT_PERMIT_READ, /* permissions */ + 0, /* handle */ + (uint8*)& gattService /* pValue */ + }, + #ifndef HID_VOICE_SPEC + // Characteristic Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &serviceChangedCharProps + }, + + // Attribute Service Changed + { + { ATT_BT_UUID_SIZE, serviceChangedUUID }, + 0, + 0, + NULL + }, + + // Client Characteristic configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8*)indCharCfg + } + #endif +}; + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static void gattServApp_ProcessMsg( gattMsgEvent_t* pMsg ); +static bStatus_t gattServApp_ProcessExchangeMTUReq( gattMsgEvent_t* pMsg ); +static bStatus_t gattServApp_ProcessFindByTypeValueReq( gattMsgEvent_t* pMsg, uint16* pErrHandle ); +static bStatus_t gattServApp_ProcessReadByTypeReq( gattMsgEvent_t* pMsg, uint16* pErrHandle ); +static bStatus_t gattServApp_ProcessReadReq( gattMsgEvent_t* pMsg, uint16* pErrHandle ); +static bStatus_t gattServApp_ProcessReadBlobReq( gattMsgEvent_t* pMsg, uint16* pErrHandle ); +static bStatus_t gattServApp_ProcessReadMultiReq( gattMsgEvent_t* pMsg, uint16* pErrHandle ); +static bStatus_t gattServApp_ProcessReadByGrpTypeReq( gattMsgEvent_t* pMsg, uint16* pErrHandle ); +static bStatus_t gattServApp_ProcessWriteReq( gattMsgEvent_t* pMsg, uint16* pErrHandle ); +static bStatus_t gattServApp_ProcessPrepareWriteReq( gattMsgEvent_t* pMsg, uint16* pErrHandle ); +static bStatus_t gattServApp_ProcessExecuteWriteReq( gattMsgEvent_t* pMsg, uint16* pErrHandle ); + +static bStatus_t gattServApp_RegisterServiceCBs( uint16 handle, CONST gattServiceCBs_t* pServiceCBs ); +static bStatus_t gattServApp_DeregisterServiceCBs( uint16 handle ); +static bStatus_t gattServApp_SetNumPrepareWrites( uint8 numPrepareWrites ); +static uint8 gattServApp_PrepareWriteQInUse( void ); +static CONST gattServiceCBs_t* gattServApp_FindServiceCBs( uint16 service ); +static bStatus_t gattServApp_EnqueuePrepareWriteReq( uint16 connHandle, attPrepareWriteReq_t* pReq ); +static prepareWrites_t* gattServApp_FindPrepareWriteQ( uint16 connHandle ); +static gattCharCfg_t* gattServApp_FindCharCfgItem( uint16 connHandle, + gattCharCfg_t* charCfgTbl ); +static pfnGATTReadAttrCB_t gattServApp_FindReadAttrCB( uint16 handle ); +static pfnGATTWriteAttrCB_t gattServApp_FindWriteAttrCB( uint16 handle ); +static pfnGATTAuthorizeAttrCB_t gattServApp_FindAuthorizeAttrCB( uint16 handle ); + +/********************************************************************* + API FUNCTIONS +*/ + +// GATT App Callback functions +static void gattServApp_HandleConnStatusCB( uint16 connHandle, uint8 changeType ); +static bStatus_t gattServApp_WriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ); + +/********************************************************************* + PROFILE CALLBACKS +*/ +// GATT Service Callbacks +CONST gattServiceCBs_t gattServiceCBs = +{ + NULL, // Read callback function pointer + gattServApp_WriteAttrCB, // Write callback function pointer + NULL // Authorization callback function pointer +}; +static gattServMsgCB_t s_GATTServCB = NULL; +/********************************************************************* + @fn GATTServApp_RegisterForMsgs + + @brief Register your task ID to receive event messages from + the GATT Server Application. + + @param taskId - Default task ID to send events + + @return none +*/ +void GATTServApp_RegisterForMsg( uint8 taskID ) +{ + appTaskID = taskID; +} + +/********************************************************************* + @fn GATTServApp_Init + + @brief Initialize the GATT Server Application. + + @param taskId - Task identifier for the desired task + + @return none +*/ +void GATTServApp_Init( uint8 taskId ) +{ + GATTServApp_TaskID = taskId; + // Initialize Client Characteristic Configuration attributes + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, indCharCfg ); + + // Initialize Prepare Write Table + for ( uint8 i = 0; i < MAX_NUM_LL_CONN; i++ ) + { + // Initialize connection handle + prepareWritesTbl[i].connHandle = INVALID_CONNHANDLE; + // Initialize the prepare write queue + prepareWritesTbl[i].pPrepareWriteQ = NULL; + } + + // Set up the initial prepare write queues + gattServApp_SetNumPrepareWrites( GATT_MAX_NUM_PREPARE_WRITES ); + // Register to receive incoming ATT Requests + GATT_RegisterForReq( GATTServApp_TaskID ); + // Register with Link DB to receive link status change callback + linkDB_Register( gattServApp_HandleConnStatusCB ); +} + +/********************************************************************* + @fn GATTServApp_ProcessEvent + + @brief GATT Server Application Task event processor. This function + is called to process all events for the task. Events include + timers, messages and any other user defined events. + + @param task_id - The OSAL assigned task ID. + @param events - events to process. This is a bit map and can + contain more than one event. + + @return none +*/ +uint16 GATTServApp_ProcessEvent( uint8 task_id, uint16 events ) +{ + if ( events & SYS_EVENT_MSG ) + { + osal_event_hdr_t* pMsg; + + if ( (pMsg = ( osal_event_hdr_t*)osal_msg_receive( GATTServApp_TaskID )) != NULL ) + { + // Process incoming messages + switch ( pMsg->event ) + { + // Incoming GATT message + case GATT_MSG_EVENT: + gattServApp_ProcessMsg( (gattMsgEvent_t*)pMsg ); + break; + + default: + // Unsupported message + break; + } + + // Release the OSAL message + VOID osal_msg_deallocate( (uint8*)pMsg ); + } + + // return unprocessed events + return (events ^ SYS_EVENT_MSG); + } + + // Discard unknown events + return 0; +} + +/****************************************************************************** + @fn GATTServApp_RegisterService + + @brief Register a service's attribute list and callback functions with + the GATT Server Application. + + @param pAttrs - Array of attribute records to be registered + @param numAttrs - Number of attributes in array + @param pServiceCBs - Service callback function pointers + + @return SUCCESS: Service registered successfully. + INVALIDPARAMETER: Invalid service field. + FAILURE: Not enough attribute handles available. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t GATTServApp_RegisterService( gattAttribute_t* pAttrs, uint16 numAttrs, + CONST gattServiceCBs_t* pServiceCBs ) +{ + uint8 status; + + // First register the service attribute list with GATT Server + if ( pAttrs != NULL ) + { + gattService_t service; + service.attrs = pAttrs; + service.numAttrs = numAttrs; + status = GATT_RegisterService( &service ); + + if ( ( status == SUCCESS ) && ( pServiceCBs != NULL ) ) + { + // Register the service CBs with GATT Server Application + status = gattServApp_RegisterServiceCBs( GATT_SERVICE_HANDLE( pAttrs ), + pServiceCBs ); + } + } + else + { + status = INVALIDPARAMETER; + } + + return ( status ); +} + +/****************************************************************************** + @fn GATTServApp_DeregisterService + + @brief Deregister a service's attribute list and callback functions from + the GATT Server Application. + + NOTE: It's the caller's responsibility to free the service attribute + list returned from this API. + + @param handle - handle of service to be deregistered + @param p2pAttrs - pointer to array of attribute records (to be returned) + + @return SUCCESS: Service deregistered successfully. + FAILURE: Service not found. +*/ +bStatus_t GATTServApp_DeregisterService( uint16 handle, gattAttribute_t** p2pAttrs ) +{ + uint8 status; + // First deregister the service CBs with GATT Server Application + status = gattServApp_DeregisterServiceCBs( handle ); + + if ( status == SUCCESS ) + { + gattService_t service; + // Deregister the service attribute list with GATT Server + status = GATT_DeregisterService( handle, &service ); + + if ( status == SUCCESS ) + { + if ( p2pAttrs != NULL ) + { + *p2pAttrs = service.attrs; + } + } + } + + return ( status ); +} + +/********************************************************************* + @fn GATTServApp_SetParameter + + @brief Set a GATT Server parameter. + + @param param - Profile parameter ID + @param len - length of data to right + @param pValue - pointer to data to write. This is dependent on the + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast + to uint16 pointer). + + @return SUCCESS: Parameter set successful + FAILURE: Parameter in use + INVALIDPARAMETER: Invalid parameter + bleInvalidRange: Invalid value + bleMemAllocError: Memory allocation failed +*/ +bStatus_t GATTServApp_SetParameter( uint8 param, uint8 len, void* pValue ) +{ + bStatus_t status = SUCCESS; + + switch ( param ) + { + case GATT_PARAM_NUM_PREPARE_WRITES: + if ( len == sizeof ( uint8 ) ) + { + if ( !gattServApp_PrepareWriteQInUse() ) + { + // Set the new nunber of prepare writes + status = gattServApp_SetNumPrepareWrites( *((uint8*)pValue) ); + } + else + { + status = FAILURE; + } + } + else + { + status = bleInvalidRange; + } + + break; + + default: + status = INVALIDPARAMETER; + break; + } + + return ( status ); +} + +/********************************************************************* + @fn GATTServApp_GetParameter + + @brief Get a GATT Server parameter. + + @param param - Profile parameter ID + @param pValue - pointer to data to put. This is dependent on the + parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be + cast to uint16 pointer). + + @return SUCCESS: Parameter get successful + INVALIDPARAMETER: Invalid parameter +*/ +bStatus_t GATTServApp_GetParameter( uint8 param, void* pValue ) +{ + bStatus_t status = SUCCESS; + + switch ( param ) + { + case GATT_PARAM_NUM_PREPARE_WRITES: + *((uint8*)pValue) = maxNumPrepareWrites; + break; + + default: + status = INVALIDPARAMETER; + break; + } + + return ( status ); +} + +/********************************************************************* + @fn gattServApp_SetNumPrepareWrites + + @brief Set the maximum number of the prepare writes. + + @param numPrepareWrites - number of prepare writes + + @return SUCCESS: New number set successfully. + bleMemAllocError: Memory allocation failed. +*/ +static bStatus_t gattServApp_SetNumPrepareWrites( uint8 numPrepareWrites ) +{ + attPrepareWriteReq_t* pQueue; + uint16 queueSize = ( MAX_NUM_LL_CONN * numPrepareWrites * sizeof( attPrepareWriteReq_t ) ); + // First make sure no one can get access to the Prepare Write Table + maxNumPrepareWrites = 0; + + // Free the existing prepare write queues + if ( prepareWritesTbl[0].pPrepareWriteQ != NULL ) + { + #ifndef PREPARE_QUEUE_STATIC + osal_mem_free( prepareWritesTbl[0].pPrepareWriteQ ); + #endif + + // Null out the prepare writes queues + for ( uint8 i = 0; i < MAX_NUM_LL_CONN; i++ ) + { + prepareWritesTbl[i].pPrepareWriteQ = NULL; + } + } + + // Allocate the prepare write queues + #ifdef PREPARE_QUEUE_STATIC + pQueue = prepareQueue; + #else + pQueue = osal_mem_alloc( queueSize ); + #endif + + if ( pQueue != NULL ) + { + // Initialize the prepare write queues + VOID osal_memset( pQueue, 0, queueSize ); + + // Set up the prepare write queue for each client (i.e., connection) + for ( uint8 i = 0; i < MAX_NUM_LL_CONN; i++ ) + { + uint8 nextQ = i * numPrepareWrites; // Index of next available queue + prepareWritesTbl[i].pPrepareWriteQ = &(pQueue[nextQ]); + + // Mark the prepare write request items as empty + for ( uint8 j = 0; j < numPrepareWrites; j++ ) + { + prepareWritesTbl[i].pPrepareWriteQ[j].handle = GATT_INVALID_HANDLE; + } + } + + // Set the new number of prepare writes + maxNumPrepareWrites = numPrepareWrites; + return ( SUCCESS ); + } + + return ( bleMemAllocError ); +} + +/********************************************************************* + @fn GATTServApp_FindAttr + + @brief Find the attribute record within a service attribute + table for a given attribute value pointer. + + @param pAttrTbl - pointer to attribute table + @param numAttrs - number of attributes in attribute table + @param pValue - pointer to attribute value + + @return Pointer to attribute record. NULL, if not found. +*/ +gattAttribute_t* GATTServApp_FindAttr( gattAttribute_t* pAttrTbl, uint16 numAttrs, uint8* pValue ) +{ + for ( uint16 i = 0; i < numAttrs; i++ ) + { + if ( pAttrTbl[i].pValue == pValue ) + { + // Attribute record found + return ( &(pAttrTbl[i]) ); + } + } + + return ( (gattAttribute_t*)NULL ); +} + +/****************************************************************************** + @fn GATTServApp_AddService + + @brief Add function for the GATT Service. + + @param services - services to add. This is a bit map and can + contain more than one service. + + @return SUCCESS: Service added successfully. + INVALIDPARAMETER: Invalid service field. + FAILURE: Not enough attribute handles available. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t GATTServApp_AddService( uint32 services ) +{ + uint8 status = SUCCESS; + + if ( services & GATT_SERVICE ) + { + // Register GATT attribute list and CBs with GATT Server Application + status = GATTServApp_RegisterService( gattAttrTbl, GATT_NUM_ATTRS( gattAttrTbl ), + &gattServiceCBs ); + } + + return ( status ); +} + +/****************************************************************************** + @fn GATTServApp_DelService + + @brief Delete function for the GATT Service. + + @param services - services to delete. This is a bit map and can + contain more than one service. + + @return SUCCESS: Service deleted successfully. + FAILURE: Service not found. +*/ +bStatus_t GATTServApp_DelService( uint32 services ) +{ + uint8 status = SUCCESS; + + if ( services & GATT_SERVICE ) + { + // Deregister GATT attribute list and CBs from GATT Server Application + status = GATTServApp_DeregisterService( GATT_SERVICE_HANDLE( gattAttrTbl ), NULL ); + } + + return ( status ); +} + +/****************************************************************************** + @fn gattServApp_RegisterServiceCBs + + @brief Register callback functions for a service. + + @param handle - handle of service being registered + @param pServiceCBs - pointer to service CBs to be registered + + @return SUCCESS: Service CBs were registered successfully. + INVALIDPARAMETER: Invalid service CB field. + bleMemAllocError: Memory allocation error occurred. +*/ +static bStatus_t gattServApp_RegisterServiceCBs( uint16 handle, + CONST gattServiceCBs_t* pServiceCBs ) +{ + serviceCBsList_t* pNewItem; + + // Make sure the service handle is specified + if ( handle == GATT_INVALID_HANDLE ) + { + return ( INVALIDPARAMETER ); + } + + // Fill in the new service list + pNewItem = (serviceCBsList_t*)osal_mem_alloc( sizeof( serviceCBsList_t ) ); + + if ( pNewItem == NULL ) + { + // Not enough memory + return ( bleMemAllocError ); + } + + // Set up new service CBs item + pNewItem->next = NULL; + pNewItem->serviceInfo.handle = handle; + pNewItem->serviceInfo.pCBs = pServiceCBs; + + // Find spot in list + if ( serviceCBsList == NULL ) + { + // First item in list + serviceCBsList = pNewItem; + } + else + { + serviceCBsList_t* pLoop = serviceCBsList; + + // Look for end of list + while ( pLoop->next != NULL ) + { + pLoop = pLoop->next; + } + + // Put new item at end of list + pLoop->next = pNewItem; + } + + return ( SUCCESS ); +} + +/****************************************************************************** + @fn gattServApp_DeregisterServiceCBs + + @brief Deregister callback functions for a service. + + @param handle - handle of service CBs to be deregistered + + @return SUCCESS: Service CBs were deregistered successfully. + FAILURE: Service CBs were not found. +*/ +static bStatus_t gattServApp_DeregisterServiceCBs( uint16 handle ) +{ + serviceCBsList_t* pLoop = serviceCBsList; + serviceCBsList_t* pPrev = NULL; + + // Look for service + while ( pLoop != NULL ) + { + if ( pLoop->serviceInfo.handle == handle ) + { + // Service CBs found; unlink it + if ( pPrev == NULL ) + { + // First item in list + serviceCBsList = pLoop->next; + } + else + { + pPrev->next = pLoop->next; + } + + // Free the service CB record + osal_mem_free( pLoop ); + return ( SUCCESS ); + } + + pPrev = pLoop; + pLoop = pLoop->next; + } + + // Service CBs not found + return ( FAILURE ); +} + +/********************************************************************* + @fn gattServApp_FindServiceCBs + + @brief Find service's callback record. + + @param handle - owner of service + + @return Pointer to service record. NULL, otherwise. +*/ +static CONST gattServiceCBs_t* gattServApp_FindServiceCBs( uint16 handle ) +{ + serviceCBsList_t* pLoop = serviceCBsList; + + while ( pLoop != NULL ) + { + if ( pLoop->serviceInfo.handle == handle ) + { + return ( pLoop->serviceInfo.pCBs ); + } + + // Try next service + pLoop = pLoop->next; + } + + return ( (gattServiceCBs_t*)NULL ); +} + +/********************************************************************* + @fn gattServApp_ProcessMsg + + @brief GATT Server App message processing function. + + @param pMsg - pointer to received message + + @return Success or Failure +*/ +static void gattServApp_ProcessMsg( gattMsgEvent_t* pMsg ) +{ + uint16 errHandle = GATT_INVALID_HANDLE; + uint8 status; + #if defined ( TESTMODES ) + + if ( paramValue == GATT_TESTMODE_NO_RSP ) + { + // Notify GATT that a message has been processed + // Note: This call is optional if flow control is not used. + GATT_AppCompletedMsg( pMsg ); + // Just ignore the incoming request messages + return; + } + + #endif + + // Process the GATT server message + switch ( pMsg->method ) + { + case ATT_EXCHANGE_MTU_REQ: + status = gattServApp_ProcessExchangeMTUReq( pMsg ); + break; + + case ATT_FIND_BY_TYPE_VALUE_REQ: + status = gattServApp_ProcessFindByTypeValueReq( pMsg, &errHandle ); + break; + + case ATT_READ_BY_TYPE_REQ: + status = gattServApp_ProcessReadByTypeReq( pMsg, &errHandle ); + break; + + case ATT_READ_REQ: + status = gattServApp_ProcessReadReq( pMsg, &errHandle ); + break; + + case ATT_READ_BLOB_REQ: + status = gattServApp_ProcessReadBlobReq( pMsg, &errHandle ); + break; + + case ATT_READ_MULTI_REQ: + status = gattServApp_ProcessReadMultiReq( pMsg, &errHandle ); + break; + + case ATT_READ_BY_GRP_TYPE_REQ: + status = gattServApp_ProcessReadByGrpTypeReq( pMsg, &errHandle ); + break; + + case ATT_WRITE_REQ: + status = gattServApp_ProcessWriteReq( pMsg, &errHandle ); + break; + + case ATT_PREPARE_WRITE_REQ: + status = gattServApp_ProcessPrepareWriteReq( pMsg, &errHandle ); + break; + + case ATT_EXECUTE_WRITE_REQ: + status = gattServApp_ProcessExecuteWriteReq( pMsg, &errHandle ); + break; + + default: + // Unknown request - ignore it! + status = SUCCESS; + break; + } + + // See if we need to send an error response back + if ( status != SUCCESS ) + { + // Make sure the request was not sent locally + if ( pMsg->hdr.status != bleNotConnected ) + { + attErrorRsp_t* pRsp = &rsp.errorRsp; + pRsp->reqOpcode = pMsg->method; + pRsp->handle = errHandle; + pRsp->errCode = status; + VOID ATT_ErrorRsp( pMsg->connHandle, pRsp ); + } + } + + // Notify GATT that a message has been processed + // Note: This call is optional if flow control is not used. + GATT_AppCompletedMsg( pMsg ); + + // if app task ask the gatt message, copy and send to app task + if(s_GATTServCB) + s_GATTServCB(pMsg); +} + +/********************************************************************* + @fn gattServApp_ProcessExchangeMTUReq + + @brief Process Exchange MTU Request. + + @param pMsg - pointer to received message + + @return Success +*/ +static bStatus_t gattServApp_ProcessExchangeMTUReq( gattMsgEvent_t* pMsg ) +{ + attExchangeMTURsp_t* pRsp = &rsp.exchangeMTURsp; + // ATT_MTU shall be set to the minimum of the Client Rx MTU and Server Rx MTU values + // Set the Server Rx MTU parameter to the maximum MTU that this server can receive + #if defined ( TESTMODES ) + + if ( paramValue == GATT_TESTMODE_MAX_MTU_SIZE ) + { + pRsp->serverRxMTU = ATT_MAX_MTU_SIZE; + } + else + #endif + pRsp->serverRxMTU = g_ATT_MTU_SIZE_MAX;//ATT_MTU_SIZE; + + // Send response back + VOID ATT_ExchangeMTURsp( pMsg->connHandle, pRsp ); + return ( SUCCESS ); +} + +/********************************************************************* + @fn gattServApp_ProcessFindByTypeValueReq + + @brief Process Find By Type Value Request. + + @param pMsg - pointer to received message + @param pErrHandle - attribute handle that generates an error + + @return Success or Failure +*/ +static bStatus_t gattServApp_ProcessFindByTypeValueReq( gattMsgEvent_t* pMsg, uint16* pErrHandle ) +{ + attFindByTypeValueReq_t* pReq = &pMsg->msg.findByTypeValueReq; + attFindByTypeValueRsp_t* pRsp = &rsp.findByTypeValueRsp; + gattAttribute_t* pAttr; + uint16 service; + // Initialize the response + VOID osal_memset( pRsp, 0, sizeof( attFindByTypeValueRsp_t ) ); + // Only attributes with attribute handles between and including the Starting + // Handle parameter and the Ending Handle parameter that match the requested + // attribute type and the attribute value will be returned. + // All attribute types are effectively compared as 128-bit UUIDs, + // even if a 16-bit UUID is provided in this request or defined + // for an attribute. + pAttr = GATT_FindHandleUUID( pReq->startHandle, pReq->endHandle, + pReq->type.uuid, pReq->type.len, &service ); + + while ( ( pAttr != NULL ) && ( pRsp->numInfo < g_ATT_MAX_NUM_HANDLES_INFO ) ) + { + uint16 grpEndHandle; + + // It is not possible to use this request on an attribute that has a value + // that is longer than (ATT_MTU - 7). + if ( GATTServApp_ReadAttr( pMsg->connHandle, pAttr, service, attrValue, + &attrLen, 0, ((gAttMtuSize[pMsg->connHandle])-7) ) == SUCCESS ) + { + // Attribute values should be compared in terms of length and binary representation. + if ( ( pReq->len == attrLen ) && osal_memcmp( pReq->value, attrValue, attrLen) ) + { + // New attribute found + // Set the Found Handle to the attribute that has the exact attribute + // type and attribute value from the request. + pRsp->handlesInfo[pRsp->numInfo].handle = pAttr->handle; + } + } + + // Try to find the next attribute + pAttr = GATT_FindNextAttr( pAttr, pReq->endHandle, service, &grpEndHandle ); + + // Set Group End Handle + if ( pRsp->handlesInfo[pRsp->numInfo].handle != 0 ) + { + // If the attribute type is a grouping attribute, the Group End Handle + // shall be defined by that higher layer specification. If the attribute + // type is not a grouping attribute, the Group End Handle shall be equal + // to the Found Attribute Handle. + if ( pAttr != NULL ) + { + pRsp->handlesInfo[pRsp->numInfo++].grpEndHandle = grpEndHandle; + } + else + { + // If no other attributes with the same attribute type exist after the + // Found Attribute Handle, the Group End Handle shall be set to 0xFFFF. + pRsp->handlesInfo[pRsp->numInfo++].grpEndHandle = GATT_MAX_HANDLE; + } + } + } // while + + if ( pRsp->numInfo > 0 ) + { + // Send a response back + VOID ATT_FindByTypeValueRsp( pMsg->connHandle, pRsp ); + return ( SUCCESS ); + } + + *pErrHandle = pReq->startHandle; + return ( ATT_ERR_ATTR_NOT_FOUND ); +} + +/********************************************************************* + @fn gattServApp_ProcessReadByTypeReq + + @brief Process Read By Type Request. + + @param pMsg - pointer to received message + @param pErrHandle - attribute handle that generates an error + + @return Success or Failure +*/ +static bStatus_t gattServApp_ProcessReadByTypeReq( gattMsgEvent_t* pMsg, uint16* pErrHandle ) +{ + attReadByTypeReq_t* pReq = &pMsg->msg.readByTypeReq; + attReadByTypeRsp_t* pRsp = &rsp.readByTypeRsp; + uint16 startHandle = pReq->startHandle; + uint8 dataLen = 0; + uint8 status = SUCCESS; + + // Only the attributes with attribute handles between and including the + // Starting Handle and the Ending Handle with the attribute type that is + // the same as the Attribute Type given will be returned. + + // Make sure there's enough room at least for an attribute handle (no value) + while ( dataLen <= (gAttMtuSize[pMsg->connHandle]-4) ) + { + uint16 service; + gattAttribute_t* pAttr; + // All attribute types are effectively compared as 128-bit UUIDs, even if + // a 16-bit UUID is provided in this request or defined for an attribute. + pAttr = GATT_FindHandleUUID( startHandle, pReq->endHandle, pReq->type.uuid, + pReq->type.len, &service ); + + if ( pAttr == NULL ) + { + break; // No more attribute found + } + + // Update start handle so it has the right value if we break from the loop + startHandle = pAttr->handle; + // Make sure the attribute has sufficient permissions to allow reading + status = GATT_VerifyReadPermissions( pMsg->connHandle, pAttr->permissions ); + + if ( status != SUCCESS ) + { + break; + } + + // Read the attribute value. If the attribute value is longer than + // (ATT_MTU - 4) or 253 octets, whichever is smaller, then the first + // (ATT_MTU - 4) or 253 octets shall be included in this response. + status = GATTServApp_ReadAttr( pMsg->connHandle, pAttr, service, attrValue, + &attrLen, 0, (((gAttMtuSize[pMsg->connHandle]))-4) ); + + if ( status != SUCCESS ) + { + break; // Cannot read the attribute value + } + + // See if this is the first attribute found + if ( dataLen == 0 ) + { + // Use the length of the first attribute value for the length field + pRsp->len = 2 + attrLen; + } + else + { + // If the attributes have attribute values that have the same length + // then these attributes can all be read in a single request. + if ( pRsp->len != 2 + attrLen ) + { + break; + } + } + + // Make sure there's enough room for this attribute handle and value + if ( dataLen + attrLen > (((gAttMtuSize[pMsg->connHandle]))-4) ) + { + break; + } + + // Add the handle value pair to the response + pRsp->dataList[dataLen++] = LO_UINT16( pAttr->handle ); + pRsp->dataList[dataLen++] = HI_UINT16( pAttr->handle ); + VOID osal_memcpy( &(pRsp->dataList[dataLen]), attrValue, attrLen ); + dataLen += attrLen; + + if ( startHandle == GATT_MAX_HANDLE ) + { + break; // We're done + } + + // Update start handle and search again + startHandle++; + } // while + + // See what to respond + if ( dataLen > 0 ) + { + // Set the number of attribute handle-value pairs found + pRsp->numPairs = dataLen / pRsp->len; + // Send a response back + VOID ATT_ReadByTypeRsp( pMsg->connHandle, pRsp ); + return ( SUCCESS ); + } + + if ( status == SUCCESS ) + { + // Attribute not found -- dataLen must be 0 + status = ATT_ERR_ATTR_NOT_FOUND; + } + + *pErrHandle = startHandle; + return ( status ); +} + +/********************************************************************* + @fn gattServApp_ProcessReadReq + + @brief Process Read Request. + + @param pMsg - pointer to received message + @param pErrHandle - attribute handle that generates an error + + @return Success or Failure +*/ +static bStatus_t gattServApp_ProcessReadReq( gattMsgEvent_t* pMsg, uint16* pErrHandle ) +{ + attReadReq_t* pReq = &pMsg->msg.readReq; + gattAttribute_t* pAttr; + uint16 service; + uint8 status; + pAttr = GATT_FindHandle( pReq->handle, &service ); + + if ( pAttr != NULL ) + { + attReadRsp_t* pRsp = &rsp.readRsp; + // Build and send a response back. If the attribute value is longer + // than (ATT_MTU - 1) then (ATT_MTU - 1) octets shall be included + // in this response. + status = GATTServApp_ReadAttr( pMsg->connHandle, pAttr, service, pRsp->value, + &pRsp->len, 0, (((gAttMtuSize[pMsg->connHandle]))-1) ); + + if ( status == SUCCESS ) + { + // Send a response back + VOID ATT_ReadRsp( pMsg->connHandle, pRsp ); + } + } + else + { + status = ATT_ERR_INVALID_HANDLE; + } + + if ( status != SUCCESS ) + { + *pErrHandle = pReq->handle; + } + + return ( status ); +} + +/********************************************************************* + @fn gattServApp_ProcessReadBlobReq + + @brief Process Read Blob Request. + + @param pMsg - pointer to received message + @param pErrHandle - attribute handle that generates an error + + @return Success or Failure +*/ +static bStatus_t gattServApp_ProcessReadBlobReq( gattMsgEvent_t* pMsg, uint16* pErrHandle ) +{ + attReadBlobReq_t* pReq = &pMsg->msg.readBlobReq; + gattAttribute_t* pAttr; + uint16 service; + uint8 status; + pAttr = GATT_FindHandle( pReq->handle, &service ); + + if ( pAttr != NULL ) + { + attReadBlobRsp_t* pRsp = &rsp.readBlobRsp; + // Read part attribute value. If the attribute value is longer than + // (Value Offset + ATT_MTU - 1) then (ATT_MTU - 1) octets from Value + // Offset shall be included in this response. + status = GATTServApp_ReadAttr( pMsg->connHandle, pAttr, service, pRsp->value, + &pRsp->len, pReq->offset, (((gAttMtuSize[pMsg->connHandle]))-1) ); + + if ( status == SUCCESS ) + { + // Send a response back + VOID ATT_ReadBlobRsp( pMsg->connHandle, pRsp ); + } + } + else + { + status = ATT_ERR_INVALID_HANDLE; + } + + if ( status != SUCCESS ) + { + *pErrHandle = pReq->handle; + } + + return ( status ); +} + +/********************************************************************* + @fn gattServApp_ProcessReadMultiReq + + @brief Process Read Multiple Request. + + @param pMsg - pointer to received message + @param pErrHandle - attribute handle that generates an error + + @return Success or Failure +*/ +static bStatus_t gattServApp_ProcessReadMultiReq( gattMsgEvent_t* pMsg, uint16* pErrHandle ) +{ + attReadMultiReq_t* pReq = &pMsg->msg.readMultiReq; + attReadMultiRsp_t* pRsp = &rsp.readMultiRsp; + uint8 status = SUCCESS; + pRsp->len = 0; + + for ( uint8 i = 0; ( i < pReq->numHandles ) && ( pRsp->len < (((gAttMtuSize[pMsg->connHandle]))-1) ); i++ ) + { + gattAttribute_t* pAttr; + uint16 service; + pAttr = GATT_FindHandle( pReq->handle[i], &service ); + + if ( pAttr == NULL ) + { + // Should never get here! + status = ATT_ERR_INVALID_HANDLE; + // The handle of the first attribute causing the error + *pErrHandle = pReq->handle[i]; + break; + } + + // If the Set Of Values parameter is longer than (ATT_MTU - 1) then only + // the first (ATT_MTU - 1) octets shall be included in this response. + status = GATTServApp_ReadAttr( pMsg->connHandle, pAttr, service, attrValue, + &attrLen, 0, (((gAttMtuSize[pMsg->connHandle]))-1) ); + + if ( status != SUCCESS ) + { + // The handle of the first attribute causing the error + *pErrHandle = pReq->handle[i]; + break; + } + + // Make sure there's enough room in the response for this attribute value + if ( pRsp->len + attrLen > (((gAttMtuSize[pMsg->connHandle]))-1) ) + { + attrLen = (((gAttMtuSize[pMsg->connHandle]))-1) - pRsp->len; + } + + // Append this value to the end of the response + VOID osal_memcpy( &(pRsp->values[pRsp->len]), attrValue, attrLen ); + pRsp->len += attrLen; + } + + if ( status == SUCCESS ) + { + // Send a response back + VOID ATT_ReadMultiRsp( pMsg->connHandle, pRsp ); + } + + return ( status ); +} + +/********************************************************************* + @fn gattServApp_ProcessReadByGrpTypeReq + + @brief Process Read By Group Type Request. + + @param pMsg - pointer to received message + @param pErrHandle - attribute handle that generates an error + + @return Success or Failure +*/ +static bStatus_t gattServApp_ProcessReadByGrpTypeReq( gattMsgEvent_t* pMsg, uint16* pErrHandle ) +{ + attReadByGrpTypeReq_t* pReq = &pMsg->msg.readByGrpTypeReq; + attReadByGrpTypeRsp_t* pRsp = &rsp.readByGrpTypeRsp; + uint16 service; + gattAttribute_t* pAttr; + uint16 dataLen = 0; + uint8 status = SUCCESS; + // Only the attributes with attribute handles between and including the + // Starting Handle and the Ending Handle with the attribute type that is + // the same as the Attribute Type given will be returned. + // All attribute types are effectively compared as 128-bit UUIDs, + // even if a 16-bit UUID is provided in this request or defined + // for an attribute. + pAttr = GATT_FindHandleUUID( pReq->startHandle, pReq->endHandle, + pReq->type.uuid, pReq->type.len, &service ); + + while ( pAttr != NULL ) + { + uint16 endGrpHandle; + // The service, include and characteristic declarations are readable and + // require no authentication or authorization, therefore insufficient + // authentication or read not permitted errors shall not occur. + status = GATT_VerifyReadPermissions( pMsg->connHandle, pAttr->permissions ); + + if ( status != SUCCESS ) + { + *pErrHandle = pAttr->handle; + break; + } + + // Read the attribute value. If the attribute value is longer than + // (ATT_MTU - 6) or 251 octets, whichever is smaller, then the first + // (ATT_MTU - 6) or 251 octets shall be included in this response. + status = GATTServApp_ReadAttr( pMsg->connHandle, pAttr, service, attrValue, + &attrLen, 0, (((gAttMtuSize[pMsg->connHandle]))-6) ); + + if ( status != SUCCESS ) + { + // Cannot read the attribute value + *pErrHandle = pAttr->handle; + break; + } + + // See if this is the first attribute found + if ( dataLen == 0 ) + { + // Use the length of the first attribute value for the length field + pRsp->len = 2 + 2 + attrLen; + } + else + { + // If the attributes have attribute values that have the same length + // then these attributes can all be read in a single request. + if ( pRsp->len != 2 + 2 + attrLen ) + { + break; // We're done here + } + + // Make sure there's enough room for this attribute handle, end group handle and value + if ( dataLen + attrLen > (((gAttMtuSize[pMsg->connHandle]))-6) ) + { + break; // We're done here + } + } + + // Add Attribute Handle to the response + pRsp->dataList[dataLen++] = LO_UINT16( pAttr->handle ); + pRsp->dataList[dataLen++] = HI_UINT16( pAttr->handle ); + // Try to find the next attribute + pAttr = GATT_FindNextAttr( pAttr, pReq->endHandle, service, &endGrpHandle ); + + // Add End Group Handle to the response + if ( pAttr != NULL ) + { + // The End Group Handle is the handle of the last attribute within the + // service definition + pRsp->dataList[dataLen++] = LO_UINT16( endGrpHandle ); + pRsp->dataList[dataLen++] = HI_UINT16( endGrpHandle ); + } + else + { + // The ending handle of the last service can be 0xFFFF + pRsp->dataList[dataLen++] = LO_UINT16( GATT_MAX_HANDLE ); + pRsp->dataList[dataLen++] = HI_UINT16( GATT_MAX_HANDLE ); + } + + // Add Attribute Value to the response + VOID osal_memcpy( &(pRsp->dataList[dataLen]), attrValue, attrLen ); + dataLen += attrLen; + } // while + + // See what to respond + if ( dataLen > 0 ) + { + // Set the number of attribute handle, end group handle and value sets found + pRsp->numGrps = dataLen / pRsp->len; + // Send a response back + VOID ATT_ReadByGrpTypeRsp( pMsg->connHandle, pRsp ); + return ( SUCCESS ); + } + + if ( status == SUCCESS ) + { + // No grouping attribute found -- dataLen must be 0 + status = ATT_ERR_ATTR_NOT_FOUND; + } + + *pErrHandle = pReq->startHandle; + return ( status ); +} + +/********************************************************************* + @fn gattServApp_ProcessWriteReq + + @brief Process Write Request or Command. + + @param pMsg - pointer to received message + @param pErrHandle - attribute handle that generates an error + + @return Success or Failure +*/ +static bStatus_t gattServApp_ProcessWriteReq( gattMsgEvent_t* pMsg, uint16* pErrHandle ) +{ + attWriteReq_t* pReq = &(pMsg->msg.writeReq); + gattAttribute_t* pAttr; + uint16 service; + uint8 status = SUCCESS; + // No Error Response or Write Response shall be sent in response to Write + // Command. If the server cannot write this attribute for any reason the + // command shall be ignored. + pAttr = GATT_FindHandle( pReq->handle, &service ); + + if ( pAttr != NULL ) + { + // Authorization is handled by the application/profile + if ( gattPermitAuthorWrite( pAttr->permissions ) ) + { + // Use Service's authorization callback to authorize the request + pfnGATTAuthorizeAttrCB_t pfnCB = gattServApp_FindAuthorizeAttrCB( service ); + + if ( pfnCB != NULL ) + { + status = (*pfnCB)( pMsg->connHandle, pAttr, ATT_WRITE_REQ ); + } + else + { + status = ATT_ERR_UNLIKELY; + } + } + + // If everything is fine then try to write the new value + if ( status == SUCCESS ) + { + // Use Service's write callback to write the request + status = GATTServApp_WriteAttr( pMsg->connHandle, pReq->handle, + pReq->value, pReq->len, 0 ); + + if ( ( status == SUCCESS ) && ( pReq->cmd == FALSE ) ) + { + // Send a response back + //VOID ATT_WriteRsp( pMsg->connHandle ); + uint8 st=ATT_WriteRsp( pMsg->connHandle ); +// if(st) +// { +// AT_LOG("[ATT_RSP ERR] %x %x\n",st,l2capSegmentPkt.fragment); +// } + } + } + } + else + { + status = ATT_ERR_INVALID_HANDLE; + } + + if ( status != SUCCESS ) + { + *pErrHandle = pReq->handle; + } + + return ( pReq->cmd ? SUCCESS : status ); +} + +/********************************************************************* + @fn gattServApp_ProcessPrepareWriteReq + + @brief Process Prepare Write Request. + + @param pMsg - pointer to received message + @param pErrHandle - attribute handle that generates an error + + @return Success or Failure +*/ +static bStatus_t gattServApp_ProcessPrepareWriteReq( gattMsgEvent_t* pMsg, uint16* pErrHandle ) +{ + attPrepareWriteReq_t* pReq = &pMsg->msg.prepareWriteReq; + gattAttribute_t* pAttr; + uint16 service; + uint8 status = SUCCESS; + pAttr = GATT_FindHandle( pReq->handle, &service ); + + if ( pAttr != NULL ) + { + // Authorization is handled by the application/profile + if ( gattPermitAuthorWrite( pAttr->permissions ) ) + { + // Use Service's authorization callback to authorize the request + pfnGATTAuthorizeAttrCB_t pfnCB = gattServApp_FindAuthorizeAttrCB( service ); + + if ( pfnCB != NULL ) + { + status = (*pfnCB)( pMsg->connHandle, pAttr, ATT_WRITE_REQ ); + } + else + { + status = ATT_ERR_UNLIKELY; + } + } + + if ( status == SUCCESS ) + { + #if defined ( TESTMODES ) + + if ( paramValue == GATT_TESTMODE_CORRUPT_PW_DATA ) + { + pReq->value[0] = ~(pReq->value[0]); + } + + #endif + // Enqueue the request for now + status = gattServApp_EnqueuePrepareWriteReq( pMsg->connHandle, pReq ); + + if ( status == SUCCESS ) + { + //LOG("pre off[%d] len[%d]\n", pReq->offset, pReq->len); + // Send a response back + VOID ATT_PrepareWriteRsp( pMsg->connHandle, (attPrepareWriteRsp_t*)pReq ); + } + } + } + else + { + status = ATT_ERR_INVALID_HANDLE; + } + + if ( status != SUCCESS ) + { + *pErrHandle = pReq->handle; + } + + return ( status ); +} + +/********************************************************************* + @fn gattServApp_ProcessExecuteWriteReq + + @brief Process Execute Write Request. + + @param pMsg - pointer to received message + @param pErrHandle - attribute handle that generates an error + + @return Success or Failure +*/ +static bStatus_t gattServApp_ProcessExecuteWriteReq( gattMsgEvent_t* pMsg, uint16* pErrHandle ) +{ + attExecuteWriteReq_t* pReq = &pMsg->msg.executeWriteReq; + prepareWrites_t* pQueue; + uint8 status = SUCCESS; + // See if this client has a prepare write queue + pQueue = gattServApp_FindPrepareWriteQ( pMsg->connHandle ); + + if ( pQueue != NULL ) + { + for ( uint8 i = 0; i < maxNumPrepareWrites; i++ ) + { + attPrepareWriteReq_t* pWriteReq = &(pQueue->pPrepareWriteQ[i]); + + // See if there're any prepared write requests in the queue + if ( pWriteReq->handle == GATT_INVALID_HANDLE ) + { + break; // We're done + } + + // Execute the request + if ( pReq->flags == ATT_WRITE_PREPARED_VALUES ) + { + status = GATTServApp_WriteAttr( pMsg->connHandle, pWriteReq->handle, + pWriteReq->value, pWriteReq->len, + pWriteReq->offset ); + + // If the prepare write requests can not be written, the queue shall + // be cleared and then an Error Response shall be sent with a high + // layer defined error code. + if ( status != SUCCESS ) + { + // Cancel the remaining prepared writes + pReq->flags = ATT_CANCEL_PREPARED_WRITES; + // The Attribute Handle in Error shall be set to the attribute handle + // of the attribute from the prepare write queue that caused this + // application error + *pErrHandle = pWriteReq->handle; + } + } + else // ATT_CANCEL_PREPARED_WRITES + { + // Cancel all prepared writes - just ignore the request + } + + // Clear the queue item + VOID osal_memset( pWriteReq, 0, sizeof( attPrepareWriteRsp_t ) ); + // Mark this item as empty + pWriteReq->handle = GATT_INVALID_HANDLE; + } // for loop + + // Mark this queue as empty + pQueue->connHandle = INVALID_CONNHANDLE; + } + + // Send a response back + if ( status == SUCCESS ) + { + VOID ATT_ExecuteWriteRsp( pMsg->connHandle ); + } + + return ( status ); +} + +/********************************************************************* + @fn gattServApp_EnqueuePrepareWriteReq + + @brief Enqueue Prepare Write Request. + + @param connHandle - connection packet was received on + @param pReq - pointer to request + + @return Success or Failure +*/ +static bStatus_t gattServApp_EnqueuePrepareWriteReq( uint16 connHandle, attPrepareWriteReq_t* pReq ) +{ + prepareWrites_t* pQueue; + // First see if there's queue already assocaited with this client + pQueue = gattServApp_FindPrepareWriteQ( connHandle ); + + if ( pQueue == NULL ) + { + // Find a queue for this client + pQueue = gattServApp_FindPrepareWriteQ( INVALID_CONNHANDLE ); + + if ( pQueue != NULL ) + { + pQueue->connHandle = connHandle; + } + } + + // If a queue is found for this client then enqueue the request + if ( pQueue != NULL ) + { + for ( uint8 i = 0; i < maxNumPrepareWrites; i++ ) + { + if ( pQueue->pPrepareWriteQ[i].handle == GATT_INVALID_HANDLE ) + { + // Store the request here + VOID osal_memcpy( &(pQueue->pPrepareWriteQ[i]), pReq, sizeof ( attPrepareWriteReq_t ) ); + //LOG("enq off[%d]len[%d]\n", pReq->offset, pReq->len); + return ( SUCCESS ); + } + } + } + + return ( ATT_ERR_PREPARE_QUEUE_FULL ); +} + +/********************************************************************* + @fn gattServApp_FindPrepareWriteQ + + @brief Find client's queue. + + @param connHandle - connection used by client + + @return Pointer to queue. NULL, otherwise. +*/ +static prepareWrites_t* gattServApp_FindPrepareWriteQ( uint16 connHandle ) +{ + // First see if this client has already a queue + for ( uint8 i = 0; i < MAX_NUM_LL_CONN; i++ ) + { + if ( prepareWritesTbl[i].connHandle == connHandle ) + { + // Queue found + return ( &(prepareWritesTbl[i]) ); + } + } + + return ( (prepareWrites_t*)NULL ); +} + +/********************************************************************* + @fn gattServApp_PrepareWriteQInUse + + @brief Check to see if the prepare write queue is in use. + + @param void + + @return TRUE if queue in use. FALSE, otherwise. +*/ +static uint8 gattServApp_PrepareWriteQInUse( void ) +{ + // See if any prepare write queue is in use + for ( uint8 i = 0; i < MAX_NUM_LL_CONN; i++ ) + { + if ( prepareWritesTbl[i].connHandle != INVALID_CONNHANDLE ) + { + for ( uint8 j = 0; j < maxNumPrepareWrites; j++ ) + { + if ( prepareWritesTbl[i].pPrepareWriteQ[j].handle != GATT_INVALID_HANDLE ) + { + // Queue item is in use + return ( TRUE ); + } + } // for + } + } // for + + return ( FALSE ); +} + +/********************************************************************* + @fn gattServApp_FindCharCfgItem + + @brief Find the characteristic configuration for a given client. + Uses the connection handle to search the charactersitic + configuration table of a client. + + @param connHandle - connection handle (0xFFFF for empty entry) + @param charCfgTbl - characteristic configuration table. + + @return pointer to the found item. NULL, otherwise. +*/ +static gattCharCfg_t* gattServApp_FindCharCfgItem( uint16 connHandle, + gattCharCfg_t* charCfgTbl ) +{ + for ( uint8 i = 0; i < GATT_MAX_NUM_CONN; i++ ) + { + if ( charCfgTbl[i].connHandle == connHandle ) + { + // Entry found + return ( &(charCfgTbl[i]) ); + } + } + + return ( (gattCharCfg_t*)NULL ); +} + +/********************************************************************* + @fn gattServApp_FindReadAttrCB + + @brief Find the Read Attribute CB function pointer for a given service. + + @param handle - service attribute handle + + @return pointer to the found CB. NULL, otherwise. +*/ +static pfnGATTReadAttrCB_t gattServApp_FindReadAttrCB( uint16 handle ) +{ + CONST gattServiceCBs_t* pCBs = gattServApp_FindServiceCBs( handle ); + return ( ( pCBs == NULL ) ? NULL : pCBs->pfnReadAttrCB ); +} + +/********************************************************************* + @fn gattServApp_FindWriteAttrCB + + @brief Find the Write CB Attribute function pointer for a given service. + + @param handle - service attribute handle + + @return pointer to the found CB. NULL, otherwise. +*/ +static pfnGATTWriteAttrCB_t gattServApp_FindWriteAttrCB( uint16 handle ) +{ + CONST gattServiceCBs_t* pCBs = gattServApp_FindServiceCBs( handle ); + return ( ( pCBs == NULL ) ? NULL : pCBs->pfnWriteAttrCB ); +} + +/********************************************************************* + @fn gattServApp_FindAuthorizeAttrCB + + @brief Find the Authorize Attribute CB function pointer for a given service. + + @param handle - service attribute handle + + @return pointer to the found CB. NULL, otherwise. +*/ +static pfnGATTAuthorizeAttrCB_t gattServApp_FindAuthorizeAttrCB( uint16 handle ) +{ + CONST gattServiceCBs_t* pCBs = gattServApp_FindServiceCBs( handle ); + return ( ( pCBs == NULL ) ? NULL : pCBs->pfnAuthorizeAttrCB ); +} + +/********************************************************************* + @fn gattServApp_ValidateWriteAttrCB + + @brief Validate and/or Write attribute data + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be written + @param len - length of data + @param offset - offset of the first octet to be written + + @return Success or Failure +*/ +static bStatus_t gattServApp_WriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ) +{ + bStatus_t status = SUCCESS; + + if ( pAttr->type.len == ATT_BT_UUID_SIZE ) + { + // 16-bit UUID + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + switch ( uuid ) + { + case GATT_CLIENT_CHAR_CFG_UUID: + status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len, + offset, GATT_CLIENT_CFG_INDICATE ); + break; + + default: + // Should never get here! + status = ATT_ERR_INVALID_HANDLE; + } + } + else + { + // 128-bit UUID + status = ATT_ERR_INVALID_HANDLE; + } + + return ( status ); +} + +/********************************************************************* + @fn GATTServApp_ReadAttr + + @brief Read an attribute. If the format of the attribute value + is unknown to GATT Server, use the callback function + provided by the Service. + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param service - handle of owner service + @param pValue - pointer to data to be read + @param pLen - length of data to be read + @param offset - offset of the first octet to be read + @param maxLen - maximum length of data to be read + + @return Success or Failure +*/ +uint8 GATTServApp_ReadAttr( uint16 connHandle, gattAttribute_t* pAttr, + uint16 service, uint8* pValue, uint16* pLen, + uint16 offset, uint8 maxLen ) +{ + uint8 useCB = FALSE; + bStatus_t status = SUCCESS; + + // Authorization is handled by the application/profile + if ( gattPermitAuthorRead( pAttr->permissions ) ) + { + // Use Service's authorization callback to authorize the request + pfnGATTAuthorizeAttrCB_t pfnCB = gattServApp_FindAuthorizeAttrCB( service ); + + if ( pfnCB != NULL ) + { + status = (*pfnCB)( connHandle, pAttr, ATT_READ_REQ ); + } + else + { + status = ATT_ERR_UNLIKELY; + } + + if ( status != SUCCESS ) + { + // Read operation failed! + return ( status ); + } + } + + // Check the UUID length + if ( pAttr->type.len == ATT_BT_UUID_SIZE ) + { + // 16-bit UUID + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + switch ( uuid ) + { + case GATT_PRIMARY_SERVICE_UUID: + case GATT_SECONDARY_SERVICE_UUID: + + // Make sure it's not a blob operation + if ( offset == 0 ) + { + gattAttrType_t* pType = (gattAttrType_t*)(pAttr->pValue); + *pLen = pType->len; + VOID osal_memcpy( pValue, pType->uuid, pType->len ); + } + else + { + status = ATT_ERR_ATTR_NOT_LONG; + } + + break; + + case GATT_CHARACTER_UUID: + + // Make sure it's not a blob operation + if ( offset == 0 ) + { + gattAttribute_t* pCharValue; + // The Attribute Value of a Characteristic Declaration includes the + // Characteristic Properties, Characteristic Value Attribute Handle + // and UUID. + *pLen = 1; + pValue[0] = *pAttr->pValue; // Properties + // The Characteristic Value Attribute exists immediately following + // the Characteristic Declaration. + pCharValue = GATT_FindHandle( pAttr->handle+1, NULL ); + + if ( pCharValue != NULL ) + { + // It can be a 128-bit UUID + *pLen += (2 + pCharValue->type.len); + // Attribute Handle + pValue[1] = LO_UINT16( pCharValue->handle ); + pValue[2] = HI_UINT16( pCharValue->handle ); + // Attribute UUID + VOID osal_memcpy( &(pValue[3]), pCharValue->type.uuid, pCharValue->type.len ); + } + else + { + // Should never get here! + *pLen += (2 + ATT_BT_UUID_SIZE); + // Set both Attribute Handle and UUID to 0 + VOID osal_memset( &(pValue[1]), 0, (2 + ATT_BT_UUID_SIZE) ); + } + } + else + { + status = ATT_ERR_ATTR_NOT_LONG; + } + + break; + + case GATT_INCLUDE_UUID: + + // Make sure it's not a blob operation + if ( offset == 0 ) + { + uint16 servHandle; + uint16 endGrpHandle; + gattAttribute_t* pIncluded; + uint16 handle = *((uint16*)(pAttr->pValue)); + // The Attribute Value of an Include Declaration is set the + // included service Attribute Handle, the End Group Handle, + // and the service UUID. The Service UUID shall only be present + // when the UUID is a 16-bit Bluetooth UUID. + *pLen = 4; + pValue[0] = LO_UINT16( handle ); + pValue[1] = HI_UINT16( handle ); + // Find the included service attribute record + pIncluded = GATT_FindHandle( handle, &servHandle ); + + if ( pIncluded != NULL ) + { + gattAttrType_t* pServiceUUID = (gattAttrType_t*)pIncluded->pValue; + + // Find out the End Group handle + if ( ( GATT_FindNextAttr( pIncluded, GATT_MAX_HANDLE, + servHandle, &endGrpHandle ) == NULL ) && + ( !gattSecondaryServiceType( pIncluded->type ) ) ) + { + // The ending handle of the last service can be 0xFFFF + endGrpHandle = GATT_MAX_HANDLE; + } + + // Include only 16-bit Service UUID + if ( pServiceUUID->len == ATT_BT_UUID_SIZE ) + { + VOID osal_memcpy( &(pValue[4]), pServiceUUID->uuid, ATT_BT_UUID_SIZE ); + *pLen += ATT_BT_UUID_SIZE; + } + } + else + { + // Should never get here! + endGrpHandle = handle; + } + + // End Group Handle + pValue[2] = LO_UINT16( endGrpHandle ); + pValue[3] = HI_UINT16( endGrpHandle ); + } + else + { + status = ATT_ERR_ATTR_NOT_LONG; + } + + break; + + case GATT_CLIENT_CHAR_CFG_UUID: + + // Make sure it's not a blob operation + if ( offset == 0 ) + { + uint16 value = GATTServApp_ReadCharCfg( connHandle, + (gattCharCfg_t*)(pAttr->pValue) ); + *pLen = 2; + pValue[0] = LO_UINT16( value ); + pValue[1] = HI_UINT16( value ); + } + else + { + status = ATT_ERR_ATTR_NOT_LONG; + } + + break; + + case GATT_CHAR_EXT_PROPS_UUID: + case GATT_SERV_CHAR_CFG_UUID: + + // Make sure it's not a blob operation + if ( offset == 0 ) + { + uint16 value = *((uint16*)(pAttr->pValue)); + *pLen = 2; + pValue[0] = LO_UINT16( value ); + pValue[1] = HI_UINT16( value ); + } + else + { + status = ATT_ERR_ATTR_NOT_LONG; + } + + break; + + case GATT_CHAR_USER_DESC_UUID: + { + uint8 len = osal_strlen( (char*)(pAttr->pValue) ); // Could be a long attribute + + // If the value offset of the Read Blob Request is greater than the + // length of the attribute value, an Error Response shall be sent with + // the error code Invalid Offset. + if ( offset <= len ) + { + // If the value offset is equal than the length of the attribute + // value, then the length of the part attribute value shall be zero. + if ( offset == len ) + { + len = 0; + } + else + { + // If the attribute value is longer than (Value Offset + maxLen) + // then maxLen octets from Value Offset shall be included in + // this response. + if ( len > ( offset + maxLen ) ) + { + len = maxLen; + } + else + { + len -= offset; + } + } + + *pLen = len; + VOID osal_memcpy( pValue, &(pAttr->pValue[offset]), len ); + } + else + { + status = ATT_ERR_INVALID_OFFSET; + } + } + break; + + case GATT_CHAR_FORMAT_UUID: + + // Make sure it's not a blob operation + if ( offset == 0 ) + { + gattCharFormat_t* pFormat = (gattCharFormat_t*)(pAttr->pValue); + *pLen = 7; + pValue[0] = pFormat->format; + pValue[1] = pFormat->exponent; + pValue[2] = LO_UINT16( pFormat->unit ); + pValue[3] = HI_UINT16( pFormat->unit ); + pValue[4] = pFormat->nameSpace; + pValue[5] = LO_UINT16( pFormat->desc ); + pValue[6] = HI_UINT16( pFormat->desc ); + } + else + { + status = ATT_ERR_ATTR_NOT_LONG; + } + + break; + + default: + useCB = TRUE; + break; + } + } + else + { + useCB = TRUE; + } + + if ( useCB == TRUE ) + { + // Use Service's read callback to process the request + pfnGATTReadAttrCB_t pfnCB = gattServApp_FindReadAttrCB( service ); + + if ( pfnCB != NULL ) + { + // Read the attribute value + status = (*pfnCB)( connHandle, pAttr, pValue, pLen, offset, maxLen ); + } + else + { + status = ATT_ERR_UNLIKELY; + } + } + + return ( status ); +} + +/********************************************************************* + @fn GATTServApp_WriteAttr + + @brief Write attribute data + + @param connHandle - connection message was received on + @param handle - attribute handle + @param pValue - pointer to data to be written + @param len - length of data + @param offset - offset of the first octet to be written + + @return Success or Failure +*/ +uint8 GATTServApp_WriteAttr( uint16 connHandle, uint16 handle, + uint8* pValue, uint16 len, uint16 offset ) +{ + uint16 service; + gattAttribute_t* pAttr; + bStatus_t status; + // Find the owner of the attribute + pAttr = GATT_FindHandle( handle, &service ); + + if ( pAttr != NULL ) + { + // Find out the owner's callback functions + pfnGATTWriteAttrCB_t pfnCB = gattServApp_FindWriteAttrCB( service ); + + if ( pfnCB != NULL ) + { + // Try to write the new value + status = (*pfnCB)( connHandle, pAttr, pValue, len, offset ); + } + else + { + status = ATT_ERR_UNLIKELY; + } + } + else + { + status = ATT_ERR_INVALID_HANDLE; + } + + return ( status ); +} + +/********************************************************************* + @fn GATTServApp_SetParamValue + + @brief Set a GATT Server Application Parameter value. Use this + function to change the default GATT parameter values. + + @param value - new param value + + @return void +*/ +void GATTServApp_SetParamValue( uint16 value ) +{ + #if defined ( TESTMODES ) + paramValue = value; + #else + VOID value; + #endif +} + +/********************************************************************* + @fn GATTServApp_GetParamValue + + @brief Get a GATT Server Application Parameter value. + + @param none + + @return GATT Parameter value +*/ +uint16 GATTServApp_GetParamValue( void ) +{ + #if defined ( TESTMODES ) + return ( paramValue ); + #else + return ( 0 ); + #endif +} + +/********************************************************************* + @fn GATTServApp_UpdateCharCfg + + @brief Update the Client Characteristic Configuration for a given + Client. + + Note: This API should only be called from the Bond Manager. + + @param connHandle - connection handle. + @param attrHandle - attribute handle. + @param value - characteristic configuration value (from NV). + + @return Success or Failure +*/ +bStatus_t GATTServApp_UpdateCharCfg( uint16 connHandle, uint16 attrHandle, uint16 value ) +{ + uint8 buf[2]; + buf[0] = LO_UINT16( value ); + buf[1] = HI_UINT16( value ); + return ( GATTServApp_WriteAttr( connHandle, attrHandle, buf, 2, 0 ) ); +} + +/********************************************************************* + @fn GATTServApp_SendServiceChangedInd + + @brief Send out a Service Changed Indication. + + @param connHandle - connection to use + @param taskId - task to be notified of confirmation + + @return SUCCESS: Indication was sent successfully. + FAILURE: Service Changed attribute not found. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A confirmation is pending with this client. +*/ +bStatus_t GATTServApp_SendServiceChangedInd( uint16 connHandle, uint8 taskId ) +{ + uint16 value = GATTServApp_ReadCharCfg( connHandle, indCharCfg ); + + if ( value & GATT_CLIENT_CFG_INDICATE ) + { + return ( GATT_ServiceChangedInd( connHandle, taskId ) ); + } + + return ( FAILURE ); +} + +/********************************************************************* + @fn GATTServApp_InitCharCfg + + @brief Initialize the client characteristic configuration table. + + Note: Each client has its own instantiation of the Client + Characteristic Configuration. Reads/Writes of the Client + Characteristic Configuration only only affect the + configuration of that client. + + @param connHandle - connection handle (0xFFFF for all connections). + @param charCfgTbl - client characteristic configuration table. + + @return none +*/ +void GATTServApp_InitCharCfg( uint16 connHandle, gattCharCfg_t* charCfgTbl ) +{ + // Initialize Client Characteristic Configuration attributes + if ( connHandle == INVALID_CONNHANDLE ) + { + for ( uint8 i = 0; i < GATT_MAX_NUM_CONN; i++ ) + { + charCfgTbl[i].connHandle = INVALID_CONNHANDLE; + charCfgTbl[i].value = GATT_CFG_NO_OPERATION; + } + } + else + { + gattCharCfg_t* pItem = gattServApp_FindCharCfgItem( connHandle, charCfgTbl ); + + if ( pItem != NULL ) + { + pItem->connHandle = INVALID_CONNHANDLE; + pItem->value = GATT_CFG_NO_OPERATION; + } + } +} + +/********************************************************************* + @fn GATTServApp_ReadCharCfg + + @brief Read the client characteristic configuration for a given + client. + + Note: Each client has its own instantiation of the Client + Characteristic Configuration. Reads of the Client + Characteristic Configuration only shows the configuration + for that client. + + @param connHandle - connection handle. + @param charCfgTbl - client characteristic configuration table. + + @return attribute value +*/ +uint16 GATTServApp_ReadCharCfg( uint16 connHandle, gattCharCfg_t* charCfgTbl ) +{ + gattCharCfg_t* pItem; + pItem = gattServApp_FindCharCfgItem( connHandle, charCfgTbl ); + + if ( pItem != NULL ) + { + return ( (uint16)(pItem->value) ); + } + + return ( (uint16)GATT_CFG_NO_OPERATION ); +} + +/********************************************************************* + @fn GATTServApp_WriteCharCfg + + @brief Write the client characteristic configuration for a given + client. + + Note: Each client has its own instantiation of the Client + Characteristic Configuration. Writes of the Client + Characteristic Configuration only only affect the + configuration of that client. + + @param connHandle - connection handle. + @param charCfgTbl - client characteristic configuration table. + @param value - attribute new value. + + @return Success or Failure +*/ +uint8 GATTServApp_WriteCharCfg( uint16 connHandle, gattCharCfg_t* charCfgTbl, + uint16 value ) +{ + gattCharCfg_t* pItem; + pItem = gattServApp_FindCharCfgItem( connHandle, charCfgTbl ); + + if ( pItem == NULL ) + { + pItem = gattServApp_FindCharCfgItem( INVALID_CONNHANDLE, charCfgTbl ); + + if ( pItem == NULL ) + { + return ( ATT_ERR_INSUFFICIENT_RESOURCES ); + } + + pItem->connHandle = connHandle; + } + + // Write the new value for this client + pItem->value = value; + return ( SUCCESS ); +} + +/********************************************************************* + @fn GATTServApp_ProcessCCCWriteReq + + @brief Process the client characteristic configuration + write request for a given client. + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be written + @param len - length of data + @param offset - offset of the first octet to be written + @param validCfg - valid configuration + + @return Success or Failure +*/ +bStatus_t GATTServApp_ProcessCCCWriteReq( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint8 len, uint16 offset, + uint16 validCfg ) +{ + bStatus_t status = SUCCESS; + + // Validate the value + if ( offset == 0 ) + { + if ( len == 2 ) + { + uint16 value = BUILD_UINT16( pValue[0], pValue[1] ); + + // Validate characteristic configuration bit field + if ( ( value & ~validCfg ) == 0 ) // indicate and/or notify + { + // Write the value if it's changed + if ( GATTServApp_ReadCharCfg( connHandle, + (gattCharCfg_t*)(pAttr->pValue) ) != value ) + { + status = GATTServApp_WriteCharCfg( connHandle, + (gattCharCfg_t*)(pAttr->pValue), + value ); + + if ( status == SUCCESS ) + { + // Notify the application + GATTServApp_SendCCCUpdatedEvent( connHandle, pAttr->handle, value ); + } + } + } + else + { + status = ATT_ERR_INVALID_VALUE; + } + } + else + { + status = ATT_ERR_INVALID_VALUE_SIZE; + } + } + else + { + status = ATT_ERR_ATTR_NOT_LONG; + } + + return ( status ); +} + +/********************************************************************* + @fn GATTServApp_ProcessCharCfg + + @brief Process Client Charateristic Configuration change. + + @param charCfgTbl - characteristic configuration table. + @param pValue - pointer to attribute value. + @param authenticated - whether an authenticated link is required. + @param attrTbl - attribute table. + @param numAttrs - number of attributes in attribute table. + @param taskId - task to be notified of confirmation. + + @return Success or Failure +*/ +#include "log.h" +bStatus_t GATTServApp_ProcessCharCfg( gattCharCfg_t* charCfgTbl, uint8* pValue, + uint8 authenticated, gattAttribute_t* attrTbl, + uint16 numAttrs, uint8 taskId ) +{ + bStatus_t status = SUCCESS; +// for ( uint8 i = 0; i < GATT_MAX_NUM_CONN; i++ ) + { +// gattCharCfg_t* pItem = &(charCfgTbl[i]); + gattCharCfg_t* pItem = charCfgTbl; + + if ( ( pItem->connHandle != INVALID_CONNHANDLE ) && + ( pItem->value != GATT_CFG_NO_OPERATION ) ) + { + gattAttribute_t* pAttr; + // Find the characteristic value attribute + pAttr = GATTServApp_FindAttr( attrTbl, numAttrs, pValue ); + + if ( pAttr != NULL ) + { + attHandleValueNoti_t noti; + + // If the attribute value is longer than (ATT_MTU - 3) octets, then + // only the first (ATT_MTU - 3) octets of this attributes value can + // be sent in a notification. + if ( GATTServApp_ReadAttr( pItem->connHandle, pAttr, + GATT_SERVICE_HANDLE( attrTbl ), noti.value, + ¬i.len, 0, (((gAttMtuSize[pItem->connHandle]))-3) ) == SUCCESS ) + { + noti.handle = pAttr->handle; + + if ( pItem->value & GATT_CLIENT_CFG_NOTIFY ) + { + status |= GATT_Notification( pItem->connHandle, ¬i, authenticated ); + } + + if ( pItem->value & GATT_CLIENT_CFG_INDICATE ) + { + status |= GATT_Indication( pItem->connHandle, (attHandleValueInd_t*)¬i, + authenticated, taskId ); + } + } + } + } + } // for + return ( status ); +} + +/********************************************************************* + @fn gattServApp_HandleConnStatusCB + + @brief GATT Server Application link status change handler function. + + @param connHandle - connection handle + @param changeType - type of change + + @return none +*/ +static void gattServApp_HandleConnStatusCB( uint16 connHandle, uint8 changeType ) +{ + // Check to see if the connection has dropped + if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) || + ( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && + ( !linkDB_Up( connHandle ) ) ) ) + { + prepareWrites_t* pQueue = gattServApp_FindPrepareWriteQ( connHandle ); + + // See if this client has a prepare write queue + if ( pQueue != NULL ) + { + for ( uint8 i = 0; i < maxNumPrepareWrites; i++ ) + { + attPrepareWriteReq_t* pWriteReq = &(pQueue->pPrepareWriteQ[i]); + + // See if there're any prepared write requests in the queue + if ( pWriteReq->handle == GATT_INVALID_HANDLE ) + { + break; + } + + // Clear the queue item + VOID osal_memset( pWriteReq, 0, sizeof( attPrepareWriteRsp_t ) ); + } // for loop + + // Mark this queue as empty + pQueue->connHandle = INVALID_CONNHANDLE; + } + + // Reset Client Char Config when connection drops + GATTServApp_InitCharCfg( connHandle, indCharCfg ); + } +} + +/********************************************************************* + @fn GATTServApp_SendCCCUpdatedEvent + + @brief Build and send the GATT_CLIENT_CHAR_CFG_UPDATED_EVENT to + the app. + + @param connHandle - connection handle + @param attrHandle - attribute handle + @param value - attribute new value + + @return none +*/ +void GATTServApp_SendCCCUpdatedEvent( uint16 connHandle, uint16 attrHandle, uint16 value ) +{ + if ( appTaskID != INVALID_TASK_ID ) + { + // Allocate, build and send event + gattClientCharCfgUpdatedEvent_t* pEvent = + (gattClientCharCfgUpdatedEvent_t*)osal_msg_allocate( (uint16)(sizeof ( gattClientCharCfgUpdatedEvent_t )) ); + + if ( pEvent ) + { + pEvent->hdr.event = GATT_SERV_MSG_EVENT; + pEvent->hdr.status = SUCCESS; + pEvent->method = GATT_CLIENT_CHAR_CFG_UPDATED_EVENT; + pEvent->connHandle = connHandle; + pEvent->attrHandle = attrHandle; + pEvent->value = value; + VOID osal_msg_send( appTaskID, (uint8*)pEvent ); + } + } +} + +bStatus_t gattServApp_RegisterCB(gattServMsgCB_t cb) +{ + s_GATTServCB = cb; + return SUCCESS; +} + + +#endif // ( CENTRAL_CFG | PERIPHERAL_CFG ) + +/**************************************************************************** +****************************************************************************/ diff --git a/src/components/profiles/HID/hiddev.c b/src/components/profiles/HID/hiddev.c new file mode 100644 index 0000000..0067a64 --- /dev/null +++ b/src/components/profiles/HID/hiddev.c @@ -0,0 +1,1468 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + + +/********************************************************************* + INCLUDES +*/ + +#include "OSAL.h" +#include "gatt.h" +#include "hci.h" +#include "gapgattserver.h" +#include "gattservapp.h" +#include "gatt_uuid.h" +#include "gatt_profile_uuid.h" +#include "linkdb.h" +#include "peripheral.h" +#include "gapbondmgr.h" +#include "devinfoservice.h" +#include "battservice.h" +#include "scanparamservice.h" + + +#include "hiddev.h" +#include "hidkbd.h" + +#include "global_config.h" +#include "ll_def.h" + +#include "hidkbdservice.h" +//#include "touch_key.h" +#include "log.h" + +/********************************************************************* + MACROS +*/ + +// Battery measurement period in ms +#define DEFAULT_BATT_PERIOD 15000 + +// TRUE to run scan parameters refresh notify test +#define DEFAULT_SCAN_PARAM_NOTIFY_TEST TRUE + +// Advertising intervals (units of 625us, 160=100ms) +#define HID_INITIAL_ADV_INT_MIN 48 +#define HID_INITIAL_ADV_INT_MAX 80 +#define HID_HIGH_ADV_INT_MIN 32 +#define HID_HIGH_ADV_INT_MAX 48 +#define HID_LOW_ADV_INT_MIN 32//1600 +#define HID_LOW_ADV_INT_MAX 48//1600 + +// Advertising timeouts in sec +#define HID_INITIAL_ADV_TIMEOUT 60 +#define HID_HIGH_ADV_TIMEOUT 5 +#define HID_LOW_ADV_TIMEOUT 0 + +// Heart Rate Task Events +#define START_DEVICE_EVT 0x0001 +#define BATT_PERIODIC_EVT 0x0002 +#define HID_IDLE_EVT 0x0004 +#define HID_SEND_REPORT_EVT 0x0008 + +#define HID_UPPARAM_EVT 0X0010 +#define HID_TEST_EVT 0x0100 + +#define reportQEmpty() ( firstQIdx == lastQIdx ) + + +#define CCD_CHECK_EN_FLAG 0 + +/********************************************************************* + CONSTANTS +*/ + +#define HID_DEV_DATA_LEN 8 + +#ifdef HID_DEV_RPT_QUEUE_LEN + #define HID_DEV_REPORT_Q_SIZE (HID_DEV_RPT_QUEUE_LEN+1) +#else + #define HID_DEV_REPORT_Q_SIZE (10+1) +#endif + +/********************************************************************* + TYPEDEFS +*/ + +typedef struct +{ + uint8 id; + uint8 type; + uint8 len; + uint8 data[HID_DEV_DATA_LEN]; +} hidDevReport_t; + +/********************************************************************* + GLOBAL VARIABLES +*/ + +// Task ID +uint8 hidDevTaskId; + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +// HID report mapping table +extern hidRptMap_t hidRptMap[]; + + +/********************************************************************* + LOCAL VARIABLES +*/ + +// GAP State +gaprole_States_t hidDevGapState = GAPROLE_INIT; + +// TRUE if connection is secure +static uint8 hidDevConnSecure = FALSE; + +// GAP connection handle +uint16 gapConnHandle; + +// TRUE if pairing in progress +static uint8 hidDevPairingStarted = FALSE; + +// Status of last pairing +static uint8 pairingStatus = SUCCESS; + +static hidRptMap_t* pHidDevRptTbl; + +static uint8 hidDevRptTblLen; + +static hidDevCB_t* pHidDevCB; + +static hidDevCfg_t* pHidDevCfg; + +// Whether to change to the preferred connection parameters +static uint8 updateConnParams = TRUE; + +// Pending reports +static uint8 firstQIdx = 0; +static uint8 lastQIdx = 0; +static hidDevReport_t hidDevReportQ[HID_DEV_REPORT_Q_SIZE]; + +// Last report sent out +static attHandleValueNoti_t lastNoti = { 0 }; + +/********************************************************************* + LOCAL FUNCTIONS +*/ + +static void hidDev_ProcessOSALMsg( osal_event_hdr_t* pMsg ); +static void hidDevProcessGattMsg( gattMsgEvent_t* pMsg ); +static void hidDevDisconnected( void ); +static void hidDevGapStateCB( gaprole_States_t newState ); +static void hidDevPairStateCB( uint16 connHandle, uint8 state, uint8 status ); +static void hidDevPasscodeCB( uint8* deviceAddr, uint16 connectionHandle, + uint8 uiInputs, uint8 uiOutputs ); +void hidDevBattCB( uint8 event ); +void hidDevScanParamCB( uint8 event ); +static void hidDevBattPeriodicTask( void ); +static hidRptMap_t* hidDevRptByHandle( uint16 handle ); +static hidRptMap_t* hidDevRptById( uint8 id, uint8 type ); +static hidRptMap_t* hidDevRptByCccdHandle( uint16 handle ); +static void hidDevEnqueueReport( uint8 id, uint8 type, uint8 len, uint8* pData ); +static hidDevReport_t* hidDevDequeueReport( void ); +static void hidDevSendReport( uint8 id, uint8 type, uint8 len, uint8* pData ); +static void hidDevHighAdvertising( void ); +static void hidDevLowAdvertising( void ); +static void hidDevInitialAdvertising( void ); +static uint8 hidDevBondCount( void ); +static void hidDevStartIdleTimer( void ); +static void hidDevStopIdleTimer( void ); +static void HidDev_scanParamCB(uint8_t event); + +/********************************************************************* + PROFILE CALLBACKS +*/ +// GAP Role Callbacks +static gapRolesCBs_t hidDev_PeripheralCBs = +{ + hidDevGapStateCB, // Profile State Change Callbacks + NULL // When a valid RSSI is read from controller +}; + +// Bond Manager Callbacks +static const gapBondCBs_t hidDevBondCB = +{ + hidDevPasscodeCB, + hidDevPairStateCB +}; + + + + + + + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/********************************************************************* + @fn HidDev_Init + + @brief Initialization function for the Hid Dev Task. + This is called during initialization and should contain + any application specific initialization (ie. hardware + initialization/setup, table initialization, power up + notificaiton ... ). + + @param task_id - the ID assigned by OSAL. This ID should be + used to send messages and set timers. + + @return none +*/ +void HidDev_Init( uint8 task_id ) +{ + hidDevTaskId = task_id; + // Setup the GAP Bond Manager + { + uint8 syncWL = TRUE; + // If a bond is created, the HID Device should write the address of the + // HID Host in the HID Device controller's white list and set the HID + // Device controller's advertising filter policy to 'process scan and + // connection requests only from devices in the White List'. + VOID GAPBondMgr_SetParameter( GAPBOND_AUTO_SYNC_WL, sizeof( uint8 ), &syncWL ); + } + // Set up services + GGS_AddService( GATT_ALL_SERVICES ); // GAP + GATTServApp_AddService( GATT_ALL_SERVICES ); // GATT attributes + DevInfo_AddService( ); + Batt_AddService(); + ScanParam_AddService(); + Batt_Register(NULL); + // Register for Scan Parameters service callback. + ScanParam_Register(HidDev_scanParamCB); + //touch_init(on_key); + // Setup a delayed profile startup + osal_set_event( hidDevTaskId, START_DEVICE_EVT ); +} + +/********************************************************************* + @fn HidDev_ProcessEvent + + @brief Hid Dev Task event processor. This function + is called to process all events for the task. Events + include timers, messages and any other user defined events. + + @param task_id - The OSAL assigned task ID. + @param events - events to process. This is a bit map and can + contain more than one event. + + @return events not processed +*/ +uint16 HidDev_ProcessEvent( uint8 task_id, uint16 events ) +{ + VOID task_id; // OSAL required parameter that isn't used in this function + LOG("%s\n",__FUNCTION__); + + if ( events & SYS_EVENT_MSG ) + { + uint8* pMsg; + + if ( (pMsg = osal_msg_receive( hidDevTaskId )) != NULL ) + { + hidDev_ProcessOSALMsg( (osal_event_hdr_t*)pMsg ); + // Release the OSAL message + VOID osal_msg_deallocate( pMsg ); + } + + // return unprocessed events + return (events ^ SYS_EVENT_MSG); + } + + if ( events & START_DEVICE_EVT ) + { + // Start the Device + VOID GAPRole_StartDevice( &hidDev_PeripheralCBs ); + // Register with bond manager after starting device + GAPBondMgr_Register( (gapBondCBs_t*) &hidDevBondCB ); + // GAPBondMgr_SetParameter(GAPBOND_ERASE_ALLBONDS,0,NULL); + LOG("start Device EVT\n\r"); + return ( events ^ START_DEVICE_EVT ); + } + + if ( events & HID_IDLE_EVT ) + { + if ( hidDevGapState == GAPROLE_CONNECTED ) + { + // if pairing in progress then restart timer + if ( hidDevPairingStarted ) + { + hidDevStartIdleTimer(); + LOG("hidDevStartIdleTimer \n\r"); + } + // else disconnect + else + { + //GAPRole_TerminateConnection(); + LOG("hidDevStartIdleTimer disconnect \n\r"); + } + } + + return ( events ^ HID_IDLE_EVT ); + } + + if ( events & BATT_PERIODIC_EVT ) + { + // Perform periodic battery task + hidDevBattPeriodicTask(); + return ( events ^ BATT_PERIODIC_EVT ); + } + + if ( events & HID_SEND_REPORT_EVT ) + { + // if connection is secure + if ( hidDevConnSecure ) + { + LOG("Send Hid Report\n\r"); + hidDevReport_t* pReport = hidDevDequeueReport(); + + if ( pReport != NULL ) + { + // Send report + hidDevSendReport( pReport->id, pReport->type, pReport->len, pReport->data ); + } + + return ( reportQEmpty() ? events^ HID_SEND_REPORT_EVT : events ); + } + + return ( events ^ HID_SEND_REPORT_EVT ); + } + + if( events & HID_UPPARAM_EVT) + { + uint8 bleupdateConnParams = TRUE; + uint8 enable_update_request= TRUE; + + if(hidDevGapState==GAPROLE_CONNECTED) + { + GAPRole_SetParameter( GAPROLE_PARAM_UPDATE_ENABLE, sizeof( uint8 ), &enable_update_request ); + GAPRole_SetParameter( GAPROLE_PARAM_UPDATE_REQ, sizeof( uint8 ), &bleupdateConnParams ); + LOG("device updata connected parament"); + } + + return ( events ^ HID_UPPARAM_EVT ); + } + + return 0; +} + +/********************************************************************* + @fn HidDev_Register + + @brief Register a callback function with HID Dev. + + @param pCfg - Parameter configuration. + @param pfnServiceCB - Callback function. + + @return None. +*/ +void HidDev_Register( hidDevCfg_t* pCfg, hidDevCB_t* pCBs ) +{ + pHidDevCB = pCBs; + pHidDevCfg = pCfg; +} + +/********************************************************************* + @fn HidDev_RegisterReports + + @brief Register the report table with HID Dev. + + @param numReports - Length of report table. + @param pRpt - Report table. + + @return None. +*/ +void HidDev_RegisterReports( uint8 numReports, hidRptMap_t* pRpt ) +{ + pHidDevRptTbl = pRpt; + hidDevRptTblLen = numReports; +} + +/********************************************************************* + @fn HidDev_Report + + @brief Send a HID report. + + @param id - HID report ID. + @param type - HID report type. + @param len - Length of report. + @param pData - Report data. + + @return None. +*/ +void HidDev_Report( uint8 id, uint8 type, uint8 len, uint8* pData ) +{ + // if connected + if ( hidDevGapState == GAPROLE_CONNECTED ) + { + // if connection is secure + if ( hidDevConnSecure ) + { + // Make sure there're no pending reports + if ( reportQEmpty() ) + { + // send report + hidDevSendReport( id, type, len, pData ); + LOG("send key action\n\r"); + return; // we're done + } + } + } + // else if not already advertising + else if ( hidDevGapState != GAPROLE_ADVERTISING ) + { + // if bonded + if ( hidDevBondCount() > 0 ) + { + // start high duty cycle advertising + hidDevHighAdvertising(); + } + // else not bonded + else + { + // start initial advertising + hidDevInitialAdvertising(); + } + } + + // hidDev task will send report when secure connection is established + hidDevEnqueueReport( id, type, len, pData ); +} + +/********************************************************************* + @fn HidDev_Close + + @brief Close the connection or stop advertising. + + @return None. +*/ +void HidDev_Close( void ) +{ + uint8 param; + + // if connected then disconnect + if ( hidDevGapState == GAPROLE_CONNECTED ) + { + GAPRole_TerminateConnection(); + } + // else stop advertising + else + { + param = FALSE; + GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), ¶m ); + } +} + +/********************************************************************* + @fn HidDev_SetParameter + + @brief Set a HID Dev parameter. + + @param param - Profile parameter ID + @param len - length of data to right + @param pValue - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t HidDev_SetParameter( uint8 param, uint8 len, void* pValue ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case HIDDEV_ERASE_ALLBONDS: + if ( len == 0 ) + { + // See if the last report sent out wasn't a release key + if ( osal_isbufset( lastNoti.value, 0x00, lastNoti.len ) == FALSE ) + { + // Send a release report before disconnecting, otherwise + // the last pressed key would get 'stuck' on the HID Host. + osal_memset( lastNoti.value, 0x00, lastNoti.len ); + GATT_Notification( gapConnHandle, &lastNoti, FALSE ); + } + + // Drop connection + if ( hidDevGapState == GAPROLE_CONNECTED ) + { + GAPRole_TerminateConnection(); + } + + // Flush report queue + firstQIdx = lastQIdx = 0; + // Erase bonding info + GAPBondMgr_SetParameter( GAPBOND_ERASE_ALLBONDS, 0, NULL ); + } + else + { + ret = bleInvalidRange; + } + + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn HidDev_GetParameter + + @brief Get a HID Dev parameter. + + @param param - Profile parameter ID + @param pValue - pointer to data to get. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t HidDev_GetParameter( uint8 param, void* pValue ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn HidDev_PasscodeRsp + + @brief Respond to a passcode request. + + @param status - SUCCESS if passcode is available, otherwise + see @ref SMP_PAIRING_FAILED_DEFINES. + @param passcode - integer value containing the passcode. + + @return none +*/ +void HidDev_PasscodeRsp( uint8 status, uint32 passcode ) +{ + // Send passcode response + GAPBondMgr_PasscodeRsp( gapConnHandle, status, passcode ); +} + +/********************************************************************* + @fn HidDev_ReadAttrCB + + @brief HID Dev attribute read callback. + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be read + @param pLen - length of data to be read + @param offset - offset of the first octet to be read + @param maxLen - maximum length of data to be read + @param method - type of read message + + @return SUCCESS, blePending or Failure +*/ +uint8 HidDev_ReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ) +{ + bStatus_t status = SUCCESS; + hidRptMap_t* pRpt; + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + // Only report map is long + if ( offset > 0 && uuid != REPORT_MAP_UUID ) + { + return ( ATT_ERR_ATTR_NOT_LONG ); + } + + if ( uuid == REPORT_UUID || + uuid == BOOT_KEY_INPUT_UUID || + uuid == BOOT_KEY_OUTPUT_UUID || + uuid == BOOT_MOUSE_INPUT_UUID ) + { + // find report ID in table + if ( (pRpt = hidDevRptByHandle(pAttr->handle)) != NULL ) + { + // execute report callback + status = (*pHidDevCB->reportCB)( pRpt->id, pRpt->type, uuid, + HID_DEV_OPER_READ, pLen, pValue ); + } + else + { + *pLen = 0; + } + } + else if ( uuid == REPORT_MAP_UUID ) + { + // verify offset + if ( offset >= hidReportMapLen ) + { + status = ATT_ERR_INVALID_OFFSET; + } + else + { + // determine read length + *pLen = MIN( maxLen, (hidReportMapLen - offset) ); + // copy data + osal_memcpy( pValue, pAttr->pValue + offset, *pLen ); + } + } + else if ( uuid == HID_INFORMATION_UUID ) + { + *pLen = HID_INFORMATION_LEN; + osal_memcpy( pValue, pAttr->pValue, HID_INFORMATION_LEN ); + } + else if ( uuid == GATT_REPORT_REF_UUID ) + { + *pLen = HID_REPORT_REF_LEN; + osal_memcpy( pValue, pAttr->pValue, HID_REPORT_REF_LEN ); + } + else if ( uuid == PROTOCOL_MODE_UUID ) + { + *pLen = HID_PROTOCOL_MODE_LEN; + pValue[0] = pAttr->pValue[0]; + } + else if ( uuid == GATT_EXT_REPORT_REF_UUID ) + { + *pLen = HID_EXT_REPORT_REF_LEN; + osal_memcpy( pValue, pAttr->pValue, HID_EXT_REPORT_REF_LEN ); + } + + // restart idle timer + if ( status == SUCCESS ) + { + hidDevStartIdleTimer(); + } + + return ( status ); +} + +/********************************************************************* + @fn HidDev_WriteAttrCB + + @brief HID Dev attribute read callback. + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be written + @param len - length of data + @param offset - offset of the first octet to be written + + @return Success or Failure +*/ +bStatus_t HidDev_WriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ) +{ + bStatus_t status = SUCCESS; + hidRptMap_t* pRpt; + + // Make sure it's not a blob operation (no attributes in the profile are long) + if ( offset > 0 ) + { + return ( ATT_ERR_ATTR_NOT_LONG ); + } + + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + if ( uuid == REPORT_UUID || + uuid == BOOT_KEY_OUTPUT_UUID ) + { + // find report ID in table + if ((pRpt = hidDevRptByHandle(pAttr->handle)) != NULL) + { + // execute report callback + status = (*pHidDevCB->reportCB)( pRpt->id, pRpt->type, uuid, + HID_DEV_OPER_WRITE, &len, pValue ); + } + } + else if ( uuid == HID_CTRL_PT_UUID ) + { + // Validate length and value range + if ( len == 1 ) + { + if ( pValue[0] == HID_CMD_SUSPEND || pValue[0] == HID_CMD_EXIT_SUSPEND ) + { + // execute HID app event callback + (*pHidDevCB->evtCB)( (pValue[0] == HID_CMD_SUSPEND) ? + HID_DEV_SUSPEND_EVT : HID_DEV_EXIT_SUSPEND_EVT ); + } + else + { + status = ATT_ERR_INVALID_VALUE; + } + } + else + { + status = ATT_ERR_INVALID_VALUE_SIZE; + } + } + else if ( uuid == GATT_CLIENT_CHAR_CFG_UUID ) + { + status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len, + offset, GATT_CLIENT_CFG_NOTIFY ); + + if ( status == SUCCESS ) + { + uint16 charCfg = BUILD_UINT16( pValue[0], pValue[1] ); + + // find report ID in table + if ( (pRpt = hidDevRptByCccdHandle(pAttr->handle)) != NULL ) + { + // execute report callback + (*pHidDevCB->reportCB)( pRpt->id, pRpt->type, uuid, + (charCfg == GATT_CLIENT_CFG_NOTIFY) ? + HID_DEV_OPER_ENABLE : HID_DEV_OPER_DISABLE, + &len, pValue ); + } + } + } + else if ( uuid == PROTOCOL_MODE_UUID ) + { + if ( len == HID_PROTOCOL_MODE_LEN ) + { + if ( pValue[0] == HID_PROTOCOL_MODE_BOOT || + pValue[0] == HID_PROTOCOL_MODE_REPORT ) + { + pAttr->pValue[0] = pValue[0]; + // execute HID app event callback + (*pHidDevCB->evtCB)( (pValue[0] == HID_PROTOCOL_MODE_BOOT) ? + HID_DEV_SET_BOOT_EVT : HID_DEV_SET_REPORT_EVT ); + } + else + { + status = ATT_ERR_INVALID_VALUE; + } + } + else + { + status = ATT_ERR_INVALID_VALUE_SIZE; + } + } + + // restart idle timer + if (status == SUCCESS) + { + hidDevStartIdleTimer(); + } + + return ( status ); +} + +/********************************************************************* + @fn hidDev_ProcessOSALMsg + + @brief Process an incoming task message. + + @param pMsg - message to process + + @return none +*/ +static void hidDev_ProcessOSALMsg( osal_event_hdr_t* pMsg ) +{ + switch ( pMsg->event ) + { + case GATT_MSG_EVENT: + hidDevProcessGattMsg( (gattMsgEvent_t*) pMsg ); + break; + + default: + break; + } +} + +/********************************************************************* + @fn hidDevProcessGattMsg + + @brief Process GATT messages + + @return none +*/ +static void hidDevProcessGattMsg( gattMsgEvent_t* pMsg ) +{ +} + +/********************************************************************* + @fn hidDevHandleConnStatusCB + + @brief Reset client char config. + + @param connHandle - connection handle + @param changeType - type of change + + @return none +*/ +static void hidDevHandleConnStatusCB( uint16 connHandle, uint8 changeType ) +{ + uint8 i; + hidRptMap_t* p = pHidDevRptTbl; + uint16 retHandle; + gattAttribute_t* pAttr; + + // Make sure this is not loopback connection + if ( connHandle != LOOPBACK_CONNHANDLE ) + { + if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) || + ( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && + ( !linkDB_Up( connHandle ) ) ) ) + { + for ( i = hidDevRptTblLen; i > 0; i--, p++ ) + { + if ( p->cccdHandle != 0 ) + { + if ( (pAttr = GATT_FindHandle(p->cccdHandle, &retHandle)) != NULL ) + { + GATTServApp_InitCharCfg( connHandle, (gattCharCfg_t*) pAttr->pValue ); + } + } + } + } + } +} + +/********************************************************************* + @fn hidDevDisconnected + + @brief Handle disconnect. + + @return none +*/ +static void hidDevDisconnected( void ) +{ + uint8 enable_update_request =FALSE; + // Stop idle timer + hidDevStopIdleTimer(); + // Reset client characteristic configuration descriptors + Batt_HandleConnStatusCB( gapConnHandle, LINKDB_STATUS_UPDATE_REMOVED ); + //ScanParam_HandleConnStatusCB( gapConnHandle, LINKDB_STATUS_UPDATE_REMOVED ); + hidDevHandleConnStatusCB( gapConnHandle, LINKDB_STATUS_UPDATE_REMOVED ); + // Reset state variables + hidDevConnSecure = FALSE; + hidProtocolMode = HID_PROTOCOL_MODE_REPORT; + hidDevPairingStarted = FALSE; + // Reset last report sent out + osal_memset( &lastNoti, 0, sizeof( attHandleValueNoti_t ) ); + GAPRole_SetParameter( GAPROLE_PARAM_UPDATE_ENABLE, sizeof( uint8 ), &enable_update_request ); + osal_stop_timerEx(hidDevTaskId, HID_UPPARAM_EVT); + + // if bonded and normally connectable start advertising + if ( ( hidDevBondCount() > 0 ) && + ( pHidDevCfg->hidFlags & HID_FLAGS_REMOTE_WAKE ) ) //HID_FLAGS_REMOTE_WAKE HID_FLAGS_NORMALLY_CONNECTABLE + { + // hidDevDirectAdvertising(); + // LOG("hidDev Direct Advertising \n\r"); + hidDevLowAdvertising(); + LOG("hidDev Low Advertising \n\r"); + } + else + { + hidDevLowAdvertising(); + LOG("hidDev Low Advertising \n\r"); + } +} + +/********************************************************************* + @fn hidDevGapStateCB + + @brief Notification from the profile of a state change. + + @param newState - new state + + @return none +*/ +void hidDevGapStateCB( gaprole_States_t newState ) +{ + LOG("%s, %d\n",__FUNCTION__, newState); + + // if connected + if ( newState == GAPROLE_CONNECTED ) + { + // get connection handle + GAPRole_GetParameter( GAPROLE_CONNHANDLE, &gapConnHandle ); + // connection not secure yet + hidDevConnSecure = FALSE; + uint8 peerAddress[B_ADDR_LEN]; + GAPRole_GetParameter(GAPROLE_CONN_BD_ADDR, peerAddress); + LOG("Master Mac:%02X,%02X,%02X,%02X,%02X,%02X\n\r",peerAddress[5],peerAddress[4],peerAddress[3],peerAddress[2],peerAddress[1],peerAddress[0]); + // start idle timer + hidDevStartIdleTimer(); + } + // if disconnected + else if ( hidDevGapState == GAPROLE_CONNECTED && + newState != GAPROLE_CONNECTED ) + { + LOG("disconnect advisting \n\r"); + hidDevDisconnected(); + updateConnParams = TRUE; + g_instant_cnt=0; + + if ( pairingStatus == SMP_PAIRING_FAILED_CONFIRM_VALUE ) + { + // bonding failed due to mismatched confirm values + hidDevInitialAdvertising(); + pairingStatus = SUCCESS; + LOG("hidDev Initial Advertising \n\r"); + } + } + // if started + else if ( newState == GAPROLE_STARTED ) + { + // nothing to do for now! + } + + hidDevGapState = newState; +} + +/********************************************************************* + @fn hidDevPairStateCB + + @brief Pairing state callback. + + @return none +*/ +void hidDevPairStateCB( uint16 connHandle, uint8 state, uint8 status ) +{ + if ( state == GAPBOND_PAIRING_STATE_STARTED ) + { + hidDevPairingStarted = TRUE; + } + else if ( state == GAPBOND_PAIRING_STATE_COMPLETE ) + { + hidDevPairingStarted = FALSE; + + if ( status == SUCCESS ) + { + hidDevConnSecure = TRUE; + LOG("Pair Success\n\r"); + osal_start_timerEx(hidKbdTaskId, HID_TEST_EVT, 5000); + //osal_start_timerEx(hidDevTaskId, HID_UPPARAM_EVT, 15000);//3000 + } + else + { + LOG("Pair Fail\n\r"); + } + + pairingStatus = status; + } + else if ( state == GAPBOND_PAIRING_STATE_BONDED ) + { + if ( status == SUCCESS ) + { + hidDevConnSecure = TRUE; + // osal_start_timerEx(hidKbdTaskId, HID_TEST_EVT, 5000); + // osal_start_timerEx(hidDevTaskId, HID_UPPARAM_EVT, 15000);//3000 + osal_start_timerEx(hidKbdTaskId, HID_TEST_EVT, 5000); + LOG("bond Success\n\r"); + } + } + + //if(hidDevConnSecure){ + // osal_start_reload_timer(hidDevTaskId, HID_TEST_EVT, 1000); + //} + //LOG("pair state=%d\n\r",state); + if ( !reportQEmpty() && hidDevConnSecure ) + { + LOG("Set Send Report EVENT\n\r"); + // Notify our task to send out pending reports + osal_set_event( hidDevTaskId, HID_SEND_REPORT_EVT ); + } +} + +/********************************************************************* + @fn hidDevPasscodeCB + + @brief Passcode callback. + + @param deviceAddr - address of device to pair with, and could be either public or random. + @param connectionHandle - connection handle + @param uiInputs - pairing User Interface Inputs - Ask user to input passcode + @param uiOutputs - pairing User Interface Outputs - Display passcode + + @return none +*/ +void hidDevPasscodeCB( uint8* deviceAddr, uint16 connectionHandle, + uint8 uiInputs, uint8 uiOutputs ) +{ + if ( pHidDevCB && pHidDevCB->passcodeCB ) + { + // execute HID app passcode callback + (*pHidDevCB->passcodeCB)( deviceAddr, connectionHandle, uiInputs, uiOutputs ); + } + else + { + // Send passcode response + GAPBondMgr_PasscodeRsp( connectionHandle, SUCCESS, 0 ); + } +} + +/********************************************************************* + @fn hidDevBattCB + + @brief Callback function for battery service. + + @param event - service event + + @return none +*/ +void hidDevBattCB( uint8 event ) +{ + if ( event == BATT_LEVEL_NOTI_ENABLED ) + { + // if connected start periodic measurement + if ( hidDevGapState == GAPROLE_CONNECTED ) + { + osal_start_timerEx( hidDevTaskId, BATT_PERIODIC_EVT, DEFAULT_BATT_PERIOD ); + } + } + else if ( event == BATT_LEVEL_NOTI_DISABLED ) + { + // stop periodic measurement + osal_stop_timerEx( hidDevTaskId, BATT_PERIODIC_EVT ); + } +} + +/********************************************************************* + @fn hidDevScanParamCB + + @brief Callback function for scan parameter service. + + @param event - service event + + @return none +*/ +void hidDevScanParamCB( uint8 event ) +{ +} + +/********************************************************************* + @fn hidDevBattPeriodicTask + + @brief Perform a periodic task for battery measurement. + + @param none + + @return none +*/ +static void hidDevBattPeriodicTask( void ) +{ + if ( hidDevGapState == GAPROLE_CONNECTED ) + { + // perform battery level check + Batt_MeasLevel( ); + // Restart timer + osal_start_timerEx( hidDevTaskId, BATT_PERIODIC_EVT, DEFAULT_BATT_PERIOD ); + } +} + +/********************************************************************* + @fn hidDevRptByHandle + + @brief Find the HID report structure for the given handle. + + @param handle - ATT handle + + @return Pointer to HID report structure +*/ +static hidRptMap_t* hidDevRptByHandle( uint16 handle ) +{ + uint8 i; + hidRptMap_t* p = pHidDevRptTbl; + + for ( i = hidDevRptTblLen; i > 0; i--, p++ ) + { + if ( p->handle == handle && p->mode == hidProtocolMode) + { + return p; + } + } + + return NULL; +} + +/********************************************************************* + @fn hidDevRptByCccdHandle + + @brief Find the HID report structure for the given CCC handle. + + @param handle - ATT handle + + @return Pointer to HID report structure +*/ +static hidRptMap_t* hidDevRptByCccdHandle( uint16 handle ) +{ + uint8 i; + hidRptMap_t* p = pHidDevRptTbl; + + for ( i = hidDevRptTblLen; i > 0; i--, p++ ) + { + if ( p->cccdHandle == handle) + { + return p; + } + } + + return NULL; +} + +/********************************************************************* + @fn hidDevRptById + + @brief Find the HID report structure for the Report ID and type. + + @param id - HID report ID + @param type - HID report type + + @return Pointer to HID report structure +*/ +static hidRptMap_t* hidDevRptById( uint8 id, uint8 type ) +{ + uint8 i; + hidRptMap_t* p = pHidDevRptTbl; + + for ( i = hidDevRptTblLen; i > 0; i--, p++ ) + { + if ( p->id == id && p->type == type && p->mode == hidProtocolMode ) + { + return p; + } + } + + return NULL; +} + + +#if CCD_CHECK_EN_FLAG +/********************************************************************* + @fn hidDevSendReport + + @brief Send a HID report. + + @param id - HID report ID. + @param type - HID report type. + @param len - Length of report. + @param pData - Report data. + + @return None. +*/ +static void hidDevSendReport( uint8 id, uint8 type, uint8 len, uint8* pData ) +{ + hidRptMap_t* pRpt; + gattAttribute_t* pAttr; + uint16 retHandle; + LOG("%s\n",__FUNCTION__); + + // Get ATT handle for report + if ( (pRpt = hidDevRptById(id, type)) != NULL ) + { + // if notifications are enabled + if ( (pAttr = GATT_FindHandle(pRpt->cccdHandle, &retHandle)) != NULL ) + { + uint16 value; + value = GATTServApp_ReadCharCfg( gapConnHandle, (gattCharCfg_t*) pAttr->pValue ); + + if ( value & GATT_CLIENT_CFG_NOTIFY ) + { + // After service discovery and encryption, the HID Device should request to + // change to the preferred connection parameters that best suit its use case. + if ( updateConnParams ) + { + GAPRole_SetParameter( GAPROLE_PARAM_UPDATE_REQ, sizeof( uint8 ), &updateConnParams ); + updateConnParams = FALSE; + } + + // send notification + lastNoti.handle = pRpt->handle; + lastNoti.len = len; + osal_memcpy(lastNoti.value, pData, len); + GATT_Notification( gapConnHandle, &lastNoti, FALSE ); + // start idle timer + hidDevStartIdleTimer(); + } + else + { + LOG("notify fail\n\r"); + } + } + } +} +#else +/********************************************************************* + @fn hidDevSendReport + + @brief Send a HID report. + + @param id - HID report ID. + @param type - HID report type. + @param len - Length of report. + @param pData - Report data. + + @return None. +*/ +static void hidDevSendReport( uint8 id, uint8 type, uint8 len, uint8* pData ) +{ + hidRptMap_t* pRpt; + gattAttribute_t* pAttr; + uint16 retHandle; + LOG("%s\n",__FUNCTION__); + + // Get ATT handle for report + if ( (pRpt = hidDevRptById(id, type)) != NULL ) + { + // if notifications are enabled + if ( (pAttr = GATT_FindHandle(pRpt->cccdHandle, &retHandle)) != NULL ) + { + uint16 value; + value = GATTServApp_ReadCharCfg( gapConnHandle, (gattCharCfg_t*) pAttr->pValue ); + + //if ( value & GATT_CLIENT_CFG_NOTIFY ) + { + // After service discovery and encryption, the HID Device should request to + // change to the preferred connection parameters that best suit its use case. + if ( updateConnParams ) + { + GAPRole_SetParameter( GAPROLE_PARAM_UPDATE_REQ, sizeof( uint8 ), &updateConnParams ); + updateConnParams = FALSE; + } + + // send notification + lastNoti.handle = pRpt->handle; + lastNoti.len = len; + osal_memcpy(lastNoti.value, pData, len); + GATT_Notification( gapConnHandle, &lastNoti, FALSE ); + // start idle timer + hidDevStartIdleTimer(); + } + } + } +} +#endif + + +/********************************************************************* + @fn hidDevEnqueueReport + + @brief Enqueue a HID report to be sent later. + + @param id - HID report ID. + @param type - HID report type. + @param len - Length of report. + @param pData - Report data. + + @return None. +*/ +static void hidDevEnqueueReport( uint8 id, uint8 type, uint8 len, uint8* pData ) +{ + // Enqueue only if bonded + if ( hidDevBondCount() > 0 ) + { + // Update last index + lastQIdx = ( lastQIdx + 1 ) % HID_DEV_REPORT_Q_SIZE; + + if ( lastQIdx == firstQIdx ) + { + // Queue overflow; discard oldest report + firstQIdx = ( firstQIdx + 1 ) % HID_DEV_REPORT_Q_SIZE; + } + + // Save report + hidDevReportQ[lastQIdx].id = id; + hidDevReportQ[lastQIdx].type = type; + hidDevReportQ[lastQIdx].len = len; + osal_memcpy( hidDevReportQ[lastQIdx].data, pData, len ); + + if ( hidDevConnSecure ) + { + // Notify our task to send out pending reports + osal_set_event( hidDevTaskId, HID_SEND_REPORT_EVT ); + } + } +} + +/********************************************************************* + @fn hidDevDequeueReport + + @brief Dequeue a HID report to be sent out. + + @param id - HID report ID. + @param type - HID report type. + @param len - Length of report. + @param pData - Report data. + + @return None. +*/ +static hidDevReport_t* hidDevDequeueReport( void ) +{ + if ( reportQEmpty() ) + { + return NULL; + } + + // Update first index + firstQIdx = ( firstQIdx + 1 ) % HID_DEV_REPORT_Q_SIZE; + return ( &(hidDevReportQ[firstQIdx]) ); +} + +/********************************************************************* + @fn hidDevHighAdvertising + + @brief Start advertising at a high duty cycle. + + @param None. + + @return None. +*/ +static void hidDevHighAdvertising( void ) +{ + uint8 param; + VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MIN, HID_HIGH_ADV_INT_MIN ); + VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MAX, HID_HIGH_ADV_INT_MAX ); + VOID GAP_SetParamValue( TGAP_LIM_ADV_TIMEOUT, HID_HIGH_ADV_TIMEOUT ); + // Setup adverstising filter policy first + param = GAP_FILTER_POLICY_WHITE; + VOID GAPRole_SetParameter( GAPROLE_ADV_FILTER_POLICY, sizeof( uint8 ), ¶m ); + param = TRUE; + GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), ¶m ); + LOG("high adv\n\r"); +} + +/********************************************************************* + @fn hidDevLowAdvertising + + @brief Start advertising at a low duty cycle. + + @param None. + + @return None. +*/ +static void hidDevLowAdvertising( void ) +{ + uint8 param; + #if 0 + static uint8_t cnt=0; + uint8_t macAddr[6]= {0x11,0x22,0x33,0x44,0x55,0x66}; + param = FALSE; + GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), ¶m ); + cnt++; + macAddr[5]+=cnt; + volatile uint8_t* P_ownPublicAddr=(volatile uint8_t*)0x1fff11f9; + *(P_ownPublicAddr++)=macAddr[0]; + *(P_ownPublicAddr++)=macAddr[1]; + *(P_ownPublicAddr++)=macAddr[2]; + *(P_ownPublicAddr++)=macAddr[3]; + *(P_ownPublicAddr++)=macAddr[4]; + *(P_ownPublicAddr++)=macAddr[5]; + HCI_ReadBDADDRCmd(); + #endif + param=GAP_ADRPT_ADV_IND;//GAP_ADRPT_ADV_DIRECT_IND; + GAPRole_SetParameter( GAPROLE_ADV_EVENT_TYPE, sizeof(uint8),¶m ); + VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MIN, HID_LOW_ADV_INT_MIN ); + VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MAX, HID_LOW_ADV_INT_MAX ); + VOID GAP_SetParamValue( TGAP_LIM_ADV_TIMEOUT, HID_LOW_ADV_TIMEOUT ); + // Setup adverstising filter policy first + param = GAP_FILTER_POLICY_ALL;//GAP_FILTER_POLICY_WHITE teddy modify + VOID GAPRole_SetParameter( GAPROLE_ADV_FILTER_POLICY, sizeof( uint8 ), ¶m ); + param = TRUE; + VOID GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), ¶m ); +} + +/********************************************************************* + @fn hidDevInitialAdvertising + + @brief Start advertising for initial connection + + @return None. +*/ +static void hidDevInitialAdvertising( void ) +{ + uint8 param; + VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MIN, HID_INITIAL_ADV_INT_MIN ); + VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MAX, HID_INITIAL_ADV_INT_MAX ); + VOID GAP_SetParamValue( TGAP_LIM_ADV_TIMEOUT, HID_INITIAL_ADV_TIMEOUT ); + // Setup adverstising filter policy first + param = GAP_FILTER_POLICY_ALL; + VOID GAPRole_SetParameter( GAPROLE_ADV_FILTER_POLICY, sizeof( uint8 ), ¶m ); + param = TRUE; + VOID GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), ¶m ); +} + +/********************************************************************* + @fn hidDevBondCount + + @brief Gets the total number of bonded devices. + + @param None. + + @return number of bonded devices. +*/ +static uint8 hidDevBondCount( void ) +{ + uint8 bondCnt = 0; + VOID GAPBondMgr_GetParameter( GAPBOND_BOND_COUNT, &bondCnt ); + return ( bondCnt ); +} + +/********************************************************************* + @fn hidDevStartIdleTimer + + @brief Start the idle timer. + + @return None. +*/ +static void hidDevStartIdleTimer( void ) +{ + if ( pHidDevCfg->idleTimeout > 0 ) + { + osal_start_timerEx( hidDevTaskId, HID_IDLE_EVT, pHidDevCfg->idleTimeout ); + } +} + +/********************************************************************* + @fn hidDevStopIdleTimer + + @brief Stop the idle timer. + + @return None. +*/ +static void hidDevStopIdleTimer( void ) +{ + osal_stop_timerEx( hidDevTaskId, HID_IDLE_EVT ); +} + + +/********************************************************************* + @fn HidDev_scanParamCB + + @brief Callback function for scan parameter service. + + @param event - service event + + @return none +*/ +static void HidDev_scanParamCB(uint8_t event) +{ + // Do nothing. +} + + + + + +/********************************************************************* +*********************************************************************/ diff --git a/src/components/profiles/HID/hiddev.h b/src/components/profiles/HID/hiddev.h new file mode 100644 index 0000000..2b32fc1 --- /dev/null +++ b/src/components/profiles/HID/hiddev.h @@ -0,0 +1,301 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + + +#ifndef HIDDEV_H +#define HIDDEV_H + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +// HID Device Parameters +#define HIDDEV_ERASE_ALLBONDS 0 // Erase all of the bonded devices. Write Only. No Size. + +// HID read/write operation +#define HID_DEV_OPER_WRITE 0 // Write operation +#define HID_DEV_OPER_READ 1 // Read operation +#define HID_DEV_OPER_ENABLE 2 // Notification enabled for report ID +#define HID_DEV_OPER_DISABLE 3 // Notifications disabled for report ID + +// HID callback events +#define HID_DEV_SUSPEND_EVT 0 // HID suspend +#define HID_DEV_EXIT_SUSPEND_EVT 1 // HID exit suspend +#define HID_DEV_SET_BOOT_EVT 2 // HID set boot mode +#define HID_DEV_SET_REPORT_EVT 3 // HID set report mode + +/* HID Report type */ +#define HID_REPORT_TYPE_INPUT 1 +#define HID_REPORT_TYPE_OUTPUT 2 +#define HID_REPORT_TYPE_FEATURE 3 + +/* HID information flags */ +#define HID_FLAGS_REMOTE_WAKE 0x01 // RemoteWake +#define HID_FLAGS_NORMALLY_CONNECTABLE 0x02 // NormallyConnectable + +/* Control point commands */ +#define HID_CMD_SUSPEND 0x00 // Suspend +#define HID_CMD_EXIT_SUSPEND 0x01 // Exit Suspend + +/* HID protocol mode values */ +#define HID_PROTOCOL_MODE_BOOT 0x00 // Boot Protocol Mode +#define HID_PROTOCOL_MODE_REPORT 0x01 // Report Protocol Mode + +/* Attribute value lengths */ +#define HID_PROTOCOL_MODE_LEN 1 // HID Protocol Mode +#define HID_INFORMATION_LEN 4 // HID Information +#define HID_REPORT_REF_LEN 2 // HID Report Reference Descriptor +#define HID_EXT_REPORT_REF_LEN 2 // External Report Reference Descriptor + +// HID Keyboard/Keypad Usage IDs (subset of the codes available in the USB HID Usage Tables spec) +#define HID_KEYBOARD_RESERVED 0 // 0x00 - No event inidicated +#define HID_KEYBOARD_A 4 // 0x04 - Keyboard a and A +#define HID_KEYBOARD_B 5 // 0x05 - Keyboard b and B +#define HID_KEYBOARD_C 6 // 0x06 - Keyboard c and C +#define HID_KEYBOARD_D 7 // 0x07 - Keyboard d and D +#define HID_KEYBOARD_E 8 // 0x08 - Keyboard e and E +#define HID_KEYBOARD_F 9 // 0x09 - Keyboard f and F +#define HID_KEYBOARD_G 10 // 0x0A - Keyboard g and G +#define HID_KEYBOARD_H 11 // 0x0B - Keyboard h and H +#define HID_KEYBOARD_I 12 // 0x0C - Keyboard i and I +#define HID_KEYBOARD_J 13 // 0x0D - Keyboard j and J +#define HID_KEYBOARD_K 14 // 0x0E - Keyboard k and K +#define HID_KEYBOARD_L 15 // 0x0F - Keyboard l and L +#define HID_KEYBOARD_M 16 // 0x10 - Keyboard m and M +#define HID_KEYBOARD_N 17 // 0x11 - Keyboard n and N +#define HID_KEYBOARD_O 18 // 0x12 - Keyboard o and O +#define HID_KEYBOARD_P 19 // 0x13 - Keyboard p and p +#define HID_KEYBOARD_Q 20 // 0x14 - Keyboard q and Q +#define HID_KEYBOARD_R 21 // 0x15 - Keyboard r and R +#define HID_KEYBOARD_S 22 // 0x16 - Keyboard s and S +#define HID_KEYBOARD_T 23 // 0x17 - Keyboard t and T +#define HID_KEYBOARD_U 24 // 0x18 - Keyboard u and U +#define HID_KEYBOARD_V 25 // 0x19 - Keyboard v and V +#define HID_KEYBOARD_W 26 // 0x1A - Keyboard w and W +#define HID_KEYBOARD_X 27 // 0x1B - Keyboard x and X +#define HID_KEYBOARD_Y 28 // 0x1C - Keyboard y and Y +#define HID_KEYBOARD_Z 29 // 0x1D - Keyboard z and Z +#define HID_KEYBOARD_1 30 // 0x1E - Keyboard 1 and ! +#define HID_KEYBOARD_2 31 // 0x1F - Keyboard 2 and @ +#define HID_KEYBOARD_3 32 // 0x20 - Keyboard 3 and # +#define HID_KEYBOARD_4 33 // 0x21 - Keyboard 4 and % +#define HID_KEYBOARD_5 34 // 0x22 - Keyboard 5 and % +#define HID_KEYBOARD_6 35 // 0x23 - Keyboard 6 and ^ +#define HID_KEYBOARD_7 36 // 0x24 - Keyboard 7 and & +#define HID_KEYBOARD_8 37 // 0x25 - Keyboard 8 and * +#define HID_KEYBOARD_9 38 // 0x26 - Keyboard 9 and ( +#define HID_KEYBOARD_0 39 // 0x27 - Keyboard 0 and ) +#define HID_KEYBOARD_RETURN 40 // 0x28 - Keyboard Return (ENTER) +#define HID_KEYBOARD_ESCAPE 41 // 0x29 - Keyboard ESCAPE +#define HID_KEYBOARD_DELETE 42 // 0x2A - Keyboard DELETE (Backspace) +#define HID_KEYBOARD_TAB 43 // 0x2B - Keyboard Tab +#define HID_KEYBOARD_SPACEBAR 44 // 0x2C - Keyboard Spacebar +#define HID_KEYBOARD_MINUS 45 // 0x2D - Keyboard - and (underscore) +#define HID_KEYBOARD_EQUAL 46 // 0x2E - Keyboard = and + +#define HID_KEYBOARD_LEFT_BRKT 47 // 0x2F - Keyboard [ and { +#define HID_KEYBOARD_RIGHT_BRKT 48 // 0x30 - Keyboard ] and } +#define HID_KEYBOARD_BACK_SLASH 49 // 0x31 - Keyboard \ and | +#define HID_KEYBOARD_SEMI_COLON 51 // 0x33 - Keyboard ; and : +#define HID_KEYBOARD_SGL_QUOTE 52 // 0x34 - Keyboard ' and " +#define HID_KEYBOARD_GRV_ACCENT 53 // 0x35 - Keyboard Grave Accent and Tilde +#define HID_KEYBOARD_COMMA 54 // 0x36 - Keyboard , and < +#define HID_KEYBOARD_DOT 55 // 0x37 - Keyboard . and > +#define HID_KEYBOARD_FWD_SLASH 56 // 0x38 - Keyboard / and ? +#define HID_KEYBOARD_CAPS_LOCK 57 // 0x39 - Keyboard Caps Lock +#define HID_KEYBOARD_F1 58 // 0x3A - Keyboard F1 +#define HID_KEYBOARD_F2 59 // 0x3B - Keyboard F2 +#define HID_KEYBOARD_F3 60 // 0x3C - Keyboard F3 +#define HID_KEYBOARD_F4 61 // 0x3D - Keyboard F4 +#define HID_KEYBOARD_F5 62 // 0x3E - Keyboard F5 +#define HID_KEYBOARD_F6 63 // 0x3F - Keyboard F6 +#define HID_KEYBOARD_F7 64 // 0x40 - Keyboard F7 +#define HID_KEYBOARD_F8 65 // 0x41 - Keyboard F8 +#define HID_KEYBOARD_F9 66 // 0x42 - Keyboard F9 +#define HID_KEYBOARD_F10 67 // 0x43 - Keyboard F10 +#define HID_KEYBOARD_F11 68 // 0x44 - Keyboard F11 +#define HID_KEYBOARD_F12 69 // 0x45 - Keyboard F12 +#define HID_KEYBOARD_PRNT_SCREEN 70 // 0x46 - Keyboard Print Screen +#define HID_KEYBOARD_SCROLL_LOCK 71 // 0x47 - Keyboard Scroll Lock +#define HID_KEYBOARD_PAUSE 72 // 0x48 - Keyboard Pause +#define HID_KEYBOARD_INSERT 73 // 0x49 - Keyboard Insert +#define HID_KEYBOARD_HOME 74 // 0x4A - Keyboard Home +#define HID_KEYBOARD_PAGE_UP 75 // 0x4B - Keyboard PageUp +#define HID_KEYBOARD_DELETE_FWD 76 // 0x4C - Keyboard Delete Forward +#define HID_KEYBOARD_END 77 // 0x4D - Keyboard End +#define HID_KEYBOARD_PAGE_DOWN 78 // 0x4E - Keyboard PageDown +#define HID_KEYBOARD_RIGHT_ARROW 79 // 0x4F - Keyboard RightArrow +#define HID_KEYBOARD_LEFT_ARROW 80 // 0x50 - Keyboard LeftArrow +#define HID_KEYBOARD_DOWN_ARROW 81 // 0x51 - Keyboard DownArrow +#define HID_KEYBOARD_UP_ARROW 82 // 0x52 - Keyboard UpArrow +#define HID_KEYBPAD_NUM_LOCK 83 // 0x53 - Keypad Num Lock and Clear +#define HID_KEYBPAD_DIVIDE 84 // 0x54 - Keypad / +#define HID_KEYBOARD_MULTIPLY 85 // 0x55 - Keypad * +#define HID_KEYBOARD_SUBTRACT 86 // 0x56 - Keypad - +#define HID_KEYBPAD_ADD 87 // 0x57 - Keypad + +#define HID_KEYBPAD_ENTER 88 // 0x58 - Keypad ENTER +#define HID_KEYBPAD_1 89 // 0x59 - Keypad 1 and End +#define HID_KEYBPAD_2 90 // 0x5A - Keypad 2 and Down Arrow +#define HID_KEYBPAD_3 91 // 0x5B - Keypad 3 and PageDn +#define HID_KEYBPAD_4 92 // 0x5C - Keypad 4 and Lfet Arrow +#define HID_KEYBPAD_5 93 // 0x5D - Keypad 5 +#define HID_KEYBPAD_6 94 // 0x5E - Keypad 6 and Right Arrow +#define HID_KEYBPAD_7 95 // 0x5F - Keypad 7 and Home +#define HID_KEYBPAD_8 96 // 0x60 - Keypad 8 and Up Arrow +#define HID_KEYBPAD_9 97 // 0x61 - Keypad 9 and PageUp +#define HID_KEYBPAD_0 98 // 0x62 - Keypad 0 and Insert +#define HID_KEYBPAD_DOT 99 // 0x63 - Keypad . and Delete +#define HID_KEYBOARD_MUTE 127 // 0x7F - Keyboard Mute +#define HID_KEYBOARD_VOLUME_UP 128 // 0x80 - Keyboard Volume up +#define HID_KEYBOARD_VOLUME_DOWN 129 // 0x81 - Keyboard Volume down +#define HID_KEYBOARD_LEFT_CTRL 224 // 0xE0 - Keyboard LeftContorl +#define HID_KEYBOARD_LEFT_SHIFT 225 // 0xE1 - Keyboard LeftShift +#define HID_KEYBOARD_LEFT_ALT 226 // 0xE2 - Keyboard LeftAlt +#define HID_KEYBOARD_LEFT_GUI 227 // 0xE3 - Keyboard LeftGUI +#define HID_KEYBOARD_RIGHT_CTRL 228 // 0xE4 - Keyboard LeftContorl +#define HID_KEYBOARD_RIGHT_SHIFT 229 // 0xE5 - Keyboard LeftShift +#define HID_KEYBOARD_RIGHT_ALT 230 // 0xE6 - Keyboard LeftAlt +#define HID_KEYBOARD_RIGHT_GUI 231 // 0xE7 - Keyboard RightGUI + +#define HID_MOUSE_BUTTON_LEFT 253 +#define HID_MOUSE_BUTTON_MIDDLE 254 +#define HID_MOUSE_BUTTON_RIGHT 255 + +// HID Consumer Usage IDs (subset of the codes available in the USB HID Usage Tables spec) +#define HID_CONSUMER_POWER 48 // 0x30 - Power +#define HID_CONSUMER_RESET 49 // 0x31 - Reset +#define HID_CONSUMER_SLEEP 50 // 0x32 - Sleep + +#define HID_CONSUMER_MENU 64 // 0x40 - Menu +#define HID_CONSUMER_SELECTION 128 // 0x80 - Selection +#define HID_CONSUMER_ASSIGN_SEL 129 // 0x81 - Assign Selection +#define HID_CONSUMER_MODE_STEP 130 // 0x82 - Mode Step +#define HID_CONSUMER_RECALL_LAST 131 // 0x83 - Recall Last +#define HID_CONSUMER_QUIT 148 // 0x94 - Quit +#define HID_CONSUMER_HELP 149 // 0x95 - Help +#define HID_CONSUMER_CHANNEL_UP 156 // 0x9C - Channel Increment +#define HID_CONSUMER_CHANNEL_DOWN 157 // 0x9D - Channel Decrement + +#define HID_CONSUMER_PLAY 176 // 0xB0 - Play +#define HID_CONSUMER_PAUSE 177 // 0xB1 - Pause +#define HID_CONSUMER_RECORD 178 // 0xB2 - Record +#define HID_CONSUMER_FAST_FORWARD 179 // 0xB3 - Fast Forward +#define HID_CONSUMER_REWIND 180 // 0xB4 - Rewind +#define HID_CONSUMER_SCAN_NEXT_TRK 181 // 0xB5 - Scan Next Track +#define HID_CONSUMER_SCAN_PREV_TRK 182 // 0xB6 - Scan Previous Track +#define HID_CONSUMER_STOP 183 // 0xB7 - Stop +#define HID_CONSUMER_EJECT 184 // 0xB8 - Eject +#define HID_CONSUMER_RANDOM_PLAY 185 // 0xB9 - Random Play +#define HID_CONSUMER_SELECT_DISC 186 // 0xBA - Select Disk +#define HID_CONSUMER_ENTER_DISC 187 // 0xBB - Enter Disc +#define HID_CONSUMER_REPEAT 188 // 0xBC - Repeat +#define HID_CONSUMER_STOP_EJECT 204 // 0xCC - Stop/Eject +#define HID_CONSUMER_PLAY_PAUSE 205 // 0xCD - Play/Pause +#define HID_CONSUMER_PLAY_SKIP 206 // 0xCE - Play/Skip + +#define HID_CONSUMER_VOLUME 224 // 0xE0 - Volume +#define HID_CONSUMER_BALANCE 225 // 0xE1 - Balance +#define HID_CONSUMER_MUTE 226 // 0xE2 - Mute +#define HID_CONSUMER_BASS 227 // 0xE3 - Bass +#define HID_CONSUMER_VOLUME_UP 233 // 0xE9 - Volume Increment +#define HID_CONSUMER_VOLUME_DOWN 234 // 0xEA - Volume Decrement + +/********************************************************************* + TYPEDEFS +*/ + +// HID report mapping table +typedef struct +{ + uint16 handle; // Handle of report characteristic + uint16 cccdHandle; // Handle of CCCD for report characteristic + uint8 id; // Report ID + uint8 type; // Report type + uint8 mode; // Protocol mode (report or boot) +} hidRptMap_t; + +// HID dev configuration structure +typedef struct +{ + uint32 idleTimeout; // Idle timeout in milliseconds + uint8 hidFlags; // HID feature flags + +} hidDevCfg_t; + +/********************************************************************* + Global Variables +*/ + +// These variables are defined in the service .c file that uses HID Dev + +// HID report map length +extern uint16 hidReportMapLen; + +// HID protocol mode +extern uint8 hidProtocolMode; + +/********************************************************************* + Profile Callbacks +*/ + +// HID Report callback +typedef uint8 (*hidDevReportCB_t)( uint8 id, uint8 type, uint16 uuid, + uint8 oper, uint16* pLen, uint8* pData ); + +// HID event callback +typedef void (*hidDevEvtCB_t)( uint8 evt ); + +// HID passcode callback +typedef void (*hidDevPasscodeCB_t)( uint8* deviceAddr, uint16 connectionHandle, + uint8 uiInputs, uint8 uiOutputs ); + +typedef struct +{ + hidDevReportCB_t reportCB; + hidDevEvtCB_t evtCB; + hidDevPasscodeCB_t passcodeCB; +} hidDevCB_t; + + +extern void hidDevGapStateCB( gaprole_States_t newState ); +extern void hidDevPairStateCB( uint16 connHandle, uint8 state, uint8 status ); +extern void hidDevPasscodeCB( uint8* deviceAddr, uint16 connectionHandle, + uint8 uiInputs, uint8 uiOutputs ); +extern void HidDev_Init( uint8 task_id ); +extern uint16 HidDev_ProcessEvent( uint8 task_id, uint16 events ); +extern void HidDev_Register( hidDevCfg_t* pCfg, hidDevCB_t* pCBs ); +extern void HidDev_RegisterReports( uint8 numReports, hidRptMap_t* pRpt ); +extern void HidDev_Report( uint8 id, uint8 type, uint8 len, uint8* pData ); +extern void HidDev_Close( void ); +extern bStatus_t HidDev_SetParameter( uint8 param, uint8 len, void* pValue ); +extern bStatus_t HidDev_GetParameter( uint8 param, void* pValue ); +extern void HidDev_PasscodeRsp( uint8 status, uint32 passcode ); +extern bStatus_t HidDev_ReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, + uint8 maxLen); +extern bStatus_t HidDev_WriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* HIDDEV_H */ diff --git a/src/components/profiles/HID/hidkbdservice.c b/src/components/profiles/HID/hidkbdservice.c new file mode 100644 index 0000000..2259ee1 --- /dev/null +++ b/src/components/profiles/HID/hidkbdservice.c @@ -0,0 +1,969 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/****************************************************************************** + + *****************************************************************************/ + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "att.h" +#include "gatt.h" +#include "gatt_uuid.h" +#include "gatt_profile_uuid.h" +#include "linkdb.h" +#include "gattservapp.h" +#include "hidkbdservice.h" +#include "peripheral.h" +#include "hiddev.h" +#include "battservice.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ +// HID service +CONST uint8 hidServUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(HID_SERV_UUID), HI_UINT16(HID_SERV_UUID) +}; + +// HID Boot Keyboard Input Report characteristic +CONST uint8 hidBootKeyInputUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(BOOT_KEY_INPUT_UUID), HI_UINT16(BOOT_KEY_INPUT_UUID) +}; + +// HID Boot Mouse Input Report characteristic +CONST uint8 hidBootMouseInputUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(BOOT_MOUSE_INPUT_UUID), HI_UINT16(BOOT_MOUSE_INPUT_UUID) +}; + +// HID Boot Keyboard Output Report characteristic +CONST uint8 hidBootKeyOutputUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(BOOT_KEY_OUTPUT_UUID), HI_UINT16(BOOT_KEY_OUTPUT_UUID) +}; + +// HID Information characteristic +CONST uint8 hidInfoUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(HID_INFORMATION_UUID), HI_UINT16(HID_INFORMATION_UUID) +}; + +// HID Report Map characteristic +CONST uint8 hidReportMapUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(REPORT_MAP_UUID), HI_UINT16(REPORT_MAP_UUID) +}; + +// HID Control Point characteristic +CONST uint8 hidControlPointUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(HID_CTRL_PT_UUID), HI_UINT16(HID_CTRL_PT_UUID) +}; + +// HID Report characteristic +CONST uint8 hidReportUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(REPORT_UUID), HI_UINT16(REPORT_UUID) +}; + +// HID Protocol Mode characteristic +CONST uint8 hidProtocolModeUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(PROTOCOL_MODE_UUID), HI_UINT16(PROTOCOL_MODE_UUID) +}; + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +// HID Information characteristic value +static CONST uint8 hidInfo[HID_INFORMATION_LEN] = +{ + LO_UINT16(0x0111), HI_UINT16(0x0111), // bcdHID (USB HID version) + 0x00, // bCountryCode + HID_KBD_FLAGS // Flags +}; + + +static CONST uint8 hidReportMap[] = +{ + #if 0 + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x02, // Usage (Mouse) + 0xA1, 0x01, // Collection (Application) + 0x85, HID_RPT_ID_MOUSE_IN, // Report Id (1) 0X01 + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Physical) + 0x05, 0x09, // Usage Page (Buttons) + 0x19, 0x01, // Usage Minimum (01) - Button 1 + 0x29, 0x03, // Usage Maximum (03) - Button 3 + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x03, // Report Count (3) + 0x81, 0x02, // Input (Data, Variable, Absolute) - Button states + 0x75, 0x05, // Report Size (5) + 0x95, 0x01, // Report Count (1) + 0x81, 0x01, // Input (Constant) - Padding or Reserved bits + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x38, // Usage (Wheel) + 0x15, 0x81, // Logical Minimum (-127) + 0x25, 0x7F, // Logical Maximum (127) + 0x75, 0x08, // Report Size (8) + 0x95, 0x03, // Report Count (3) + 0x81, 0x06, // Input (Data, Variable, Relative) - X & Y coordinate + 0xC0, // End Collection + 0xC0, // End Collection + + 0x05, 0x01, // Usage Pg (Generic Desktop) + 0x09, 0x06, // Usage (Keyboard) + 0xA1, 0x01, // Collection: (Application) + 0x85, HID_RPT_ID_KEY_IN, // Report Id (2) + // + 0x05, 0x07, // Usage Pg (Key Codes) + 0x19, 0xE0, // Usage Min (224) + 0x29, 0xE7, // Usage Max (231) + 0x15, 0x00, // Log Min (0) + 0x25, 0x01, // Log Max (1) + // + // Modifier byte + 0x75, 0x01, // Report Size (1) + 0x95, 0x08, // Report Count (8) + 0x81, 0x02, // Input: (Data, Variable, Absolute) + // + // Reserved byte + 0x95, 0x01, // Report Count (1) + 0x75, 0x08, // Report Size (8) + 0x81, 0x01, // Input: (Constant) + // + // LED report + 0x95, 0x05, // Report Count (5) + 0x75, 0x01, // Report Size (1) + 0x05, 0x08, // Usage Pg (LEDs) + 0x19, 0x01, // Usage Min (1) + 0x29, 0x05, // Usage Max (5) + 0x91, 0x02, // Output: (Data, Variable, Absolute) + // + // LED report padding + 0x95, 0x01, // Report Count (1) + 0x75, 0x03, // Report Size (3) + 0x91, 0x01, // Output: (Constant) + // + // Key arrays (6 bytes) + 0x95, 0x06, // Report Count (6) + 0x75, 0x08, // Report Size (8) + 0x15, 0x00, // Log Min (0) + 0x25, 0x65, // Log Max (101) + 0x05, 0x07, // Usage Pg (Key Codes) + 0x19, 0x00, // Usage Min (0) + 0x29, 0x65, // Usage Max (101) + 0x81, 0x00, // Input: (Data, Array) + // + 0xC0, // End Collection + #endif + + #if EN_CONSUMER_MODE + #if 0 + 0x05, 0x0C, // Usage Pg (Consumer Devices) + 0x09, 0x01, // Usage (Consumer Control) + 0xA1, 0x01, // Collection (Application) + 0x85, HID_RPT_ID_CC_IN, // Report Id (3) + 0x09, 0x02, // Usage (Numeric Key Pad) + 0xA1, 0x02, // Collection (Logical) + 0x05, 0x09, // Usage Pg (Button) + 0x19, 0x01, // Usage Min (Button 1) + 0x29, 0x0A, // Usage Max (Button 10) + 0x15, 0x01, // Logical Min (1) + 0x25, 0x0A, // Logical Max (10) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x81, 0x00, // Input (Data, Ary, Abs) + 0xC0, // End Collection + + 0x05, 0x0C, // Usage Pg (Consumer Devices) + 0x09, 0x86, // Usage (Channel) + 0x15, 0xFF, // Logical Min (-1) + 0x25, 0x01, // Logical Max (1) + 0x75, 0x02, // Report Size (2) + 0x95, 0x01, // Report Count (1) + 0x81, 0x46, // Input (Data, Var, Rel, Null) + 0x09, 0xE9, // Usage (Volume Up) + 0x09, 0xEA, // Usage (Volume Down) + 0x15, 0x00, // Logical Min (0) + 0x75, 0x01, // Report Size (1) + 0x95, 0x02, // Report Count (2) + 0x81, 0x02, // Input (Data, Var, Abs) + 0x09, 0xE2, // Usage (Mute) + 0x09, 0x30, // Usage (Power) + 0x09, 0x83, // Usage (Recall Last) + 0x09, 0x81, // Usage (Assign Selection) + 0x09, 0xB0, // Usage (Play) + 0x09, 0xB1, // Usage (Pause) + 0x09, 0xB2, // Usage (Record) + 0x09, 0xB3, // Usage (Fast Forward) + 0x09, 0xB4, // Usage (Rewind) + 0x09, 0xB5, // Usage (Scan Next) + 0x09, 0xB6, // Usage (Scan Prev) + 0x09, 0xB7, // Usage (Stop) + 0x15, 0x01, // Logical Min (1) + 0x25, 0x0C, // Logical Max (12) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x81, 0x00, // Input (Data, Ary, Abs) + 0x09, 0x80, // Usage (Selection) + 0xA1, 0x02, // Collection (Logical) + 0x05, 0x09, // Usage Pg (Button) + 0x19, 0x01, // Usage Min (Button 1) + 0x29, 0x03, // Usage Max (Button 3) + 0x15, 0x01, // Logical Min (1) + 0x25, 0x03, // Logical Max (3) + 0x75, 0x02, // Report Size (2) + 0x81, 0x00, // Input (Data, Ary, Abs) + 0xC0, // End Collection + 0x81, 0x03, // Input (Const, Var, Abs) + 0xC0 /* End Collection */ + #else + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x06, /* Usage (Keyboard), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, 0x02, /* Report ID (1), */ + 0x05, 0x07, /* Usage Page (Keyboard), */ + 0x19, 0xE0, /* Usage Minimum (KB Leftcontrol), */ + 0x29, 0xE7, /* Usage Maximum (KB Right GUI), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x08, /* Report Count (8), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x01, /* Report Count (1), */ + 0x75, 0x08, /* Report Size (8), */ + 0x81, 0x01, /* Input (Constant), */ + 0x95, 0x05, /* Report Count (5), */ + 0x75, 0x01, /* Report Size (1), */ + 0x05, 0x08, /* Usage Page (LED), */ + 0x19, 0x01, /* Usage Minimum (01h), */ + 0x29, 0x05, /* Usage Maximum (05h), */ + 0x91, 0x02, /* Output (Variable), */ + 0x95, 0x01, /* Report Count (1), */ + 0x75, 0x03, /* Report Size (3), */ + 0x91, 0x01, /* Output (Constant), */ + 0x95, 0x06, /* Report Count (6), */ + 0x75, 0x08, /* Report Size (8), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x25, 0x65, /* Logical Maximum (101), */ + 0x05, 0x07, /* Usage Page (Keyboard), */ + 0x19, 0x00, /* Usage Minimum (None), */ + 0x29, 0x65, /* Usage Maximum (KB Application), */ + 0x81, 0x00, /* Input, */ + 0xC0, /* End Collection, */ + + 0x05, 0x0C, /* Usage Page (Consumer), */ + 0x09, 0x01, /* Usage (Consumer Control), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, 0x03, /* Report ID (2), */ + 0x75, 0x10, /* Report Size (16), */ + 0x95, 0x01, /* Report Count (1), */ + 0x15, 0x01, /* Logical Minimum (1), */ + 0x26, 0x8C, 0x02, /* Logical Maximum (652), */ + 0x19, 0x01, /* Usage Minimum (Consumer Control), */ + 0x2A, 0x8C, 0x02, /* Usage Maximum (AC Send), */ + 0x81, 0x60, /* Input (No Preferred, Null State), */ + 0xC0, /* End Collection, */ + + #endif + + #endif + +}; + + + + +// HID report map length +uint16 hidReportMapLen = sizeof(hidReportMap); + +// HID report mapping table +hidRptMap_t hidRptMap[HID_NUM_REPORTS]; + +/********************************************************************* + Profile Attributes - variables +*/ + +// HID Service attribute +static CONST gattAttrType_t hidService = { ATT_BT_UUID_SIZE, hidServUUID }; + +// Include attribute (Battery service) +static uint16 include = GATT_INVALID_HANDLE; + +// HID Information characteristic +static uint8 hidInfoProps = GATT_PROP_READ; + +// HID Report Map characteristic +static uint8 hidReportMapProps = GATT_PROP_READ; + +// HID External Report Reference Descriptor +static uint8 hidExtReportRefDesc[ATT_BT_UUID_SIZE] = +{ LO_UINT16(BATT_LEVEL_UUID), HI_UINT16(BATT_LEVEL_UUID) }; + +// HID Control Point characteristic +static uint8 hidControlPointProps = GATT_PROP_WRITE_NO_RSP; +static uint8 hidControlPoint; + +// HID Protocol Mode characteristic +static uint8 hidProtocolModeProps = GATT_PROP_READ | GATT_PROP_WRITE_NO_RSP; +uint8 hidProtocolMode = HID_PROTOCOL_MODE_REPORT; + +// HID Report characteristic, key input +static uint8 hidReportKeyInProps = GATT_PROP_READ | GATT_PROP_NOTIFY; +static uint8 hidReportKeyIn; +static gattCharCfg_t hidReportKeyInClientCharCfg[GATT_MAX_NUM_CONN]; + +// HID Report Reference characteristic descriptor, key input +static uint8 hidReportRefKeyIn[HID_REPORT_REF_LEN] = +{ HID_RPT_ID_KEY_IN, HID_REPORT_TYPE_INPUT }; + +// HID Report characteristic, LED output +static uint8 hidReportLedOutProps = GATT_PROP_READ | GATT_PROP_WRITE | GATT_PROP_WRITE_NO_RSP; +static uint8 hidReportLedOut; + +// HID Report Reference characteristic descriptor, LED output +static uint8 hidReportRefLedOut[HID_REPORT_REF_LEN] = +{ HID_RPT_ID_LED_OUT, HID_REPORT_TYPE_OUTPUT }; + +// HID Boot Keyboard Input Report +static uint8 hidReportBootKeyInProps = GATT_PROP_READ | GATT_PROP_NOTIFY; +static uint8 hidReportBootKeyIn; +static gattCharCfg_t hidReportBootKeyInClientCharCfg[GATT_MAX_NUM_CONN]; + +// HID Boot Keyboard Output Report +static uint8 hidReportBootKeyOutProps = GATT_PROP_READ | GATT_PROP_WRITE | GATT_PROP_WRITE_NO_RSP; +static uint8 hidReportBootKeyOut; + +// HID Boot Mouse Input Report +static uint8 hidReportBootMouseInProps = GATT_PROP_READ | GATT_PROP_NOTIFY; +static uint8 hidReportBootMouseIn; +static gattCharCfg_t hidReportBootMouseInClientCharCfg[GATT_MAX_NUM_CONN]; + +// Feature Report +static uint8 hidReportFeatureProps = GATT_PROP_READ | GATT_PROP_WRITE; +static uint8 hidReportFeature; + +// HID Report Reference characteristic descriptor, Feature +static uint8 hidReportRefFeature[HID_REPORT_REF_LEN] = +{ HID_RPT_ID_FEATURE, HID_REPORT_TYPE_FEATURE }; + +#if EN_MOUSE_REPORT + +// HID Report Reference characteristic descriptor, mouse input +static uint8 hidReportRefMouseIn[HID_REPORT_REF_LEN] = +{ HID_RPT_ID_MOUSE_IN, HID_REPORT_TYPE_INPUT }; + +static uint8 hidReportMouseInProps = GATT_PROP_READ | GATT_PROP_NOTIFY; +static uint8 hidReportMouseIn; +static gattCharCfg_t hidReportMouseInClientCharCfg[GATT_MAX_NUM_CONN]; + +#endif +#if EN_CONSUMER_MODE +// HID Report Reference characteristic descriptor, consumer control input +static uint8 hidReportRefCCIn[HID_REPORT_REF_LEN] = +{ HID_RPT_ID_CC_IN, HID_REPORT_TYPE_INPUT }; + +// HID Report characteristic, consumer control input +static uint8 hidReportCCInProps = GATT_PROP_READ | GATT_PROP_NOTIFY; +static uint8 hidReportCCIn; +static gattCharCfg_t hidReportCCInClientCharCfg[GATT_MAX_NUM_CONN]; + +#endif + + + +/********************************************************************* + Profile Attributes - Table +*/ + +static gattAttribute_t hidAttrTbl[] = +{ + // HID Service + { + { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */ + GATT_PERMIT_READ, /* permissions */ + 0, /* handle */ + (uint8*)& hidService /* pValue */ + }, + + // Included service (battery) + { + { ATT_BT_UUID_SIZE, includeUUID }, + GATT_PERMIT_READ, + 0, + (uint8*)& include + }, + #if 1 + + // HID Information characteristic declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidInfoProps + }, + + // HID Information characteristic + { + { ATT_BT_UUID_SIZE, hidInfoUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + (uint8*) hidInfo + }, + #endif + + // HID Control Point characteristic declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidControlPointProps + }, + + // HID Control Point characteristic + { + { ATT_BT_UUID_SIZE, hidControlPointUUID }, + GATT_PERMIT_ENCRYPT_WRITE, + 0, + &hidControlPoint + }, + + // HID Protocol Mode characteristic declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidProtocolModeProps + }, + + // HID Protocol Mode characteristic + { + { ATT_BT_UUID_SIZE, hidProtocolModeUUID }, + GATT_PERMIT_ENCRYPT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + &hidProtocolMode + }, + + + // HID Report Map characteristic declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportMapProps + }, + + // HID Report Map characteristic + { + { ATT_BT_UUID_SIZE, hidReportMapUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + (uint8*) hidReportMap + }, + + // HID External Report Reference Descriptor + { + { ATT_BT_UUID_SIZE, extReportRefUUID }, + GATT_PERMIT_READ, + 0, + hidExtReportRefDesc + }, + #if EN_MOUSE_REPORT +// HID Report characteristic, mouse input declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportMouseInProps + }, + + // HID Report characteristic, mouse input + { + { ATT_BT_UUID_SIZE, hidReportUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + &hidReportMouseIn + }, + + // HID Report characteristic client characteristic configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + (uint8*)& hidReportMouseInClientCharCfg + }, + + // HID Report Reference characteristic descriptor, mouse input + { + { ATT_BT_UUID_SIZE, reportRefUUID }, + GATT_PERMIT_READ, + 0, + hidReportRefMouseIn + }, + + + #endif + + + // HID Report characteristic, key input declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportKeyInProps + }, + + // HID Report characteristic, key input + { + { ATT_BT_UUID_SIZE, hidReportUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + &hidReportKeyIn + }, + + // HID Report characteristic client characteristic configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + (uint8*)& hidReportKeyInClientCharCfg + }, + + // HID Report Reference characteristic descriptor, key input + { + { ATT_BT_UUID_SIZE, reportRefUUID }, + GATT_PERMIT_READ, + 0, + hidReportRefKeyIn + }, + + // HID Report characteristic, LED output declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportLedOutProps + }, + + // HID Report characteristic, LED output + { + { ATT_BT_UUID_SIZE, hidReportUUID }, + GATT_PERMIT_ENCRYPT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + &hidReportLedOut + }, + + // HID Report Reference characteristic descriptor, LED output + { + { ATT_BT_UUID_SIZE, reportRefUUID }, + GATT_PERMIT_READ, + 0, + hidReportRefLedOut + }, + + // HID Boot Keyboard Input Report declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportBootKeyInProps + }, + + // HID Boot Keyboard Input Report + { + { ATT_BT_UUID_SIZE, hidBootKeyInputUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + &hidReportBootKeyIn + }, + + // HID Boot Keyboard Input Report characteristic client characteristic configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + (uint8*)& hidReportBootKeyInClientCharCfg + }, + + // HID Boot Keyboard Output Report declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportBootKeyOutProps + }, + + // HID Boot Keyboard Output Report + { + { ATT_BT_UUID_SIZE, hidBootKeyOutputUUID }, + GATT_PERMIT_ENCRYPT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + &hidReportBootKeyOut + }, + + #if EN_CONSUMER_MODE + // HID Report characteristic declaration, consumer control + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportCCInProps + }, + + // HID Report characteristic, consumer control + { + { ATT_BT_UUID_SIZE, hidReportUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + &hidReportCCIn + }, + + // HID Report characteristic client characteristic configuration, consumer control + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + (uint8*)& hidReportCCInClientCharCfg + }, + + // HID Report Reference characteristic descriptor, consumer control + { + { ATT_BT_UUID_SIZE, reportRefUUID }, + GATT_PERMIT_READ, + 0, + hidReportRefCCIn + }, + + #endif + + // HID Boot Mouse Input Report declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportBootMouseInProps + }, + + // HID Boot Mouse Input Report + { + { ATT_BT_UUID_SIZE, hidBootMouseInputUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + &hidReportBootMouseIn + }, + + // HID Boot Mouse Input Report characteristic client characteristic configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + (uint8*)& hidReportBootMouseInClientCharCfg + }, + + // Feature Report declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportFeatureProps + }, + + // Feature Report + { + { ATT_BT_UUID_SIZE, hidReportUUID}, + GATT_PERMIT_ENCRYPT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + &hidReportFeature + }, + + // HID Report Reference characteristic descriptor, feature + { + { ATT_BT_UUID_SIZE, reportRefUUID }, + GATT_PERMIT_READ, + 0, + hidReportRefFeature + }, + + + #if 0 + + // HID Information characteristic declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidInfoProps + }, + + // HID Information characteristic + { + { ATT_BT_UUID_SIZE, hidInfoUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + (uint8*) hidInfo + }, + #endif +}; + +/********************************************************************* + LOCAL FUNCTIONS +*/ + +/********************************************************************* + PROFILE CALLBACKS +*/ + +// Service Callbacks +CONST gattServiceCBs_t hidKbdCBs = +{ + HidDev_ReadAttrCB, // Read callback function pointer + HidDev_WriteAttrCB, // Write callback function pointer + NULL // Authorization callback function pointer +}; + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/********************************************************************* + @fn HidKbd_AddService + + @brief Initializes the HID Service by registering + GATT attributes with the GATT server. + + @return Success or Failure +*/ +bStatus_t HidKbd_AddService( void ) +{ + uint8 status = SUCCESS; + // Initialize Client Characteristic Configuration attributes + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, hidReportKeyInClientCharCfg ); + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, hidReportBootKeyInClientCharCfg ); + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, hidReportBootMouseInClientCharCfg ); + // Register GATT attribute list and CBs with GATT Server App + status = GATTServApp_RegisterService( hidAttrTbl, GATT_NUM_ATTRS( hidAttrTbl ), &hidKbdCBs ); + // Set up included service + Batt_GetParameter( BATT_PARAM_SERVICE_HANDLE, + &GATT_INCLUDED_HANDLE( hidAttrTbl, HID_INCLUDED_SERVICE_IDX ) ); + // Construct map of reports to characteristic handles + // Each report is uniquely identified via its ID and type + // Key input report + hidRptMap[0].id = hidReportRefKeyIn[0]; + hidRptMap[0].type = hidReportRefKeyIn[1]; + hidRptMap[0].handle = hidAttrTbl[HID_REPORT_KEY_IN_IDX].handle; + hidRptMap[0].cccdHandle = hidAttrTbl[HID_REPORT_KEY_IN_CCCD_IDX].handle; + hidRptMap[0].mode = HID_PROTOCOL_MODE_REPORT; + // LED output report + hidRptMap[1].id = hidReportRefLedOut[0]; + hidRptMap[1].type = hidReportRefLedOut[1]; + hidRptMap[1].handle = hidAttrTbl[HID_REPORT_LED_OUT_IDX].handle; + hidRptMap[1].cccdHandle = 0; + hidRptMap[1].mode = HID_PROTOCOL_MODE_REPORT; + // Boot keyboard input report + // Use same ID and type as key input report + hidRptMap[2].id = hidReportRefKeyIn[0]; + hidRptMap[2].type = hidReportRefKeyIn[1]; + hidRptMap[2].handle = hidAttrTbl[HID_BOOT_KEY_IN_IDX].handle; + hidRptMap[2].cccdHandle = hidAttrTbl[HID_BOOT_KEY_IN_CCCD_IDX].handle; + hidRptMap[2].mode = HID_PROTOCOL_MODE_BOOT; + // Boot keyboard output report + // Use same ID and type as LED output report + hidRptMap[3].id = hidReportRefLedOut[0]; + hidRptMap[3].type = hidReportRefLedOut[1]; + hidRptMap[3].handle = hidAttrTbl[HID_BOOT_KEY_OUT_IDX].handle; + hidRptMap[3].cccdHandle = 0; + hidRptMap[3].mode = HID_PROTOCOL_MODE_BOOT; + // Boot mouse input report + hidRptMap[4].id = HID_RPT_ID_MOUSE_IN; + hidRptMap[4].type = HID_REPORT_TYPE_INPUT; + hidRptMap[4].handle = hidAttrTbl[HID_BOOT_MOUSE_IN_IDX].handle; + hidRptMap[4].cccdHandle = hidAttrTbl[HID_BOOT_MOUSE_IN_CCCD_IDX].handle; + hidRptMap[4].mode = HID_PROTOCOL_MODE_BOOT; + // Feature report + hidRptMap[5].id = hidReportRefFeature[0]; + hidRptMap[5].type = hidReportRefFeature[1]; + hidRptMap[5].handle = hidAttrTbl[HID_FEATURE_IDX].handle; + hidRptMap[5].cccdHandle = 0; + hidRptMap[5].mode = HID_PROTOCOL_MODE_REPORT; + // Battery level input report + Batt_GetParameter( BATT_PARAM_BATT_LEVEL_IN_REPORT, &(hidRptMap[6]) ); + #if EN_MOUSE_REPORT + // Mouse input report + hidRptMap[7].id = hidReportRefMouseIn[0]; + hidRptMap[7].type = hidReportRefMouseIn[1]; + hidRptMap[7].handle = hidAttrTbl[HID_REPORT_MOUSE_IN_IDX].handle; + hidRptMap[7].cccdHandle = hidAttrTbl[HID_REPORT_MOUSE_IN_CCCD_IDX].handle; + hidRptMap[7].mode = HID_PROTOCOL_MODE_REPORT; + #endif + #if EN_CONSUMER_MODE + // Consumer Control input report + hidRptMap[8].id = hidReportRefCCIn[0]; + hidRptMap[8].type = hidReportRefCCIn[1]; + hidRptMap[8].handle = hidAttrTbl[HID_REPORT_CC_IN_IDX].handle; + hidRptMap[8].cccdHandle = hidAttrTbl[HID_REPORT_CC_IN_CCCD_IDX].handle; + hidRptMap[8].mode = HID_PROTOCOL_MODE_REPORT; + #endif + // Setup report ID map + HidDev_RegisterReports( HID_NUM_REPORTS, hidRptMap ); + return ( status ); +} + +/********************************************************************* + @fn HidKbd_SetParameter + + @brief Set a HID Kbd parameter. + + @param id - HID report ID. + @param type - HID report type. + @param uuid - attribute uuid. + @param len - length of data to right. + @param pValue - pointer to data to write. This is dependent on + the input parameters and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return GATT status code. +*/ +uint8 HidKbd_SetParameter( uint8 id, uint8 type, uint16 uuid, uint16 len, void* pValue ) +{ + bStatus_t ret = SUCCESS; + + switch ( uuid ) + { + case REPORT_UUID: + if ( type == HID_REPORT_TYPE_OUTPUT ) + { + if ( len == 1 ) + { + hidReportLedOut = *((uint8*)pValue); + } + else + { + ret = ATT_ERR_INVALID_VALUE_SIZE; + } + } + else if ( type == HID_REPORT_TYPE_FEATURE ) + { + if ( len == 1 ) + { + hidReportFeature = *((uint8*)pValue); + } + else + { + ret = ATT_ERR_INVALID_VALUE_SIZE; + } + } + else + { + ret = ATT_ERR_ATTR_NOT_FOUND; + } + + break; + + case BOOT_KEY_OUTPUT_UUID: + if ( len == 1 ) + { + hidReportBootKeyOut = *((uint8*)pValue); + } + else + { + ret = ATT_ERR_INVALID_VALUE_SIZE; + } + + break; + + default: + // ignore the request + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn HidKbd_GetParameter + + @brief Get a HID Kbd parameter. + + @param id - HID report ID. + @param type - HID report type. + @param uuid - attribute uuid. + @param pLen - length of data to be read + @param pValue - pointer to data to get. This is dependent on + the input parameters and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return GATT status code. +*/ +uint8 HidKbd_GetParameter( uint8 id, uint8 type, uint16 uuid, uint16* pLen, void* pValue ) +{ + switch ( uuid ) + { + case REPORT_UUID: + if ( type == HID_REPORT_TYPE_OUTPUT ) + { + *((uint8*)pValue) = hidReportLedOut; + *pLen = 1; + } + else if ( type == HID_REPORT_TYPE_FEATURE ) + { + *((uint8*)pValue) = hidReportFeature; + *pLen = 1; + } + else + { + *pLen = 0; + } + + break; + + case BOOT_KEY_OUTPUT_UUID: + *((uint8*)pValue) = hidReportBootKeyOut; + *pLen = 1; + break; + + default: + *pLen = 0; + break; + } + + return ( SUCCESS ); +} + +/********************************************************************* +*********************************************************************/ diff --git a/src/components/profiles/HID/hidkbdservice.h b/src/components/profiles/HID/hidkbdservice.h new file mode 100644 index 0000000..b51dbc2 --- /dev/null +++ b/src/components/profiles/HID/hidkbdservice.h @@ -0,0 +1,189 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + + +#ifndef HIDKBDSERVICE_H +#define HIDKBDSERVICE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + CONSTANTS +*/ + + + + +// HID Report IDs for the service + + +#define HID_RPT_ID_MOUSE_IN 1 // Mouse input report ID +#define HID_RPT_ID_KEY_IN 2 // Keyboard input report ID +#define HID_RPT_ID_CC_IN 3 + + + +#define HID_RPT_ID_LED_OUT 0 // LED output report ID +#define HID_RPT_ID_FEATURE 0 // Feature report ID + + + +#define EN_CONSUMER_MODE 1 + +#define EN_MOUSE_REPORT 1 + + +// Number of HID reports defined in the service +#define HID_NUM_REPORTS 9//7 + + + +// Attribute index enumeration-- these indexes match array elements above +enum +{ + + HID_SERVICE_IDX, // HID Service + HID_INCLUDED_SERVICE_IDX, // Included Service + #if 1 + HID_INFO_DECL_IDX, // HID Information characteristic declaration + HID_INFO_IDX, // HID Information characteristic + #endif + HID_CONTROL_POINT_DECL_IDX, // HID Control Point characteristic declaration + HID_CONTROL_POINT_IDX, // HID Control Point characteristic + HID_PROTOCOL_MODE_DECL_IDX, // HID Protocol Mode characteristic declaration + HID_PROTOCOL_MODE_IDX, // HID Protocol Mode characteristic + HID_REPORT_MAP_DECL_IDX, // HID Report Map characteristic declaration + HID_REPORT_MAP_IDX, // HID Report Map characteristic + HID_EXT_REPORT_REF_DESC_IDX, // HID External Report Reference Descriptor + + #if EN_MOUSE_REPORT + HID_REPORT_MOUSE_IN_DECL_IDX, // HID Report characteristic, mouse input declaration + HID_REPORT_MOUSE_IN_IDX, // HID Report characteristic, mouse input + HID_REPORT_MOUSE_IN_CCCD_IDX, // HID Report characteristic client characteristic configuration + HID_REPORT_REF_MOUSE_IN_IDX, // HID Report Reference characteristic descriptor, mouse input + + #endif + + HID_REPORT_KEY_IN_DECL_IDX, // HID Report characteristic, key input declaration + HID_REPORT_KEY_IN_IDX, // HID Report characteristic, key input + HID_REPORT_KEY_IN_CCCD_IDX, // HID Report characteristic client characteristic configuration + HID_REPORT_REF_KEY_IN_IDX, // HID Report Reference characteristic descriptor, key input + HID_REPORT_LED_OUT_DECL_IDX, // HID Report characteristic, LED output declaration + HID_REPORT_LED_OUT_IDX, // HID Report characteristic, LED output + HID_REPORT_REF_LED_OUT_IDX, // HID Report Reference characteristic descriptor, LED output + HID_BOOT_KEY_IN_DECL_IDX, // HID Boot Keyboard Input Report declaration + HID_BOOT_KEY_IN_IDX, // HID Boot Keyboard Input Report + HID_BOOT_KEY_IN_CCCD_IDX, // HID Boot Keyboard Input Report characteristic client characteristic configuration + HID_BOOT_KEY_OUT_DECL_IDX, // HID Boot Keyboard Output Report declaration + HID_BOOT_KEY_OUT_IDX, // HID Boot Keyboard Output Report + + #if EN_CONSUMER_MODE + HID_REPORT_CC_IN_DECL_IDX, // HID Report characteristic declaration, consumer control + HID_REPORT_CC_IN_IDX, // HID Report characteristic, consumer control + HID_REPORT_CC_IN_CCCD_IDX, // HID Report characteristic client characteristic configuration, consumer control + HID_REPORT_REF_CC_IN_IDX, // HID Report Reference characteristic descriptor, consumer control + #endif + HID_BOOT_MOUSE_IN_DECL_IDX, // HID Boot Mouse Input Report declaration + HID_BOOT_MOUSE_IN_IDX, // HID Boot Mouse Input Report + HID_BOOT_MOUSE_IN_CCCD_IDX, // HID Boot Mouse Input Report characteristic client characteristic configuration + HID_FEATURE_DECL_IDX, // Feature Report declaration + HID_FEATURE_IDX, // Feature Report + HID_REPORT_REF_FEATURE_IDX // HID Report Reference characteristic descriptor, feature + + #if 0 + , + HID_INFO_DECL_IDX, // HID Information characteristic declaration + HID_INFO_IDX, // HID Information characteristic + #endif +}; + + + + + +// HID feature flags +#define HID_KBD_FLAGS HID_FLAGS_REMOTE_WAKE + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + Profile Callbacks +*/ + + +/********************************************************************* + API FUNCTIONS +*/ + +/********************************************************************* + @fn HidKbd_AddService + + @brief Initializes the HID service for keyboard by registering + GATT attributes with the GATT server. + + @param none + + @return Success or Failure +*/ +extern bStatus_t HidKbd_AddService(void); + +/********************************************************************* + @fn HidKbd_SetParameter + + @brief Set a HID Kbd parameter. + + @param id - HID report ID. + @param type - HID report type. + @param uuid - attribute uuid. + @param len - length of data to right. + @param pValue - pointer to data to write. This is dependent on + the input parameters and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return GATT status code. +*/ +extern uint8 HidKbd_SetParameter( uint8 id, uint8 type, uint16 uuid, uint16 len, void* pValue ); + +/********************************************************************* + @fn HidKbd_GetParameter + + @brief Get a HID Kbd parameter. + + @param id - HID report ID. + @param type - HID report type. + @param uuid - attribute uuid. + @param pLen - length of data to be read. + @param pValue - pointer to data to get. This is dependent on + the input parameters and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return GATT status code. +*/ +extern uint8 HidKbd_GetParameter( uint8 id, uint8 type, uint16 uuid, uint16* pLen, void* pValue ); + + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* HIDKBDSERVICE_H */ diff --git a/src/components/profiles/HIDVoice/hiddev.c b/src/components/profiles/HIDVoice/hiddev.c new file mode 100644 index 0000000..94486f1 --- /dev/null +++ b/src/components/profiles/HIDVoice/hiddev.c @@ -0,0 +1,1356 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + + +/********************************************************************* + INCLUDES +*/ + +#include "OSAL.h" +#include "gatt.h" +#include "hci.h" +#include "gapgattserver.h" +#include "gattservapp.h" +#include "gatt_uuid.h" +#include "gatt_profile_uuid.h" +#include "linkdb.h" +#include "peripheral.h" +#include "gapbondmgr.h" +#include "devinfoservice.h" +#include "battservice.h" +#include "scanparamservice.h" + + +#include "hiddev.h" +#include "hidkbd.h" + +#include "hidkbdservice.h" +//#include "touch_key.h" +#include "log.h" + +/********************************************************************* + MACROS +*/ + +// Battery measurement period in ms +#define DEFAULT_BATT_PERIOD 15000 + +// TRUE to run scan parameters refresh notify test +#define DEFAULT_SCAN_PARAM_NOTIFY_TEST TRUE + +// Advertising intervals (units of 625us, 160=100ms) +#define HID_INITIAL_ADV_INT_MIN 48 +#define HID_INITIAL_ADV_INT_MAX 80 +#define HID_HIGH_ADV_INT_MIN 32 +#define HID_HIGH_ADV_INT_MAX 48 +#define HID_LOW_ADV_INT_MIN 1600 +#define HID_LOW_ADV_INT_MAX 1600 + +// Advertising timeouts in sec +#define HID_INITIAL_ADV_TIMEOUT 60 +#define HID_HIGH_ADV_TIMEOUT 5 +#define HID_LOW_ADV_TIMEOUT 0 + +// Heart Rate Task Events +#define START_DEVICE_EVT 0x0001 +#define BATT_PERIODIC_EVT 0x0002 +#define HID_IDLE_EVT 0x0004 +#define HID_SEND_REPORT_EVT 0x0008 + + + +#define reportQEmpty() ( firstQIdx == lastQIdx ) + +/********************************************************************* + CONSTANTS +*/ + +#define HID_DEV_DATA_LEN 8 + +#ifdef HID_DEV_RPT_QUEUE_LEN + #define HID_DEV_REPORT_Q_SIZE (HID_DEV_RPT_QUEUE_LEN+1) +#else + #define HID_DEV_REPORT_Q_SIZE (10+1) +#endif + +/********************************************************************* + TYPEDEFS +*/ + +typedef struct +{ + uint8 id; + uint8 type; + uint8 len; + uint8 data[HID_DEV_DATA_LEN]; +} hidDevReport_t; + +/********************************************************************* + GLOBAL VARIABLES +*/ + +// Task ID +uint8 hidDevTaskId; + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +// HID report mapping table +extern hidRptMap_t hidRptMap[]; + + +/********************************************************************* + LOCAL VARIABLES +*/ + +// GAP State +gaprole_States_t hidDevGapState = GAPROLE_INIT; + +// TRUE if connection is secure +static uint8 hidDevConnSecure = FALSE; + +// GAP connection handle +uint16 gapConnHandle; + +// TRUE if pairing in progress +static uint8 hidDevPairingStarted = FALSE; + +// Status of last pairing +static uint8 pairingStatus = SUCCESS; + +static hidRptMap_t* pHidDevRptTbl; + +static uint8 hidDevRptTblLen; + +static hidDevCB_t* pHidDevCB; + +static hidDevCfg_t* pHidDevCfg; + +// Whether to change to the preferred connection parameters +static uint8 updateConnParams = TRUE; + +// Pending reports +static uint8 firstQIdx = 0; +static uint8 lastQIdx = 0; +static hidDevReport_t hidDevReportQ[HID_DEV_REPORT_Q_SIZE]; + +// Last report sent out +static attHandleValueNoti_t lastNoti = { 0 }; + +/********************************************************************* + LOCAL FUNCTIONS +*/ + +static void hidDev_ProcessOSALMsg( osal_event_hdr_t* pMsg ); +static void hidDevProcessGattMsg( gattMsgEvent_t* pMsg ); +static void hidDevDisconnected( void ); +static void hidDevGapStateCB( gaprole_States_t newState ); +static void hidDevPairStateCB( uint16 connHandle, uint8 state, uint8 status ); +static void hidDevPasscodeCB( uint8* deviceAddr, uint16 connectionHandle, + uint8 uiInputs, uint8 uiOutputs ); +void hidDevBattCB( uint8 event ); +void hidDevScanParamCB( uint8 event ); +static void hidDevBattPeriodicTask( void ); +static hidRptMap_t* hidDevRptByHandle( uint16 handle ); +static hidRptMap_t* hidDevRptById( uint8 id, uint8 type ); +static hidRptMap_t* hidDevRptByCccdHandle( uint16 handle ); +static void hidDevEnqueueReport( uint8 id, uint8 type, uint8 len, uint8* pData ); +static hidDevReport_t* hidDevDequeueReport( void ); +static void hidDevSendReport( uint8 id, uint8 type, uint8 len, uint8* pData ); +static void hidDevHighAdvertising( void ); +static void hidDevLowAdvertising( void ); +static void hidDevInitialAdvertising( void ); +static uint8 hidDevBondCount( void ); +static void hidDevStartIdleTimer( void ); +static void hidDevStopIdleTimer( void ); +static void HidDev_scanParamCB(uint8_t event); + +/********************************************************************* + PROFILE CALLBACKS +*/ +// GAP Role Callbacks +static gapRolesCBs_t hidDev_PeripheralCBs = +{ + hidDevGapStateCB, // Profile State Change Callbacks + NULL // When a valid RSSI is read from controller +}; + +// Bond Manager Callbacks +static const gapBondCBs_t hidDevBondCB = +{ + hidDevPasscodeCB, + hidDevPairStateCB +}; + + + + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/********************************************************************* + @fn HidDev_Init + + @brief Initialization function for the Hid Dev Task. + This is called during initialization and should contain + any application specific initialization (ie. hardware + initialization/setup, table initialization, power up + notificaiton ... ). + + @param task_id - the ID assigned by OSAL. This ID should be + used to send messages and set timers. + + @return none +*/ +void HidDev_Init( uint8 task_id ) +{ + hidDevTaskId = task_id; + // Setup the GAP Bond Manager + { + uint8 syncWL = FALSE;//TRUE; + // If a bond is created, the HID Device should write the address of the + // HID Host in the HID Device controller's white list and set the HID + // Device controller's advertising filter policy to 'process scan and + // connection requests only from devices in the White List'. + VOID GAPBondMgr_SetParameter( GAPBOND_AUTO_SYNC_WL, sizeof( uint8 ), &syncWL ); + } + // Set up services + GGS_AddService( GATT_ALL_SERVICES ); // GAP + GATTServApp_AddService( GATT_ALL_SERVICES ); // GATT attributes + DevInfo_AddService( ); + Batt_AddService(); + ScanParam_AddService(); + Batt_Register(NULL); + // Register for Scan Parameters service callback. + ScanParam_Register(HidDev_scanParamCB); + //touch_init(on_key); + // Setup a delayed profile startup + osal_set_event( hidDevTaskId, START_DEVICE_EVT ); +} + +/********************************************************************* + @fn HidDev_ProcessEvent + + @brief Hid Dev Task event processor. This function + is called to process all events for the task. Events + include timers, messages and any other user defined events. + + @param task_id - The OSAL assigned task ID. + @param events - events to process. This is a bit map and can + contain more than one event. + + @return events not processed +*/ +uint16 HidDev_ProcessEvent( uint8 task_id, uint16 events ) +{ + VOID task_id; // OSAL required parameter that isn't used in this function + LOG("%s\n",__FUNCTION__); + + if ( events & SYS_EVENT_MSG ) + { + uint8* pMsg; + + if ( (pMsg = osal_msg_receive( hidDevTaskId )) != NULL ) + { + hidDev_ProcessOSALMsg( (osal_event_hdr_t*)pMsg ); + // Release the OSAL message + VOID osal_msg_deallocate( pMsg ); + } + + // return unprocessed events + return (events ^ SYS_EVENT_MSG); + } + + if ( events & START_DEVICE_EVT ) + { + // Start the Device + VOID GAPRole_StartDevice( &hidDev_PeripheralCBs ); + // Register with bond manager after starting device + GAPBondMgr_Register( (gapBondCBs_t*) &hidDevBondCB ); + GAPBondMgr_SetParameter(GAPBOND_ERASE_ALLBONDS,0,NULL); + LOG("start Device EVT\n\r"); + return ( events ^ START_DEVICE_EVT ); + } + + if ( events & HID_IDLE_EVT ) + { + if ( hidDevGapState == GAPROLE_CONNECTED ) + { + // if pairing in progress then restart timer + if ( hidDevPairingStarted ) + { + hidDevStartIdleTimer(); + LOG("hidDevStartIdleTimer \n\r"); + } + // else disconnect + else + { + GAPRole_TerminateConnection(); + } + } + + return ( events ^ HID_IDLE_EVT ); + } + + if ( events & BATT_PERIODIC_EVT ) + { + // Perform periodic battery task + hidDevBattPeriodicTask(); + return ( events ^ BATT_PERIODIC_EVT ); + } + + if ( events & HID_SEND_REPORT_EVT ) + { + // if connection is secure + if ( hidDevConnSecure ) + { + LOG("Send Hid Report\n\r"); + hidDevReport_t* pReport = hidDevDequeueReport(); + + if ( pReport != NULL ) + { + // Send report + hidDevSendReport( pReport->id, pReport->type, pReport->len, pReport->data ); + } + + return ( reportQEmpty() ? events^ HID_SEND_REPORT_EVT : events ); + } + + return ( events ^ HID_SEND_REPORT_EVT ); + } + + return 0; +} + +/********************************************************************* + @fn HidDev_Register + + @brief Register a callback function with HID Dev. + + @param pCfg - Parameter configuration. + @param pfnServiceCB - Callback function. + + @return None. +*/ +void HidDev_Register( hidDevCfg_t* pCfg, hidDevCB_t* pCBs ) +{ + pHidDevCB = pCBs; + pHidDevCfg = pCfg; +} + +/********************************************************************* + @fn HidDev_RegisterReports + + @brief Register the report table with HID Dev. + + @param numReports - Length of report table. + @param pRpt - Report table. + + @return None. +*/ +void HidDev_RegisterReports( uint8 numReports, hidRptMap_t* pRpt ) +{ + pHidDevRptTbl = pRpt; + hidDevRptTblLen = numReports; +} + +/********************************************************************* + @fn HidDev_Report + + @brief Send a HID report. + + @param id - HID report ID. + @param type - HID report type. + @param len - Length of report. + @param pData - Report data. + + @return None. +*/ +void HidDev_Report( uint8 id, uint8 type, uint8 len, uint8* pData ) +{ + // if connected + if ( hidDevGapState == GAPROLE_CONNECTED ) + { + // if connection is secure + if ( hidDevConnSecure ) + { + // Make sure there're no pending reports + if ( reportQEmpty() ) + { + // send report + hidDevSendReport( id, type, len, pData ); + LOG("send key action\n\r"); + return; // we're done + } + } + } + // else if not already advertising + else if ( hidDevGapState != GAPROLE_ADVERTISING ) + { + // if bonded + if ( hidDevBondCount() > 0 ) + { + // start high duty cycle advertising + hidDevHighAdvertising(); + } + // else not bonded + else + { + // start initial advertising + hidDevInitialAdvertising(); + } + } + + // hidDev task will send report when secure connection is established + hidDevEnqueueReport( id, type, len, pData ); +} + +/********************************************************************* + @fn HidDev_Close + + @brief Close the connection or stop advertising. + + @return None. +*/ +void HidDev_Close( void ) +{ + uint8 param; + + // if connected then disconnect + if ( hidDevGapState == GAPROLE_CONNECTED ) + { + GAPRole_TerminateConnection(); + } + // else stop advertising + else + { + param = FALSE; + GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), ¶m ); + } +} + +/********************************************************************* + @fn HidDev_SetParameter + + @brief Set a HID Dev parameter. + + @param param - Profile parameter ID + @param len - length of data to right + @param pValue - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t HidDev_SetParameter( uint8 param, uint8 len, void* pValue ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case HIDDEV_ERASE_ALLBONDS: + if ( len == 0 ) + { + // See if the last report sent out wasn't a release key + if ( osal_isbufset( lastNoti.value, 0x00, lastNoti.len ) == FALSE ) + { + // Send a release report before disconnecting, otherwise + // the last pressed key would get 'stuck' on the HID Host. + osal_memset( lastNoti.value, 0x00, lastNoti.len ); + GATT_Notification( gapConnHandle, &lastNoti, FALSE ); + } + + // Drop connection + if ( hidDevGapState == GAPROLE_CONNECTED ) + { + GAPRole_TerminateConnection(); + } + + // Flush report queue + firstQIdx = lastQIdx = 0; + // Erase bonding info + GAPBondMgr_SetParameter( GAPBOND_ERASE_ALLBONDS, 0, NULL ); + } + else + { + ret = bleInvalidRange; + } + + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn HidDev_GetParameter + + @brief Get a HID Dev parameter. + + @param param - Profile parameter ID + @param pValue - pointer to data to get. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t HidDev_GetParameter( uint8 param, void* pValue ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn HidDev_PasscodeRsp + + @brief Respond to a passcode request. + + @param status - SUCCESS if passcode is available, otherwise + see @ref SMP_PAIRING_FAILED_DEFINES. + @param passcode - integer value containing the passcode. + + @return none +*/ +void HidDev_PasscodeRsp( uint8 status, uint32 passcode ) +{ + // Send passcode response + GAPBondMgr_PasscodeRsp( gapConnHandle, status, passcode ); +} + +/********************************************************************* + @fn HidDev_ReadAttrCB + + @brief HID Dev attribute read callback. + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be read + @param pLen - length of data to be read + @param offset - offset of the first octet to be read + @param maxLen - maximum length of data to be read + @param method - type of read message + + @return SUCCESS, blePending or Failure +*/ +uint8 HidDev_ReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ) +{ + bStatus_t status = SUCCESS; + hidRptMap_t* pRpt; + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + // Only report map is long + if ( offset > 0 && uuid != REPORT_MAP_UUID ) + { + return ( ATT_ERR_ATTR_NOT_LONG ); + } + + if ( uuid == REPORT_UUID || + uuid == BOOT_KEY_INPUT_UUID || + uuid == BOOT_KEY_OUTPUT_UUID || + uuid == BOOT_MOUSE_INPUT_UUID ) + { + // find report ID in table + if ( (pRpt = hidDevRptByHandle(pAttr->handle)) != NULL ) + { + // execute report callback + status = (*pHidDevCB->reportCB)( pRpt->id, pRpt->type, uuid, + HID_DEV_OPER_READ, pLen, pValue ); + } + else + { + *pLen = 0; + } + } + else if ( uuid == REPORT_MAP_UUID ) + { + // verify offset + if ( offset >= hidReportMapLen ) + { + status = ATT_ERR_INVALID_OFFSET; + } + else + { + // determine read length + *pLen = MIN( maxLen, (hidReportMapLen - offset) ); + // copy data + osal_memcpy( pValue, pAttr->pValue + offset, *pLen ); + } + } + else if ( uuid == HID_INFORMATION_UUID ) + { + *pLen = HID_INFORMATION_LEN; + osal_memcpy( pValue, pAttr->pValue, HID_INFORMATION_LEN ); + } + else if ( uuid == GATT_REPORT_REF_UUID ) + { + *pLen = HID_REPORT_REF_LEN; + osal_memcpy( pValue, pAttr->pValue, HID_REPORT_REF_LEN ); + } + else if ( uuid == PROTOCOL_MODE_UUID ) + { + *pLen = HID_PROTOCOL_MODE_LEN; + pValue[0] = pAttr->pValue[0]; + } + else if ( uuid == GATT_EXT_REPORT_REF_UUID ) + { + *pLen = HID_EXT_REPORT_REF_LEN; + osal_memcpy( pValue, pAttr->pValue, HID_EXT_REPORT_REF_LEN ); + } + + // restart idle timer + if ( status == SUCCESS ) + { + hidDevStartIdleTimer(); + } + + return ( status ); +} + +/********************************************************************* + @fn HidDev_WriteAttrCB + + @brief HID Dev attribute read callback. + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be written + @param len - length of data + @param offset - offset of the first octet to be written + + @return Success or Failure +*/ +bStatus_t HidDev_WriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ) +{ + bStatus_t status = SUCCESS; + hidRptMap_t* pRpt; + + // Make sure it's not a blob operation (no attributes in the profile are long) + if ( offset > 0 ) + { + return ( ATT_ERR_ATTR_NOT_LONG ); + } + + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + if ( uuid == REPORT_UUID || + uuid == BOOT_KEY_OUTPUT_UUID ) + { + // find report ID in table + if ((pRpt = hidDevRptByHandle(pAttr->handle)) != NULL) + { + // execute report callback + status = (*pHidDevCB->reportCB)( pRpt->id, pRpt->type, uuid, + HID_DEV_OPER_WRITE, &len, pValue ); + } + } + else if ( uuid == HID_CTRL_PT_UUID ) + { + // Validate length and value range + if ( len == 1 ) + { + if ( pValue[0] == HID_CMD_SUSPEND || pValue[0] == HID_CMD_EXIT_SUSPEND ) + { + // execute HID app event callback + (*pHidDevCB->evtCB)( (pValue[0] == HID_CMD_SUSPEND) ? + HID_DEV_SUSPEND_EVT : HID_DEV_EXIT_SUSPEND_EVT ); + } + else + { + status = ATT_ERR_INVALID_VALUE; + } + } + else + { + status = ATT_ERR_INVALID_VALUE_SIZE; + } + } + else if ( uuid == GATT_CLIENT_CHAR_CFG_UUID ) + { + status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len, + offset, GATT_CLIENT_CFG_NOTIFY ); + + if ( status == SUCCESS ) + { + uint16 charCfg = BUILD_UINT16( pValue[0], pValue[1] ); + + // find report ID in table + if ( (pRpt = hidDevRptByCccdHandle(pAttr->handle)) != NULL ) + { + if(hidRptMap[5].cccdHandle==pRpt->cccdHandle) + { + LOG("Audio cfg%4X\n\r",charCfg); + } + + // execute report callback + (*pHidDevCB->reportCB)( pRpt->id, pRpt->type, uuid, + (charCfg == GATT_CLIENT_CFG_NOTIFY) ? + HID_DEV_OPER_ENABLE : HID_DEV_OPER_DISABLE, + &len, pValue ); + } + } + } + else if ( uuid == PROTOCOL_MODE_UUID ) + { + if ( len == HID_PROTOCOL_MODE_LEN ) + { + if ( pValue[0] == HID_PROTOCOL_MODE_BOOT || + pValue[0] == HID_PROTOCOL_MODE_REPORT ) + { + pAttr->pValue[0] = pValue[0]; + // execute HID app event callback + (*pHidDevCB->evtCB)( (pValue[0] == HID_PROTOCOL_MODE_BOOT) ? + HID_DEV_SET_BOOT_EVT : HID_DEV_SET_REPORT_EVT ); + } + else + { + status = ATT_ERR_INVALID_VALUE; + } + } + else + { + status = ATT_ERR_INVALID_VALUE_SIZE; + } + } + + // restart idle timer + if (status == SUCCESS) + { + hidDevStartIdleTimer(); + } + + return ( status ); +} + +/********************************************************************* + @fn hidDev_ProcessOSALMsg + + @brief Process an incoming task message. + + @param pMsg - message to process + + @return none +*/ +static void hidDev_ProcessOSALMsg( osal_event_hdr_t* pMsg ) +{ + switch ( pMsg->event ) + { + case GATT_MSG_EVENT: + hidDevProcessGattMsg( (gattMsgEvent_t*) pMsg ); + break; + + default: + break; + } +} + +/********************************************************************* + @fn hidDevProcessGattMsg + + @brief Process GATT messages + + @return none +*/ +static void hidDevProcessGattMsg( gattMsgEvent_t* pMsg ) +{ +} + +/********************************************************************* + @fn hidDevHandleConnStatusCB + + @brief Reset client char config. + + @param connHandle - connection handle + @param changeType - type of change + + @return none +*/ +static void hidDevHandleConnStatusCB( uint16 connHandle, uint8 changeType ) +{ + uint8 i; + hidRptMap_t* p = pHidDevRptTbl; + uint16 retHandle; + gattAttribute_t* pAttr; + + // Make sure this is not loopback connection + if ( connHandle != LOOPBACK_CONNHANDLE ) + { + if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) || + ( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && + ( !linkDB_Up( connHandle ) ) ) ) + { + for ( i = hidDevRptTblLen; i > 0; i--, p++ ) + { + if ( p->cccdHandle != 0 ) + { + if ( (pAttr = GATT_FindHandle(p->cccdHandle, &retHandle)) != NULL ) + { + GATTServApp_InitCharCfg( connHandle, (gattCharCfg_t*) pAttr->pValue ); + } + } + } + } + } +} + +/********************************************************************* + @fn hidDevDisconnected + + @brief Handle disconnect. + + @return none +*/ +static void hidDevDisconnected( void ) +{ + // Stop idle timer + hidDevStopIdleTimer(); + // Reset client characteristic configuration descriptors + Batt_HandleConnStatusCB( gapConnHandle, LINKDB_STATUS_UPDATE_REMOVED ); + //ScanParam_HandleConnStatusCB( gapConnHandle, LINKDB_STATUS_UPDATE_REMOVED ); + hidDevHandleConnStatusCB( gapConnHandle, LINKDB_STATUS_UPDATE_REMOVED ); + // Reset state variables + hidDevConnSecure = FALSE; + hidProtocolMode = HID_PROTOCOL_MODE_REPORT; + hidDevPairingStarted = FALSE; + // Reset last report sent out + osal_memset( &lastNoti, 0, sizeof( attHandleValueNoti_t ) ); + + // if bonded and normally connectable start advertising + if ( ( hidDevBondCount() > 0 ) && + ( pHidDevCfg->hidFlags & HID_FLAGS_NORMALLY_CONNECTABLE ) ) + { + hidDevLowAdvertising(); + } +} + +/********************************************************************* + @fn hidDevGapStateCB + + @brief Notification from the profile of a state change. + + @param newState - new state + + @return none +*/ +void hidDevGapStateCB( gaprole_States_t newState ) +{ + LOG("%s, %d\n",__FUNCTION__, newState); + + // if connected + if ( newState == GAPROLE_CONNECTED ) + { + // get connection handle + GAPRole_GetParameter( GAPROLE_CONNHANDLE, &gapConnHandle ); + // connection not secure yet + hidDevConnSecure = FALSE; + // don't start advertising when connection is closed + uint8 param = FALSE; + GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), ¶m ); + uint8 peerAddress[B_ADDR_LEN]; + GAPRole_GetParameter(GAPROLE_CONN_BD_ADDR, peerAddress); + LOG("Master Mac:%02X,%02X,%02X,%02X,%02X,%02X\n\r",peerAddress[5],peerAddress[4],peerAddress[3],peerAddress[2],peerAddress[1],peerAddress[0]); + // start idle timer + hidDevStartIdleTimer(); + } + // if disconnected + else if ( hidDevGapState == GAPROLE_CONNECTED && + newState != GAPROLE_CONNECTED ) + { +// GAPBondMgr_SetParameter(GAPBOND_ERASE_ALLBONDS,0,NULL); + hidDevDisconnected(); + updateConnParams = TRUE; + + if ( pairingStatus == SMP_PAIRING_FAILED_CONFIRM_VALUE ) + { + // bonding failed due to mismatched confirm values + hidDevInitialAdvertising(); + pairingStatus = SUCCESS; + } + } + // if started + else if ( newState == GAPROLE_STARTED ) + { + // nothing to do for now! + } + + hidDevGapState = newState; +} + +/********************************************************************* + @fn hidDevPairStateCB + + @brief Pairing state callback. + + @return none +*/ +static void hidDevPairStateCB( uint16 connHandle, uint8 state, uint8 status ) +{ + if ( state == GAPBOND_PAIRING_STATE_STARTED ) + { + hidDevPairingStarted = TRUE; + } + else if ( state == GAPBOND_PAIRING_STATE_COMPLETE ) + { + hidDevPairingStarted = FALSE; + + if ( status == SUCCESS ) + { + hidDevConnSecure = TRUE; + LOG("Pair Success\n\r"); + } + else + { + LOG("Pair Fail\n\r"); + } + + pairingStatus = status; + } + else if ( state == GAPBOND_PAIRING_STATE_BONDED ) + { + if ( status == SUCCESS ) + { + hidDevConnSecure = TRUE; + } + } + + if ( !reportQEmpty() && hidDevConnSecure ) + { + LOG("Set Send Report EVENT\n\r"); + // Notify our task to send out pending reports + osal_set_event( hidDevTaskId, HID_SEND_REPORT_EVT ); + } +} + +/********************************************************************* + @fn hidDevPasscodeCB + + @brief Passcode callback. + + @param deviceAddr - address of device to pair with, and could be either public or random. + @param connectionHandle - connection handle + @param uiInputs - pairing User Interface Inputs - Ask user to input passcode + @param uiOutputs - pairing User Interface Outputs - Display passcode + + @return none +*/ +void hidDevPasscodeCB( uint8* deviceAddr, uint16 connectionHandle, + uint8 uiInputs, uint8 uiOutputs ) +{ + if ( pHidDevCB && pHidDevCB->passcodeCB ) + { + // execute HID app passcode callback + (*pHidDevCB->passcodeCB)( deviceAddr, connectionHandle, uiInputs, uiOutputs ); + } + else + { + // Send passcode response + GAPBondMgr_PasscodeRsp( connectionHandle, SUCCESS, 0 ); + } +} + +/********************************************************************* + @fn hidDevBattCB + + @brief Callback function for battery service. + + @param event - service event + + @return none +*/ +void hidDevBattCB( uint8 event ) +{ + if ( event == BATT_LEVEL_NOTI_ENABLED ) + { + // if connected start periodic measurement + if ( hidDevGapState == GAPROLE_CONNECTED ) + { + osal_start_timerEx( hidDevTaskId, BATT_PERIODIC_EVT, DEFAULT_BATT_PERIOD ); + } + } + else if ( event == BATT_LEVEL_NOTI_DISABLED ) + { + // stop periodic measurement + osal_stop_timerEx( hidDevTaskId, BATT_PERIODIC_EVT ); + } +} + +/********************************************************************* + @fn hidDevScanParamCB + + @brief Callback function for scan parameter service. + + @param event - service event + + @return none +*/ +void hidDevScanParamCB( uint8 event ) +{ +} + +/********************************************************************* + @fn hidDevBattPeriodicTask + + @brief Perform a periodic task for battery measurement. + + @param none + + @return none +*/ +static void hidDevBattPeriodicTask( void ) +{ + if ( hidDevGapState == GAPROLE_CONNECTED ) + { + // perform battery level check + Batt_MeasLevel( ); + // Restart timer + osal_start_timerEx( hidDevTaskId, BATT_PERIODIC_EVT, DEFAULT_BATT_PERIOD ); + } +} + +/********************************************************************* + @fn hidDevRptByHandle + + @brief Find the HID report structure for the given handle. + + @param handle - ATT handle + + @return Pointer to HID report structure +*/ +static hidRptMap_t* hidDevRptByHandle( uint16 handle ) +{ + uint8 i; + hidRptMap_t* p = pHidDevRptTbl; + + for ( i = hidDevRptTblLen; i > 0; i--, p++ ) + { + if ( p->handle == handle && p->mode == hidProtocolMode) + { + return p; + } + } + + return NULL; +} + +/********************************************************************* + @fn hidDevRptByCccdHandle + + @brief Find the HID report structure for the given CCC handle. + + @param handle - ATT handle + + @return Pointer to HID report structure +*/ +static hidRptMap_t* hidDevRptByCccdHandle( uint16 handle ) +{ + uint8 i; + hidRptMap_t* p = pHidDevRptTbl; + + for ( i = hidDevRptTblLen; i > 0; i--, p++ ) + { + if ( p->cccdHandle == handle) + { + if(i==HID_VOICE_START_IN_CCCD_IDX) + { + LOG("Voice Notify Enable!!!!!\n\r"); + } + + return p; + } + } + + return NULL; +} + +/********************************************************************* + @fn hidDevRptById + + @brief Find the HID report structure for the Report ID and type. + + @param id - HID report ID + @param type - HID report type + + @return Pointer to HID report structure +*/ +static hidRptMap_t* hidDevRptById( uint8 id, uint8 type ) +{ + uint8 i; + hidRptMap_t* p = pHidDevRptTbl; + + for ( i = hidDevRptTblLen; i > 0; i--, p++ ) + { + if ( p->id == id && p->type == type && p->mode == hidProtocolMode ) + { + return p; + } + } + + return NULL; +} + +/********************************************************************* + @fn hidDevSendReport + + @brief Send a HID report. + + @param id - HID report ID. + @param type - HID report type. + @param len - Length of report. + @param pData - Report data. + + @return None. +*/ +static void hidDevSendReport( uint8 id, uint8 type, uint8 len, uint8* pData ) +{ + hidRptMap_t* pRpt; + gattAttribute_t* pAttr; + uint16 retHandle; + LOG("%s\n",__FUNCTION__); + + // Get ATT handle for report + if ( (pRpt = hidDevRptById(id, type)) != NULL ) + { + // if notifications are enabled + if ( (pAttr = GATT_FindHandle(pRpt->cccdHandle, &retHandle)) != NULL ) + { + uint16 value; + value = GATTServApp_ReadCharCfg( gapConnHandle, (gattCharCfg_t*) pAttr->pValue ); + + if ( value & GATT_CLIENT_CFG_NOTIFY ) + { + // After service discovery and encryption, the HID Device should request to + // change to the preferred connection parameters that best suit its use case. + if ( updateConnParams ) + { + GAPRole_SetParameter( GAPROLE_PARAM_UPDATE_REQ, sizeof( uint8 ), &updateConnParams ); + updateConnParams = FALSE; + } + + // send notification + lastNoti.handle = pRpt->handle; + lastNoti.len = len; + osal_memcpy(lastNoti.value, pData, len); + GATT_Notification( gapConnHandle, &lastNoti, FALSE ); + // start idle timer + hidDevStartIdleTimer(); + } + else + { + LOG("notify fail\n\r"); + } + } + } +} + +/********************************************************************* + @fn hidDevEnqueueReport + + @brief Enqueue a HID report to be sent later. + + @param id - HID report ID. + @param type - HID report type. + @param len - Length of report. + @param pData - Report data. + + @return None. +*/ +static void hidDevEnqueueReport( uint8 id, uint8 type, uint8 len, uint8* pData ) +{ + // Enqueue only if bonded + if ( hidDevBondCount() > 0 ) + { + // Update last index + lastQIdx = ( lastQIdx + 1 ) % HID_DEV_REPORT_Q_SIZE; + + if ( lastQIdx == firstQIdx ) + { + // Queue overflow; discard oldest report + firstQIdx = ( firstQIdx + 1 ) % HID_DEV_REPORT_Q_SIZE; + } + + // Save report + hidDevReportQ[lastQIdx].id = id; + hidDevReportQ[lastQIdx].type = type; + hidDevReportQ[lastQIdx].len = len; + osal_memcpy( hidDevReportQ[lastQIdx].data, pData, len ); + + if ( hidDevConnSecure ) + { + // Notify our task to send out pending reports + osal_set_event( hidDevTaskId, HID_SEND_REPORT_EVT ); + } + } +} + +/********************************************************************* + @fn hidDevDequeueReport + + @brief Dequeue a HID report to be sent out. + + @param id - HID report ID. + @param type - HID report type. + @param len - Length of report. + @param pData - Report data. + + @return None. +*/ +static hidDevReport_t* hidDevDequeueReport( void ) +{ + if ( reportQEmpty() ) + { + return NULL; + } + + // Update first index + firstQIdx = ( firstQIdx + 1 ) % HID_DEV_REPORT_Q_SIZE; + return ( &(hidDevReportQ[firstQIdx]) ); +} + +/********************************************************************* + @fn hidDevHighAdvertising + + @brief Start advertising at a high duty cycle. + + @param None. + + @return None. +*/ +static void hidDevHighAdvertising( void ) +{ + uint8 param; + VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MIN, HID_HIGH_ADV_INT_MIN ); + VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MAX, HID_HIGH_ADV_INT_MAX ); + VOID GAP_SetParamValue( TGAP_LIM_ADV_TIMEOUT, HID_HIGH_ADV_TIMEOUT ); + // Setup adverstising filter policy first + param = GAP_FILTER_POLICY_WHITE; + VOID GAPRole_SetParameter( GAPROLE_ADV_FILTER_POLICY, sizeof( uint8 ), ¶m ); + param = TRUE; + GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), ¶m ); +} + +/********************************************************************* + @fn hidDevLowAdvertising + + @brief Start advertising at a low duty cycle. + + @param None. + + @return None. +*/ +static void hidDevLowAdvertising( void ) +{ + uint8 param; + VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MIN, HID_LOW_ADV_INT_MIN ); + VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MAX, HID_LOW_ADV_INT_MAX ); + VOID GAP_SetParamValue( TGAP_LIM_ADV_TIMEOUT, HID_LOW_ADV_TIMEOUT ); + // Setup adverstising filter policy first + param = GAP_FILTER_POLICY_ALL;//GAP_FILTER_POLICY_WHITE teddy modify + VOID GAPRole_SetParameter( GAPROLE_ADV_FILTER_POLICY, sizeof( uint8 ), ¶m ); + param = TRUE; + VOID GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), ¶m ); +} + +/********************************************************************* + @fn hidDevInitialAdvertising + + @brief Start advertising for initial connection + + @return None. +*/ +static void hidDevInitialAdvertising( void ) +{ + uint8 param; + VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MIN, HID_INITIAL_ADV_INT_MIN ); + VOID GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MAX, HID_INITIAL_ADV_INT_MAX ); + VOID GAP_SetParamValue( TGAP_LIM_ADV_TIMEOUT, HID_INITIAL_ADV_TIMEOUT ); + // Setup adverstising filter policy first + param = GAP_FILTER_POLICY_ALL; + VOID GAPRole_SetParameter( GAPROLE_ADV_FILTER_POLICY, sizeof( uint8 ), ¶m ); + param = TRUE; + VOID GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), ¶m ); +} + +/********************************************************************* + @fn hidDevBondCount + + @brief Gets the total number of bonded devices. + + @param None. + + @return number of bonded devices. +*/ +static uint8 hidDevBondCount( void ) +{ + uint8 bondCnt = 0; + VOID GAPBondMgr_GetParameter( GAPBOND_BOND_COUNT, &bondCnt ); + return ( bondCnt ); +} + +/********************************************************************* + @fn hidDevStartIdleTimer + + @brief Start the idle timer. + + @return None. +*/ +static void hidDevStartIdleTimer( void ) +{ + if ( pHidDevCfg->idleTimeout > 0 ) + { + osal_start_timerEx( hidDevTaskId, HID_IDLE_EVT, pHidDevCfg->idleTimeout ); + } +} + +/********************************************************************* + @fn hidDevStopIdleTimer + + @brief Stop the idle timer. + + @return None. +*/ +static void hidDevStopIdleTimer( void ) +{ + osal_stop_timerEx( hidDevTaskId, HID_IDLE_EVT ); +} + + +/********************************************************************* + @fn HidDev_scanParamCB + + @brief Callback function for scan parameter service. + + @param event - service event + + @return none +*/ +static void HidDev_scanParamCB(uint8_t event) +{ + // Do nothing. +} + + +/********************************************************************* +*********************************************************************/ diff --git a/src/components/profiles/HIDVoice/hiddev.h b/src/components/profiles/HIDVoice/hiddev.h new file mode 100644 index 0000000..57d054e --- /dev/null +++ b/src/components/profiles/HIDVoice/hiddev.h @@ -0,0 +1,310 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + + +#ifndef HIDDEV_H +#define HIDDEV_H + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +// HID Device Parameters +#define HIDDEV_ERASE_ALLBONDS 0 // Erase all of the bonded devices. Write Only. No Size. + +// HID read/write operation +#define HID_DEV_OPER_WRITE 0 // Write operation +#define HID_DEV_OPER_READ 1 // Read operation +#define HID_DEV_OPER_ENABLE 2 // Notification enabled for report ID +#define HID_DEV_OPER_DISABLE 3 // Notifications disabled for report ID + +// HID callback events +#define HID_DEV_SUSPEND_EVT 0 // HID suspend +#define HID_DEV_EXIT_SUSPEND_EVT 1 // HID exit suspend +#define HID_DEV_SET_BOOT_EVT 2 // HID set boot mode +#define HID_DEV_SET_REPORT_EVT 3 // HID set report mode + +/* HID Report type */ +#define HID_REPORT_TYPE_INPUT 1 +#define HID_REPORT_TYPE_OUTPUT 2 +#define HID_REPORT_TYPE_FEATURE 3 + +/* HID information flags */ +#define HID_FLAGS_REMOTE_WAKE 0x01 // RemoteWake +#define HID_FLAGS_NORMALLY_CONNECTABLE 0x02 // NormallyConnectable + +/* Control point commands */ +#define HID_CMD_SUSPEND 0x00 // Suspend +#define HID_CMD_EXIT_SUSPEND 0x01 // Exit Suspend + +/* HID protocol mode values */ +#define HID_PROTOCOL_MODE_BOOT 0x00 // Boot Protocol Mode +#define HID_PROTOCOL_MODE_REPORT 0x01 // Report Protocol Mode + +/* Attribute value lengths */ +#define HID_PROTOCOL_MODE_LEN 1 // HID Protocol Mode +#define HID_INFORMATION_LEN 4 // HID Information +#define HID_REPORT_REF_LEN 2 // HID Report Reference Descriptor +#define HID_EXT_REPORT_REF_LEN 2 // External Report Reference Descriptor + +// HID Keyboard/Keypad Usage IDs (subset of the codes available in the USB HID Usage Tables spec) +#define HID_KEYBOARD_RESERVED 0 // 0x00 - No event inidicated +#define HID_KEYBOARD_A 4 // 0x04 - Keyboard a and A +#define HID_KEYBOARD_B 5 // 0x05 - Keyboard b and B +#define HID_KEYBOARD_C 6 // 0x06 - Keyboard c and C +#define HID_KEYBOARD_D 7 // 0x07 - Keyboard d and D +#define HID_KEYBOARD_E 8 // 0x08 - Keyboard e and E +#define HID_KEYBOARD_F 9 // 0x09 - Keyboard f and F +#define HID_KEYBOARD_G 10 // 0x0A - Keyboard g and G +#define HID_KEYBOARD_H 11 // 0x0B - Keyboard h and H +#define HID_KEYBOARD_I 12 // 0x0C - Keyboard i and I +#define HID_KEYBOARD_J 13 // 0x0D - Keyboard j and J +#define HID_KEYBOARD_K 14 // 0x0E - Keyboard k and K +#define HID_KEYBOARD_L 15 // 0x0F - Keyboard l and L +#define HID_KEYBOARD_M 16 // 0x10 - Keyboard m and M +#define HID_KEYBOARD_N 17 // 0x11 - Keyboard n and N +#define HID_KEYBOARD_O 18 // 0x12 - Keyboard o and O +#define HID_KEYBOARD_P 19 // 0x13 - Keyboard p and p +#define HID_KEYBOARD_Q 20 // 0x14 - Keyboard q and Q +#define HID_KEYBOARD_R 21 // 0x15 - Keyboard r and R +#define HID_KEYBOARD_S 22 // 0x16 - Keyboard s and S +#define HID_KEYBOARD_T 23 // 0x17 - Keyboard t and T +#define HID_KEYBOARD_U 24 // 0x18 - Keyboard u and U +#define HID_KEYBOARD_V 25 // 0x19 - Keyboard v and V +#define HID_KEYBOARD_W 26 // 0x1A - Keyboard w and W +#define HID_KEYBOARD_X 27 // 0x1B - Keyboard x and X +#define HID_KEYBOARD_Y 28 // 0x1C - Keyboard y and Y +#define HID_KEYBOARD_Z 29 // 0x1D - Keyboard z and Z +#define HID_KEYBOARD_1 30 // 0x1E - Keyboard 1 and ! +#define HID_KEYBOARD_2 31 // 0x1F - Keyboard 2 and @ +#define HID_KEYBOARD_3 32 // 0x20 - Keyboard 3 and # +#define HID_KEYBOARD_4 33 // 0x21 - Keyboard 4 and % +#define HID_KEYBOARD_5 34 // 0x22 - Keyboard 5 and % +#define HID_KEYBOARD_6 35 // 0x23 - Keyboard 6 and ^ +#define HID_KEYBOARD_7 36 // 0x24 - Keyboard 7 and & +#define HID_KEYBOARD_8 37 // 0x25 - Keyboard 8 and * +#define HID_KEYBOARD_9 38 // 0x26 - Keyboard 9 and ( +#define HID_KEYBOARD_0 39 // 0x27 - Keyboard 0 and ) +#define HID_KEYBOARD_RETURN 40 // 0x28 - Keyboard Return (ENTER) +#define HID_KEYBOARD_ESCAPE 41 // 0x29 - Keyboard ESCAPE +#define HID_KEYBOARD_DELETE 42 // 0x2A - Keyboard DELETE (Backspace) +#define HID_KEYBOARD_TAB 43 // 0x2B - Keyboard Tab +#define HID_KEYBOARD_SPACEBAR 44 // 0x2C - Keyboard Spacebar +#define HID_KEYBOARD_MINUS 45 // 0x2D - Keyboard - and (underscore) +#define HID_KEYBOARD_EQUAL 46 // 0x2E - Keyboard = and + +#define HID_KEYBOARD_LEFT_BRKT 47 // 0x2F - Keyboard [ and { +#define HID_KEYBOARD_RIGHT_BRKT 48 // 0x30 - Keyboard ] and } +#define HID_KEYBOARD_BACK_SLASH 49 // 0x31 - Keyboard \ and | +#define HID_KEYBOARD_SEMI_COLON 51 // 0x33 - Keyboard ; and : +#define HID_KEYBOARD_SGL_QUOTE 52 // 0x34 - Keyboard ' and " +#define HID_KEYBOARD_GRV_ACCENT 53 // 0x35 - Keyboard Grave Accent and Tilde +#define HID_KEYBOARD_COMMA 54 // 0x36 - Keyboard , and < +#define HID_KEYBOARD_DOT 55 // 0x37 - Keyboard . and > +#define HID_KEYBOARD_FWD_SLASH 56 // 0x38 - Keyboard / and ? +#define HID_KEYBOARD_CAPS_LOCK 57 // 0x39 - Keyboard Caps Lock +#define HID_KEYBOARD_F1 58 // 0x3A - Keyboard F1 +#define HID_KEYBOARD_F2 59 // 0x3B - Keyboard F2 +#define HID_KEYBOARD_F3 60 // 0x3C - Keyboard F3 +#define HID_KEYBOARD_F4 61 // 0x3D - Keyboard F4 +#define HID_KEYBOARD_F5 62 // 0x3E - Keyboard F5 +#define HID_KEYBOARD_F6 63 // 0x3F - Keyboard F6 +#define HID_KEYBOARD_F7 64 // 0x40 - Keyboard F7 +#define HID_KEYBOARD_F8 65 // 0x41 - Keyboard F8 +#define HID_KEYBOARD_F9 66 // 0x42 - Keyboard F9 +#define HID_KEYBOARD_F10 67 // 0x43 - Keyboard F10 +#define HID_KEYBOARD_F11 68 // 0x44 - Keyboard F11 +#define HID_KEYBOARD_F12 69 // 0x45 - Keyboard F12 +#define HID_KEYBOARD_PRNT_SCREEN 70 // 0x46 - Keyboard Print Screen +#define HID_KEYBOARD_SCROLL_LOCK 71 // 0x47 - Keyboard Scroll Lock +#define HID_KEYBOARD_PAUSE 72 // 0x48 - Keyboard Pause +#define HID_KEYBOARD_INSERT 73 // 0x49 - Keyboard Insert +#define HID_KEYBOARD_HOME 74 // 0x4A - Keyboard Home +#define HID_KEYBOARD_PAGE_UP 75 // 0x4B - Keyboard PageUp +#define HID_KEYBOARD_DELETE_FWD 76 // 0x4C - Keyboard Delete Forward +#define HID_KEYBOARD_END 77 // 0x4D - Keyboard End +#define HID_KEYBOARD_PAGE_DOWN 78 // 0x4E - Keyboard PageDown +#define HID_KEYBOARD_RIGHT_ARROW 79 // 0x4F - Keyboard RightArrow +#define HID_KEYBOARD_LEFT_ARROW 80 // 0x50 - Keyboard LeftArrow +#define HID_KEYBOARD_DOWN_ARROW 81 // 0x51 - Keyboard DownArrow +#define HID_KEYBOARD_UP_ARROW 82 // 0x52 - Keyboard UpArrow +#define HID_KEYBPAD_NUM_LOCK 83 // 0x53 - Keypad Num Lock and Clear +#define HID_KEYBPAD_DIVIDE 84 // 0x54 - Keypad / +#define HID_KEYBOARD_MULTIPLY 85 // 0x55 - Keypad * +#define HID_KEYBOARD_SUBTRACT 86 // 0x56 - Keypad - +#define HID_KEYBPAD_ADD 87 // 0x57 - Keypad + +#define HID_KEYBPAD_ENTER 88 // 0x58 - Keypad ENTER +#define HID_KEYBPAD_1 89 // 0x59 - Keypad 1 and End +#define HID_KEYBPAD_2 90 // 0x5A - Keypad 2 and Down Arrow +#define HID_KEYBPAD_3 91 // 0x5B - Keypad 3 and PageDn +#define HID_KEYBPAD_4 92 // 0x5C - Keypad 4 and Lfet Arrow +#define HID_KEYBPAD_5 93 // 0x5D - Keypad 5 +#define HID_KEYBPAD_6 94 // 0x5E - Keypad 6 and Right Arrow +#define HID_KEYBPAD_7 95 // 0x5F - Keypad 7 and Home +#define HID_KEYBPAD_8 96 // 0x60 - Keypad 8 and Up Arrow +#define HID_KEYBPAD_9 97 // 0x61 - Keypad 9 and PageUp +#define HID_KEYBPAD_0 98 // 0x62 - Keypad 0 and Insert +#define HID_KEYBPAD_DOT 99 // 0x63 - Keypad . and Delete +#define HID_KEYBOARD_MUTE 127 // 0x7F - Keyboard Mute +#define HID_KEYBOARD_VOLUME_UP 128 // 0x80 - Keyboard Volume up +#define HID_KEYBOARD_VOLUME_DOWN 129 // 0x81 - Keyboard Volume down +#define HID_KEYBOARD_LEFT_CTRL 224 // 0xE0 - Keyboard LeftContorl +#define HID_KEYBOARD_LEFT_SHIFT 225 // 0xE1 - Keyboard LeftShift +#define HID_KEYBOARD_LEFT_ALT 226 // 0xE2 - Keyboard LeftAlt +#define HID_KEYBOARD_LEFT_GUI 227 // 0xE3 - Keyboard LeftGUI +#define HID_KEYBOARD_RIGHT_CTRL 228 // 0xE4 - Keyboard LeftContorl +#define HID_KEYBOARD_RIGHT_SHIFT 229 // 0xE5 - Keyboard LeftShift +#define HID_KEYBOARD_RIGHT_ALT 230 // 0xE6 - Keyboard LeftAlt +#define HID_KEYBOARD_RIGHT_GUI 231 // 0xE7 - Keyboard RightGUI + +#define HID_MOUSE_BUTTON_LEFT 253 +#define HID_MOUSE_BUTTON_MIDDLE 254 +#define HID_MOUSE_BUTTON_RIGHT 255 + +// HID Consumer Usage IDs (subset of the codes available in the USB HID Usage Tables spec) +#define HID_CONSUMER_POWER 48 // 0x30 - Power +#define HID_CONSUMER_RESET 49 // 0x31 - Reset +#define HID_CONSUMER_SLEEP 50 // 0x32 - Sleep + +#define HID_CONSUMER_MENU 64 // 0x40 - Menu +#define HID_CONSUMER_SELECTION 128 // 0x80 - Selection +#define HID_CONSUMER_ASSIGN_SEL 129 // 0x81 - Assign Selection +#define HID_CONSUMER_MODE_STEP 130 // 0x82 - Mode Step +#define HID_CONSUMER_RECALL_LAST 131 // 0x83 - Recall Last +#define HID_CONSUMER_QUIT 148 // 0x94 - Quit +#define HID_CONSUMER_HELP 149 // 0x95 - Help +#define HID_CONSUMER_CHANNEL_UP 156 // 0x9C - Channel Increment +#define HID_CONSUMER_CHANNEL_DOWN 157 // 0x9D - Channel Decrement + +#define HID_CONSUMER_PLAY 176 // 0xB0 - Play +#define HID_CONSUMER_PAUSE 177 // 0xB1 - Pause +#define HID_CONSUMER_RECORD 178 // 0xB2 - Record +#define HID_CONSUMER_FAST_FORWARD 179 // 0xB3 - Fast Forward +#define HID_CONSUMER_REWIND 180 // 0xB4 - Rewind +#define HID_CONSUMER_SCAN_NEXT_TRK 181 // 0xB5 - Scan Next Track +#define HID_CONSUMER_SCAN_PREV_TRK 182 // 0xB6 - Scan Previous Track +#define HID_CONSUMER_STOP 183 // 0xB7 - Stop +#define HID_CONSUMER_EJECT 184 // 0xB8 - Eject +#define HID_CONSUMER_RANDOM_PLAY 185 // 0xB9 - Random Play +#define HID_CONSUMER_SELECT_DISC 186 // 0xBA - Select Disk +#define HID_CONSUMER_ENTER_DISC 187 // 0xBB - Enter Disc +#define HID_CONSUMER_REPEAT 188 // 0xBC - Repeat +#define HID_CONSUMER_STOP_EJECT 204 // 0xCC - Stop/Eject +#define HID_CONSUMER_PLAY_PAUSE 205 // 0xCD - Play/Pause +#define HID_CONSUMER_PLAY_SKIP 206 // 0xCE - Play/Skip + +#define HID_CONSUMER_VOLUME 224 // 0xE0 - Volume +#define HID_CONSUMER_BALANCE 225 // 0xE1 - Balance +#define HID_CONSUMER_MUTE 226 // 0xE2 - Mute +#define HID_CONSUMER_BASS 227 // 0xE3 - Bass +#define HID_CONSUMER_VOLUME_UP 233 // 0xE9 - Volume Increment +#define HID_CONSUMER_VOLUME_DOWN 234 // 0xEA - Volume Decrement + +/**********my define android HID keys value*****/ +#define HID_ANDROID_CONSUMER_MENU 101//0x65 - adnroid menu +#define HID_USER_DEFINE_CH_UP 54//0x36 - user define ch+ +#define HID_USER_DEFINE_CH_DOWN 55//0x37 - user define ch- + +/********************************************************************* + TYPEDEFS +*/ + +// HID report mapping table +typedef struct +{ + uint16 handle; // Handle of report characteristic + uint16 cccdHandle; // Handle of CCCD for report characteristic + uint8 id; // Report ID + uint8 type; // Report type + uint8 mode; // Protocol mode (report or boot) +} hidRptMap_t; + +// HID dev configuration structure +typedef struct +{ + uint32 idleTimeout; // Idle timeout in milliseconds + uint8 hidFlags; // HID feature flags + +} hidDevCfg_t; + +/********************************************************************* + Global Variables +*/ + +// These variables are defined in the service .c file that uses HID Dev + +// HID report map length +extern uint16 hidReportMapLen; + +// HID protocol mode +extern uint8 hidProtocolMode; + +//extern uint16 gapConnHandle; + +/********************************************************************* + Profile Callbacks +*/ + +// HID Report callback +typedef uint8 (*hidDevReportCB_t)( uint8 id, uint8 type, uint16 uuid, + uint8 oper, uint16* pLen, uint8* pData ); + +// HID event callback +typedef void (*hidDevEvtCB_t)( uint8 evt ); + +// HID passcode callback +typedef void (*hidDevPasscodeCB_t)( uint8* deviceAddr, uint16 connectionHandle, + uint8 uiInputs, uint8 uiOutputs ); + +typedef struct +{ + hidDevReportCB_t reportCB; + hidDevEvtCB_t evtCB; + hidDevPasscodeCB_t passcodeCB; +} hidDevCB_t; + + +extern void hidDevGapStateCB( gaprole_States_t newState ); +extern void hidDevPairStateCB( uint16 connHandle, uint8 state, uint8 status ); +extern void hidDevPasscodeCB( uint8* deviceAddr, uint16 connectionHandle, + uint8 uiInputs, uint8 uiOutputs ); +extern void HidDev_Init( uint8 task_id ); +extern uint16 HidDev_ProcessEvent( uint8 task_id, uint16 events ); +extern void HidDev_Register( hidDevCfg_t* pCfg, hidDevCB_t* pCBs ); +extern void HidDev_RegisterReports( uint8 numReports, hidRptMap_t* pRpt ); +extern void HidDev_Report( uint8 id, uint8 type, uint8 len, uint8* pData ); +extern void HidDev_Close( void ); +extern bStatus_t HidDev_SetParameter( uint8 param, uint8 len, void* pValue ); +extern bStatus_t HidDev_GetParameter( uint8 param, void* pValue ); +extern void HidDev_PasscodeRsp( uint8 status, uint32 passcode ); +extern bStatus_t HidDev_ReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, + uint8 maxLen); +extern bStatus_t HidDev_WriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* HIDDEV_H */ + + diff --git a/src/components/profiles/HIDVoice/hidkbdservice.c b/src/components/profiles/HIDVoice/hidkbdservice.c new file mode 100644 index 0000000..b174360 --- /dev/null +++ b/src/components/profiles/HIDVoice/hidkbdservice.c @@ -0,0 +1,1572 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/****************************************************************************** + + *****************************************************************************/ + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "att.h" +#include "gatt.h" +#include "gatt_uuid.h" +#include "gatt_profile_uuid.h" +#include "linkdb.h" +#include "gattservapp.h" +#include "hidkbdservice.h" +#include "peripheral.h" +#include "hiddev.h" +#include "battservice.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ +// HID service +CONST uint8 hidServUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(HID_SERV_UUID), HI_UINT16(HID_SERV_UUID) +}; + +// HID Boot Keyboard Input Report characteristic +CONST uint8 hidBootKeyInputUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(BOOT_KEY_INPUT_UUID), HI_UINT16(BOOT_KEY_INPUT_UUID) +}; + +// HID Boot Mouse Input Report characteristic +CONST uint8 hidBootMouseInputUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(BOOT_MOUSE_INPUT_UUID), HI_UINT16(BOOT_MOUSE_INPUT_UUID) +}; + +// HID Boot Keyboard Output Report characteristic +CONST uint8 hidBootKeyOutputUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(BOOT_KEY_OUTPUT_UUID), HI_UINT16(BOOT_KEY_OUTPUT_UUID) +}; + +// HID Information characteristic +CONST uint8 hidInfoUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(HID_INFORMATION_UUID), HI_UINT16(HID_INFORMATION_UUID) +}; + +// HID Report Map characteristic +CONST uint8 hidReportMapUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(REPORT_MAP_UUID), HI_UINT16(REPORT_MAP_UUID) +}; + +// HID Control Point characteristic +CONST uint8 hidControlPointUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(HID_CTRL_PT_UUID), HI_UINT16(HID_CTRL_PT_UUID) +}; + +// HID Report characteristic +CONST uint8 hidReportUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(REPORT_UUID), HI_UINT16(REPORT_UUID) +}; + +// HID Protocol Mode characteristic +CONST uint8 hidProtocolModeUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(PROTOCOL_MODE_UUID), HI_UINT16(PROTOCOL_MODE_UUID) +}; + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +// HID Information characteristic value +static CONST uint8 hidInfo[HID_INFORMATION_LEN] = +{ + LO_UINT16(0x0111), HI_UINT16(0x0111), // bcdHID (USB HID version) + 0x00, // bCountryCode + HID_KBD_FLAGS // Flags +}; + +// HID Report Map characteristic value +// Keyboard report descriptor (using format for Boot interface descriptor) +#if FOLLOW_TI_MAP + +static CONST uint8 hidReportMap[] = +{ + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xA1, 0x01, // COLLECTION (Application) + 0x85, HID_RPT_ID_KEY_IN, // REPORT_ID (1) + // + 0x05, 0x07, // USAGE_PAGE (Key Codes) + 0x19, 0xE0, // USAGE_MIN (224) + 0x29, 0xE7, // USAGE_MAX (231) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + // + // Modifier byte + 0x95, 0x08, // REPORT_COUNT (8) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data, Variable, Absolute) + // + // Reserved byte + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x01, // INPUT (Constant) + // + // LED report + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MIN (1) + 0x29, 0x05, // USAGE_MAX (5) + 0x91, 0x02, // OUTPUT (Data, Variable, Absolute) + // + // LED report padding + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x01, // OUTPUT (Constant) + // + // Key arrays (6 bytes) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Key Codes) + 0x19, 0x00, // USAGE_MIN (0) + 0x29, 0x65, // USAGE_MAX (101) + 0x81, 0x00, // INPUT (Data, Array) + // + 0xC0, // END_COLLECTION + // + 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) + 0x09, 0x01, // USAGE (Consumer Control) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, HID_RPT_ID_CC_IN, // REPORT_ID (2) + // + 0x09, 0x30, // USAGE (Power) + 0x09, 0xCD, // USAGE (Play/Pause) + 0x09, 0xB7, // USAGE (Stop) + 0x09, 0xB5, // USAGE (Skip track) + 0x09, 0xB6, // USAGE (Previous track) + 0x09, 0xB3, // USAGE (Fast forward) + 0x09, 0xB4, // USAGE (Rewind) + 0x09, 0xB2, // USAGE (Record) + 0x09, 0xE9, // USAGE (Volume up) + 0x09, 0xEA, // USAGE (Volume down) + 0x09, 0xE2, // USAGE (Mute) + 0x15, 0x01, // LOGICAL_MINIMUM (1) + 0x25, 0x0B, // LOGICAL_MAXIMUM (11) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + // + 0xC0, // END_COLLECTION + + //Voice collection + 0x05, 0x0C, // Usage Page (Consumer Devices) + 0x09, 0x01, // Usage (Consumer Control) + 0xA1, 0x01, // Collection (Application) + 0x85, HID_RPT_ID_VOICE_START_IN, // Report ID (10) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x75, 0x08, // Report Size (8) + 0x95, 0x05, // Report Count (5) + 0x09, 0x01, // Usage (Consumer Control) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x85, HID_RPT_ID_VOICE_DATA_IN, // Report ID (11) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x75, 0x08, // Report Size (8) + 0x95, 0x14, // Report Count (20) + 0x09, 0x01, // Usage (Consumer Control) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + + 0xC0 // END_COLLECTION +}; + + +#else +static CONST uint8 hidReportMap[] = +{ + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x02, // Usage (Mouse) + 0xA1, 0x01, // Collection (Application) + 0x85, HID_RPT_ID_MOUSE_IN, // Report Id (1) 0X01 + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Physical) + 0x05, 0x09, // Usage Page (Buttons) + 0x19, 0x01, // Usage Minimum (01) - Button 1 + 0x29, 0x03, // Usage Maximum (03) - Button 3 + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x03, // Report Count (3) + 0x81, 0x02, // Input (Data, Variable, Absolute) - Button states + 0x75, 0x05, // Report Size (5) + 0x95, 0x01, // Report Count (1) + 0x81, 0x01, // Input (Constant) - Padding or Reserved bits + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x38, // Usage (Wheel) + 0x15, 0x81, // Logical Minimum (-127) + 0x25, 0x7F, // Logical Maximum (127) + 0x75, 0x08, // Report Size (8) + 0x95, 0x03, // Report Count (3) + 0x81, 0x06, // Input (Data, Variable, Relative) - X & Y coordinate + 0xC0, // End Collection + 0xC0, // End Collection + + 0x05, 0x01, // Usage Pg (Generic Desktop) + 0x09, 0x06, // Usage (Keyboard) + 0xA1, 0x01, // Collection: (Application) + 0x85, HID_RPT_ID_KEY_IN, // Report Id (2) + // + 0x05, 0x07, // Usage Pg (Key Codes) + 0x19, 0xE0, // Usage Min (224) + 0x29, 0xE7, // Usage Max (231) + 0x15, 0x00, // Log Min (0) + 0x25, 0x01, // Log Max (1) + // + // Modifier byte + 0x75, 0x01, // Report Size (1) + 0x95, 0x08, // Report Count (8) + 0x81, 0x02, // Input: (Data, Variable, Absolute) + // + // Reserved byte + 0x95, 0x01, // Report Count (1) + 0x75, 0x08, // Report Size (8) + 0x81, 0x01, // Input: (Constant) + // + // LED report + 0x95, 0x05, // Report Count (5) + 0x75, 0x01, // Report Size (1) + 0x05, 0x08, // Usage Pg (LEDs) + 0x19, 0x01, // Usage Min (1) + 0x29, 0x05, // Usage Max (5) + 0x91, 0x02, // Output: (Data, Variable, Absolute) + // + // LED report padding + 0x95, 0x01, // Report Count (1) + 0x75, 0x03, // Report Size (3) + 0x91, 0x01, // Output: (Constant) + // + // Key arrays (6 bytes) + 0x95, 0x06, // Report Count (6) + 0x75, 0x08, // Report Size (8) + 0x15, 0x00, // Log Min (0) + 0x25, 0x65, // Log Max (101) + 0x05, 0x07, // Usage Pg (Key Codes) + 0x19, 0x00, // Usage Min (0) + 0x29, 0x65, // Usage Max (101) + 0x81, 0x00, // Input: (Data, Array) + // + 0xC0, // End Collection + + #if EN_CONSUMER_MODE + + 0x05, 0x0C, // Usage Pg (Consumer Devices) + 0x09, 0x01, // Usage (Consumer Control) + 0xA1, 0x01, // Collection (Application) + 0x85, HID_RPT_ID_CC_IN, // Report Id (3) + 0x09, 0x02, // Usage (Numeric Key Pad) + 0xA1, 0x02, // Collection (Logical) + 0x05, 0x09, // Usage Pg (Button) + 0x19, 0x01, // Usage Min (Button 1) + 0x29, 0x0A, // Usage Max (Button 10) + 0x15, 0x01, // Logical Min (1) + 0x25, 0x0A, // Logical Max (10) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x81, 0x00, // Input (Data, Ary, Abs) + 0xC0, // End Collection + + 0x05, 0x0C, // Usage Pg (Consumer Devices) + 0x09, 0x86, // Usage (Channel) + 0x15, 0xFF, // Logical Min (-1) + 0x25, 0x01, // Logical Max (1) + 0x75, 0x02, // Report Size (2) + 0x95, 0x01, // Report Count (1) + 0x81, 0x46, // Input (Data, Var, Rel, Null) + 0x09, 0xE9, // Usage (Volume Up) + 0x09, 0xEA, // Usage (Volume Down) + 0x15, 0x00, // Logical Min (0) + 0x75, 0x01, // Report Size (1) + 0x95, 0x02, // Report Count (2) + 0x81, 0x02, // Input (Data, Var, Abs) + 0x09, 0xE2, // Usage (Mute) + 0x09, 0x30, // Usage (Power) + 0x09, 0x83, // Usage (Recall Last) + 0x09, 0x81, // Usage (Assign Selection) + 0x09, 0xB0, // Usage (Play) + 0x09, 0xB1, // Usage (Pause) + 0x09, 0xB2, // Usage (Record) + 0x09, 0xB3, // Usage (Fast Forward) + 0x09, 0xB4, // Usage (Rewind) + 0x09, 0xB5, // Usage (Scan Next) + 0x09, 0xB6, // Usage (Scan Prev) + 0x09, 0xB7, // Usage (Stop) + 0x15, 0x01, // Logical Min (1) + 0x25, 0x0C, // Logical Max (12) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x81, 0x00, // Input (Data, Ary, Abs) + 0x09, 0x80, // Usage (Selection) + 0xA1, 0x02, // Collection (Logical) + 0x05, 0x09, // Usage Pg (Button) + 0x19, 0x01, // Usage Min (Button 1) + 0x29, 0x03, // Usage Max (Button 3) + 0x15, 0x01, // Logical Min (1) + 0x25, 0x03, // Logical Max (3) + 0x75, 0x02, // Report Size (2) + 0x81, 0x00, // Input (Data, Ary, Abs) + 0xC0, // End Collection + 0x81, 0x03, // Input (Const, Var, Abs) + 0xC0, // End Collection + + + #endif + + #if EN_VOICE_MODE + //Voice collection + 0x05, 0x0C, // Usage Page (Consumer Devices) + 0x09, 0x01, // Usage (Consumer Control) + 0xA1, 0x01, // Collection (Application) + 0x85, HID_RPT_ID_VOICE_START_IN, // Report ID (10) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x75, 0x08, // Report Size (8) + 0x95, 0x05, // Report Count (5) + 0x09, 0x01, // Usage (Consumer Control) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x85, HID_RPT_ID_VOICE_DATA_IN, // Report ID (11) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x75, 0x08, // Report Size (8) + 0x95, 0x14, // Report Count (20) + 0x09, 0x01, // Usage (Consumer Control) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + + 0xC0 // END_COLLECTION + + #endif + +}; + +#endif + + +// HID report map length +uint16 hidReportMapLen = sizeof(hidReportMap); + +// HID report mapping table +hidRptMap_t hidRptMap[HID_NUM_REPORTS]; + +/********************************************************************* + Profile Attributes - variables +*/ + +#if FOLLOW_TI_MAP +// HID Service attribute +static CONST gattAttrType_t hidService = { ATT_BT_UUID_SIZE, hidServUUID }; + +// Include attribute (Battery service) +static uint16 include = GATT_INVALID_HANDLE; + +// HID Information characteristic +static uint8 hidInfoProps = GATT_PROP_READ; + +// HID Control Point characteristic +static uint8 hidControlPointProps = GATT_PROP_WRITE_NO_RSP; +static uint8 hidControlPoint; + +// HID Protocol Mode characteristic +static uint8 hidProtocolModeProps = GATT_PROP_READ | GATT_PROP_WRITE_NO_RSP; +uint8 hidProtocolMode = HID_PROTOCOL_MODE_REPORT; + +// HID Report Map characteristic +static uint8 hidReportMapProps = GATT_PROP_READ; + +// HID External Report Reference Descriptor +static uint8 hidExtReportRefDesc[ATT_BT_UUID_SIZE] = +{ LO_UINT16(BATT_LEVEL_UUID), HI_UINT16(BATT_LEVEL_UUID) }; + +// HID Report characteristic, key input +static uint8 hidReportKeyInProps = GATT_PROP_READ | GATT_PROP_NOTIFY; +static uint8 hidReportKeyIn; +static gattCharCfg_t hidReportKeyInClientCharCfg[GATT_MAX_NUM_CONN]; + +// HID Report Reference characteristic descriptor, key input +static uint8 hidReportRefKeyIn[HID_REPORT_REF_LEN] = +{ HID_RPT_ID_KEY_IN, HID_REPORT_TYPE_INPUT }; + +// HID Report characteristic, LED output +static uint8 hidReportLedOutProps = GATT_PROP_READ | + GATT_PROP_WRITE | + GATT_PROP_WRITE_NO_RSP; +static uint8 hidReportLedOut; + +// HID Report Reference characteristic descriptor, LED output +static uint8 hidReportRefLedOut[HID_REPORT_REF_LEN] = +{ HID_RPT_ID_LED_OUT, HID_REPORT_TYPE_OUTPUT }; + +// HID Boot Keyboard Input Report +static uint8 hidReportBootKeyInProps = GATT_PROP_READ | GATT_PROP_NOTIFY; +static uint8 hidReportBootKeyIn; +static gattCharCfg_t hidReportBootKeyInClientCharCfg[GATT_MAX_NUM_CONN]; + +// HID Boot Keyboard Output Report +static uint8 hidReportBootKeyOutProps = GATT_PROP_READ | + GATT_PROP_WRITE | + GATT_PROP_WRITE_NO_RSP; +static uint8 hidReportBootKeyOut; + +// HID Report characteristic, consumer control input +static uint8 hidReportCCInProps = GATT_PROP_READ | GATT_PROP_NOTIFY; +static uint8 hidReportCCIn; +static gattCharCfg_t hidReportCCInClientCharCfg[GATT_MAX_NUM_CONN]; + +// HID Report Reference characteristic descriptor, consumer control input +static uint8 hidReportRefCCIn[HID_REPORT_REF_LEN] = +{ HID_RPT_ID_CC_IN, HID_REPORT_TYPE_INPUT }; + +#if 0 +// HID Report characteristic, Voice Start +static uint8 hidReportVoiceStartProps = GATT_PROP_READ | GATT_PROP_NOTIFY; +static uint8 hidReportVoiceStart; +static gattCharCfg_t hidReportVoiceStartInClientCharCfg[GATT_MAX_NUM_CONN]; +static uint8 hidReportRefVoiceStart[HID_REPORT_REF_LEN] = +{ HID_RPT_ID_VOICE_START_IN, HID_REPORT_TYPE_INPUT }; + +// HID Report characteristic, Voice Data +static uint8 hidReportVoiceDataProps = GATT_PROP_READ | GATT_PROP_NOTIFY; +static uint8 hidReportVoiceData; +static gattCharCfg_t hidReportVoiceDataInClientCharCfg[GATT_MAX_NUM_CONN]; +static uint8 hidReportRefVoiceData[HID_REPORT_REF_LEN] = +{ HID_RPT_ID_VOICE_DATA_IN, HID_REPORT_TYPE_INPUT }; + +#endif + +#else + +// HID Service attribute +static CONST gattAttrType_t hidService = { ATT_BT_UUID_SIZE, hidServUUID }; + +// Include attribute (Battery service) +static uint16 include = GATT_INVALID_HANDLE; + +// HID Information characteristic +static uint8 hidInfoProps = GATT_PROP_READ; + +// HID Report Map characteristic +static uint8 hidReportMapProps = GATT_PROP_READ; + +// HID External Report Reference Descriptor +static uint8 hidExtReportRefDesc[ATT_BT_UUID_SIZE] = +{ LO_UINT16(BATT_LEVEL_UUID), HI_UINT16(BATT_LEVEL_UUID) }; + +// HID Control Point characteristic +static uint8 hidControlPointProps = GATT_PROP_WRITE_NO_RSP; +static uint8 hidControlPoint; + +// HID Protocol Mode characteristic +static uint8 hidProtocolModeProps = GATT_PROP_READ | GATT_PROP_WRITE_NO_RSP; +uint8 hidProtocolMode = HID_PROTOCOL_MODE_REPORT; + +// HID Report characteristic, key input +static uint8 hidReportKeyInProps = GATT_PROP_READ | GATT_PROP_NOTIFY; +static uint8 hidReportKeyIn; +static gattCharCfg_t hidReportKeyInClientCharCfg[GATT_MAX_NUM_CONN]; + +// HID Report Reference characteristic descriptor, key input +static uint8 hidReportRefKeyIn[HID_REPORT_REF_LEN] = +{ HID_RPT_ID_KEY_IN, HID_REPORT_TYPE_INPUT }; + +// HID Report characteristic, LED output +static uint8 hidReportLedOutProps = GATT_PROP_READ | GATT_PROP_WRITE | GATT_PROP_WRITE_NO_RSP; +static uint8 hidReportLedOut; + +// HID Report Reference characteristic descriptor, LED output +static uint8 hidReportRefLedOut[HID_REPORT_REF_LEN] = +{ HID_RPT_ID_LED_OUT, HID_REPORT_TYPE_OUTPUT }; + +// HID Boot Keyboard Input Report +static uint8 hidReportBootKeyInProps = GATT_PROP_READ | GATT_PROP_NOTIFY; +static uint8 hidReportBootKeyIn; +static gattCharCfg_t hidReportBootKeyInClientCharCfg[GATT_MAX_NUM_CONN]; + +// HID Boot Keyboard Output Report +static uint8 hidReportBootKeyOutProps = GATT_PROP_READ | GATT_PROP_WRITE | GATT_PROP_WRITE_NO_RSP; +static uint8 hidReportBootKeyOut; + +// HID Boot Mouse Input Report +static uint8 hidReportBootMouseInProps = GATT_PROP_READ | GATT_PROP_NOTIFY; +static uint8 hidReportBootMouseIn; +static gattCharCfg_t hidReportBootMouseInClientCharCfg[GATT_MAX_NUM_CONN]; + +// Feature Report +static uint8 hidReportFeatureProps = GATT_PROP_READ | GATT_PROP_WRITE; +static uint8 hidReportFeature; + +// HID Report Reference characteristic descriptor, Feature +static uint8 hidReportRefFeature[HID_REPORT_REF_LEN] = +{ HID_RPT_ID_FEATURE, HID_REPORT_TYPE_FEATURE }; + + +#if EN_VOICE_MODE + +// HID Report characteristic, Voice Start +static uint8 hidReportVoiceStartProps = GATT_PROP_READ | GATT_PROP_NOTIFY; +static uint8 hidReportVoiceStart; +static gattCharCfg_t* hidReportVoiceStartInClientCharCfg; +static uint8 hidReportRefVoiceStart[HID_REPORT_REF_LEN] = +{ HID_RPT_ID_VOICE_START_IN, HID_REPORT_TYPE_INPUT }; + +// HID Report characteristic, Voice Data +static uint8 hidReportVoiceDataProps = GATT_PROP_READ | GATT_PROP_NOTIFY; +static uint8 hidReportVoiceData; +static gattCharCfg_t* hidReportVoiceDataInClientCharCfg; +static uint8 hidReportRefVoiceData[HID_REPORT_REF_LEN] = +{ HID_RPT_ID_VOICE_DATA_IN, HID_REPORT_TYPE_INPUT }; + + +#endif + +#if EN_MOUSE_REPORT + +// HID Report Reference characteristic descriptor, mouse input +static uint8 hidReportRefMouseIn[HID_REPORT_REF_LEN] = +{ HID_RPT_ID_MOUSE_IN, HID_REPORT_TYPE_INPUT }; + +static uint8 hidReportMouseInProps = GATT_PROP_READ | GATT_PROP_NOTIFY; +static uint8 hidReportMouseIn; +static gattCharCfg_t hidReportMouseInClientCharCfg[GATT_MAX_NUM_CONN]; + +#endif + +#if EN_CONSUMER_MODE +// HID Report Reference characteristic descriptor, consumer control input +static uint8 hidReportRefCCIn[HID_REPORT_REF_LEN] = +{ HID_RPT_ID_CC_IN, HID_REPORT_TYPE_INPUT }; + +// HID Report characteristic, consumer control input +static uint8 hidReportCCInProps = GATT_PROP_READ | GATT_PROP_NOTIFY; +static uint8 hidReportCCIn; +static gattCharCfg_t hidReportCCInClientCharCfg[GATT_MAX_NUM_CONN]; + +#endif + +#endif + +/********************************************************************* + Profile Attributes - Table +*/ +#if FOLLOW_TI_MAP + +static gattAttribute_t hidAttrTbl[] = +{ + // HID Service + { + { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */ + GATT_PERMIT_READ, /* permissions */ + 0, /* handle */ + (uint8*)& hidService /* pValue */ + }, + + // Included service (battery) + { + { ATT_BT_UUID_SIZE, includeUUID }, + GATT_PERMIT_READ, + 0, + (uint8*)& include + }, + + // HID Information characteristic declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidInfoProps + }, + + // HID Information characteristic + { + { ATT_BT_UUID_SIZE, hidInfoUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + (uint8*) hidInfo + }, + + // HID Control Point characteristic declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidControlPointProps + }, + + // HID Control Point characteristic + { + { ATT_BT_UUID_SIZE, hidControlPointUUID }, + GATT_PERMIT_ENCRYPT_WRITE, + 0, + &hidControlPoint + }, + + // HID Protocol Mode characteristic declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidProtocolModeProps + }, + + // HID Protocol Mode characteristic + { + { ATT_BT_UUID_SIZE, hidProtocolModeUUID }, + GATT_PERMIT_ENCRYPT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + &hidProtocolMode + }, + + + // HID Report Map characteristic declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportMapProps + }, + + // HID Report Map characteristic + { + { ATT_BT_UUID_SIZE, hidReportMapUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + (uint8*) hidReportMap + }, + + // HID External Report Reference Descriptor + { + { ATT_BT_UUID_SIZE, extReportRefUUID }, + GATT_PERMIT_READ, + 0, + hidExtReportRefDesc + }, + + // HID Report characteristic declaration, key input + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportKeyInProps + }, + + // HID Report characteristic, key input + { + { ATT_BT_UUID_SIZE, hidReportUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + &hidReportKeyIn + }, + + // HID Report characteristic client characteristic configuration, key input + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + (uint8*)& hidReportKeyInClientCharCfg + }, + + // HID Report Reference characteristic descriptor, key input + { + { ATT_BT_UUID_SIZE, reportRefUUID }, + GATT_PERMIT_READ, + 0, + hidReportRefKeyIn + }, + + // HID Report characteristic, LED output declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportLedOutProps + }, + + // HID Report characteristic, LED output + { + { ATT_BT_UUID_SIZE, hidReportUUID }, + GATT_PERMIT_ENCRYPT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + &hidReportLedOut + }, + + // HID Report Reference characteristic descriptor, LED output + { + { ATT_BT_UUID_SIZE, reportRefUUID }, + GATT_PERMIT_READ, + 0, + hidReportRefLedOut + }, + + // HID Boot Keyboard Input Report declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportBootKeyInProps + }, + + // HID Boot Keyboard Input Report + { + { ATT_BT_UUID_SIZE, hidBootKeyInputUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + &hidReportBootKeyIn + }, + + // HID Boot Keyboard Input Report characteristic client characteristic configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + (uint8*)& hidReportBootKeyInClientCharCfg + }, + + // HID Boot Keyboard Output Report declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportBootKeyOutProps + }, + + // HID Boot Keyboard Output Report + { + { ATT_BT_UUID_SIZE, hidBootKeyOutputUUID }, + GATT_PERMIT_ENCRYPT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + &hidReportBootKeyOut + }, + + // HID Report characteristic declaration, consumer control + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportCCInProps + }, + + // HID Report characteristic, consumer control + { + { ATT_BT_UUID_SIZE, hidReportUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + &hidReportCCIn + }, + + // HID Report characteristic client characteristic configuration, consumer control + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + (uint8*)& hidReportCCInClientCharCfg + }, + + // HID Report Reference characteristic descriptor, consumer control + { + { ATT_BT_UUID_SIZE, reportRefUUID }, + GATT_PERMIT_READ, + 0, + hidReportRefCCIn + }, + + #if 0 + + // HID Voice Start Input Report declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportVoiceStartProps + }, + + // HID Voice Start Input Report + { + { ATT_BT_UUID_SIZE, hidReportUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + &hidReportVoiceStart + }, + + // HID Voice Start Input Report characteristic client characteristic configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + (uint8*)& hidReportVoiceStartInClientCharCfg + }, + + // HID Report Reference characteristic descriptor, Voice Start + { + { ATT_BT_UUID_SIZE, reportRefUUID }, + GATT_PERMIT_READ, + 0, + hidReportRefVoiceStart + }, + + // HID Voice Data Input Report declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportVoiceDataProps + }, + + // HID Voice Data Input Report + { + { ATT_BT_UUID_SIZE, hidReportUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + &hidReportVoiceData + }, + + // HID Voice Data Input Report characteristic client characteristic configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + (uint8*)& hidReportVoiceDataInClientCharCfg + }, + + // HID Report Reference characteristic descriptor, Voice Data + { + { ATT_BT_UUID_SIZE, reportRefUUID }, + GATT_PERMIT_READ, + 0, + hidReportRefVoiceData + }, + #endif +}; + + +#else +static gattAttribute_t hidAttrTbl[] = +{ + // HID Service + { + { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */ + GATT_PERMIT_READ, /* permissions */ + 0, /* handle */ + (uint8*)& hidService /* pValue */ + }, + + // Included service (battery) + { + { ATT_BT_UUID_SIZE, includeUUID }, + GATT_PERMIT_READ, + 0, + (uint8*)& include + }, + + // HID Information characteristic declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidInfoProps + }, + + // HID Information characteristic + { + { ATT_BT_UUID_SIZE, hidInfoUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + (uint8*) hidInfo + }, + + // HID Control Point characteristic declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidControlPointProps + }, + + // HID Control Point characteristic + { + { ATT_BT_UUID_SIZE, hidControlPointUUID }, + GATT_PERMIT_ENCRYPT_WRITE, + 0, + &hidControlPoint + }, + + // HID Protocol Mode characteristic declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidProtocolModeProps + }, + + // HID Protocol Mode characteristic + { + { ATT_BT_UUID_SIZE, hidProtocolModeUUID }, + GATT_PERMIT_ENCRYPT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + &hidProtocolMode + }, + + + // HID Report Map characteristic declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportMapProps + }, + + // HID Report Map characteristic + { + { ATT_BT_UUID_SIZE, hidReportMapUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + (uint8*) hidReportMap + }, + + // HID External Report Reference Descriptor + { + { ATT_BT_UUID_SIZE, extReportRefUUID }, + GATT_PERMIT_READ, + 0, + hidExtReportRefDesc + }, + #if EN_MOUSE_REPORT +// HID Report characteristic, mouse input declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportMouseInProps + }, + + // HID Report characteristic, mouse input + { + { ATT_BT_UUID_SIZE, hidReportUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + &hidReportMouseIn + }, + + // HID Report characteristic client characteristic configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + (uint8*)& hidReportMouseInClientCharCfg + }, + + // HID Report Reference characteristic descriptor, mouse input + { + { ATT_BT_UUID_SIZE, reportRefUUID }, + GATT_PERMIT_READ, + 0, + hidReportRefMouseIn + }, + + + #endif + + + // HID Report characteristic, key input declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportKeyInProps + }, + + // HID Report characteristic, key input + { + { ATT_BT_UUID_SIZE, hidReportUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + &hidReportKeyIn + }, + + // HID Report characteristic client characteristic configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + (uint8*)& hidReportKeyInClientCharCfg + }, + + // HID Report Reference characteristic descriptor, key input + { + { ATT_BT_UUID_SIZE, reportRefUUID }, + GATT_PERMIT_READ, + 0, + hidReportRefKeyIn + }, + + // HID Report characteristic, LED output declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportLedOutProps + }, + + // HID Report characteristic, LED output + { + { ATT_BT_UUID_SIZE, hidReportUUID }, + GATT_PERMIT_ENCRYPT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + &hidReportLedOut + }, + + // HID Report Reference characteristic descriptor, LED output + { + { ATT_BT_UUID_SIZE, reportRefUUID }, + GATT_PERMIT_READ, + 0, + hidReportRefLedOut + }, + + // HID Boot Keyboard Input Report declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportBootKeyInProps + }, + + // HID Boot Keyboard Input Report + { + { ATT_BT_UUID_SIZE, hidBootKeyInputUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + &hidReportBootKeyIn + }, + + // HID Boot Keyboard Input Report characteristic client characteristic configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + (uint8*)& hidReportBootKeyInClientCharCfg + }, + + // HID Boot Keyboard Output Report declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportBootKeyOutProps + }, + + // HID Boot Keyboard Output Report + { + { ATT_BT_UUID_SIZE, hidBootKeyOutputUUID }, + GATT_PERMIT_ENCRYPT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + &hidReportBootKeyOut + }, + + #if EN_CONSUMER_MODE + // HID Report characteristic declaration, consumer control + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportCCInProps + }, + + // HID Report characteristic, consumer control + { + { ATT_BT_UUID_SIZE, hidReportUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + &hidReportCCIn + }, + + // HID Report characteristic client characteristic configuration, consumer control + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + (uint8*)& hidReportCCInClientCharCfg + }, + + // HID Report Reference characteristic descriptor, consumer control + { + { ATT_BT_UUID_SIZE, reportRefUUID }, + GATT_PERMIT_READ, + 0, + hidReportRefCCIn + }, + + #endif + + // HID Boot Mouse Input Report declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportBootMouseInProps + }, + + // HID Boot Mouse Input Report + { + { ATT_BT_UUID_SIZE, hidBootMouseInputUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + &hidReportBootMouseIn + }, + + // HID Boot Mouse Input Report characteristic client characteristic configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + (uint8*)& hidReportBootMouseInClientCharCfg + }, + + // Feature Report declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportFeatureProps + }, + + // Feature Report + { + { ATT_BT_UUID_SIZE, hidReportUUID}, + GATT_PERMIT_ENCRYPT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + &hidReportFeature + }, + + // HID Report Reference characteristic descriptor, feature + { + { ATT_BT_UUID_SIZE, reportRefUUID }, + GATT_PERMIT_READ, + 0, + hidReportRefFeature + }, + #if EN_VOICE_MODE + // HID Voice Start Input Report declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportVoiceStartProps + }, + + // HID Voice Start Input Report + { + { ATT_BT_UUID_SIZE, hidReportUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + &hidReportVoiceStart + }, + + // HID Voice Start Input Report characteristic client characteristic configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + (uint8*)& hidReportVoiceStartInClientCharCfg + }, + + // HID Report Reference characteristic descriptor, Voice Start + { + { ATT_BT_UUID_SIZE, reportRefUUID }, + GATT_PERMIT_READ, + 0, + hidReportRefVoiceStart + }, + + // HID Voice Data Input Report declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &hidReportVoiceDataProps + }, + + // HID Voice Data Input Report + { + { ATT_BT_UUID_SIZE, hidReportUUID }, + GATT_PERMIT_ENCRYPT_READ, + 0, + &hidReportVoiceData + }, + + // HID Voice Data Input Report characteristic client characteristic configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + (uint8*)& hidReportVoiceDataInClientCharCfg + }, + + // HID Report Reference characteristic descriptor, Voice Data + { + { ATT_BT_UUID_SIZE, reportRefUUID }, + GATT_PERMIT_READ, + 0, + hidReportRefVoiceData + }, + #endif +}; +#endif + + + +/********************************************************************* + LOCAL FUNCTIONS +*/ + +/********************************************************************* + PROFILE CALLBACKS +*/ + +// Service Callbacks +CONST gattServiceCBs_t hidKbdCBs = +{ + HidDev_ReadAttrCB, // Read callback function pointer + HidDev_WriteAttrCB, // Write callback function pointer + NULL // Authorization callback function pointer +}; + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/********************************************************************* + @fn HidKbd_AddService + + @brief Initializes the HID Service by registering + GATT attributes with the GATT server. + + @return Success or Failure +*/ + +#if FOLLOW_TI_MAP +bStatus_t HidKbd_AddService( void ) +{ + uint8 status = SUCCESS; + // Initialize Client Characteristic Configuration attributes + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, hidReportKeyInClientCharCfg ); + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, hidReportBootKeyInClientCharCfg ); + GATTServApp_InitCharCfg(INVALID_CONNHANDLE, hidReportCCInClientCharCfg); + #if 0 + GATTServApp_InitCharCfg(INVALID_CONNHANDLE, hidReportVoiceStartInClientCharCfg); + GATTServApp_InitCharCfg(INVALID_CONNHANDLE, hidReportVoiceDataInClientCharCfg); + #endif + // Register GATT attribute list and CBs with GATT Server App + status = GATTServApp_RegisterService( hidAttrTbl, GATT_NUM_ATTRS( hidAttrTbl ), &hidKbdCBs ); + // Set up included service + Batt_GetParameter( BATT_PARAM_SERVICE_HANDLE, + &GATT_INCLUDED_HANDLE( hidAttrTbl, HID_INCLUDED_SERVICE_IDX ) ); + // Construct map of reports to characteristic handles + // Each report is uniquely identified via its ID and type + // Key input report + hidRptMap[0].id = hidReportRefKeyIn[0]; + hidRptMap[0].type = hidReportRefKeyIn[1]; + hidRptMap[0].handle = hidAttrTbl[HID_REPORT_KEY_IN_IDX].handle; + hidRptMap[0].cccdHandle = hidAttrTbl[HID_REPORT_KEY_IN_CCCD_IDX].handle; + hidRptMap[0].mode = HID_PROTOCOL_MODE_REPORT; + // LED output report + hidRptMap[1].id = hidReportRefLedOut[0]; + hidRptMap[1].type = hidReportRefLedOut[1]; + hidRptMap[1].handle = hidAttrTbl[HID_REPORT_LED_OUT_IDX].handle; + hidRptMap[1].cccdHandle = 0; + hidRptMap[1].mode = HID_PROTOCOL_MODE_REPORT; + // Boot keyboard input report + // Use same ID and type as key input report + hidRptMap[2].id = hidReportRefKeyIn[0]; + hidRptMap[2].type = hidReportRefKeyIn[1]; + hidRptMap[2].handle = hidAttrTbl[HID_BOOT_KEY_IN_IDX].handle; + hidRptMap[2].cccdHandle = hidAttrTbl[HID_BOOT_KEY_IN_CCCD_IDX].handle; + hidRptMap[2].mode = HID_PROTOCOL_MODE_BOOT; + // Boot keyboard output report + // Use same ID and type as LED output report + hidRptMap[3].id = hidReportRefLedOut[0]; + hidRptMap[3].type = hidReportRefLedOut[1]; + hidRptMap[3].handle = hidAttrTbl[HID_BOOT_KEY_OUT_IDX].handle; + hidRptMap[3].cccdHandle = 0; + hidRptMap[3].mode = HID_PROTOCOL_MODE_BOOT; + // Consumer Control input report + hidRptMap[4].id = hidReportRefCCIn[0]; + hidRptMap[4].type = hidReportRefCCIn[1]; + hidRptMap[4].handle = hidAttrTbl[HID_REPORT_CC_IN_IDX].handle; + hidRptMap[4].cccdHandle = hidAttrTbl[HID_REPORT_CC_IN_CCCD_IDX].handle; + hidRptMap[4].mode = HID_PROTOCOL_MODE_REPORT; + #if 0 + // Voice Start input report + hidRptMap[5].id = hidReportRefVoiceStart[0]; + hidRptMap[5].type = hidReportRefVoiceStart[1]; + hidRptMap[5].handle = hidAttrTbl[HID_VOICE_START_IN_IDX].handle; + hidRptMap[5].cccdHandle = hidAttrTbl[HID_VOICE_START_IN_CCCD_IDX].handle; + hidRptMap[5].mode = HID_PROTOCOL_MODE_REPORT; + // Voice Data input report + hidRptMap[6].id = hidReportRefVoiceData[0]; + hidRptMap[6].type = hidReportRefVoiceData[1]; + hidRptMap[6].handle = hidAttrTbl[HID_VOICE_DATA_IN_IDX].handle; + hidRptMap[6].cccdHandle = hidAttrTbl[HID_VOICE_DATA_IN_CCCD_IDX].handle; + hidRptMap[6].mode = HID_PROTOCOL_MODE_REPORT; + #endif + // Battery level input report + VOID Batt_GetParameter( BATT_PARAM_BATT_LEVEL_IN_REPORT, &(hidRptMap[2]) ); + // Setup report ID map + HidDev_RegisterReports( HID_NUM_REPORTS, hidRptMap ); + return ( status ); +} + +#else +bStatus_t HidKbd_AddService( void ) +{ + uint8 status = SUCCESS; + // Initialize Client Characteristic Configuration attributes + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, hidReportKeyInClientCharCfg ); + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, hidReportBootKeyInClientCharCfg ); + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, hidReportBootMouseInClientCharCfg ); + // Register GATT attribute list and CBs with GATT Server App + status = GATTServApp_RegisterService( hidAttrTbl, GATT_NUM_ATTRS( hidAttrTbl ), &hidKbdCBs ); + // Set up included service + Batt_GetParameter( BATT_PARAM_SERVICE_HANDLE, + &GATT_INCLUDED_HANDLE( hidAttrTbl, HID_INCLUDED_SERVICE_IDX ) ); + // Construct map of reports to characteristic handles + // Each report is uniquely identified via its ID and type + // Key input report + hidRptMap[0].id = hidReportRefKeyIn[0]; + hidRptMap[0].type = hidReportRefKeyIn[1]; + hidRptMap[0].handle = hidAttrTbl[HID_REPORT_KEY_IN_IDX].handle; + hidRptMap[0].cccdHandle = hidAttrTbl[HID_REPORT_KEY_IN_CCCD_IDX].handle; + hidRptMap[0].mode = HID_PROTOCOL_MODE_REPORT; + // LED output report + hidRptMap[1].id = hidReportRefLedOut[0]; + hidRptMap[1].type = hidReportRefLedOut[1]; + hidRptMap[1].handle = hidAttrTbl[HID_REPORT_LED_OUT_IDX].handle; + hidRptMap[1].cccdHandle = 0; + hidRptMap[1].mode = HID_PROTOCOL_MODE_REPORT; + // Boot keyboard input report + // Use same ID and type as key input report + hidRptMap[2].id = hidReportRefKeyIn[0]; + hidRptMap[2].type = hidReportRefKeyIn[1]; + hidRptMap[2].handle = hidAttrTbl[HID_BOOT_KEY_IN_IDX].handle; + hidRptMap[2].cccdHandle = hidAttrTbl[HID_BOOT_KEY_IN_CCCD_IDX].handle; + hidRptMap[2].mode = HID_PROTOCOL_MODE_BOOT; + // Boot keyboard output report + // Use same ID and type as LED output report + hidRptMap[3].id = hidReportRefLedOut[0]; + hidRptMap[3].type = hidReportRefLedOut[1]; + hidRptMap[3].handle = hidAttrTbl[HID_BOOT_KEY_OUT_IDX].handle; + hidRptMap[3].cccdHandle = 0; + hidRptMap[3].mode = HID_PROTOCOL_MODE_BOOT; + // Boot mouse input report + hidRptMap[4].id = HID_RPT_ID_MOUSE_IN; + hidRptMap[4].type = HID_REPORT_TYPE_INPUT; + hidRptMap[4].handle = hidAttrTbl[HID_BOOT_MOUSE_IN_IDX].handle; + hidRptMap[4].cccdHandle = hidAttrTbl[HID_BOOT_MOUSE_IN_CCCD_IDX].handle; + hidRptMap[4].mode = HID_PROTOCOL_MODE_BOOT; + // Feature report + hidRptMap[5].id = hidReportRefFeature[0]; + hidRptMap[5].type = hidReportRefFeature[1]; + hidRptMap[5].handle = hidAttrTbl[HID_FEATURE_IDX].handle; + hidRptMap[5].cccdHandle = 0; + hidRptMap[5].mode = HID_PROTOCOL_MODE_REPORT; + // Battery level input report + VOID Batt_GetParameter( BATT_PARAM_BATT_LEVEL_IN_REPORT, &(hidRptMap[6]) ); + #if EN_VOICE_MODE + // Voice Start input report + hidRptMap[7].id = hidReportRefVoiceStart[0]; + hidRptMap[7].type = hidReportRefVoiceStart[1]; + hidRptMap[7].handle = hidAttrTbl[HID_VOICE_START_IN_IDX].handle; + hidRptMap[7].cccdHandle = hidAttrTbl[HID_VOICE_START_IN_CCCD_IDX].handle; + hidRptMap[7].mode = HID_PROTOCOL_MODE_REPORT; + // Voice Data input report + hidRptMap[8].id = hidReportRefVoiceData[0]; + hidRptMap[8].type = hidReportRefVoiceData[1]; + hidRptMap[8].handle = hidAttrTbl[HID_VOICE_DATA_IN_IDX].handle; + hidRptMap[8].cccdHandle = hidAttrTbl[HID_VOICE_DATA_IN_CCCD_IDX].handle; + hidRptMap[8].mode = HID_PROTOCOL_MODE_REPORT; + #endif + #if EN_MOUSE_REPORT + // Mouse input report + hidRptMap[9].id = hidReportRefMouseIn[0]; + hidRptMap[9].type = hidReportRefMouseIn[1]; + hidRptMap[9].handle = hidAttrTbl[HID_REPORT_MOUSE_IN_IDX].handle; + hidRptMap[9].cccdHandle = hidAttrTbl[HID_REPORT_MOUSE_IN_CCCD_IDX].handle; + hidRptMap[9].mode = HID_PROTOCOL_MODE_REPORT; + #endif + #if EN_CONSUMER_MODE + // Consumer Control input report + hidRptMap[10].id = hidReportRefCCIn[0]; + hidRptMap[10].type = hidReportRefCCIn[1]; + hidRptMap[10].handle = hidAttrTbl[HID_REPORT_CC_IN_IDX].handle; + hidRptMap[10].cccdHandle = hidAttrTbl[HID_REPORT_CC_IN_CCCD_IDX].handle; + hidRptMap[10].mode = HID_PROTOCOL_MODE_REPORT; + #endif + // Setup report ID map + HidDev_RegisterReports( HID_NUM_REPORTS, hidRptMap ); + return ( status ); +} + +#endif + +/********************************************************************* + @fn HidKbd_SetParameter + + @brief Set a HID Kbd parameter. + + @param id - HID report ID. + @param type - HID report type. + @param uuid - attribute uuid. + @param len - length of data to right. + @param pValue - pointer to data to write. This is dependent on + the input parameters and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return GATT status code. +*/ +uint8 HidKbd_SetParameter( uint8 id, uint8 type, uint16 uuid, uint16 len, void* pValue ) +{ + bStatus_t ret = SUCCESS; + + switch ( uuid ) + { + case REPORT_UUID: + if ( type == HID_REPORT_TYPE_OUTPUT ) + { + if ( len == 1 ) + { + hidReportLedOut = *((uint8*)pValue); + } + else + { + ret = ATT_ERR_INVALID_VALUE_SIZE; + } + } + else if ( type == HID_REPORT_TYPE_FEATURE ) + { + if ( len == 1 ) + { + // hidReportFeature = *((uint8 *)pValue); + } + else + { + ret = ATT_ERR_INVALID_VALUE_SIZE; + } + } + else + { + ret = ATT_ERR_ATTR_NOT_FOUND; + } + + break; + + case BOOT_KEY_OUTPUT_UUID: + if ( len == 1 ) + { + hidReportBootKeyOut = *((uint8*)pValue); + } + else + { + ret = ATT_ERR_INVALID_VALUE_SIZE; + } + + break; + + default: + // ignore the request + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn HidKbd_GetParameter + + @brief Get a HID Kbd parameter. + + @param id - HID report ID. + @param type - HID report type. + @param uuid - attribute uuid. + @param pLen - length of data to be read + @param pValue - pointer to data to get. This is dependent on + the input parameters and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return GATT status code. +*/ +uint8 HidKbd_GetParameter( uint8 id, uint8 type, uint16 uuid, uint16* pLen, void* pValue ) +{ + switch ( uuid ) + { + case REPORT_UUID: + if ( type == HID_REPORT_TYPE_OUTPUT ) + { + *((uint8*)pValue) = hidReportLedOut; + *pLen = 1; + } + else if ( type == HID_REPORT_TYPE_FEATURE ) + { + // *((uint8 *)pValue) = hidReportFeature; + // *pLen = 1; + } + else + { + *pLen = 0; + } + + break; + + case BOOT_KEY_OUTPUT_UUID: + *((uint8*)pValue) = hidReportBootKeyOut; + *pLen = 1; + break; + + default: + *pLen = 0; + break; + } + + return ( SUCCESS ); +} + +/********************************************************************* +*********************************************************************/ diff --git a/src/components/profiles/HIDVoice/hidkbdservice.h b/src/components/profiles/HIDVoice/hidkbdservice.h new file mode 100644 index 0000000..cd5d70f --- /dev/null +++ b/src/components/profiles/HIDVoice/hidkbdservice.h @@ -0,0 +1,274 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + + +#ifndef HIDKBDSERVICE_H +#define HIDKBDSERVICE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + CONSTANTS +*/ + +#define FOLLOW_TI_MAP 1 + + +#if FOLLOW_TI_MAP +// Number of HID reports defined in the service +#define HID_NUM_REPORTS 5//7 + +// HID Report IDs for the service +#define HID_RPT_ID_LED_OUT 0 // LED output report ID +#define HID_RPT_ID_KEY_IN 1 // Keyboard input report ID +#define HID_RPT_ID_CC_IN 2 // Consumer Control input report ID +#define HID_RPT_ID_VOICE_START_IN 10 // Voice Start input report ID +#define HID_RPT_ID_VOICE_DATA_IN 11 // Voice Data input report ID + +//voice defines +#define BLE_VOICE_CMD_STOP 0x00 +#define BLE_VOICE_CMD_START 0x04 +#define HID_VOICE_IN_START_LEN 5 + + +#define HID_RPT_ID_MOUSE_IN 0xFF + + + + +enum +{ + HID_SERVICE_IDX, // HID Service + HID_INCLUDED_SERVICE_IDX, // Included Service (battery) + HID_INFO_DECL_IDX, // HID Information characteristic declaration + HID_INFO_IDX, // HID Information characteristic + HID_CONTROL_POINT_DECL_IDX, // HID Control Point characteristic declaration + HID_CONTROL_POINT_IDX, // HID Control Point characteristic + HID_PROTOCOL_MODE_DECL_IDX, // HID Protocol Mode characteristic declaration + HID_PROTOCOL_MODE_IDX, // HID Protocol Mode characteristic + HID_REPORT_MAP_DECL_IDX, // HID Report Map characteristic declaration + HID_REPORT_MAP_IDX, // HID Report Map characteristic + HID_EXT_REPORT_REF_DESC_IDX, // HID External Report Reference Descriptor + HID_REPORT_KEY_IN_DECL_IDX, // HID Report characteristic declaration, key input + HID_REPORT_KEY_IN_IDX, // HID Report characteristic, key input + HID_REPORT_KEY_IN_CCCD_IDX, // HID Report characteristic client characteristic configuration, key input + HID_REPORT_REF_KEY_IN_IDX, // HID Report Reference characteristic descriptor, key input + HID_REPORT_LED_OUT_DECL_IDX, // HID Report characteristic, LED output declaration + HID_REPORT_LED_OUT_IDX, // HID Report characteristic, LED output + HID_REPORT_REF_LED_OUT_IDX, // HID Report Reference characteristic descriptor, LED output + HID_BOOT_KEY_IN_DECL_IDX, // HID Boot Keyboard Input Report declaration + HID_BOOT_KEY_IN_IDX, // HID Boot Keyboard Input Report + HID_BOOT_KEY_IN_CCCD_IDX, // HID Boot Keyboard Input Report characteristic client characteristic configuration + HID_BOOT_KEY_OUT_DECL_IDX, // HID Boot Keyboard Output Report declaration + HID_BOOT_KEY_OUT_IDX, // HID Boot Keyboard Output Report + HID_REPORT_CC_IN_DECL_IDX, // HID Report characteristic declaration, consumer control + HID_REPORT_CC_IN_IDX, // HID Report characteristic, consumer control + HID_REPORT_CC_IN_CCCD_IDX, // HID Report characteristic client characteristic configuration, consumer control + HID_REPORT_REF_CC_IN_IDX, // HID Report Reference characteristic descriptor, consumer control + HID_VOICE_START_IN_DECL_IDX, // HID Voice Start Input Report declaration + HID_VOICE_START_IN_IDX, // HID Voice Start Input Report + HID_VOICE_START_IN_CCCD_IDX, // HID Voice Start Input Report characteristic client characteristic configuration + HID_REPORT_REF_VOICE_START_IDX, // HID Report Reference characteristic descriptor, Voice Start + HID_VOICE_DATA_IN_DECL_IDX, // HID Voice Start Input Report declaration + HID_VOICE_DATA_IN_IDX, // HID Voice Start Input Report + HID_VOICE_DATA_IN_CCCD_IDX, // HID Voice Start Input Report characteristic client characteristic configuration + HID_REPORT_REF_VOICE_DATA_IDX, // HID Report Reference characteristic descriptor, Voice Start +}; + +#else + + +// HID Report IDs for the service + + +#define HID_RPT_ID_MOUSE_IN 1 // Mouse input report ID +#define HID_RPT_ID_KEY_IN 2 // Keyboard input report ID +#define HID_RPT_ID_CC_IN 3 + + + +#define HID_RPT_ID_LED_OUT 0 // LED output report ID +#define HID_RPT_ID_FEATURE 0 // Feature report ID + + +#define EN_VOICE_MODE 1 + +#define EN_CONSUMER_MODE 1 + +#define EN_MOUSE_REPORT 1 + + +#if EN_VOICE_MODE + +#define HID_RPT_ID_VOICE_START_IN 10 // Voice Start input report ID +#define HID_RPT_ID_VOICE_DATA_IN 11 // Voice Data input report ID + +// Number of HID reports defined in the service +#define HID_NUM_REPORTS 11 + +//voice defines +#define BLE_VOICE_CMD_STOP 0x00 +#define BLE_VOICE_CMD_START 0x04 + + + + +#else +// Number of HID reports defined in the service +#define HID_NUM_REPORTS 7 + + +#endif + +// Attribute index enumeration-- these indexes match array elements above +enum +{ + HID_SERVICE_IDX, // HID Service + HID_INCLUDED_SERVICE_IDX, // Included Service + HID_INFO_DECL_IDX, // HID Information characteristic declaration + HID_INFO_IDX, // HID Information characteristic + HID_CONTROL_POINT_DECL_IDX, // HID Control Point characteristic declaration + HID_CONTROL_POINT_IDX, // HID Control Point characteristic + HID_PROTOCOL_MODE_DECL_IDX, // HID Protocol Mode characteristic declaration + HID_PROTOCOL_MODE_IDX, // HID Protocol Mode characteristic + HID_REPORT_MAP_DECL_IDX, // HID Report Map characteristic declaration + HID_REPORT_MAP_IDX, // HID Report Map characteristic + HID_EXT_REPORT_REF_DESC_IDX, // HID External Report Reference Descriptor + + #if EN_MOUSE_REPORT + HID_REPORT_MOUSE_IN_DECL_IDX, // HID Report characteristic, mouse input declaration + HID_REPORT_MOUSE_IN_IDX, // HID Report characteristic, mouse input + HID_REPORT_MOUSE_IN_CCCD_IDX, // HID Report characteristic client characteristic configuration + HID_REPORT_REF_MOUSE_IN_IDX, // HID Report Reference characteristic descriptor, mouse input + + #endif + + HID_REPORT_KEY_IN_DECL_IDX, // HID Report characteristic, key input declaration + HID_REPORT_KEY_IN_IDX, // HID Report characteristic, key input + HID_REPORT_KEY_IN_CCCD_IDX, // HID Report characteristic client characteristic configuration + HID_REPORT_REF_KEY_IN_IDX, // HID Report Reference characteristic descriptor, key input + HID_REPORT_LED_OUT_DECL_IDX, // HID Report characteristic, LED output declaration + HID_REPORT_LED_OUT_IDX, // HID Report characteristic, LED output + HID_REPORT_REF_LED_OUT_IDX, // HID Report Reference characteristic descriptor, LED output + HID_BOOT_KEY_IN_DECL_IDX, // HID Boot Keyboard Input Report declaration + HID_BOOT_KEY_IN_IDX, // HID Boot Keyboard Input Report + HID_BOOT_KEY_IN_CCCD_IDX, // HID Boot Keyboard Input Report characteristic client characteristic configuration + HID_BOOT_KEY_OUT_DECL_IDX, // HID Boot Keyboard Output Report declaration + HID_BOOT_KEY_OUT_IDX, // HID Boot Keyboard Output Report + + #if EN_CONSUMER_MODE + HID_REPORT_CC_IN_DECL_IDX, // HID Report characteristic declaration, consumer control + HID_REPORT_CC_IN_IDX, // HID Report characteristic, consumer control + HID_REPORT_CC_IN_CCCD_IDX, // HID Report characteristic client characteristic configuration, consumer control + HID_REPORT_REF_CC_IN_IDX, // HID Report Reference characteristic descriptor, consumer control + #endif + HID_BOOT_MOUSE_IN_DECL_IDX, // HID Boot Mouse Input Report declaration + HID_BOOT_MOUSE_IN_IDX, // HID Boot Mouse Input Report + HID_BOOT_MOUSE_IN_CCCD_IDX, // HID Boot Mouse Input Report characteristic client characteristic configuration + HID_FEATURE_DECL_IDX, // Feature Report declaration + HID_FEATURE_IDX, // Feature Report + HID_REPORT_REF_FEATURE_IDX // HID Report Reference characteristic descriptor, feature + #if EN_VOICE_MODE + , + HID_VOICE_START_IN_DECL_IDX, // HID Voice Start Input Report declaration + HID_VOICE_START_IN_IDX, // HID Voice Start Input Report + HID_VOICE_START_IN_CCCD_IDX, // HID Voice Start Input Report characteristic client characteristic configuration + HID_REPORT_REF_VOICE_START_IDX, // HID Report Reference characteristic descriptor, Voice Start + HID_VOICE_DATA_IN_DECL_IDX, // HID Voice Start Input Report declaration + HID_VOICE_DATA_IN_IDX, // HID Voice Start Input Report + HID_VOICE_DATA_IN_CCCD_IDX, // HID Voice Start Input Report characteristic client characteristic configuration + HID_REPORT_REF_VOICE_DATA_IDX, // HID Report Reference characteristic descriptor, Voice Start + + #endif +}; + +#endif + + + +// HID feature flags +#define HID_KBD_FLAGS HID_FLAGS_REMOTE_WAKE + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + Profile Callbacks +*/ + + +/********************************************************************* + API FUNCTIONS +*/ + +/********************************************************************* + @fn HidKbd_AddService + + @brief Initializes the HID service for keyboard by registering + GATT attributes with the GATT server. + + @param none + + @return Success or Failure +*/ +extern bStatus_t HidKbd_AddService(void); + +/********************************************************************* + @fn HidKbd_SetParameter + + @brief Set a HID Kbd parameter. + + @param id - HID report ID. + @param type - HID report type. + @param uuid - attribute uuid. + @param len - length of data to right. + @param pValue - pointer to data to write. This is dependent on + the input parameters and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return GATT status code. +*/ +extern uint8 HidKbd_SetParameter( uint8 id, uint8 type, uint16 uuid, uint16 len, void* pValue ); + +/********************************************************************* + @fn HidKbd_GetParameter + + @brief Get a HID Kbd parameter. + + @param id - HID report ID. + @param type - HID report type. + @param uuid - attribute uuid. + @param pLen - length of data to be read. + @param pValue - pointer to data to get. This is dependent on + the input parameters and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return GATT status code. +*/ +extern uint8 HidKbd_GetParameter( uint8 id, uint8 type, uint16 uuid, uint16* pLen, void* pValue ); + + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* HIDKBDSERVICE_H */ diff --git a/src/components/profiles/Keys/simplekeys.c b/src/components/profiles/Keys/simplekeys.c new file mode 100644 index 0000000..ae0ccf3 --- /dev/null +++ b/src/components/profiles/Keys/simplekeys.c @@ -0,0 +1,400 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: simplekey.c + Revised: + Revision: + + Description: Simple Keys Profile + + + +**************************************************************************************************/ + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "linkdb.h" +#include "att.h" +#include "gatt.h" +#include "gatt_uuid.h" +#include "gattservapp.h" +#include "gapbondmgr.h" + +#include "simplekeys.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +#define SERVAPP_NUM_ATTR_SUPPORTED 5 + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ +// SK Service UUID: 0x1800 +CONST uint8 skServUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(SK_SERV_UUID), HI_UINT16(SK_SERV_UUID) +}; + +// Key Pressed UUID: 0x1801 +CONST uint8 keyPressedUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(SK_KEYPRESSED_UUID), HI_UINT16(SK_KEYPRESSED_UUID) +}; + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +/********************************************************************* + Profile Attributes - variables +*/ + +// SK Service attribute +static CONST gattAttrType_t skService = { ATT_BT_UUID_SIZE, skServUUID }; + +// Keys Pressed Characteristic Properties +static uint8 skCharProps = GATT_PROP_NOTIFY; + +// Key Pressed State Characteristic +static uint8 skKeyPressed = 0; + +// Key Pressed Characteristic Configs +static gattCharCfg_t skConfig[GATT_MAX_NUM_CONN]; + +// Key Pressed Characteristic User Description +static uint8 skCharUserDesp[16] = "Key Press State\0"; + + +/********************************************************************* + Profile Attributes - Table +*/ + +static gattAttribute_t simplekeysAttrTbl[SERVAPP_NUM_ATTR_SUPPORTED] = +{ + // Simple Keys Service + { + { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */ + GATT_PERMIT_READ, /* permissions */ + 0, /* handle */ + (uint8*)& skService /* pValue */ + }, + + // Characteristic Declaration for Keys + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &skCharProps + }, + + // Characteristic Value- Key Pressed + { + { ATT_BT_UUID_SIZE, keyPressedUUID }, + 0, + 0, + &skKeyPressed + }, + + // Characteristic configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8*)skConfig + }, + + // Characteristic User Description + { + { ATT_BT_UUID_SIZE, charUserDescUUID }, + GATT_PERMIT_READ, + 0, + skCharUserDesp + }, +}; + + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static uint8 sk_ReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ); +static bStatus_t sk_WriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ); + +static void sk_HandleConnStatusCB( uint16 connHandle, uint8 changeType ); + +/********************************************************************* + PROFILE CALLBACKS +*/ +// SK Service Callbacks +CONST gattServiceCBs_t skCBs = +{ + sk_ReadAttrCB, // Read callback function pointer + sk_WriteAttrCB, // Write callback function pointer + NULL // Authorization callback function pointer +}; + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/********************************************************************* + @fn SK_AddService + + @brief Initializes the Simple Key service by registering + GATT attributes with the GATT server. + + @param services - services to add. This is a bit map and can + contain more than one service. + + @return Success or Failure +*/ +bStatus_t SK_AddService( uint32 services ) +{ + uint8 status = SUCCESS; + // Initialize Client Characteristic Configuration attributes + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, skConfig ); + // Register with Link DB to receive link status change callback + VOID linkDB_Register( sk_HandleConnStatusCB ); + + if ( services & SK_SERVICE ) + { + // Register GATT attribute list and CBs with GATT Server App + status = GATTServApp_RegisterService( simplekeysAttrTbl, + GATT_NUM_ATTRS( simplekeysAttrTbl ), + &skCBs ); + } + + return ( status ); +} + +/********************************************************************* + @fn SK_SetParameter + + @brief Set a Simple Key Profile parameter. + + @param param - Profile parameter ID + @param len - length of data to right + @param pValue - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t SK_SetParameter( uint8 param, uint8 len, void* pValue ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case SK_KEY_ATTR: + if ( len == sizeof ( uint8 ) ) + { + skKeyPressed = *((uint8*)pValue); + // See if Notification/Indication has been enabled + GATTServApp_ProcessCharCfg( skConfig, &skKeyPressed, FALSE, + simplekeysAttrTbl, GATT_NUM_ATTRS( simplekeysAttrTbl ), + INVALID_TASK_ID ); + } + else + { + ret = bleInvalidRange; + } + + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn SK_GetParameter + + @brief Get a Simple Key Profile parameter. + + @param param - Profile parameter ID + @param pValue - pointer to data to put. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t SK_GetParameter( uint8 param, void* pValue ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case SK_KEY_ATTR: + *((uint8*)pValue) = skKeyPressed; + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn sk_ReadAttrCB + + @brief Read an attribute. + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be read + @param pLen - length of data to be read + @param offset - offset of the first octet to be read + @param maxLen - maximum length of data to be read + + @return Success or Failure +*/ +static uint8 sk_ReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ) +{ + bStatus_t status = SUCCESS; + + // Make sure it's not a blob operation (no attributes in the profile are long + if ( offset > 0 ) + { + return ( ATT_ERR_ATTR_NOT_LONG ); + } + + if ( pAttr->type.len == ATT_BT_UUID_SIZE ) + { + // 16-bit UUID + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + switch ( uuid ) + { + // No need for "GATT_SERVICE_UUID" or "GATT_CLIENT_CHAR_CFG_UUID" cases; + // gattserverapp handles this type for reads + + // simple keys characteristic does not have read permissions, but because it + // can be sent as a notification, it must be included here + case SK_KEYPRESSED_UUID: + *pLen = 1; + pValue[0] = *pAttr->pValue; + break; + + default: + // Should never get here! + *pLen = 0; + status = ATT_ERR_ATTR_NOT_FOUND; + break; + } + } + else + { + // 128-bit UUID + *pLen = 0; + status = ATT_ERR_INVALID_HANDLE; + } + + return ( status ); +} + +/********************************************************************* + @fn sk_WriteAttrCB + + @brief Validate attribute data prior to a write operation + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be written + @param len - length of data + @param offset - offset of the first octet to be written + + @return Success or Failure +*/ +static bStatus_t sk_WriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ) +{ + bStatus_t status = SUCCESS; + + if ( pAttr->type.len == ATT_BT_UUID_SIZE ) + { + // 16-bit UUID + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + switch ( uuid ) + { + case GATT_CLIENT_CHAR_CFG_UUID: + status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len, + offset, GATT_CLIENT_CFG_NOTIFY ); + break; + + default: + // Should never get here! + status = ATT_ERR_ATTR_NOT_FOUND; + break; + } + } + else + { + // 128-bit UUID + status = ATT_ERR_INVALID_HANDLE; + } + + return ( status ); +} + +/********************************************************************* + @fn sk_HandleConnStatusCB + + @brief Simple Keys Profile link status change handler function. + + @param connHandle - connection handle + @param changeType - type of change + + @return none +*/ +static void sk_HandleConnStatusCB( uint16 connHandle, uint8 changeType ) +{ + // Make sure this is not loopback connection + if ( connHandle != LOOPBACK_CONNHANDLE ) + { + // Reset Client Char Config if connection has dropped + if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) || + ( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && + ( !linkDB_Up( connHandle ) ) ) ) + { + GATTServApp_InitCharCfg( connHandle, skConfig ); + } + } +} + + +/********************************************************************* +*********************************************************************/ diff --git a/src/components/profiles/Keys/simplekeys.h b/src/components/profiles/Keys/simplekeys.h new file mode 100644 index 0000000..d899e07 --- /dev/null +++ b/src/components/profiles/Keys/simplekeys.h @@ -0,0 +1,108 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: simplekeys.h + Revised: + Revision: + + Description: This file contains the Simple Keys Profile header file. + + + +**************************************************************************************************/ + +#ifndef SIMPLEKEYS_H +#define SIMPLEKEYS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + CONSTANTS +*/ + +// Profile Parameters +#define SK_KEY_ATTR 0 // RW uint8 - Profile Attribute value + +// SK Service UUID +#define SK_SERV_UUID 0xFFE0 + +// Key Pressed UUID +#define SK_KEYPRESSED_UUID 0xFFE1 + +// Key Values +#define SK_KEY_LEFT 0x01 +#define SK_KEY_RIGHT 0x02 + +// Simple Keys Profile Services bit fields +#define SK_SERVICE 0x00000001 + +/********************************************************************* + TYPEDEFS +*/ + + + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + Profile Callbacks +*/ + + +/********************************************************************* + API FUNCTIONS +*/ + +/* + SK_AddService- Initializes the Simple Key service by registering + GATT attributes with the GATT server. + + @param services - services to add. This is a bit map and can + contain more than one service. +*/ + +extern bStatus_t SK_AddService( uint32 services ); + +/* + SK_SetParameter - Set a Simple Key Profile parameter. + + param - Profile parameter ID + len - length of data to right + pValue - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). +*/ +extern bStatus_t SK_SetParameter( uint8 param, uint8 len, void* pValue ); + +/* + SK_GetParameter - Get a Simple Key Profile parameter. + + param - Profile parameter ID + pValue - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). +*/ +extern bStatus_t SK_GetParameter( uint8 param, void* pValue ); + + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* SIMPLEKEYS_H */ diff --git a/src/components/profiles/Roles/broadcaster.c b/src/components/profiles/Roles/broadcaster.c new file mode 100644 index 0000000..0c73b46 --- /dev/null +++ b/src/components/profiles/Roles/broadcaster.c @@ -0,0 +1,610 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "hci_tl.h" + +#include "gap.h" + +#include "broadcaster.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ +// Profile Events +#define START_ADVERTISING_EVT 0x0001 + +#define DEFAULT_ADVERT_OFF_TIME 30000 // 30 seconds + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ +static uint8 gapRole_TaskID; // Task ID for internal task/event processing + +static gaprole_States_t gapRole_state; + +/********************************************************************* + Profile Parameters - reference GAPROLE_PROFILE_PARAMETERS for + descriptions +*/ + +static uint8 gapRole_profileRole; +static uint8 gapRole_bdAddr[B_ADDR_LEN]; +static uint8 gapRole_AdvEnabled = TRUE; +static uint16 gapRole_AdvertOffTime = DEFAULT_ADVERT_OFF_TIME; +static uint8 gapRole_AdvertDataLen = 3; +static uint8 gapRole_AdvertData[B_MAX_ADV_LEN] = +{ + 0x02, // length of this data + GAP_ADTYPE_FLAGS, // AD Type = Flags + // BR/EDR not supported + GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +}; +static uint8 gapRole_ScanRspDataLen = 0; +static uint8 gapRole_ScanRspData[B_MAX_ADV_LEN] = {0}; +static uint8 gapRole_AdvEventType; +static uint8 gapRole_AdvDirectType; +static uint8 gapRole_AdvDirectAddr[B_ADDR_LEN] = {0}; +static uint8 gapRole_AdvChanMap; +static uint8 gapRole_AdvFilterPolicy; + +// Application callbacks +static gapRolesCBs_t* pGapRoles_AppCGs = NULL; + +/********************************************************************* + Profile Attributes - variables +*/ + +/********************************************************************* + Profile Attributes - Table +*/ + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static void gapRole_ProcessOSALMsg( osal_event_hdr_t* pMsg ); +static void gapRole_ProcessGAPMsg( gapEventHdr_t* pMsg ); +static void gapRole_SetupGAP( void ); + +/********************************************************************* + NETWORK LAYER CALLBACKS +*/ + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/********************************************************************* + @brief Set a GAP Role parameter. + + Public function defined in broadcaster.h. +*/ +bStatus_t GAPRole_SetParameter( uint16 param, uint8 len, void* pValue ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case GAPROLE_ADVERT_ENABLED: + if ( len == sizeof( uint8 ) ) + { + uint8 oldAdvEnabled = gapRole_AdvEnabled; + gapRole_AdvEnabled = *((uint8*)pValue); + + if ( (oldAdvEnabled) && (gapRole_AdvEnabled == FALSE) ) + { + // Turn off Advertising + if ( gapRole_state == GAPROLE_ADVERTISING ) + { + VOID GAP_EndDiscoverable( gapRole_TaskID ); + } + } + else if ( (oldAdvEnabled == FALSE) && (gapRole_AdvEnabled) ) + { + // Turn on Advertising + if ( (gapRole_state == GAPROLE_STARTED) + || (gapRole_state == GAPROLE_WAITING) ) + { + VOID osal_set_event( gapRole_TaskID, START_ADVERTISING_EVT ); + } + } + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADVERT_OFF_TIME: + if ( len == sizeof ( uint16 ) ) + { + gapRole_AdvertOffTime = *((uint16*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADVERT_DATA: + if ( len <= B_MAX_ADV_LEN ) + { + VOID osal_memset( gapRole_AdvertData, 0, B_MAX_ADV_LEN ); + VOID osal_memcpy( gapRole_AdvertData, pValue, len ); + gapRole_AdvertDataLen = len; + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_SCAN_RSP_DATA: + if ( len <= B_MAX_ADV_LEN ) + { + VOID osal_memset( gapRole_ScanRspData, 0, B_MAX_ADV_LEN ); + VOID osal_memcpy( gapRole_ScanRspData, pValue, len ); + gapRole_ScanRspDataLen = len; + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADV_EVENT_TYPE: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= GAP_ADTYPE_ADV_LDC_DIRECT_IND) ) + { + gapRole_AdvEventType = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADV_DIRECT_TYPE: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= ADDRTYPE_PRIVATE_RESOLVE) ) + { + gapRole_AdvDirectType = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADV_DIRECT_ADDR: + if ( len == B_ADDR_LEN ) + { + VOID osal_memcpy( gapRole_AdvDirectAddr, pValue, B_ADDR_LEN ) ; + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADV_CHANNEL_MAP: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= 0x07) ) + { + gapRole_AdvChanMap = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADV_FILTER_POLICY: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= GAP_FILTER_POLICY_WHITE) ) + { + gapRole_AdvFilterPolicy = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + default: + + // The param value isn't part of this profile, try the GAP. + if ( (param < TGAP_PARAMID_MAX) && (len == sizeof ( uint16 )) ) + { + ret = GAP_SetParamValue( param, *((uint16*)pValue) ); + } + else + { + ret = INVALIDPARAMETER; + } + + break; + } + + return ( ret ); +} + +/********************************************************************* + @brief Get a GAP Role parameter. + + Public function defined in broadcaster.h. +*/ +bStatus_t GAPRole_GetParameter( uint16 param, void* pValue ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case GAPROLE_PROFILEROLE: + *((uint8*)pValue) = gapRole_profileRole; + break; + + case GAPROLE_BD_ADDR: + VOID osal_memcpy( pValue, gapRole_bdAddr, B_ADDR_LEN ) ; + break; + + case GAPROLE_ADVERT_ENABLED: + *((uint8*)pValue) = gapRole_AdvEnabled; + break; + + case GAPROLE_ADVERT_OFF_TIME: + *((uint16*)pValue) = gapRole_AdvertOffTime; + break; + + case GAPROLE_ADVERT_DATA: + VOID osal_memcpy( pValue, gapRole_AdvertData, gapRole_AdvertDataLen ); + break; + + case GAPROLE_SCAN_RSP_DATA: + VOID osal_memcpy( pValue, gapRole_ScanRspData, gapRole_ScanRspDataLen ) ; + break; + + case GAPROLE_ADV_EVENT_TYPE: + *((uint8*)pValue) = gapRole_AdvEventType; + break; + + case GAPROLE_ADV_DIRECT_TYPE: + *((uint8*)pValue) = gapRole_AdvDirectType; + break; + + case GAPROLE_ADV_DIRECT_ADDR: + VOID osal_memcpy( pValue, gapRole_AdvDirectAddr, B_ADDR_LEN ) ; + break; + + case GAPROLE_ADV_CHANNEL_MAP: + *((uint8*)pValue) = gapRole_AdvChanMap; + break; + + case GAPROLE_ADV_FILTER_POLICY: + *((uint8*)pValue) = gapRole_AdvFilterPolicy; + break; + + default: + + // The param value isn't part of this profile, try the GAP. + if ( param < TGAP_PARAMID_MAX ) + { + *((uint16*)pValue) = GAP_GetParamValue( param ); + } + else + { + ret = INVALIDPARAMETER; + } + + break; + } + + return ( ret ); +} + +/********************************************************************* + @brief Does the device initialization. + + Public function defined in broadcaster.h. +*/ +bStatus_t GAPRole_StartDevice( gapRolesCBs_t* pAppCallbacks ) +{ + if ( gapRole_state == GAPROLE_INIT ) + { + // Clear all of the Application callbacks + if ( pAppCallbacks ) + { + pGapRoles_AppCGs = pAppCallbacks; + } + + // Start the GAP + gapRole_SetupGAP(); + return ( SUCCESS ); + } + else + { + return ( bleAlreadyInRequestedMode ); + } +} + +/********************************************************************* + LOCAL FUNCTION PROTOTYPES +*/ + +/********************************************************************* + @brief Task Initialization function. + + Internal function defined in broadcaster.h. +*/ +void GAPRole_Init( uint8 task_id ) +{ + gapRole_TaskID = task_id; + gapRole_state = GAPROLE_INIT; + GAP_RegisterForHCIMsgs( gapRole_TaskID ); + // Initialize the Profile Advertising and Connection Parameters + gapRole_profileRole = GAP_PROFILE_BROADCASTER; + gapRole_AdvEventType = GAP_ADTYPE_ADV_NONCONN_IND; + gapRole_AdvDirectType = ADDRTYPE_PUBLIC; + gapRole_AdvChanMap = GAP_ADVCHAN_ALL; + gapRole_AdvFilterPolicy = GAP_FILTER_POLICY_ALL; +} + +/********************************************************************* + @brief Task Event Processor function. + + Internal function defined in broadcaster.h. +*/ +uint16 GAPRole_ProcessEvent( uint8 task_id, uint16 events ) +{ + VOID task_id; // OSAL required parameter that isn't used in this function + + if ( events & SYS_EVENT_MSG ) + { + uint8* pMsg; + + if ( (pMsg = osal_msg_receive( gapRole_TaskID )) != NULL ) + { + gapRole_ProcessOSALMsg( (osal_event_hdr_t*)pMsg ); + // Release the OSAL message + VOID osal_msg_deallocate( pMsg ); + } + + // return unprocessed events + return (events ^ SYS_EVENT_MSG); + } + + if ( events & START_ADVERTISING_EVT ) + { + if ( gapRole_AdvEnabled ) + { + gapAdvertisingParams_t params; + // Setup advertisement parameters + params.eventType = gapRole_AdvEventType; + params.initiatorAddrType = gapRole_AdvDirectType; + VOID osal_memcpy( params.initiatorAddr, gapRole_AdvDirectAddr, B_ADDR_LEN ); + params.channelMap = gapRole_AdvChanMap; + params.filterPolicy = gapRole_AdvFilterPolicy; + + if ( GAP_MakeDiscoverable( gapRole_TaskID, ¶ms ) != SUCCESS ) + { + gapRole_state = GAPROLE_ERROR; + + if ( pGapRoles_AppCGs && pGapRoles_AppCGs->pfnStateChange ) + { + pGapRoles_AppCGs->pfnStateChange( gapRole_state ); + } + } + } + + return ( events ^ START_ADVERTISING_EVT ); + } + + // Discard unknown events + return 0; +} + +/********************************************************************* + @fn gapRole_ProcessOSALMsg + + @brief Process an incoming task message. + + @param pMsg - message to process + + @return none +*/ +static void gapRole_ProcessOSALMsg( osal_event_hdr_t* pMsg ) +{ + switch ( pMsg->event ) + { + case HCI_GAP_EVENT_EVENT: + if ( pMsg->status == HCI_COMMAND_COMPLETE_EVENT_CODE ) + { + //hciEvt_CmdComplete_t *pPkt = (hciEvt_CmdComplete_t *)pMsg; + } + + break; + + case GAP_MSG_EVENT: + gapRole_ProcessGAPMsg( (gapEventHdr_t*)pMsg ); + break; + + default: + break; + } +} + +/********************************************************************* + @fn gapRole_ProcessGAPMsg + + @brief Process an incoming task message. + + @param pMsg - message to process + + @return none +*/ +static void gapRole_ProcessGAPMsg( gapEventHdr_t* pMsg ) +{ + uint8 notify = FALSE; // State changed notify the app? (default no) + + switch ( pMsg->opcode ) + { + case GAP_DEVICE_INIT_DONE_EVENT: + { + gapDeviceInitDoneEvent_t* pPkt = (gapDeviceInitDoneEvent_t*)pMsg; + bStatus_t stat = pPkt->hdr.status; + + if ( stat == SUCCESS ) + { + // Save off the information + VOID osal_memcpy( gapRole_bdAddr, pPkt->devAddr, B_ADDR_LEN ); + gapRole_state = GAPROLE_STARTED; + // Update the advertising data + stat = GAP_UpdateAdvertisingData( gapRole_TaskID, TRUE, + gapRole_AdvertDataLen, + gapRole_AdvertData ); + } + + if ( stat != SUCCESS ) + { + gapRole_state = GAPROLE_ERROR; + } + + notify = TRUE; + } + break; + + case GAP_ADV_DATA_UPDATE_DONE_EVENT: + { + gapAdvDataUpdateEvent_t* pPkt = (gapAdvDataUpdateEvent_t*)pMsg; + + if ( pPkt->hdr.status == SUCCESS ) + { + if ( pPkt->adType ) + { + // Setup the Response Data + pPkt->hdr.status = GAP_UpdateAdvertisingData( gapRole_TaskID, + FALSE, gapRole_ScanRspDataLen, gapRole_ScanRspData ); + } + else + { + // Start advertising + VOID osal_set_event( gapRole_TaskID, START_ADVERTISING_EVT ); + } + } + + if ( pPkt->hdr.status != SUCCESS ) + { + // Set into Error state + gapRole_state = GAPROLE_ERROR; + notify = TRUE; + } + } + break; + + case GAP_MAKE_DISCOVERABLE_DONE_EVENT: + case GAP_END_DISCOVERABLE_DONE_EVENT: + { + gapMakeDiscoverableRspEvent_t* pPkt = (gapMakeDiscoverableRspEvent_t*)pMsg; + + if ( pPkt->hdr.status == SUCCESS ) + { + if ( pMsg->opcode == GAP_MAKE_DISCOVERABLE_DONE_EVENT ) + { + gapRole_state = GAPROLE_ADVERTISING; + } + else // GAP_END_DISCOVERABLE_DONE_EVENT + { + if ( gapRole_AdvertOffTime != 0 ) + { + if ( ( gapRole_AdvEnabled ) ) + { + VOID osal_start_timerEx( gapRole_TaskID, START_ADVERTISING_EVT, gapRole_AdvertOffTime ); + } + } + else + { + // Since gapRole_AdvertOffTime is set to 0, the device should not + // automatically become discoverable again after a period of time. + // Set enabler to FALSE; device will become discoverable again when + // this value gets set to TRUE + gapRole_AdvEnabled = FALSE; + } + + // In the Advertising Off period + gapRole_state = GAPROLE_WAITING; + } + } + else + { + gapRole_state = GAPROLE_ERROR; + } + + notify = TRUE; + } + break; + + default: + break; + } + + if ( notify == TRUE ) + { + // Notify the application + if ( pGapRoles_AppCGs && pGapRoles_AppCGs->pfnStateChange ) + { + pGapRoles_AppCGs->pfnStateChange( gapRole_state ); + } + } +} + +/********************************************************************* + @fn gapRole_SetupGAP + + @brief Call the GAP Device Initialization function using the + Profile Parameters. + + @param none + + @return none +*/ +static void gapRole_SetupGAP( void ) +{ + VOID GAP_DeviceInit( gapRole_TaskID, + gapRole_profileRole, 0, + NULL, NULL, NULL ); +} + +/********************************************************************* +*********************************************************************/ diff --git a/src/components/profiles/Roles/broadcaster.h b/src/components/profiles/Roles/broadcaster.h new file mode 100644 index 0000000..a9cf64d --- /dev/null +++ b/src/components/profiles/Roles/broadcaster.h @@ -0,0 +1,186 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + + +#ifndef BROADCASTER_H +#define BROADCASTER_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* ------------------------------------------------------------------- + INCLUDES +*/ + +/* ------------------------------------------------------------------- + CONSTANTS +*/ + +/** @defgroup GAPROLE_PROFILE_PARAMETERS GAP Role Parameters + @{ +*/ +#define GAPROLE_PROFILEROLE 0x300 //!< Reading this parameter will return GAP Role type. Read Only. Size is uint8. +#define GAPROLE_BD_ADDR 0x301 //!< Device's Address. Read Only. Size is uint8[B_ADDR_LEN]. This item is read from the controller. +#define GAPROLE_ADVERT_ENABLED 0x302 //!< Enable/Disable Advertising. Read/Write. Size is uint8. Default is TRUE=Enabled. +#define GAPROLE_ADVERT_OFF_TIME 0x303 //!< Advertising Off Time for Limited advertisements (in milliseconds). Read/Write. Size is uint16. Default is 30 seconds. +#define GAPROLE_ADVERT_DATA 0x304 //!< Advertisement Data. Read/Write. Size is uint8[B_MAX_ADV_LEN]. Default is "02:01:01", which means that it is a Limited Discoverable Advertisement. +#define GAPROLE_SCAN_RSP_DATA 0x305 //!< Scan Response Data. Read/Write. Size is uint8[B_MAX_ADV_LEN]. Defaults to all 0. +#define GAPROLE_ADV_EVENT_TYPE 0x306 //!< Advertisement Type. Read/Write. Size is uint8. Default is GAP_ADTYPE_ADV_IND (defined in GAP.h). +#define GAPROLE_ADV_DIRECT_TYPE 0x307 //!< Direct Advertisement Address Type. Ready/Write. Size is uint8. Default is ADDRTYPE_PUBLIC (defined in GAP.h). +#define GAPROLE_ADV_DIRECT_ADDR 0x308 //!< Direct Advertisement Address. Read/Write. Size is uint8[B_ADDR_LEN]. Default is NULL. +#define GAPROLE_ADV_CHANNEL_MAP 0x309 //!< Which channels to advertise on. Read/Write Size is uint8. Default is GAP_ADVCHAN_ALL (defined in GAP.h) +#define GAPROLE_ADV_FILTER_POLICY 0x30A //!< Filter Policy. Ignored when directed advertising is used. Read/Write. Size is uint8. Default is GAP_FILTER_POLICY_ALL (defined in GAP.h). +/** @} End GAPROLE_PROFILE_PARAMETERS */ + +/* ------------------------------------------------------------------- + TYPEDEFS +*/ + +/** + GAP Broadcaster Role States. +*/ +typedef enum +{ + GAPROLE_INIT = 0, //!< Waiting to be started + GAPROLE_STARTED, //!< Started but not advertising + GAPROLE_ADVERTISING, //!< Currently Advertising + GAPROLE_WAITING, //!< Device is started but not advertising, is in waiting period before advertising again + GAPROLE_ERROR //!< Error occurred - invalid state +} gaprole_States_t; + +/* ------------------------------------------------------------------- + MACROS +*/ + +/* ------------------------------------------------------------------- + Profile Callbacks +*/ + +/** + Callback when the device has been started. Callback event to + the Notify of a state change. +*/ +typedef void (*gapRolesStateNotify_t)( gaprole_States_t newState ); + +/** + Callback when the device has read an new RSSI value during a connection. +*/ +typedef void (*gapRolesRssiRead_t)( int8 newRSSI ); + +/** + Callback structure - must be setup by the application and used when gapRoles_StartDevice() is called. +*/ +typedef struct +{ + gapRolesStateNotify_t pfnStateChange; //!< Whenever the device changes state + gapRolesRssiRead_t pfnRssiRead; //!< When a valid RSSI is read from controller +} gapRolesCBs_t; + +/* ------------------------------------------------------------------- + API FUNCTIONS +*/ + +/** + @defgroup GAPROLES_BROADCASTER_API GAP Broadcaster Role API Functions + + @{ +*/ + +/** + @brief Set a GAP Role parameter. + + NOTE: You can call this function with a GAP Parameter ID and it will set the + GAP Parameter. GAP Parameters are defined in (gap.h). Also, + the "len" field must be set to the size of a "uint16" and the + "pValue" field must point to a "uint16". + + @param param - Profile parameter ID: @ref GAPROLE_PROFILE_PARAMETERS + @param len - length of data to write + @param pValue - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return SUCCESS or INVALIDPARAMETER (invalid paramID) +*/ +extern bStatus_t GAPRole_SetParameter( uint16 param, uint8 len, void* pValue ); + +/** + @brief Get a GAP Role parameter. + + NOTE: You can call this function with a GAP Parameter ID and it will get a + GAP Parameter. GAP Parameters are defined in (gap.h). Also, the + "pValue" field must point to a "uint16". + + @param param - Profile parameter ID: @ref GAPROLE_PROFILE_PARAMETERS + @param pValue - pointer to location to get the value. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return SUCCESS or INVALIDPARAMETER (invalid paramID) +*/ +extern bStatus_t GAPRole_GetParameter( uint16 param, void* pValue ); + +/** + @brief Does the device initialization. Only call this function once. + + @param pAppCallbacks - pointer to application callbacks. + + @return SUCCESS or bleAlreadyInRequestedMode +*/ +extern bStatus_t GAPRole_StartDevice( gapRolesCBs_t* pAppCallbacks ); + +/** + @} End GAPROLES_BROADCASTER_API +*/ + + +/* ------------------------------------------------------------------- + TASK FUNCTIONS - Don't call these. These are system functions. +*/ + +/** + @internal + + @brief Initialization function for the GAP Role Task. + This is called during initialization and should contain + any application specific initialization (ie. hardware + initialization/setup, table initialization, power up + notificaiton ... ). + + @param the ID assigned by OSAL. This ID should be + used to send messages and set timers. + + @return void +*/ +extern void GAPRole_Init( uint8 task_id ); + +/** + @internal + + @brief GAP Role Task event processor. + This function is called to process all events for the task. + Events include timers, messages and any other user defined + events. + + @param task_id - The OSAL assigned task ID. + @param events - events to process. This is a bit map and can + contain more than one event. + + @return events not processed +*/ +extern uint16 GAPRole_ProcessEvent( uint8 task_id, uint16 events ); + +/* ------------------------------------------------------------------- + -------------------------------------------------------------------*/ + +#ifdef __cplusplus +} +#endif + +#endif /* BROADCASTER_H */ diff --git a/src/components/profiles/Roles/central.c b/src/components/profiles/Roles/central.c new file mode 100644 index 0000000..59dd058 --- /dev/null +++ b/src/components/profiles/Roles/central.c @@ -0,0 +1,645 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "osal_cbtimer.h" +#include "osal_snv.h" +#include "hci_tl.h" +#include "l2cap.h" +#include "linkdb.h" +#include "gap.h" +#include "gapbondmgr.h" +#include "central.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +// Profile Events +#define START_ADVERTISING_EVT 0x0001 +#define RSSI_READ_EVT 0x0002 +#define UPDATE_PARAMS_TIMEOUT_EVT 0x0004 + +// Profile OSAL Message IDs +#define GAPCENTRALROLE_RSSI_MSG_EVT 0xE0 + +/********************************************************************* + TYPEDEFS +*/ + +// RSSI read data structure +typedef struct +{ + uint16 period; + uint16 connHandle; + uint8 timerId; +} gapCentralRoleRssi_t; + +// OSAL event structure for RSSI timer events +typedef struct +{ + osal_event_hdr_t hdr; + gapCentralRoleRssi_t* pRssi; +} gapCentralRoleRssiEvent_t; + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +// Task ID +static uint8 gapCentralRoleTaskId; + +// App callbacks +static gapCentralRoleCB_t* pGapCentralRoleCB; + +// Array of RSSI read structures +static gapCentralRoleRssi_t gapCentralRoleRssi[GAPCENTRALROLE_NUM_RSSI_LINKS]; + +/********************************************************************* + Profile Parameters - reference GAPCENTRALROLE_PROFILE_PARAMETERS for + descriptions +*/ + +static uint8 gapCentralRoleIRK[KEYLEN]; +static uint8 gapCentralRoleSRK[KEYLEN]; +static uint32 gapCentralRoleSignCounter; +static uint8 gapCentralRoleBdAddr[B_ADDR_LEN]; +static uint8 gapCentralRoleMaxScanRes = 0; + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static void gapCentralRole_ProcessOSALMsg( osal_event_hdr_t* pMsg ); +static void gapCentralRole_ProcessGAPMsg( gapEventHdr_t* pMsg ); +static gapCentralRoleRssi_t* gapCentralRole_RssiAlloc( uint16 connHandle ); +static gapCentralRoleRssi_t* gapCentralRole_RssiFind( uint16 connHandle ); +static void gapCentralRole_RssiFree( uint16 connHandle ); +static void gapCentralRole_timerCB( uint8* pData ); + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/** + @brief Start the device in Central role. This function is typically + called once during system startup. + + Public function defined in central.h. +*/ +bStatus_t GAPCentralRole_StartDevice( gapCentralRoleCB_t* pAppCallbacks ) +{ + if ( pAppCallbacks ) + { + pGapCentralRoleCB = pAppCallbacks; + } + + return GAP_DeviceInit( gapCentralRoleTaskId, GAP_PROFILE_CENTRAL, + gapCentralRoleMaxScanRes, gapCentralRoleIRK, + gapCentralRoleSRK, &gapCentralRoleSignCounter ); +} + +/** + @brief Set a parameter in the Central Profile. + + Public function defined in central.h. +*/ +bStatus_t GAPCentralRole_SetParameter( uint16 param, uint8 len, void* pValue ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case GAPCENTRALROLE_IRK: + if ( len == KEYLEN ) + { + VOID osal_memcpy( gapCentralRoleIRK, pValue, KEYLEN ) ; + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPCENTRALROLE_SRK: + if ( len == KEYLEN ) + { + VOID osal_memcpy( gapCentralRoleSRK, pValue, KEYLEN ) ; + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPCENTRALROLE_SIGNCOUNTER: + if ( len == sizeof ( uint32 ) ) + { + gapCentralRoleSignCounter = *((uint32*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPCENTRALROLE_MAX_SCAN_RES: + if ( len == sizeof ( uint8 ) ) + { + gapCentralRoleMaxScanRes = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ret; +} + +/** + @brief Get a parameter in the Central Profile. + + Public function defined in central.h. +*/ +bStatus_t GAPCentralRole_GetParameter( uint16 param, void* pValue ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case GAPCENTRALROLE_IRK: + VOID osal_memcpy( pValue, gapCentralRoleIRK, KEYLEN ) ; + break; + + case GAPCENTRALROLE_SRK: + VOID osal_memcpy( pValue, gapCentralRoleSRK, KEYLEN ) ; + break; + + case GAPCENTRALROLE_SIGNCOUNTER: + *((uint32*)pValue) = gapCentralRoleSignCounter; + break; + + case GAPCENTRALROLE_BD_ADDR: + VOID osal_memcpy( pValue, gapCentralRoleBdAddr, B_ADDR_LEN ) ; + break; + + case GAPCENTRALROLE_MAX_SCAN_RES: + *((uint8*)pValue) = gapCentralRoleMaxScanRes; + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ret; +} + +/** + @brief Terminate a link. + + Public function defined in central.h. +*/ +bStatus_t GAPCentralRole_TerminateLink( uint16 connHandle ) +{ + return GAP_TerminateLinkReq( gapCentralRoleTaskId, connHandle, HCI_DISCONNECT_REMOTE_USER_TERM ) ; +} + +/** + @brief Establish a link to a peer device. + + Public function defined in central.h. +*/ +bStatus_t GAPCentralRole_EstablishLink( uint8 highDutyCycle, uint8 whiteList, + uint8 addrTypePeer, uint8* peerAddr ) +{ + gapEstLinkReq_t params; + params.taskID = gapCentralRoleTaskId; + params.highDutyCycle = highDutyCycle; + params.whiteList = whiteList; + params.addrTypePeer = addrTypePeer; + VOID osal_memcpy( params.peerAddr, peerAddr, B_ADDR_LEN ); + return GAP_EstablishLinkReq( ¶ms ); +} + +/** + @brief Update the link connection parameters. + + Public function defined in central.h. +*/ +bStatus_t GAPCentralRole_UpdateLink( uint16 connHandle, uint16 connIntervalMin, + uint16 connIntervalMax, uint16 connLatency, + uint16 connTimeout ) +{ + return (bStatus_t) HCI_LE_ConnUpdateCmd( connHandle, connIntervalMin, + connIntervalMax, connLatency, + connTimeout, 0, 0 ); +} + +/** + @brief Start a device discovery scan. + + Public function defined in central.h. +*/ +bStatus_t GAPCentralRole_StartDiscovery( uint8 mode, uint8 activeScan, uint8 whiteList ) +{ + gapDevDiscReq_t params; + params.taskID = gapCentralRoleTaskId; + params.mode = mode; + params.activeScan = activeScan; + params.whiteList = whiteList; + return GAP_DeviceDiscoveryRequest( ¶ms ); +} + +/** + @brief Cancel a device discovery scan. + + Public function defined in central.h. +*/ +bStatus_t GAPCentralRole_CancelDiscovery( void ) +{ + return GAP_DeviceDiscoveryCancel( gapCentralRoleTaskId ); +} + +/** + @brief Start periodic RSSI reads on a link. + + Public function defined in central.h. +*/ +bStatus_t GAPCentralRole_StartRssi( uint16 connHandle, uint16 period ) +{ + gapCentralRoleRssi_t* pRssi; + + // Verify link is up + if (!linkDB_Up(connHandle)) + { + return bleIncorrectMode; + } + + // If already allocated + if ((pRssi = gapCentralRole_RssiFind( connHandle )) != NULL) + { + // Stop timer + osal_CbTimerStop( pRssi->timerId ); + } + // Allocate structure + else if ((pRssi = gapCentralRole_RssiAlloc( connHandle )) != NULL) + { + pRssi->period = period; + } + // Allocate failed + else + { + return bleNoResources; + } + + // Start timer + osal_CbTimerStart( gapCentralRole_timerCB, (uint8*) pRssi, + period, &pRssi->timerId ); + return SUCCESS; +} + +/** + @brief Cancel periodic RSSI reads on a link. + + Public function defined in central.h. +*/ +bStatus_t GAPCentralRole_CancelRssi(uint16 connHandle ) +{ + gapCentralRoleRssi_t* pRssi; + + if ((pRssi = gapCentralRole_RssiFind( connHandle )) != NULL) + { + // Stop timer + osal_CbTimerStop( pRssi->timerId ); + // Free RSSI structure + gapCentralRole_RssiFree( connHandle ); + return SUCCESS; + } + + // Not found + return bleIncorrectMode; +} + +/** + @brief Central Profile Task initialization function. + + @param taskId - Task ID. + + @return void +*/ +void GAPCentralRole_Init( uint8 taskId ) +{ + uint8 i; + gapCentralRoleTaskId = taskId; + + // Initialize internal data + for ( i = 0; i < GAPCENTRALROLE_NUM_RSSI_LINKS; i++ ) + { + gapCentralRoleRssi[i].connHandle = GAP_CONNHANDLE_ALL; + gapCentralRoleRssi[i].timerId = INVALID_TIMER_ID; + } + + // Initialize parameters + // Retore items from NV +// VOID osal_snv_read( BLE_NVID_IRK, KEYLEN, gapCentralRoleIRK ); +// VOID osal_snv_read( BLE_NVID_CSRK, KEYLEN, gapCentralRoleSRK ); +// VOID osal_snv_read( BLE_NVID_SIGNCOUNTER, sizeof( uint32 ), &gapCentralRoleSignCounter ); + // Register for HCI messages (for RSSI) + GAP_RegisterForHCIMsgs( taskId ); +} + +/** + @brief Central Profile Task event processing function. + + @param taskId - Task ID + @param events - Events. + + @return events not processed +*/ +uint16 GAPCentralRole_ProcessEvent( uint8 taskId, uint16 events ) +{ + if ( events & SYS_EVENT_MSG ) + { + uint8* pMsg; + + if ( (pMsg = osal_msg_receive( gapCentralRoleTaskId )) != NULL ) + { + gapCentralRole_ProcessOSALMsg( (osal_event_hdr_t*) pMsg ); + // Release the OSAL message + VOID osal_msg_deallocate( pMsg ); + } + + // return unprocessed events + return (events ^ SYS_EVENT_MSG); + } + + if ( events & GAP_EVENT_SIGN_COUNTER_CHANGED ) + { + // Sign counter changed, save it to NV + // VOID osal_snv_write( BLE_NVID_SIGNCOUNTER, sizeof( uint32 ), &gapCentralRoleSignCounter ); + return ( events ^ GAP_EVENT_SIGN_COUNTER_CHANGED ); + } + + // Discard unknown events + return 0; +} + +/********************************************************************* + @fn gapCentralRole_ProcessOSALMsg + + @brief Process an incoming task message. + + @param pMsg - message to process + + @return none +*/ +static void gapCentralRole_ProcessOSALMsg( osal_event_hdr_t* pMsg ) +{ + switch ( pMsg->event ) + { + case HCI_GAP_EVENT_EVENT: + if ( pMsg->status == HCI_COMMAND_COMPLETE_EVENT_CODE ) + { + hciEvt_CmdComplete_t* pPkt = (hciEvt_CmdComplete_t*) pMsg; + + if ( pPkt->cmdOpcode == HCI_READ_RSSI ) + { + uint16 connHandle = BUILD_UINT16( pPkt->pReturnParam[1], pPkt->pReturnParam[2] ); + int8 rssi = (int8) pPkt->pReturnParam[3]; + + // Report RSSI to app + if ( pGapCentralRoleCB && pGapCentralRoleCB->rssiCB ) + { + pGapCentralRoleCB->rssiCB( connHandle, rssi ); + } + } + } + + break; + + case GAP_MSG_EVENT: + gapCentralRole_ProcessGAPMsg( (gapEventHdr_t*) pMsg ); + break; + + case GAPCENTRALROLE_RSSI_MSG_EVT: + { + gapCentralRoleRssi_t* pRssi = ((gapCentralRoleRssiEvent_t*) pMsg)->pRssi; + + // If link is up and RSSI reads active + if (pRssi->connHandle != GAP_CONNHANDLE_ALL && + linkDB_Up(pRssi->connHandle)) + { + // Restart timer + osal_CbTimerStart( gapCentralRole_timerCB, (uint8*) pRssi, + pRssi->period, &pRssi->timerId ); + // Read RSSI + VOID HCI_ReadRssiCmd( pRssi->connHandle ); + } + } + break; + + default: + break; + } +} + +/********************************************************************* + @fn gapCentralRole_ProcessGAPMsg + + @brief Process an incoming task message from GAP. + + @param pMsg - message to process + + @return none +*/ +static void gapCentralRole_ProcessGAPMsg( gapEventHdr_t* pMsg ) +{ + switch ( pMsg->opcode ) + { + case GAP_DEVICE_INIT_DONE_EVENT: + { + gapDeviceInitDoneEvent_t* pPkt = (gapDeviceInitDoneEvent_t*) pMsg; + + if ( pPkt->hdr.status == SUCCESS ) + { + // Save off the generated keys + // VOID osal_snv_write( BLE_NVID_IRK, KEYLEN, gapCentralRoleIRK ); + // VOID osal_snv_write( BLE_NVID_CSRK, KEYLEN, gapCentralRoleSRK ); + // Save off the information + VOID osal_memcpy( gapCentralRoleBdAddr, pPkt->devAddr, B_ADDR_LEN ); + } + } + break; + + case GAP_LINK_ESTABLISHED_EVENT: + { + gapEstLinkReqEvent_t* pPkt = (gapEstLinkReqEvent_t*) pMsg; + + if (pPkt->hdr.status == SUCCESS) + { + // Notify the Bond Manager of the connection + VOID GAPBondMgr_LinkEst( pPkt->devAddrType, pPkt->devAddr, + pPkt->connectionHandle, GAP_PROFILE_CENTRAL ); + } + } + break; + + case GAP_LINK_TERMINATED_EVENT: + { + uint16 connHandle = ((gapTerminateLinkEvent_t*) pMsg)->connectionHandle; + VOID GAPBondMgr_ProcessGAPMsg( (gapEventHdr_t*)pMsg ); + // Cancel RSSI reads + GAPCentralRole_CancelRssi( connHandle ); + } + break; + + // temporary workaround + case GAP_SLAVE_REQUESTED_SECURITY_EVENT: + VOID GAPBondMgr_ProcessGAPMsg( pMsg ); + break; + + default: + break; + } + + // Pass event to app + if ( pGapCentralRoleCB && pGapCentralRoleCB->eventCB ) + { + pGapCentralRoleCB->eventCB( (gapCentralRoleEvent_t*) pMsg ); + } +} + +/********************************************************************* + @fn gapCentralRole_RssiAlloc + + @brief Allocate an RSSI structure. + + @param connHandle - Connection handle + + @return pointer to structure or NULL if allocation failed. +*/ +static gapCentralRoleRssi_t* gapCentralRole_RssiAlloc( uint16 connHandle ) +{ + uint8 i; + + // Find free RSSI structure + for ( i = 0; i < GAPCENTRALROLE_NUM_RSSI_LINKS; i++ ) + { + if ( gapCentralRoleRssi[i].connHandle == GAP_CONNHANDLE_ALL ) + { + gapCentralRoleRssi[i].connHandle = connHandle; + return &gapCentralRoleRssi[i]; + } + } + + // No free structure found + return NULL; +} + +/********************************************************************* + @fn gapCentralRole_RssiFind + + @brief Find an RSSI structure. + + @param connHandle - Connection handle + + @return pointer to structure or NULL if not found. +*/ +static gapCentralRoleRssi_t* gapCentralRole_RssiFind( uint16 connHandle ) +{ + uint8 i; + + // Find free RSSI structure + for ( i = 0; i < GAPCENTRALROLE_NUM_RSSI_LINKS; i++ ) + { + if ( gapCentralRoleRssi[i].connHandle == connHandle ) + { + return &gapCentralRoleRssi[i]; + } + } + + // Not found + return NULL; +} + +/********************************************************************* + @fn gapCentralRole_RssiFree + + @brief Free an RSSI structure. + + @param connHandle - Connection handle + + @return none +*/ +static void gapCentralRole_RssiFree( uint16 connHandle ) +{ + uint8 i; + + // Find RSSI structure + for ( i = 0; i < GAPCENTRALROLE_NUM_RSSI_LINKS; i++ ) + { + if ( gapCentralRoleRssi[i].connHandle == connHandle ) + { + gapCentralRoleRssi[i].connHandle = GAP_CONNHANDLE_ALL; + break; + } + } +} + +/********************************************************************* + @fn gapCentralRole_timerCB + + @brief OSAL timer callback function + + @param pData - Data pointer + + @return none +*/ +static void gapCentralRole_timerCB( uint8* pData ) +{ + gapCentralRoleRssiEvent_t* pMsg; + // Timer has expired so clear timer ID + ((gapCentralRoleRssi_t*) pData)->timerId = INVALID_TIMER_ID; + // Send OSAL message + pMsg = (gapCentralRoleRssiEvent_t*) osal_msg_allocate( sizeof(gapCentralRoleRssiEvent_t) ); + + if ( pMsg ) + { + pMsg->hdr.event = GAPCENTRALROLE_RSSI_MSG_EVT; + pMsg->pRssi = (gapCentralRoleRssi_t*) pData; + osal_msg_send ( gapCentralRoleTaskId, (uint8*) pMsg ); + } +} + +/********************************************************************* +*********************************************************************/ diff --git a/src/components/profiles/Roles/central.h b/src/components/profiles/Roles/central.h new file mode 100644 index 0000000..b739751 --- /dev/null +++ b/src/components/profiles/Roles/central.h @@ -0,0 +1,271 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ +#ifndef CENTRAL_H +#define CENTRAL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "gap.h" + +/********************************************************************* + CONSTANTS +*/ + +/** @defgroup GAPCENTRALROLE_PROFILE_PARAMETERS GAP Central Role Parameters + @{ +*/ +#define GAPCENTRALROLE_IRK 0x400 //!< Identity Resolving Key. Read/Write. Size is uint8[KEYLEN]. Default is all 0, which means that the IRK will be randomly generated. +#define GAPCENTRALROLE_SRK 0x401 //!< Signature Resolving Key. Read/Write. Size is uint8[KEYLEN]. Default is all 0, which means that the SRK will be randomly generated. +#define GAPCENTRALROLE_SIGNCOUNTER 0x402 //!< Sign Counter. Read/Write. Size is uint32. Default is 0. +#define GAPCENTRALROLE_BD_ADDR 0x403 //!< Device's Address. Read Only. Size is uint8[B_ADDR_LEN]. This item is read from the controller. +#define GAPCENTRALROLE_MAX_SCAN_RES 0x404 //!< Maximum number of discover scan results to receive. Default is 0 = unlimited. +/** @} End GAPCENTRALROLE_PROFILE_PARAMETERS */ + +/** + Number of simultaneous links with periodic RSSI reads +*/ +#ifndef GAPCENTRALROLE_NUM_RSSI_LINKS +#define GAPCENTRALROLE_NUM_RSSI_LINKS 4 +#endif + +/********************************************************************* + VARIABLES +*/ + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/** + Central Event Structure +*/ +typedef union +{ + gapEventHdr_t gap; //!< GAP_MSG_EVENT and status. + gapDeviceInitDoneEvent_t initDone; //!< GAP initialization done. + gapDeviceInfoEvent_t deviceInfo; //!< Discovery device information event structure. + gapDevDiscEvent_t discCmpl; //!< Discovery complete event structure. + gapEstLinkReqEvent_t linkCmpl; //!< Link complete event structure. + gapLinkUpdateEvent_t linkUpdate; //!< Link update event structure. + gapTerminateLinkEvent_t linkTerminate; //!< Link terminated event structure. +} gapCentralRoleEvent_t; + +/** + RSSI Read Callback Function +*/ +typedef void (*pfnGapCentralRoleRssiCB_t) +( + uint16 connHandle, //!< Connection handle. + int8 rssi //!< New RSSI value. +); + +/** + Central Event Callback Function +*/ +typedef void (*pfnGapCentralRoleEventCB_t) +( + gapCentralRoleEvent_t* pEvent //!< Pointer to event structure. +); + +/** + Central Callback Structure +*/ +typedef struct +{ + pfnGapCentralRoleRssiCB_t rssiCB; //!< RSSI callback. + pfnGapCentralRoleEventCB_t eventCB; //!< Event callback. +} gapCentralRoleCB_t; + +/********************************************************************* + VARIABLES +*/ + +/********************************************************************* + API FUNCTIONS +*/ + +/* ------------------------------------------------------------------- + Central Profile Public APIs +*/ + +/** + @defgroup CENTRAL_PROFILE_API Central Profile API Functions + + @{ +*/ + +/** + @brief Start the device in Central role. This function is typically + called once during system startup. + + @param pAppCallbacks - pointer to application callbacks + + @return SUCCESS: Operation successful.
+ bleAlreadyInRequestedMode: Device already started.
+*/ +extern bStatus_t GAPCentralRole_StartDevice( gapCentralRoleCB_t* pAppCallbacks ); + +/** + @brief Set a parameter in the Central Profile. + + @param param - profile parameter ID: @ref GAPCENTRALROLE_PROFILE_PARAMETERS + @param len - length of data to write + @param pValue - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type. + + @return SUCCESS: Operation successful.
+ INVALIDPARAMETER: Invalid parameter ID.
+*/ +extern bStatus_t GAPCentralRole_SetParameter( uint16 param, uint8 len, void* pValue ); + +/** + @brief Get a parameter in the Central Profile. + + @param param - profile parameter ID: @ref GAPCENTRALROLE_PROFILE_PARAMETERS + @param pValue - pointer to buffer to contain the read data + + @return SUCCESS: Operation successful.
+ INVALIDPARAMETER: Invalid parameter ID.
+*/ +extern bStatus_t GAPCentralRole_GetParameter( uint16 param, void* pValue ); + +/** + @brief Terminate a link. + + @param connHandle - connection handle of link to terminate + or @ref GAP_CONN_HANDLE_DEFINES + + @return SUCCESS: Terminate started.
+ bleIncorrectMode: No link to terminate.
+*/ +extern bStatus_t GAPCentralRole_TerminateLink( uint16 connHandle ); + +/** + @brief Establish a link to a peer device. + + @param highDutyCycle - TRUE to high duty cycle scan, FALSE if not + @param whiteList - determines use of the white list: @ref GAP_WHITELIST_DEFINES + @param addrTypePeer - address type of the peer device: @ref GAP_ADDR_TYPE_DEFINES + @param peerAddr - peer device address + + @return SUCCESS: started establish link process.
+ bleIncorrectMode: invalid profile role.
+ bleNotReady: a scan is in progress.
+ bleAlreadyInRequestedMode: can?t process now.
+ bleNoResources: too many links.
+*/ +extern bStatus_t GAPCentralRole_EstablishLink( uint8 highDutyCycle, uint8 whiteList, + uint8 addrTypePeer, uint8* peerAddr ); + +/** + @brief Update the link connection parameters. + + @param connHandle - connection handle + @param connIntervalMin - minimum connection interval in 1.25ms units + @param connIntervalMax - maximum connection interval in 1.25ms units + @param connLatency - number of LL latency connection events + @param connTimeout - connection timeout in 10ms units + + @return SUCCESS: Connection update started started.
+ bleIncorrectMode: No connection to update.
+*/ +extern bStatus_t GAPCentralRole_UpdateLink( uint16 connHandle, uint16 connIntervalMin, + uint16 connIntervalMax, uint16 connLatency, + uint16 connTimeout ); +/** + @brief Start a device discovery scan. + + @param mode - discovery mode: @ref GAP_DEVDISC_MODE_DEFINES + @param activeScan - TRUE to perform active scan + @param whiteList - TRUE to only scan for devices in the white list + + @return SUCCESS: Discovery scan started.
+ bleIncorrectMode: Invalid profile role.
+ bleAlreadyInRequestedMode: Not available.
+*/ +extern bStatus_t GAPCentralRole_StartDiscovery( uint8 mode, uint8 activeScan, uint8 whiteList ); + +/** + @brief Cancel a device discovery scan. + + @return SUCCESS: Cancel started.
+ bleInvalidTaskID: Not the task that started discovery.
+ bleIncorrectMode: Not in discovery mode.
+*/ +extern bStatus_t GAPCentralRole_CancelDiscovery( void ); + +/** + @brief Start periodic RSSI reads on a link. + + @param connHandle - connection handle of link + @param period - RSSI read period in ms + + @return SUCCESS: Terminate started.
+ bleIncorrectMode: No link.
+ bleNoResources: No resources.
+*/ +extern bStatus_t GAPCentralRole_StartRssi( uint16 connHandle, uint16 period ); + +/** + @brief Cancel periodic RSSI reads on a link. + + @param connHandle - connection handle of link + + @return SUCCESS: Operation successful.
+ bleIncorrectMode: No link.
+*/ +extern bStatus_t GAPCentralRole_CancelRssi(uint16 connHandle ); + +/** + @} +*/ + +/* ------------------------------------------------------------------- + TASK API - These functions must only be called by OSAL. +*/ + +/** + @internal + + @brief Central Profile Task initialization function. + + @param taskId - Task ID. + + @return void +*/ +extern void GAPCentralRole_Init( uint8 taskId ); + +/** + @internal + + @brief Central Profile Task event processing function. + + @param taskId - Task ID + @param events - Events. + + @return events not processed +*/ +extern uint16 GAPCentralRole_ProcessEvent( uint8 taskId, uint16 events ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* CENTRAL_H */ diff --git a/src/components/profiles/Roles/gap.c b/src/components/profiles/Roles/gap.c new file mode 100644 index 0000000..a1abf9a --- /dev/null +++ b/src/components/profiles/Roles/gap.c @@ -0,0 +1,203 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************* + Filename: gap.c + Revised: + Revision: + + Description: This file contains the GAP Configuration API. + + + +**************************************************************************************************/ + +#include "bcomdef.h" +#include "gap.h" +#include "sm.h" +#include "log.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +/********************************************************************* + LOCAL FUNCTION PROTOTYPES +*/ + +/********************************************************************* + API FUNCTIONS +*/ + +/********************************************************************* + Called to setup the device. Call just once. + + Public function defined in gap.h. +*/ +bStatus_t GAP_DeviceInit( uint8 taskID, + uint8 profileRole, + uint8 maxScanResponses, + uint8* pIRK, + uint8* pSRK, + uint32* pSignCounter ) +{ + bStatus_t stat = INVALIDPARAMETER; // Return status + + // Valid profile roles and supported combinations + switch ( profileRole ) + { + case GAP_PROFILE_BROADCASTER: + #if ( HOST_CONFIG & ( BROADCASTER_CFG | PERIPHERAL_CFG ) ) + { + stat = SUCCESS; + } + + #endif + break; + + case GAP_PROFILE_OBSERVER: + #if ( HOST_CONFIG & ( OBSERVER_CFG | CENTRAL_CFG ) ) + { + stat = SUCCESS; + } + + #endif + break; + + case GAP_PROFILE_PERIPHERAL: + #if ( HOST_CONFIG & PERIPHERAL_CFG ) + { + stat = SUCCESS; + } + + #endif + break; + + case GAP_PROFILE_CENTRAL: + #if ( HOST_CONFIG & CENTRAL_CFG ) + { + stat = SUCCESS; + } + + #endif + break; + + case (GAP_PROFILE_BROADCASTER | GAP_PROFILE_OBSERVER): + #if ( ( HOST_CONFIG & ( BROADCASTER_CFG | PERIPHERAL_CFG ) ) && \ + ( HOST_CONFIG & ( OBSERVER_CFG | CENTRAL_CFG ) ) ) + { + stat = SUCCESS; + } + + #endif + break; + + case (GAP_PROFILE_PERIPHERAL | GAP_PROFILE_OBSERVER): + #if ( ( HOST_CONFIG & PERIPHERAL_CFG ) && \ + ( HOST_CONFIG & ( OBSERVER_CFG | CENTRAL_CFG ) ) ) + { + stat = SUCCESS; + } + + #endif + break; + + case (GAP_PROFILE_CENTRAL | GAP_PROFILE_BROADCASTER): + #if ( ( HOST_CONFIG & CENTRAL_CFG ) && \ + ( HOST_CONFIG & ( BROADCASTER_CFG | PERIPHERAL_CFG ) ) ) + { + stat = SUCCESS; + } + + #endif + break; + + case (GAP_PROFILE_CENTRAL | GAP_PROFILE_PERIPHERAL): + { + LOG("GAP_DeviceInit: GAP_PROFILE_CENTRAL | GAP_PROFILE_PERIPHERAL \n"); + stat = SUCCESS; + } + break; + + // Invalid profile roles + default: + stat = INVALIDPARAMETER; + break; + } + + if ( stat == SUCCESS ) + { + // Setup the device configuration parameters + stat = GAP_ParamsInit( taskID, profileRole ); + + if ( stat == SUCCESS ) + { + #if ( HOST_CONFIG & ( CENTRAL_CFG | PERIPHERAL_CFG ) ) + { + GAP_SecParamsInit( pIRK, pSRK, pSignCounter ); + } + #endif + #if ( HOST_CONFIG & ( CENTRAL_CFG | OBSERVER_CFG ) ) + { +// if ( (profileRole == GAP_PROFILE_BROADCASTER) || +// (profileRole == GAP_PROFILE_PERIPHERAL) ) +// { +// maxScanResponses = 0; // Can't scan, so no need for responses. Force 0. +// } + + // Initialize GAP Central Device Manager + GAP_CentDevMgrInit( maxScanResponses ); + + #if ( HOST_CONFIG & CENTRAL_CFG ) + { + // Register GAP Central Connection processing functions + GAP_CentConnRegister(); + + // Initialize SM Initiator + SM_InitiatorInit(); + } + #endif + } + #endif + #if ( HOST_CONFIG & ( PERIPHERAL_CFG | BROADCASTER_CFG ) ) + { + // Initialize GAP Peripheral Device Manager + GAP_PeriDevMgrInit(); + + #if ( HOST_CONFIG & PERIPHERAL_CFG ) + { + // Initialize SM Responder + SM_ResponderInit(); + } + #endif + } + #endif + } + } + + return ( stat ); +} + +/********************************************************************* +*********************************************************************/ diff --git a/src/components/profiles/Roles/gapbondmgr.c b/src/components/profiles/Roles/gapbondmgr.c new file mode 100644 index 0000000..d8ad53d --- /dev/null +++ b/src/components/profiles/Roles/gapbondmgr.c @@ -0,0 +1,2293 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: gapbondmgr.c + Revised: + Revision: + + Description: GAP peripheral profile manages bonded connections + + + +**************************************************************************************************/ + +#if ( HOST_CONFIG & ( CENTRAL_CFG | PERIPHERAL_CFG ) ) + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "osal_snv.h" +#include "gap.h" +#include "linkdb.h" +#include "gatt.h" +#include "gatt_uuid.h" +#include "hci.h" +#include "gattservapp.h" +#include "gapgattserver.h" +#include "gapbondmgr.h" + +// temp set +// #define osal_snv_write( a, b, c ) (1) +// #define osal_snv_read( a, b, c ) (1) +// #define osal_snv_compact( a ) (1) +#define BOND_LOG(...) +//#define BOND_LOG LOG + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ +// Task event types +//#define GAP_BOND_SYNC_CC_EVT 0x0001 // Sync char config +//#define GAP_BOND_SAVE_REC_EVT 0x0002 // Save bond record in NV + +// Once NV usage reaches this percentage threshold, NV compaction gets triggered. +#define NV_COMPACT_THRESHOLD 80 + +// Bonded State Flags +#define GAP_BONDED_STATE_AUTHENTICATED 0x0001 +#define GAP_BONDED_STATE_SERVICE_CHANGED 0x0002 + +/** + GAP Bond Manager NV layout + + The NV definitions: + BLE_NVID_GAP_BOND_START - starting NV ID + GAP_BONDINGS_MAX - Maximum number of bonding allowed (10 is max for number of NV IDs allocated in bcomdef.h). + + A single bonding entry consists of 6 components (NV items): + Bond Record - defined as gapBondRec_t and uses GAP_BOND_REC_ID_OFFSET for an NV ID + local LTK Info - defined as gapBondLTK_t and uses GAP_BOND_LOCAL_LTK_OFFSET for an NV ID + device LTK Info - defined as gapBondLTK_t and uses GAP_BOND_DEV_LTK_OFFSET for an NV ID + device IRK - defined as "uint8 devIRK[KEYLEN]" and uses GAP_BOND_DEV_IRK_OFFSET for an NV ID + device CSRK - defined as "uint8 devCSRK[KEYLEN]" and uses GAP_BOND_DEV_CSRK_OFFSET for an NV ID + device Sign Counter - defined as a uint32 and uses GAP_BOND_DEV_SIGN_COUNTER_OFFSET for an NV ID + + When the device is initialized for the first time, all (GAP_BONDINGS_MAX) NV items are created and + initialized to all 0xFF's. A bonding record of all 0xFF's indicates that the bonding record is empty + and free to use. + + The calculation for each bonding records NV IDs: + mainRecordNvID = ((bondIdx * GAP_BOND_REC_IDS) + BLE_NVID_GAP_BOND_START) + localLTKNvID = (((bondIdx * GAP_BOND_REC_IDS) + GAP_BOND_LOCAL_LTK_OFFSET) + BLE_NVID_GAP_BOND_START) + +*/ +#define GAP_BOND_REC_ID_OFFSET 0 //!< NV ID for the main bonding record +#define GAP_BOND_LOCAL_LTK_OFFSET 1 //!< NV ID for the bonding record's local LTK information +#define GAP_BOND_DEV_LTK_OFFSET 2 //!< NV ID for the bonding records' device LTK information +#define GAP_BOND_DEV_IRK_OFFSET 3 //!< NV ID for the bonding records' device IRK +#define GAP_BOND_DEV_CSRK_OFFSET 4 //!< NV ID for the bonding records' device CSRK +#define GAP_BOND_DEV_SIGN_COUNTER_OFFSET 5 //!< NV ID for the bonding records' device Sign Counter + +#define GAP_BOND_REC_IDS 6 + +// Macros to calculate the index/offset in to NV space +#define calcNvID(Idx, offset) (((((Idx) * GAP_BOND_REC_IDS) + (offset))) + BLE_NVID_GAP_BOND_START) +#define mainRecordNvID(bondIdx) (calcNvID((bondIdx), GAP_BOND_REC_ID_OFFSET)) +#define localLTKNvID(bondIdx) (calcNvID((bondIdx), GAP_BOND_LOCAL_LTK_OFFSET)) +#define devLTKNvID(bondIdx) (calcNvID((bondIdx), GAP_BOND_DEV_LTK_OFFSET)) +#define devIRKNvID(bondIdx) (calcNvID((bondIdx), GAP_BOND_DEV_IRK_OFFSET)) +#define devCSRKNvID(bondIdx) (calcNvID((bondIdx), GAP_BOND_DEV_CSRK_OFFSET)) +#define devSignCounterNvID(bondIdx) (calcNvID((bondIdx), GAP_BOND_DEV_SIGN_COUNTER_OFFSET)) + +// Macros to calculate the GATT index/offset in to NV space +#define gattCfgNvID(Idx) ((Idx) + BLE_NVID_GATT_CFG_START) + +// Key Size Limits +#define MIN_ENC_KEYSIZE 7 //!< Minimum number of bytes for the encryption key +#define MAX_ENC_KEYSIZE 16 //!< Maximum number of bytes for the encryption key + +/********************************************************************* + TYPEDEFS +*/ + +// Structure of NV data for the connected device's encryption information +typedef struct +{ + uint8 LTK[KEYLEN]; // Long Term Key (LTK) + uint16 div; //lint -e754 // LTK eDiv + uint8 rand[B_RANDOM_NUM_SIZE]; // LTK random number + uint8 keySize; // LTK key size +} gapBondLTK_t; + +// Structure of NV data for the connected device's address information +typedef struct +{ + uint8 publicAddr[B_ADDR_LEN]; // Master's address + uint8 reconnectAddr[B_ADDR_LEN]; // Privacy Reconnection Address + uint16 stateFlags; // State flags: SM_AUTH_STATE_AUTHENTICATED & SM_AUTH_STATE_BONDING +} gapBondRec_t; + +// Structure of NV data for the connected device's characteristic configuration +typedef struct +{ + uint16 attrHandle; // attribute handle + uint8 value; // attribute value for this device +} gapBondCharCfg_t; + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ +static uint8 gapBondMgr_TaskID = INVALID_TASK_ID; // Task ID for internal task/event processing + +// GAPBonding Parameters +uint8 gapBond_PairingMode[MAX_NUM_LL_CONN] = {GAPBOND_PAIRING_MODE_WAIT_FOR_REQ}; +static uint16 gapBond_InitiateWait = 1000; // Default to 1 second +static uint8 gapBond_MITM = FALSE; +static uint8 gapBond_IOCap = GAPBOND_IO_CAP_DISPLAY_ONLY; +static uint8 gapBond_OOBDataFlag = FALSE; +static uint8 gapBond_OOBData[KEYLEN] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +static uint8 gapBond_Bonding = FALSE; +// 2020-04-22 support secure connection pairing +static uint8 gapBond_SC = FALSE; +static uint8 gapBond_keyPress = FALSE; +static uint8 gapBond_CT2 = FALSE; +static uint8 gapBond_AutoFail = FALSE; +static uint8 gapBond_AutoFailReason = SMP_PAIRING_FAILED_NOT_SUPPORTED; +static uint8 gapBond_KeyDistList = + ( + GAPBOND_KEYDIST_SENCKEY // sEncKey enabled, to send the encryption key + | GAPBOND_KEYDIST_SIDKEY // sIdKey enabled, to send the IRK, and BD_ADDR + | GAPBOND_KEYDIST_SSIGN // sSign enabled, to send the CSRK + | GAPBOND_KEYDIST_MENCKEY // mEncKey enabled, to get the master's encryption key + | GAPBOND_KEYDIST_MIDKEY // mIdKey enabled, to get the master's IRK and BD_ADDR + | GAPBOND_KEYDIST_MSIGN // mSign enabled, to get the master's CSRK + ); +static uint32 gapBond_Passcode = 0; +static uint8 gapBond_KeySize = MAX_ENC_KEYSIZE; +#if (GAP_BOND_MGR_INDEX_REPLACE) + static uint8 bondReplaceCnt=0; +#endif +#if ( HOST_CONFIG & CENTRAL_CFG ) + static uint8 gapBond_BondFailOption = GAPBOND_FAIL_TERMINATE_LINK; +#endif + +static const gapBondCBs_t* pGapBondCB = NULL; + +// Local RAM shadowed bond records +static gapBondRec_t bonds[GAP_BONDINGS_MAX] = {0}; + +static uint8 autoSyncWhiteList = FALSE; + +static uint8 eraseAllBonds = FALSE; + +static uint8 bondsToDelete[GAP_BONDINGS_MAX] = {FALSE}; + +// Globals used for saving bond record and CCC values in NV +static uint8 bondIdx = GAP_BONDINGS_MAX; +static gapAuthCompleteEvent_t* pAuthEvt[MAX_NUM_LL_CONN] = {NULL}; +//static gapAuthCompleteEvent_t* pAuthBond[GAP_BONDINGS_MAX] = {NULL}; + + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static uint8 gapBondMgrChangeState( uint8 idx, uint16 state, uint8 set ); +static uint8 gapBondMgrUpdateCharCfg( uint8 idx, uint16 attrHandle, uint16 value ); +static gapBondCharCfg_t* gapBondMgrFindCharCfgItem( uint16 attrHandle, + gapBondCharCfg_t* charCfgTbl ); +static void gapBondMgrInvertCharCfgItem( gapBondCharCfg_t* charCfgTbl ); +static uint8 gapBondMgrAddBond( gapBondRec_t* pBondRec, gapAuthCompleteEvent_t* pPkt ); +static uint8 gapBondMgrGetStateFlags( uint8 idx ); +static bStatus_t gapBondMgrGetPublicAddr( uint8 idx, uint8* pAddr ); +static uint8 gapBondMgrFindReconnectAddr( uint8* pReconnectAddr ); +static uint8 gapBondMgrFindAddr( uint8* pDevAddr ); +static uint8 gapBondMgrResolvePrivateAddr( uint8* pAddr ); +static void gapBondMgrReadBonds( void ); +static uint8 gapBondMgrFindEmpty( void ); +static uint8 gapBondMgrBondTotal( void ); +static bStatus_t gapBondMgrEraseAllBondings( void ); +static bStatus_t gapBondMgrEraseBonding( uint8 idx ); +static uint8 gapBondMgr_ProcessOSALMsg( osal_event_hdr_t* pMsg ); +static void gapBondMgrSendServiceChange( linkDBItem_t* pLinkItem ); +static void gapBondMgr_ProcessGATTMsg( gattMsgEvent_t* pMsg ); +static void gapBondMgr_ProcessGATTServMsg( gattEventHdr_t* pMsg ); +static void gapBondSetupPrivFlag( void ); +static void gapBondMgrBondReq( uint16 connHandle, uint8 idx, uint8 stateFlags, + uint8 role, uint8 startEncryption ); +static void gapBondMgrAuthenticate( uint16 connHandle, uint8 addrType, + gapPairingReq_t* pPairReq ); +static void gapBondMgr_SyncWhiteList( void ); +static uint8 gapBondMgr_SyncCharCfg( uint16 connHandle ); +static void gapBondFreeAuthEvt( uint16 connHandle ); + +static void gapBondRecvEvt(uint16 connHandle,gapBondRec_t* pBondRec, gapAuthCompleteEvent_t* pPkt ); + +#if ( HOST_CONFIG & PERIPHERAL_CFG ) + static void gapBondMgrSlaveSecurityReq( uint16 connHandle ); +#endif + +/********************************************************************* + NETWORK LAYER CALLBACKS +*/ + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/********************************************************************* + @brief Set a GAP Bond Manager parameter. + + Public function defined in gapbondmgr.h. +*/ +bStatus_t GAPBondMgr_SetParameter( uint16 param, uint8 len, void* pValue ) +{ + bStatus_t ret = SUCCESS; // return value + + switch ( param ) + { + case GAPBOND_PAIRING_MODE: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= GAPBOND_PAIRING_MODE_INITIATE) ) + { +// gapBond_PairingMode = *((uint8*)pValue); + osal_memset(gapBond_PairingMode,*((uint8*)pValue),sizeof(gapBond_PairingMode)); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPBOND_INITIATE_WAIT: + if ( len == sizeof ( uint16 ) ) + { + gapBond_InitiateWait = *((uint16*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPBOND_MITM_PROTECTION: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= TRUE) ) + { + gapBond_MITM = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPBOND_IO_CAPABILITIES: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= GAPBOND_IO_CAP_KEYBOARD_DISPLAY) ) + { + gapBond_IOCap = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPBOND_OOB_ENABLED: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= TRUE) ) + { + gapBond_OOBDataFlag = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPBOND_OOB_DATA: + if ( len == KEYLEN ) + { + VOID osal_memcpy( gapBond_OOBData, pValue, KEYLEN ) ; + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPBOND_BONDING_ENABLED: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= TRUE) ) + { + gapBond_Bonding = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPBOND_KEY_DIST_LIST: + if ( len == sizeof ( uint8 ) ) + { + gapBond_KeyDistList = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPBOND_DEFAULT_PASSCODE: + if ( (len == sizeof ( uint32 )) + && (*((uint32*)pValue) <= GAP_PASSCODE_MAX) ) + { + gapBond_Passcode = *((uint32*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPBOND_ERASE_ALLBONDS: + if ( len == 0 ) + { + // Make sure there's no active connection + if ( GAP_NumActiveConnections() == 0 ) + { + // Erase all bonding records + VOID gapBondMgrEraseAllBondings(); + // See if NV needs a compaction + VOID osal_snv_compact( NV_COMPACT_THRESHOLD ); + // Make sure Bond RAM Shadow is up-to-date + gapBondMgrReadBonds(); + } + else + { + eraseAllBonds = TRUE; + } + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPBOND_ERASE_SINGLEBOND: + if ( len == (1 + B_ADDR_LEN) ) + { + uint8 idx; + uint8 devAddr[B_ADDR_LEN]; + // Reverse bytes + VOID osal_revmemcpy( devAddr, (uint8*)pValue+1, B_ADDR_LEN ); + // Resolve address and find index + idx = GAPBondMgr_ResolveAddr( *((uint8*)pValue), devAddr, NULL ); + + if ( idx < GAP_BONDINGS_MAX ) + { + // Make sure there's no active connection + if ( GAP_NumActiveConnections() == 0 ) + { + // Erase bond + gapBondMgrEraseBonding( idx ); + // See if NV needs a compaction + VOID osal_snv_compact( NV_COMPACT_THRESHOLD ); + // Make sure Bond RAM Shadow is up-to-date + gapBondMgrReadBonds(); + } + else + { + // Mark entry to be deleted when disconnected + bondsToDelete[idx] = TRUE; + } + } + else + { + ret = INVALIDPARAMETER; + } + } + else + { + // Parameter is not the correct length + ret = bleInvalidRange; + } + + break; + + case GAPBOND_AUTO_FAIL_PAIRING: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= TRUE) ) + { + gapBond_AutoFail = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPBOND_AUTO_FAIL_REASON: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= SMP_PAIRING_FAILED_REPEATED_ATTEMPTS) ) + { + gapBond_AutoFailReason = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPBOND_KEYSIZE: + if ( (len == sizeof ( uint8 )) + && ((*((uint8*)pValue) >= MIN_ENC_KEYSIZE) && (*((uint8*)pValue) <= MAX_ENC_KEYSIZE)) ) + { + gapBond_KeySize = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPBOND_AUTO_SYNC_WL: + if ( len == sizeof( uint8 ) ) + { + uint8 oldVal = autoSyncWhiteList; + autoSyncWhiteList = *((uint8*)pValue); + + // only call if parameter changes from FALSE to TRUE + if ( ( oldVal == FALSE ) && ( autoSyncWhiteList == TRUE ) ) + { + // make sure bond is updated from NV + gapBondMgrReadBonds(); + } + } + else + { + ret = bleInvalidRange; + } + + break; + #if ( HOST_CONFIG & CENTRAL_CFG ) + + case GAPBOND_BOND_FAIL_ACTION: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= GAPBOND_FAIL_TERMINATE_ERASE_BONDS) ) + { + gapBond_BondFailOption = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + #endif + + default: + + // The param value isn't part of this profile, try the GAP. + if ( (param < TGAP_PARAMID_MAX) && (len == sizeof ( uint16 )) ) + { + ret = GAP_SetParamValue( param, *((uint16*)pValue) ); + } + else + { + ret = INVALIDPARAMETER; + } + + break; + } + + return ( ret ); +} + +/********************************************************************* + @brief Get a GAP Bond Manager parameter. + + Public function defined in gapbondmgr.h. +*/ +bStatus_t GAPBondMgr_GetParameter( uint16 param, void* pValue ) +{ + bStatus_t ret = SUCCESS; // return value + + switch ( param ) + { + case GAPBOND_PAIRING_MODE: +// *((uint8*)pValue) = gapBond_PairingMode; + break; + + case GAPBOND_INITIATE_WAIT: + *((uint16*)pValue) = gapBond_InitiateWait; + break; + + case GAPBOND_MITM_PROTECTION: + *((uint8*)pValue) = gapBond_MITM; + break; + + case GAPBOND_IO_CAPABILITIES: + *((uint8*)pValue) = gapBond_IOCap; + break; + + case GAPBOND_OOB_ENABLED: + *((uint8*)pValue) = gapBond_OOBDataFlag; + break; + + case GAPBOND_OOB_DATA: + VOID osal_memcpy( pValue, gapBond_OOBData, KEYLEN ) ; + break; + + case GAPBOND_BONDING_ENABLED: + *((uint8*)pValue) = gapBond_Bonding; + break; + + case GAPBOND_KEY_DIST_LIST: + *((uint8*)pValue) = gapBond_KeyDistList; + break; + + case GAPBOND_DEFAULT_PASSCODE: + *((uint32*)pValue) = gapBond_Passcode; + break; + + case GAPBOND_AUTO_FAIL_PAIRING: + *((uint8*)pValue) = gapBond_AutoFail; + break; + + case GAPBOND_AUTO_FAIL_REASON: + *((uint8*)pValue) = gapBond_AutoFailReason; + break; + + case GAPBOND_KEYSIZE: + *((uint8*)pValue) = gapBond_KeySize; + break; + + case GAPBOND_AUTO_SYNC_WL: + *((uint8*)pValue) = autoSyncWhiteList; + break; + + case GAPBOND_BOND_COUNT: + *((uint8*)pValue) = gapBondMgrBondTotal(); + break; + + default: + + // The param value isn't part of this profile, try the GAP. + if ( param < TGAP_PARAMID_MAX ) + { + *((uint16*)pValue) = GAP_GetParamValue( param ); + } + else + { + ret = INVALIDPARAMETER; + } + + break; + } + + return ( ret ); +} + +/********************************************************************* + @brief Notify the Bond Manager that a connection has been made. + + Public function defined in gapbondmgr.h. +*/ +bStatus_t GAPBondMgr_LinkEst( uint8 addrType, uint8* pDevAddr, uint16 connHandle, uint8 role ) +{ + uint8 idx; // NV Index + uint8 publicAddr[B_ADDR_LEN] // Place to put the public address + = {0, 0, 0, 0, 0, 0}; + idx = GAPBondMgr_ResolveAddr( addrType, pDevAddr, publicAddr ); + + if ( idx < GAP_BONDINGS_MAX ) + { + uint8 stateFlags = gapBondMgrGetStateFlags( idx ); + smSigningInfo_t signingInfo; + gapBondCharCfg_t charCfg[GAP_CHAR_CFG_MAX]; // Space to read a char cfg record from NV + // On peripheral, load the key information for the bonding + // On central and initiaiting security, load key to initiate encyption +// gapBondMgrBondReq( connHandle, idx, stateFlags, role, +// ((gapBond_PairingMode[connHandle] == GAPBOND_PAIRING_MODE_INITIATE ) ? TRUE : FALSE) ); + // bugfix : for multi-role , because GAP_Bond gapProfileRole & central to initiate bond request + // if slave , shall not send bond request + gapBondMgrBondReq( connHandle, idx, stateFlags, role, + ((role == GAP_PROFILE_CENTRAL ) ? TRUE : FALSE) ); + // Load the Signing Key + VOID osal_memset( &signingInfo, 0, sizeof ( smSigningInfo_t ) ); + + if ( osal_snv_read( devCSRKNvID(idx), KEYLEN, signingInfo.srk ) == SUCCESS ) + { + if ( osal_isbufset( signingInfo.srk, 0xFF, KEYLEN ) == FALSE ) + { + // Load the signing information for this connection + VOID osal_snv_read( devSignCounterNvID(idx), sizeof ( uint32 ), &(signingInfo.signCounter) ); + VOID GAP_Signable( connHandle, + ((stateFlags & GAP_BONDED_STATE_AUTHENTICATED) ? TRUE : FALSE), + &signingInfo ); + } + } + + // Load the characteristic configuration + if ( osal_snv_read( gattCfgNvID(idx), sizeof ( charCfg ), charCfg ) == SUCCESS ) + { + gapBondMgrInvertCharCfgItem( charCfg ); + + for ( uint8 i = 0; i < GAP_CHAR_CFG_MAX; i++ ) + { + gapBondCharCfg_t* pItem = &(charCfg[i]); + + // Apply the characteristic configuration for this connection + if ( pItem->attrHandle != GATT_INVALID_HANDLE ) + { + VOID GATTServApp_UpdateCharCfg( connHandle, pItem->attrHandle, + (uint16)(pItem->value) ); + } + } + } + + // Has there been a service change? + if ( stateFlags & GAP_BONDED_STATE_SERVICE_CHANGED ) + { + VOID GATTServApp_SendServiceChangedInd( connHandle, gapBondMgr_TaskID ); + } + } + + #if ( HOST_CONFIG & CENTRAL_CFG ) + else if ( role == GAP_PROFILE_CENTRAL && + gapBond_PairingMode[connHandle] == GAPBOND_PAIRING_MODE_INITIATE ) + { + // If Central and initiating and not bonded, then initiate pairing + gapBondMgrAuthenticate( connHandle, addrType, NULL ); + + // Call app state callback + if ( pGapBondCB && pGapBondCB->pairStateCB ) + { + pGapBondCB->pairStateCB( connHandle, GAPBOND_PAIRING_STATE_STARTED, SUCCESS ); + } + } + + #endif + #if ( HOST_CONFIG & PERIPHERAL_CFG ) + + // If Peripheral and initiating, send a slave security request to + // initiate either pairing or encryption + if ( role == GAP_PROFILE_PERIPHERAL && + gapBond_PairingMode[connHandle] == GAPBOND_PAIRING_MODE_INITIATE ) + { + gapBondMgrSlaveSecurityReq( connHandle ); + } + + #endif + return ( SUCCESS ); +} + +/********************************************************************* + @brief Resolve an address from bonding information. + + Public function defined in gapbondmgr.h. +*/ +uint8 GAPBondMgr_ResolveAddr( uint8 addrType, uint8* pDevAddr, uint8* pResolvedAddr ) +{ + uint8 idx = GAP_BONDINGS_MAX; + + switch ( addrType ) + { + case ADDRTYPE_PUBLIC: + case ADDRTYPE_STATIC: + idx = gapBondMgrFindAddr( pDevAddr ); + + if ( (idx < GAP_BONDINGS_MAX) && (pResolvedAddr) ) + { + VOID osal_memcpy( pResolvedAddr, pDevAddr, B_ADDR_LEN ); + } + + break; + + case ADDRTYPE_PRIVATE_NONRESOLVE: + // This could be a reconnection address + idx = gapBondMgrFindReconnectAddr( pDevAddr ); + + if ( (idx < GAP_BONDINGS_MAX) && (pResolvedAddr) ) + { + VOID gapBondMgrGetPublicAddr( idx, pResolvedAddr ); + } + + break; + + case ADDRTYPE_PRIVATE_RESOLVE: + // Master's don't use Private Resolvable addresses but just in case + idx = gapBondMgrResolvePrivateAddr( pDevAddr ); + + if ( (idx < GAP_BONDINGS_MAX) && (pResolvedAddr) ) + { + VOID gapBondMgrGetPublicAddr( idx, pResolvedAddr ); + } + + break; + + default: + break; + } + + return ( idx ); +} + +/********************************************************************* + @brief Set/clear the service change indication in a bond record. + + Public function defined in gapbondmgr.h. +*/ +bStatus_t GAPBondMgr_ServiceChangeInd( uint16 connectionHandle, uint8 setParam ) +{ + bStatus_t ret = bleNoResources; // return value + + if ( connectionHandle == 0xFFFF ) + { + uint8 idx; // loop counter + + // Run through the bond database and update the Service Change indication + for ( idx = 0; idx < GAP_BONDINGS_MAX; idx++ ) + { + if ( gapBondMgrChangeState( idx, GAP_BONDED_STATE_SERVICE_CHANGED, setParam ) ) + { + ret = SUCCESS; + } + } + + // If the service change indication is TRUE, tell the connected devices + if ( setParam ) + { + // Run connected database + linkDB_PerformFunc( gapBondMgrSendServiceChange ); + } + } + else + { + // Find connection information + linkDBItem_t* pLinkItem = linkDB_Find( connectionHandle ); + + if ( pLinkItem ) + { + uint8 idx; // loop counter + idx = GAPBondMgr_ResolveAddr( pLinkItem->addrType, pLinkItem->addr, NULL ); + + if ( idx < GAP_BONDINGS_MAX ) + { + // Bond found, update it. + VOID gapBondMgrChangeState( idx, GAP_BONDED_STATE_SERVICE_CHANGED, setParam ); + ret = SUCCESS; + } + + // If the service change indication is TRUE, tell the connected device + if ( setParam ) + { + gapBondMgrSendServiceChange( pLinkItem ); + } + } + else + { + ret = bleNotConnected; + } + } + + return ( ret ); +} + +/********************************************************************* + @brief Update the Characteristic Configuration in a bond record. + + Public function defined in gapbondmgr.h. +*/ +bStatus_t GAPBondMgr_UpdateCharCfg( uint16 connectionHandle, uint16 attrHandle, uint16 value ) +{ + bStatus_t ret = bleNoResources; // return value + + if ( connectionHandle == INVALID_CONNHANDLE ) + { + uint8 idx; // loop counter + + // Run through the bond database and update the Characteristic Configuration + for ( idx = 0; idx < GAP_BONDINGS_MAX; idx++ ) + { + if ( gapBondMgrUpdateCharCfg( idx, attrHandle, value ) ) + { + ret = SUCCESS; + } + } + } + else + { + // Find connection information + linkDBItem_t* pLinkItem = linkDB_Find( connectionHandle ); + + if ( pLinkItem ) + { + uint8 idx = GAPBondMgr_ResolveAddr( pLinkItem->addrType, pLinkItem->addr, NULL ); + + if ( idx < GAP_BONDINGS_MAX ) + { + // Bond found, update it. + VOID gapBondMgrUpdateCharCfg( idx, attrHandle, value ); + ret = SUCCESS; + } + } + else + { + ret = bleNotConnected; + } + } + + return ( ret ); +} + +/********************************************************************* + @brief Register callback functions with the bond manager. + + Public function defined in gapbondmgr.h. +*/ +void GAPBondMgr_Register( gapBondCBs_t* pCB ) +{ + pGapBondCB = pCB; + + if(gapBondMgr_TaskID != INVALID_TASK_ID) + { + // Take over the processing of Authentication messages + VOID GAP_SetParamValue( TGAP_AUTH_TASK_ID, gapBondMgr_TaskID ); + // Register with GATT Server App for event messages + GATTServApp_RegisterForMsg( gapBondMgr_TaskID ); + } +} + +/********************************************************************* + @brief Respond to a passcode request. + + Public function defined in gapbondmgr.h. +*/ +bStatus_t GAPBondMgr_PasscodeRsp( uint16 connectionHandle, uint8 status, uint32 passcode ) +{ + bStatus_t ret = SUCCESS; + + if ( status == SUCCESS ) + { + // Truncate the passcode + passcode = passcode % (GAP_PASSCODE_MAX + 1); + ret = GAP_PasscodeUpdate( passcode, connectionHandle ); + + if ( ret != SUCCESS ) + { + VOID GAP_TerminateAuth( connectionHandle, SMP_PAIRING_FAILED_PASSKEY_ENTRY_FAILED ); + } + } + else + { + VOID GAP_TerminateAuth( connectionHandle, status ); + } + + return ret; +} + +/********************************************************************* + @brief This is a bypass mechanism to allow the bond manager to process + GAP messages. + + Public function defined in gapbondmgr.h. +*/ +uint8 GAPBondMgr_ProcessGAPMsg( gapEventHdr_t* pMsg ) +{ + switch ( pMsg->opcode ) + { + case GAP_PASSKEY_NEEDED_EVENT: + { + gapPasskeyNeededEvent_t* pPkt = (gapPasskeyNeededEvent_t*)pMsg; + + if ( pGapBondCB && pGapBondCB->passcodeCB ) + { + // Ask app for a passcode + pGapBondCB->passcodeCB( pPkt->deviceAddr, pPkt->connectionHandle, pPkt->uiInputs, pPkt->uiOutputs ); + } + else + { + // No app support, use the default passcode + if ( GAP_PasscodeUpdate( gapBond_Passcode, pPkt->connectionHandle ) != SUCCESS ) + { + VOID GAP_TerminateAuth( pPkt->connectionHandle, SMP_PAIRING_FAILED_PASSKEY_ENTRY_FAILED ); + } + } + } + break; + + case GAP_AUTHENTICATION_COMPLETE_EVENT: + { + gapAuthCompleteEvent_t* pPkt = (gapAuthCompleteEvent_t*)pMsg; + + // Should we save bonding information (one save at a time) + if ( (pPkt->hdr.status == SUCCESS) && + (pPkt->authState & SM_AUTH_STATE_BONDING) && + (pAuthEvt[pPkt->connectionHandle] == NULL) ) + { + gapBondRec_t bondRec; + VOID osal_memset( &bondRec, 0, sizeof ( gapBondRec_t ) ) ; + + // Do we have a public address in the data? + if ( pPkt->pIdentityInfo ) + { + VOID osal_memcpy( bondRec.publicAddr, pPkt->pIdentityInfo->bd_addr, B_ADDR_LEN ); + } + else + { + linkDBItem_t* pLinkItem = linkDB_Find( pPkt->connectionHandle ); + + if ( pLinkItem ) + { + VOID osal_memcpy( bondRec.publicAddr, pLinkItem->addr, B_ADDR_LEN ); + } + else + { + // We don't have an address, so ignore the message. + break; + } + } + + // Save off of the authentication state + bondRec.stateFlags |= (pPkt->authState & SM_AUTH_STATE_AUTHENTICATED) ? GAP_BONDED_STATE_AUTHENTICATED : 0; + + if ( !gapBondMgrAddBond( &bondRec, pPkt ) ) + { + // Notify our task to save bonding information in NV + gapBondRecvEvt( pPkt->connectionHandle,&bondRec, pPkt ); +// osal_set_event( gapBondMgr_TaskID, GAP_BOND_SAVE_REC_EVT ); +// AT_LOG("osal_set_event( gapBondMgr_TaskID, GAP_BOND_SAVE_REC_EVT )\n"); + // We're not done with this message; it will be freed later + return ( FALSE ); + } + } + + // Call app state callback in the fail case. Success is handled after GAP_BOND_SAVE_REC_EVT. + if ( pGapBondCB && pGapBondCB->pairStateCB ) + { + pGapBondCB->pairStateCB( pPkt->connectionHandle, GAPBOND_PAIRING_STATE_COMPLETE, pPkt->hdr.status ); + } + } + break; + + case GAP_BOND_COMPLETE_EVENT: + // This message is received when the bonding is complete. If hdr.status is SUCCESS + // then call app state callback. If hdr.status is NOT SUCCESS, the connection will be + // dropped at the LL because of a MIC failure, so again nothing to do. + { + gapBondCompleteEvent_t* pPkt = (gapBondCompleteEvent_t*)pMsg; + #if ( HOST_CONFIG & CENTRAL_CFG ) + + if ( pPkt->hdr.status == LL_ENC_KEY_REQ_REJECTED ) + { + // LTK not found on peripheral device (Pin or Key Missing). See which + // option was configured for unsuccessful bonding. + linkDBItem_t* pLinkItem = linkDB_Find( pPkt->connectionHandle ); + + if ( pLinkItem ) + { + switch ( gapBond_BondFailOption ) + { + case GAPBOND_FAIL_INITIATE_PAIRING: + // Initiate pairing + gapBondMgrAuthenticate( pPkt->connectionHandle, pLinkItem->addrType, NULL ); + break; + + case GAPBOND_FAIL_TERMINATE_LINK: + // Drop connection + GAP_TerminateLinkReq( pLinkItem->taskID, pPkt->connectionHandle, HCI_DISCONNECT_AUTH_FAILURE ); + break; + + case GAPBOND_FAIL_TERMINATE_ERASE_BONDS: + // Set up bond manager to erase all existing bonds after connection terminates + VOID GAPBondMgr_SetParameter( GAPBOND_ERASE_ALLBONDS, 0, NULL ); + // Drop connection + GAP_TerminateLinkReq( pLinkItem->taskID, pPkt->connectionHandle, HCI_DISCONNECT_AUTH_FAILURE ); + break; + + case GAPBOND_FAIL_NO_ACTION: + + // fall through + default: + // do nothing + break; + } + } + } + + #endif + + if ( pGapBondCB && pGapBondCB->pairStateCB ) + { + pGapBondCB->pairStateCB( pPkt->connectionHandle, GAPBOND_PAIRING_STATE_BONDED, pMsg->hdr.status ); + } + } + break; + + case GAP_SIGNATURE_UPDATED_EVENT: + { + uint8 idx; + gapSignUpdateEvent_t* pPkt = (gapSignUpdateEvent_t*)pMsg; + idx = GAPBondMgr_ResolveAddr( pPkt->addrType, pPkt->devAddr, NULL ); + + if ( idx < GAP_BONDINGS_MAX ) + { + // Save the sign counter + VOID osal_snv_write( devSignCounterNvID(idx), sizeof ( uint32 ), &(pPkt->signCounter) ); + } + } + break; + #if ( HOST_CONFIG & PERIPHERAL_CFG ) + + case GAP_PAIRING_REQ_EVENT: + { + gapPairingReqEvent_t* pPkt = (gapPairingReqEvent_t*)pMsg; + + if ( gapBond_AutoFail != FALSE ) + { + // Auto Fail TEST MODE (DON'T USE THIS) - Sends pre-setup reason + VOID GAP_TerminateAuth( pPkt->connectionHandle, gapBond_AutoFailReason ); + } + else if ( gapBond_PairingMode[pPkt->connectionHandle] == GAPBOND_PAIRING_MODE_NO_PAIRING ) + { + // No Pairing - Send error + VOID GAP_TerminateAuth( pPkt->connectionHandle, SMP_PAIRING_FAILED_NOT_SUPPORTED ); + } + else + { + linkDBItem_t* pLinkItem = linkDB_Find( pPkt->connectionHandle ); + + // Requesting bonding? + if ( pPkt->pairReq.authReq & SM_AUTH_STATE_BONDING ) + { + if ( pLinkItem ) + { + if ( (pLinkItem->addrType != ADDRTYPE_PUBLIC) && (pPkt->pairReq.keyDist.mIdKey == FALSE) ) + { + uint8 publicAddr[B_ADDR_LEN]; + + // Check if we already have the public address in NV + if ( GAPBondMgr_ResolveAddr(pLinkItem->addrType, pLinkItem->addr, publicAddr ) == FALSE ) + { + // Can't bond to a non-public address if we don't know the public address + VOID GAP_TerminateAuth( pPkt->connectionHandle, SMP_PAIRING_FAILED_AUTH_REQ ); + break; + } + } + } + else + { + // Can't find the connection, ignore the message + break; + } + } + + // Send pairing response + gapBondMgrAuthenticate( pPkt->connectionHandle, pLinkItem->addrType, &(pPkt->pairReq) ); + + // Call app state callback + if ( pGapBondCB && pGapBondCB->pairStateCB ) + { + pGapBondCB->pairStateCB( pPkt->connectionHandle, GAPBOND_PAIRING_STATE_STARTED, SUCCESS ); + } + } + } + break; + #endif + #if ( HOST_CONFIG & CENTRAL_CFG ) + + case GAP_SLAVE_REQUESTED_SECURITY_EVENT: + { + uint16 connHandle = ((gapSlaveSecurityReqEvent_t*)pMsg)->connectionHandle; + uint8 idx; + uint8 publicAddr[B_ADDR_LEN] = {0, 0, 0, 0, 0, 0}; + linkDBItem_t* pLink = linkDB_Find( connHandle ); + + // If link found and not already initiating security + if (pLink != NULL && gapBond_PairingMode[connHandle] != GAPBOND_PAIRING_MODE_INITIATE) + { + // If already bonded initiate encryption + idx = GAPBondMgr_ResolveAddr( pLink->addrType, pLink->addr, publicAddr ); + + if ( idx < GAP_BONDINGS_MAX ) + { + gapBondMgrBondReq( connHandle, idx, gapBondMgrGetStateFlags( idx ), + GAP_PROFILE_CENTRAL, TRUE ); + } + else if ( gapBond_PairingMode[connHandle] == GAPBOND_PAIRING_MODE_NO_PAIRING ) + { + VOID GAP_TerminateAuth( connHandle, SMP_PAIRING_FAILED_NOT_SUPPORTED ); + } + else if (gapBond_PairingMode[connHandle] == GAPBOND_PAIRING_MODE_WAIT_FOR_REQ) + { + gapBondMgrAuthenticate( connHandle, pLink->addrType, NULL ); + } + } + } + break; + #endif + + case GAP_LINK_TERMINATED_EVENT: + { +// gapTerminateLinkEvent_t* pPkt = (gapTerminateLinkEvent_t*)pMsg; +// gapAuthCompleteEvent_t* pAuthEvtTmp = NULL; + if ( GAP_NumActiveConnections() == 0 ) + { + // See if we're asked to erase all bonding records + if ( eraseAllBonds == TRUE ) + { + VOID gapBondMgrEraseAllBondings(); + eraseAllBonds = FALSE; + // Reset bonds to delete table + osal_memset( bondsToDelete, FALSE, sizeof( bondsToDelete ) ); + } + // See if we're asked to erase all bonding records + // Reset bonds to delete table + else + { + // See if we're asked to erase any single bonding records + for (uint8 idx = 0; idx < GAP_BONDINGS_MAX; idx++) + { + if ( bondsToDelete[idx] == TRUE ) + { + VOID gapBondMgrEraseBonding( idx ); + bondsToDelete[idx] = FALSE; + } + } + } + + // See if NV needs a compaction + VOID osal_snv_compact( NV_COMPACT_THRESHOLD ); + // Make sure Bond RAM Shadow is up-to-date + // Make sure Bond RAM Shadow is up-to-date + gapBondMgrReadBonds(); + } + } + break; + + default: + break; + } + + return ( TRUE ); +} + +/********************************************************************* + LOCAL FUNCTION PROTOTYPES +*/ + +/********************************************************************* + @fn gapBondMgrChangeState + + @brief Change a state flag in the stateFlags field of the bond record. + + @param idx - Bond NV index + @param state - state flage to set or clear + @param set - TRUE to set the flag, FALSE to clear the flag + + @return TRUE if NV Record exists, FALSE if NV Record is empty +*/ +static uint8 gapBondMgrChangeState( uint8 idx, uint16 state, uint8 set ) +{ + gapBondRec_t bondRec; // Space to read a Bond record from NV + + // Look for public address that is used (not all 0xFF's) + if ( (osal_snv_read( mainRecordNvID(idx), sizeof ( gapBondRec_t ), &bondRec ) == SUCCESS) + && (osal_isbufset( bondRec.publicAddr, 0xFF, B_ADDR_LEN ) == FALSE) ) + { + // Update the state of the bonded device. + uint8 stateFlags = bondRec.stateFlags; + + if ( set ) + { + stateFlags |= state; + } + else + { + stateFlags &= ~(state); + } + + if ( stateFlags != bondRec.stateFlags ) + { + bondRec.stateFlags = stateFlags; + VOID osal_snv_write( mainRecordNvID(idx), sizeof ( gapBondRec_t ), &bondRec ); + } + + return ( TRUE ); + } + + return ( FALSE ); +} + +/********************************************************************* + @fn gapBondMgrUpdateCharCfg + + @brief Update the Characteristic Configuration of the bond record. + + @param idx - Bond NV index + @param attrHandle - attribute handle (0 means all handles) + @param value - characteristic configuration value + + @return TRUE if NV Record exists, FALSE if NV Record is empty +*/ +static uint8 gapBondMgrUpdateCharCfg( uint8 idx, uint16 attrHandle, uint16 value ) +{ + gapBondRec_t bondRec; // Space to read a Bond record from NV + + // Look for public address that is used (not all 0xFF's) + if ( ( osal_snv_read( mainRecordNvID(idx), sizeof ( gapBondRec_t ), &bondRec ) == SUCCESS ) + && ( osal_isbufset( bondRec.publicAddr, 0xFF, B_ADDR_LEN ) == FALSE ) ) + { + gapBondCharCfg_t charCfg[GAP_CHAR_CFG_MAX]; // Space to read a char cfg record from NV + + if ( osal_snv_read( gattCfgNvID(idx), sizeof ( charCfg ), charCfg ) == SUCCESS ) + { + uint8 update = FALSE; + gapBondMgrInvertCharCfgItem( charCfg ); + + if ( attrHandle == GATT_INVALID_HANDLE ) + { + if ( osal_isbufset( (uint8*)charCfg, 0x00, sizeof ( charCfg ) ) == FALSE ) + { + // Clear all characteristic configuration for this device + VOID osal_memset( (void*)charCfg, 0x00, sizeof ( charCfg ) ); + update = TRUE; + } + } + else + { + gapBondCharCfg_t* pItem = gapBondMgrFindCharCfgItem( attrHandle, charCfg ); + + if ( pItem == NULL ) + { + // Must be a new item; ignore if the value is no operation (default) + if ( ( value == GATT_CFG_NO_OPERATION ) || + ( ( pItem = gapBondMgrFindCharCfgItem( GATT_INVALID_HANDLE, charCfg ) ) == NULL ) ) + { + return ( FALSE ); // No empty entry found + } + + pItem->attrHandle = attrHandle; + } + + if ( pItem->value != value ) + { + // Update characteristic configuration + pItem->value = (uint8)value; + + if ( value == GATT_CFG_NO_OPERATION ) + { + // Erease the item + pItem->attrHandle = GATT_INVALID_HANDLE; + } + + update = TRUE; + } + } + + // Update the characteristic configuration of the bonded device. + if ( update ) + { + gapBondMgrInvertCharCfgItem( charCfg ); + VOID osal_snv_write( gattCfgNvID(idx), sizeof( charCfg ), charCfg ); + } + } + + return ( TRUE ); + } + + return ( FALSE ); +} + +/********************************************************************* + @fn gapBondMgrFindCharCfgItem + + @brief Find the Characteristic Configuration for a given attribute. + Uses the attribute handle to search the charactersitic + configuration table of a bonded device. + + @param attrHandle - attribute handle. + @param charCfgTbl - characteristic configuration table. + + @return pointer to the found item. NULL, otherwise. +*/ +static gapBondCharCfg_t* gapBondMgrFindCharCfgItem( uint16 attrHandle, + gapBondCharCfg_t* charCfgTbl ) +{ + for ( uint8 i = 0; i < GAP_CHAR_CFG_MAX; i++ ) + { + if ( charCfgTbl[i].attrHandle == attrHandle ) + { + return ( &(charCfgTbl[i]) ); + } + } + + return ( (gapBondCharCfg_t*)NULL ); +} + +/********************************************************************* + @fn gapBondMgrFindCharCfgItem + + @brief Invert the Characteristic Configuration for a given client. + + @param charCfgTbl - characteristic configuration table. + + @return none. +*/ +static void gapBondMgrInvertCharCfgItem( gapBondCharCfg_t* charCfgTbl ) +{ + for ( uint8 i = 0; i < GAP_CHAR_CFG_MAX; i++ ) + { + charCfgTbl[i].attrHandle = ~(charCfgTbl[i].attrHandle); + charCfgTbl[i].value = ~(charCfgTbl[i].value); + } +} + +/********************************************************************* + @fn gapBondMgrAddBond + + @brief Save a bond from a GAP Auth Complete Event + + @param pBondRec - basic bond record + @param pLocalLTK - LTK used by this device during pairing + @param pDevLTK - LTK used by the connected device during pairing + @param pIRK - IRK used by the connected device during pairing + @param pSRK - SRK used by the connected device during pairing + @param signCounter - Sign counter used by the connected device during pairing + + @return TRUE, if done processing bond record. FALSE, otherwise. +*/ +static uint8 gapBondMgrAddBond( gapBondRec_t* pBondRec, gapAuthCompleteEvent_t* pPkt ) +{ + // See if this is a new bond record + if ( pAuthEvt[pPkt->connectionHandle] == NULL ) + { + // Make sure we have bonding info + if ( ( pBondRec == NULL ) || ( pPkt == NULL ) ) + { + return ( TRUE ); + } + + // First see if we already have an existing bond for this device + bondIdx = gapBondMgrFindAddr( pBondRec->publicAddr ); + + if ( bondIdx >= GAP_BONDINGS_MAX ) + { + bondIdx = gapBondMgrFindEmpty(); + } + + #if(GAP_BOND_MGR_INDEX_REPLACE) + + /*replace bondIdx*/ + if(bondIdx==GAP_BONDINGS_MAX) + { + bondIdx = (bondReplaceCnt++)%GAP_BONDINGS_MAX; + } + + #endif + } + + if ( bondIdx < GAP_BONDINGS_MAX ) + { + // See if this is a new bond record + if ( pAuthEvt[pPkt->connectionHandle] == NULL ) + { + gapBondCharCfg_t charCfg[GAP_CHAR_CFG_MAX]; + // Save the main information + osal_snv_write( mainRecordNvID(bondIdx), sizeof ( gapBondRec_t ), pBondRec ); + // Write out FF's over the charactersitic configuration entry, to overwrite + // any previous bond data that may have been stored + VOID osal_memset( charCfg, 0xFF, sizeof ( charCfg ) ); + VOID osal_snv_write( gattCfgNvID(bondIdx), sizeof ( charCfg ), charCfg ); + // Update Bond RAM Shadow just with the newly added bond entry + VOID osal_memcpy( &(bonds[bondIdx]), pBondRec, sizeof ( gapBondRec_t ) ); + // Keep the OSAL message to store the security keys later - will be freed then + pAuthEvt[pPkt->connectionHandle] = pPkt; + } + else + { + // If available, save the LTK information + if ( pAuthEvt[pPkt->connectionHandle]->pSecurityInfo ) + { + VOID osal_snv_write( localLTKNvID(bondIdx), sizeof ( gapBondLTK_t ), pAuthEvt[pPkt->connectionHandle]->pSecurityInfo ); + pAuthEvt[pPkt->connectionHandle]->pSecurityInfo = NULL; + } + + // If availabe, save the connected device's LTK information + if ( pAuthEvt[pPkt->connectionHandle]->pDevSecInfo ) + { + VOID osal_snv_write( devLTKNvID(bondIdx), sizeof ( gapBondLTK_t ), pAuthEvt[pPkt->connectionHandle]->pDevSecInfo ); + pAuthEvt[pPkt->connectionHandle]->pDevSecInfo = NULL; + } + + // If available, save the connected device's IRK + if ( pAuthEvt[pPkt->connectionHandle]->pIdentityInfo ) + { + VOID osal_snv_write( devIRKNvID(bondIdx), KEYLEN, pAuthEvt[pPkt->connectionHandle]->pIdentityInfo->irk ); + pAuthEvt[pPkt->connectionHandle]->pIdentityInfo = NULL; + } + + // If available, save the connected device's Signature information + if ( pAuthEvt[pPkt->connectionHandle]->pSigningInfo ) + { + VOID osal_snv_write( devCSRKNvID(bondIdx), KEYLEN, pAuthEvt[pPkt->connectionHandle]->pSigningInfo->srk ); + VOID osal_snv_write( devSignCounterNvID(bondIdx), sizeof ( uint32 ), &(pAuthEvt[pPkt->connectionHandle]->pSigningInfo->signCounter) ); + pAuthEvt[pPkt->connectionHandle]->pSigningInfo = NULL; + } + +// else + { + if ( autoSyncWhiteList ) + { + gapBondMgr_SyncWhiteList(); + } + + // Update the GAP Privacy Flag Properties + gapBondSetupPrivFlag(); + return ( TRUE ); + } + } + + // We have more info to store + return ( FALSE ); + } + + return ( TRUE ); +} + +/********************************************************************* + @fn gapBondMgrGetStateFlags + + @brief Gets the state flags field of a bond record in NV + + @param idx + + @return stateFlags field +*/ +static uint8 gapBondMgrGetStateFlags( uint8 idx ) +{ + gapBondRec_t bondRec; + + if ( osal_snv_read( mainRecordNvID(idx), sizeof ( gapBondRec_t ), &bondRec ) == SUCCESS ) + { + return ( bondRec.stateFlags ); + } + + return ( 0 ); +} + +/********************************************************************* + @fn gapBondMgrGetPublicAddr + + @brief Copy the public Address from a bonding record + + @param idx - Bond record index + @param pAddr - a place to put the public address from NV + + @return SUCCESS if successful. + Otherwise failure. +*/ +static bStatus_t gapBondMgrGetPublicAddr( uint8 idx, uint8* pAddr ) +{ + bStatus_t stat; // return value + gapBondRec_t bondRec; // Work space for main bond record + + // Check parameters + if ( (idx >= GAP_BONDINGS_MAX) || (pAddr == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + stat = osal_snv_read( mainRecordNvID(idx), sizeof ( gapBondRec_t ), &bondRec ); + + if ( stat == SUCCESS ) + { + VOID osal_memcpy( pAddr, bondRec.publicAddr, B_ADDR_LEN ); + } + + return ( stat ); +} + +/********************************************************************* + @fn gapBondMgrFindReconnectAddr + + @brief Look through the bonding entries to find a + reconnection address. + + @param pReconnectAddr - device address to look for + + @return index to found bonding (0 - (GAP_BONDINGS_MAX-1), + GAP_BONDINGS_MAX if no empty entries +*/ +static uint8 gapBondMgrFindReconnectAddr( uint8* pReconnectAddr ) +{ + // Item doesn't exist, so create all the items + for ( uint8 idx = 0; idx < GAP_BONDINGS_MAX; idx++ ) + { + // compare reconnection address + if ( osal_memcmp( bonds[idx].reconnectAddr, pReconnectAddr, B_ADDR_LEN ) ) + { + return ( idx ); // Found it + } + } + + return ( GAP_BONDINGS_MAX ); +} + +/********************************************************************* + @fn gapBondMgrFindAddr + + @brief Look through the bonding entries to find an address. + + @param pDevAddr - device address to look for + + @return index to empty bonding (0 - (GAP_BONDINGS_MAX-1), + GAP_BONDINGS_MAX if no empty entries +*/ +static uint8 gapBondMgrFindAddr( uint8* pDevAddr ) +{ + // Item doesn't exist, so create all the items + for ( uint8 idx = 0; idx < GAP_BONDINGS_MAX; idx++ ) + { + // Read in NV Main Bond Record and compare public address + if ( osal_memcmp( bonds[idx].publicAddr, pDevAddr, B_ADDR_LEN ) ) + { + return ( idx ); // Found it + } + } + + return ( GAP_BONDINGS_MAX ); +} + +/********************************************************************* + @fn gapBondMgrResolvePrivateAddr + + @brief Look through the NV bonding entries to resolve a private + address. + + @param pDevAddr - device address to look for + + @return index to found bonding (0 - (GAP_BONDINGS_MAX-1), + GAP_BONDINGS_MAX if no entry found +*/ +static uint8 gapBondMgrResolvePrivateAddr( uint8* pDevAddr ) +{ + for ( uint8 idx = 0; idx < GAP_BONDINGS_MAX; idx++ ) + { + uint8 IRK[KEYLEN]; + + // Read in NV IRK Record and compare resovable address + if ( osal_snv_read( devIRKNvID(idx), KEYLEN, IRK ) == SUCCESS ) + { + if ( ( osal_isbufset( IRK, 0xFF, KEYLEN ) == FALSE ) && + ( GAP_ResolvePrivateAddr( IRK, pDevAddr ) == SUCCESS ) ) + { + return ( idx ); // Found it + } + } + } + + return ( GAP_BONDINGS_MAX ); +} + +/********************************************************************* + @fn gapBondMgrReadBonds + + @brief Read through NV and store them in RAM. + + @param none + + @return none +*/ +static void gapBondMgrReadBonds( void ) +{ + for ( uint8 idx = 0; idx < GAP_BONDINGS_MAX; idx++ ) + { + // See if the entry exists in NV + if ( osal_snv_read( mainRecordNvID(idx), sizeof( gapBondRec_t ), &(bonds[idx]) ) != SUCCESS ) + { + // Can't read the entry, assume that it doesn't exist + VOID osal_memset( bonds[idx].publicAddr, 0xFF, B_ADDR_LEN ); + VOID osal_memset( bonds[idx].reconnectAddr, 0xFF, B_ADDR_LEN ); + bonds[idx].stateFlags = 0; + } + } + + if ( autoSyncWhiteList ) + { + gapBondMgr_SyncWhiteList(); + } + + // Update the GAP Privacy Flag Properties + gapBondSetupPrivFlag(); +} + +/********************************************************************* + @fn gapBondMgrFindEmpty + + @brief Look through the bonding NV entries to find an empty. + + @param none + + @return index to empty bonding (0 - (GAP_BONDINGS_MAX-1), + GAP_BONDINGS_MAX if no empty entries +*/ +static uint8 gapBondMgrFindEmpty( void ) +{ + // Item doesn't exist, so create all the items + for ( uint8 idx = 0; idx < GAP_BONDINGS_MAX; idx++ ) + { + // Look for public address of all 0xFF's + if ( osal_isbufset( bonds[idx].publicAddr, 0xFF, B_ADDR_LEN ) ) + { + return ( idx ); // Found one + } + } + + return ( GAP_BONDINGS_MAX ); +} + +/********************************************************************* + @fn gapBondMgrBondTotal + + @brief Look through the bonding NV entries calculate the number + entries. + + @param none + + @return total number of bonds found +*/ +static uint8 gapBondMgrBondTotal( void ) +{ + uint8 numBonds = 0; + + // Item doesn't exist, so create all the items + for ( uint8 idx = 0; idx < GAP_BONDINGS_MAX; idx++ ) + { + // Look for public address that are not 0xFF's + if ( osal_isbufset( bonds[idx].publicAddr, 0xFF, B_ADDR_LEN ) == FALSE ) + { + numBonds++; // Found one + } + } + + return ( numBonds ); +} + +/********************************************************************* + @fn gapBondMgrEraseAllBondings + + @brief Write all 0xFF's to all of the bonding entries + + @param none + + @return SUCCESS if successful. + Otherwise, NV_OPER_FAILED for failure. +*/ +static bStatus_t gapBondMgrEraseAllBondings( void ) +{ + bStatus_t stat = SUCCESS; // return value + + // Item doesn't exist, so create all the items + for ( uint8 idx = 0; (idx < GAP_BONDINGS_MAX) && (stat == SUCCESS); idx++ ) + { + // Erasing will write/create a bonding entry + stat = gapBondMgrEraseBonding( idx ); + } + + return ( stat ); +} + +/********************************************************************* + @fn gapBondMgrEraseBonding + + @brief Write all 0xFF's to the complete bonding record + + @param idx - bonding index + + @return SUCCESS if successful. + Otherwise, NV_OPER_FAILED for failure. +*/ +static bStatus_t gapBondMgrEraseBonding( uint8 idx ) +{ + bStatus_t ret; + gapBondRec_t bondRec; + + if ( idx == bondIdx ) + { + // Stop ongoing bond store process to prevent any invalid data be written. +// osal_clear_event( gapBondMgr_TaskID, GAP_BOND_SYNC_CC_EVT ); +// osal_clear_event( gapBondMgr_TaskID, GAP_BOND_SAVE_REC_EVT ); +// gapBondFreeAuthEvt(); + } + + // First see if bonding record exists in NV, then write all 0xFF's to it + if ( ( osal_snv_read( mainRecordNvID(idx), sizeof ( gapBondRec_t ), &bondRec ) == SUCCESS ) + && (osal_isbufset( bondRec.publicAddr, 0xFF, B_ADDR_LEN ) == FALSE) ) + { + gapBondLTK_t ltk; + gapBondCharCfg_t charCfg[GAP_CHAR_CFG_MAX]; + VOID osal_memset( &bondRec, 0xFF, sizeof ( gapBondRec_t ) ); + VOID osal_memset( <k, 0xFF, sizeof ( gapBondLTK_t ) ); + VOID osal_memset( charCfg, 0xFF, sizeof ( charCfg ) ); + // Write out FF's over the entire bond entry. + ret = osal_snv_write( mainRecordNvID(idx), sizeof ( gapBondRec_t ), &bondRec ); + ret |= osal_snv_write( localLTKNvID(idx), sizeof ( gapBondLTK_t ), <k ); + ret |= osal_snv_write( devLTKNvID(idx), sizeof ( gapBondLTK_t ), <k ); + ret |= osal_snv_write( devIRKNvID(idx), KEYLEN, ltk.LTK ); + ret |= osal_snv_write( devCSRKNvID(idx), KEYLEN, ltk.LTK ); + ret |= osal_snv_write( devSignCounterNvID(idx), sizeof ( uint32 ), ltk.LTK ); + // Write out FF's over the charactersitic configuration entry. + ret |= osal_snv_write( gattCfgNvID(idx), sizeof ( charCfg ), charCfg ); + } + else + { + ret = SUCCESS; + } + + return ( ret ); +} + +/********************************************************************* + @brief Task Initialization function. + + Internal function defined in gapbondmgr.h. +*/ +void GAPBondMgr_Init( uint8 task_id ) +{ + gapBondMgr_TaskID = task_id; // Save task ID + // Setup Bond RAM Shadow + gapBondMgrReadBonds(); +} + +/********************************************************************* + @brief Task Event Processor function. + + Internal function defined in gapbondmgr.h. +*/ +uint16 GAPBondMgr_ProcessEvent( uint8 task_id, uint16 events ) +{ + VOID task_id; // OSAL required parameter that isn't used in this function + + if ( events & SYS_EVENT_MSG ) + { + uint8* pMsg; + + if ( (pMsg = osal_msg_receive( gapBondMgr_TaskID )) != NULL ) + { + if ( gapBondMgr_ProcessOSALMsg( (osal_event_hdr_t*)pMsg ) ) + { + // Release the OSAL message + VOID osal_msg_deallocate( pMsg ); + } + + // return unprocessed events + } + + // return unprocessed events + return (events ^ SYS_EVENT_MSG); + } + +// if ( events & GAP_BOND_SAVE_REC_EVT ) +// { +// +// // Save bonding record in NV +// if ( gapBondMgrAddBond( NULL, NULL ) ) +// { +// // Notify our task to update NV with CCC values stored in GATT database +// osal_set_event( gapBondMgr_TaskID, GAP_BOND_SYNC_CC_EVT ); +// +// return (events ^ GAP_BOND_SAVE_REC_EVT); +// } +// +// return ( GAP_BOND_SAVE_REC_EVT ); +// } +// +// if ( events & GAP_BOND_SYNC_CC_EVT ) +// { +// // Update NV to have same CCC values as GATT database +// // Note: pAuthEvt is a global variable used for deferring the storage +// if ( gapBondMgr_SyncCharCfg( pAuthEvt->connectionHandle ) ) +// { +// if ( pGapBondCB && pGapBondCB->pairStateCB ) +// { +// // Assume SUCCESS since we got this far. +// pGapBondCB->pairStateCB( pAuthEvt->connectionHandle, GAPBOND_PAIRING_STATE_COMPLETE, SUCCESS ); +// } +// +// // We're done storing bond record and CCC values in NV +// gapBondFreeAuthEvt(); +// +// return (events ^ GAP_BOND_SYNC_CC_EVT); +// } +// +// return ( GAP_BOND_SYNC_CC_EVT ); +// } + // Discard unknown events + return 0; +} + +/********************************************************************* + @fn gapBondMgr_ProcessOSALMsg + + @brief Process an incoming task message. + + @param pMsg - message to process + + @return TRUE if safe to deallocate incoming message, FALSE otherwise. +*/ +static uint8 gapBondMgr_ProcessOSALMsg( osal_event_hdr_t* pMsg ) +{ + uint8 safeToDealloc = TRUE; + + switch ( pMsg->event ) + { + case GAP_MSG_EVENT: + safeToDealloc = GAPBondMgr_ProcessGAPMsg( (gapEventHdr_t*)pMsg ); + break; + + case GATT_MSG_EVENT: + gapBondMgr_ProcessGATTMsg( (gattMsgEvent_t*)pMsg ); + break; + + case GATT_SERV_MSG_EVENT: + gapBondMgr_ProcessGATTServMsg( (gattEventHdr_t*)pMsg ); + break; + + default: + break; + } + + return ( safeToDealloc ); +} + +/********************************************************************* + @fn GAPBondMgr_CheckNVLen + + @brief This function will check the length of an NV Item. + + @param id - NV ID. + @param len - lengths in bytes of item. + + @return SUCCESS or FAILURE +*/ +uint8 GAPBondMgr_CheckNVLen( uint8 id, uint8 len ) +{ + uint8 stat = FAILURE; + + // Convert to index + switch ( (id - BLE_NVID_GAP_BOND_START) % GAP_BOND_REC_IDS ) + { + case GAP_BOND_REC_ID_OFFSET: + if ( len == sizeof ( gapBondRec_t ) ) + { + stat = SUCCESS; + } + + break; + + case GAP_BOND_LOCAL_LTK_OFFSET: + case GAP_BOND_DEV_LTK_OFFSET: + if ( len == sizeof ( gapBondLTK_t ) ) + { + stat = SUCCESS; + } + + break; + + case GAP_BOND_DEV_IRK_OFFSET: + case GAP_BOND_DEV_CSRK_OFFSET: + if ( len == KEYLEN ) + { + stat = SUCCESS; + } + + break; + + case GAP_BOND_DEV_SIGN_COUNTER_OFFSET: + if ( len == sizeof ( uint32 ) ) + { + stat = SUCCESS; + } + + break; + + default: + break; + } + + return ( stat ); +} + +/********************************************************************* + @fn gapBondMgr_ProcessGATTMsg + + @brief Process an incoming GATT message. + + @param pMsg - pointer to received message + + @return none +*/ +static void gapBondMgr_ProcessGATTMsg( gattMsgEvent_t* pMsg ) +{ + // Process the GATT message + switch ( pMsg->method ) + { + case ATT_HANDLE_VALUE_CFM: + // Clear Service Changed flag for this client + VOID GAPBondMgr_ServiceChangeInd( pMsg->connHandle, 0x00 ); + break; + + default: + // Unknown message + break; + } +} + +/********************************************************************* + @fn gapBondMgr_ProcessGATTServMsg + + @brief Process an incoming GATT Server App message. + + @param pMsg - pointer to received message + + @return none +*/ +static void gapBondMgr_ProcessGATTServMsg( gattEventHdr_t* pMsg ) +{ + // Process the GATT Server App message + switch ( pMsg->method ) + { + case GATT_CLIENT_CHAR_CFG_UPDATED_EVENT: + { + gattClientCharCfgUpdatedEvent_t* pEvent = (gattClientCharCfgUpdatedEvent_t*)pMsg; + VOID GAPBondMgr_UpdateCharCfg( pEvent->connHandle, pEvent->attrHandle, pEvent->value ); + } + break; + + default: + // Unknown message + break; + } +} + +/********************************************************************* + @fn gapBondMgrSendServiceChange + + @brief Tell the GATT that a service change is needed. + + @param pLinkItem - pointer to connection information + + @return none +*/ +static void gapBondMgrSendServiceChange( linkDBItem_t* pLinkItem ) +{ + VOID GATTServApp_SendServiceChangedInd( pLinkItem->connectionHandle, + gapBondMgr_TaskID ); +} + +/********************************************************************* + @fn gapBondSetupPrivFlag + + @brief Setup the GAP Privacy Flag properties. + + @param none + + @return none +*/ +static void gapBondSetupPrivFlag( void ) +{ + uint8 privFlagProp; + + if ( gapBondMgrBondTotal() > 1 ) + { + privFlagProp = GATT_PROP_READ; + } + else + { + privFlagProp = GATT_PROP_READ | GATT_PROP_WRITE; + } + + // Setup the + VOID GGS_SetParameter( GGS_PERI_PRIVACY_FLAG_PROPS, sizeof ( uint8 ), &privFlagProp ); +} + +/********************************************************************* + @fn gapBondMgrAuthenticate + + @brief Initiate authentication + + @param connHandle - connection handle + @param addrType - peer address type + @param pPairReq - Enter these parameters if the Pairing Request was already received. + NULL, if waiting for Pairing Request or if initiating. + + @return none +*/ +static void gapBondMgrAuthenticate( uint16 connHandle, uint8 addrType, + gapPairingReq_t* pPairReq ) +{ + gapAuthParams_t params; + VOID osal_memset( ¶ms, 0, sizeof ( gapAuthParams_t ) ); + // Setup the pairing parameters + params.connectionHandle = connHandle; + params.secReqs.ioCaps = gapBond_IOCap; + params.secReqs.oobAvailable = gapBond_OOBDataFlag; + params.secReqs.maxEncKeySize = gapBond_KeySize; + params.secReqs.keyDist.sEncKey = (gapBond_KeyDistList & GAPBOND_KEYDIST_SENCKEY) ? TRUE : FALSE; + params.secReqs.keyDist.sIdKey = (gapBond_KeyDistList & GAPBOND_KEYDIST_SIDKEY) ? TRUE : FALSE; + params.secReqs.keyDist.mEncKey = (gapBond_KeyDistList & GAPBOND_KEYDIST_MENCKEY) ? TRUE : FALSE; + params.secReqs.keyDist.mIdKey = (gapBond_KeyDistList & GAPBOND_KEYDIST_MIDKEY) ? TRUE : FALSE; + params.secReqs.keyDist.mSign = (gapBond_KeyDistList & GAPBOND_KEYDIST_MSIGN) ? TRUE : FALSE; + params.secReqs.keyDist.sSign = (gapBond_KeyDistList & GAPBOND_KEYDIST_SSIGN) ? TRUE : FALSE; + + // Is bond manager setup for OOB data? + if ( gapBond_OOBDataFlag ) + { + VOID osal_memcpy( params.secReqs.oob, gapBond_OOBData, KEYLEN ); + } + + if ( gapBond_Bonding && addrType != ADDRTYPE_PUBLIC ) + { + // Force a slave ID key + params.secReqs.keyDist.sIdKey = TRUE; + } + + params.secReqs.authReq |= (gapBond_Bonding) ? SM_AUTH_STATE_BONDING : 0; + params.secReqs.authReq |= (gapBond_MITM) ? SM_AUTH_STATE_AUTHENTICATED : 0; + params.secReqs.authReq |= (gapBond_SC) ? SM_AUTH_STATE_SC : 0; + params.secReqs.authReq |= (gapBond_keyPress) ? SM_AUTH_STATE_KEYPRESS : 0; + params.secReqs.authReq |= (gapBond_CT2) ? SM_AUTH_STATE_CT2 : 0; + GAP_Authenticate( ¶ms, pPairReq ); +} + +#if ( HOST_CONFIG & PERIPHERAL_CFG ) +/********************************************************************* + @fn gapBondMgrSlaveSecurityReq + + authReq |= (gapBond_Bonding) ? SM_AUTH_STATE_BONDING : 0; + authReq |= (gapBond_MITM) ? SM_AUTH_STATE_AUTHENTICATED : 0; + authReq |= (gapBond_SC) ? SM_AUTH_STATE_SC : 0; + authReq |= (gapBond_keyPress) ? SM_AUTH_STATE_KEYPRESS : 0; + authReq |= (gapBond_CT2) ? SM_AUTH_STATE_CT2 : 0; + + @param connHandle - connection handle + + @return none +*/ +static void gapBondMgrSlaveSecurityReq( uint16 connHandle ) +{ + uint8 authReq = 0; + authReq |= (gapBond_Bonding) ? SM_AUTH_STATE_BONDING : 0; + authReq |= (gapBond_MITM) ? SM_AUTH_STATE_AUTHENTICATED : 0; + authReq |= (gapBond_SC) ? SM_AUTH_STATE_SC : 0; + authReq |= (gapBond_keyPress) ? SM_AUTH_STATE_KEYPRESS : 0; + authReq |= (gapBond_CT2) ? SM_AUTH_STATE_CT2 : 0; + GAP_SendSlaveSecurityRequest( connHandle, authReq ); +} +#endif + +/********************************************************************* + @fn gapBondMgrBondReq + + @brief Initiate a GAP bond request + + @param connHandle - connection handle + @param idx - NV index of bond entry + @param stateFlags - bond state flags + @param role - master or slave role + @param startEncryption - whether or not to start encryption + + @return none +*/ +static void gapBondMgrBondReq( uint16 connHandle, uint8 idx, uint8 stateFlags, + uint8 role, uint8 startEncryption ) +{ + smSecurityInfo_t ltk; + osalSnvId_t nvId; + + if ( role == GAP_PROFILE_CENTRAL ) + { + nvId = devLTKNvID( idx ); + } + else + { + nvId = localLTKNvID( idx ); + } + + // Initialize the NV structures + VOID osal_memset( <k, 0, sizeof ( smSecurityInfo_t ) ); + + if ( osal_snv_read( nvId, sizeof ( smSecurityInfo_t ), <k ) == SUCCESS ) + { + if ( (ltk.keySize >= MIN_ENC_KEYSIZE) && (ltk.keySize <= MAX_ENC_KEYSIZE) ) + { + bStatus_t ret = GAP_Bond( connHandle, + ((stateFlags & GAP_BONDED_STATE_AUTHENTICATED) ? TRUE : FALSE), + <k, startEncryption ); + } + } +} + +/********************************************************************* + @fn gapBondMgr_SyncWhiteList + + @brief syncronize the White List with the bonds + + @param none + + @return none +*/ +static void gapBondMgr_SyncWhiteList( void ) +{ + //erase the White List + VOID HCI_LE_ClearWhiteListCmd(); + + // Write bond addresses into the White List + for( uint8 i = 0; i < GAP_BONDINGS_MAX; i++) + { + // Make sure empty addresses are not added to the White List + if ( osal_isbufset( bonds[i].publicAddr, 0xFF, B_ADDR_LEN ) == FALSE ) + { + VOID HCI_LE_AddWhiteListCmd( HCI_PUBLIC_DEVICE_ADDRESS, bonds[i].publicAddr ); + } + } +} + +/********************************************************************* + @fn gapBondMgr_SyncCharCfg + + @brief Update the Bond Manager to have the same configurations as + the GATT database. + + @param connHandle - the current connection handle to find client configurations for + + @return TRUE if sync done. FALSE, otherwise. +*/ +static uint8 gapBondMgr_SyncCharCfg( uint16 connHandle ) +{ + static gattAttribute_t* pAttr = NULL; + static uint16 service; + + // Only attributes with attribute handles between and including the Starting + // Handle parameter and the Ending Handle parameter that match the requested + // attribute type and the attribute value will be returned. + + // All attribute types are effectively compared as 128-bit UUIDs, + // even if a 16-bit UUID is provided in this request or defined + // for an attribute. + if ( pAttr == NULL ) + { + pAttr = GATT_FindHandleUUID( GATT_MIN_HANDLE, GATT_MAX_HANDLE, + clientCharCfgUUID, ATT_BT_UUID_SIZE, &service ); + } + + while ( pAttr != NULL ) + { + uint16 len; + uint8 attrVal[ATT_BT_UUID_SIZE]; + + // It is not possible to use this request on an attribute that has a value + // that is longer than 2. + if ( GATTServApp_ReadAttr( connHandle, pAttr, service, attrVal, + &len, 0, ATT_BT_UUID_SIZE ) == SUCCESS ) + { + // It is not possible to use this request on an attribute that has a value + // that is longer than 2. + uint16 value = BUILD_UINT16(attrVal[0], attrVal[1]); + + if ( value != GATT_CFG_NO_OPERATION ) + { + // NV must be updated to meet configuration of the database + VOID GAPBondMgr_UpdateCharCfg( connHandle, pAttr->handle, value ); + } + } + + // Try to find the next attribute + pAttr = GATT_FindNextAttr( pAttr, GATT_MAX_HANDLE, service, NULL ); + } + + return ( pAttr == NULL ); +} + +/********************************************************************* + @fn gapBondFreeAuthEvt + + @brief Free GAP Authentication Complete event. + + @param none + + @return none +*/ +static void gapBondFreeAuthEvt( uint16 connHandle ) +{ + if ( pAuthEvt[connHandle] != NULL ) + { + // Release the OSAL message + VOID osal_msg_deallocate( (uint8*)pAuthEvt[connHandle] ); + pAuthEvt[connHandle] = NULL; + } + + bondIdx = GAP_BONDINGS_MAX; +} + + +/***************************************************************************************** + fn: gapBondRecvEvt + + date:2020-04-26 + + brief: + + input parameters:connHandle connection handler + + + output parameters: + + + return void + + *****************************************************************************************/ +static void gapBondRecvEvt(uint16 connHandle, gapBondRec_t* pBondRec, gapAuthCompleteEvent_t* pPkt ) +{ + if ( gapBondMgrAddBond( pBondRec, pPkt ) ) + { + // Update NV to have same CCC values as GATT database + // Note: pAuthEvt is a global variable used for deferring the storage + if ( gapBondMgr_SyncCharCfg( pAuthEvt[connHandle]->connectionHandle ) ) + { + if ( pGapBondCB && pGapBondCB->pairStateCB ) + { + // Assume SUCCESS since we got this far. + pGapBondCB->pairStateCB( pAuthEvt[connHandle]->connectionHandle, GAPBOND_PAIRING_STATE_COMPLETE, SUCCESS ); + } + + // We're done storing bond record and CCC values in NV + gapBondFreeAuthEvt(connHandle); + } + } +} + + +#endif // ( CENTRAL_CFG | PERIPHERAL_CFG ) + +/********************************************************************* +*********************************************************************/ diff --git a/src/components/profiles/Roles/gapbondmgr.h b/src/components/profiles/Roles/gapbondmgr.h new file mode 100644 index 0000000..7b5219a --- /dev/null +++ b/src/components/profiles/Roles/gapbondmgr.h @@ -0,0 +1,371 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/** + @headerfile: gapbondmgr.h + $Date: + $Revision: + + @mainpage BLE GAP Bond Manager + + This GAP profile manages bonded connections between devices.

+ + +*/ + +#ifndef GAPBONDMGR_H +#define GAPBONDMGR_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* ------------------------------------------------------------------- + INCLUDES +*/ +#include "gap.h" + +/* ------------------------------------------------------------------- + CONSTANTS +*/ + +#if !defined ( GAP_BONDINGS_MAX ) +#define GAP_BONDINGS_MAX 10 //!< Maximum number of bonds that can be saved in NV. +#endif + +#if !defined ( GAP_BOND_MGR_INDEX_REPLACE ) +#define GAP_BOND_MGR_INDEX_REPLACE TRUE //!< Maximum number of bonds that can be saved in NV. +#endif + +#if !defined ( GAP_CHAR_CFG_MAX ) +#define GAP_CHAR_CFG_MAX 4 //!< Maximum number of characteristic configuration that can be saved in NV. +#endif +/** @defgroup GAPBOND_CONSTANTS_NAME GAP Bond Manager Constants + @{ +*/ + +/** @} End GAPBOND_CONSTANTS_NAME */ + +/** @defgroup GAPBOND_PROFILE_PARAMETERS GAP Bond Manager Parameters + @{ +*/ +#define GAPBOND_PAIRING_MODE 0x400 //!< Pairing Mode: @ref GAPBOND_PAIRING_MODE_DEFINES. Read/Write. Size is uint8. Default is GAPBOND_PAIRING_MODE_WAIT_FOR_REQ. +#define GAPBOND_INITIATE_WAIT 0x401 //!< Pairing Mode Initiate wait timeout. This is the time it will wait for a Pairing Request before sending the Slave Initiate Request. Read/Write. Size is uint16. Default is 1000(in milliseconds). +#define GAPBOND_MITM_PROTECTION 0x402 //!< Man-In-The-Middle (MITM) basically turns on Passkey protection in the pairing algorithm. Read/Write. Size is uint8. Default is 0(disabled). +#define GAPBOND_IO_CAPABILITIES 0x403 //!< I/O capabilities. Read/Write. Size is uint8. Default is GAPBOND_IO_CAP_DISPLAY_ONLY @ref GAPBOND_IO_CAP_DEFINES. +#define GAPBOND_OOB_ENABLED 0x404 //!< OOB data available for pairing algorithm. Read/Write. Size is uint8. Default is 0(disabled). +#define GAPBOND_OOB_DATA 0x405 //!< OOB Data. Read/Write. size uint8[16]. Default is all 0's. +#define GAPBOND_BONDING_ENABLED 0x406 //!< Request Bonding during the pairing process if enabled. Read/Write. Size is uint8. Default is 0(disabled). +#define GAPBOND_KEY_DIST_LIST 0x407 //!< The key distribution list for bonding. size is uint8. @ref GAPBOND_KEY_DIST_DEFINES. Default is sEncKey, sIdKey, mIdKey, mSign enabled. +#define GAPBOND_DEFAULT_PASSCODE 0x408 //!< The default passcode for MITM protection. size is uint32. Range is 0 - 999,999. Default is 0. +#define GAPBOND_ERASE_ALLBONDS 0x409 //!< Erase all of the bonded devices. Write Only. No Size. +#define GAPBOND_AUTO_FAIL_PAIRING 0x40A //!< TEST MODE (DO NOT USE) to automatically send a Pairing Fail when a Pairing Request is received. Read/Write. size is uint8. Default is 0 (disabled). +#define GAPBOND_AUTO_FAIL_REASON 0x40B //!< TEST MODE (DO NOT USE) Pairing Fail reason when auto failing. Read/Write. size is uint8. Default is 0x05 (SMP_PAIRING_FAILED_NOT_SUPPORTED). +#define GAPBOND_KEYSIZE 0x40C //!< Key Size used in pairing. Read/Write. size is uint8. Default is 16. +#define GAPBOND_AUTO_SYNC_WL 0x40D //!< Clears the White List adds to it each unique address stored by bonds in NV. Read/Write. Size is uint8. Default is FALSE. +#define GAPBOND_BOND_COUNT 0x40E //!< Gets the total number of bonds stored in NV. Read Only. Size is uint8. Default is 0 (no bonds). +#define GAPBOND_BOND_FAIL_ACTION 0x40F //!< Possible actions Central may take upon an unsuccessful bonding. Write Only. Size is uint8. Default is 0x02 (Terminate link upon unsuccessful bonding). +#define GAPBOND_ERASE_SINGLEBOND 0x410 //!< Erase a single bonded device. Write only. Must provide address type followed by device address. + +/** @} End GAPBOND_PROFILE_PARAMETERS */ + +/** @defgroup GAPBOND_PAIRING_MODE_DEFINES GAP Bond Manager Pairing Modes + @{ +*/ +#define GAPBOND_PAIRING_MODE_NO_PAIRING 0x00 //!< Pairing is not allowed +#define GAPBOND_PAIRING_MODE_WAIT_FOR_REQ 0x01 //!< Wait for a pairing request or slave security request +#define GAPBOND_PAIRING_MODE_INITIATE 0x02 //!< Don't wait, initiate a pairing request or slave security request +/** @} End GAPBOND_PAIRING_MODE_DEFINES */ + +/** @defgroup GAPBOND_IO_CAP_DEFINES GAP Bond Manager I/O Capabilities + @{ +*/ +#define GAPBOND_IO_CAP_DISPLAY_ONLY 0x00 //!< Display Only Device +#define GAPBOND_IO_CAP_DISPLAY_YES_NO 0x01 //!< Display and Yes and No Capable +#define GAPBOND_IO_CAP_KEYBOARD_ONLY 0x02 //!< Keyboard Only +#define GAPBOND_IO_CAP_NO_INPUT_NO_OUTPUT 0x03 //!< No Display or Input Device +#define GAPBOND_IO_CAP_KEYBOARD_DISPLAY 0x04 //!< Both Keyboard and Display Capable +/** @} End GAPBOND_IO_CAP_DEFINES */ + +/** @defgroup GAPBOND_KEY_DIST_DEFINES GAP Bond Manager Key Distribution + @{ +*/ +#define GAPBOND_KEYDIST_SENCKEY 0x01 //!< Slave Encryption Key +#define GAPBOND_KEYDIST_SIDKEY 0x02 //!< Slave IRK and ID information +#define GAPBOND_KEYDIST_SSIGN 0x04 //!< Slave CSRK +#define GAPBOND_KEYDIST_MENCKEY 0x08 //!< Master Encrypton Key +#define GAPBOND_KEYDIST_MIDKEY 0x10 //!< Master IRK and ID information +#define GAPBOND_KEYDIST_MSIGN 0x20 //!< Master CSRK +/** @} End GAPBOND_IO_CAP_DEFINES */ + + +/** @defgroup GAPBOND_PAIRING_STATE_DEFINES GAP Bond Manager Pairing States + @{ +*/ +#define GAPBOND_PAIRING_STATE_STARTED 0x00 //!< Pairing started +#define GAPBOND_PAIRING_STATE_COMPLETE 0x01 //!< Pairing complete +#define GAPBOND_PAIRING_STATE_BONDED 0x02 //!< Devices bonded +/** @} End GAPBOND_PAIRING_STATE_DEFINES */ + +/** @defgroup SMP_PAIRING_FAILED_DEFINES Pairing failure status values + @{ +*/ +#define SMP_PAIRING_FAILED_PASSKEY_ENTRY_FAILED 0x01 //!< The user input of the passkey failed, for example, the user cancelled the operation. +#define SMP_PAIRING_FAILED_OOB_NOT_AVAIL 0x02 //!< The OOB data is not available +#define SMP_PAIRING_FAILED_AUTH_REQ 0x03 //!< The pairing procedure can't be performed as authentication requirements can't be met due to IO capabilities of one or both devices +#define SMP_PAIRING_FAILED_CONFIRM_VALUE 0x04 //!< The confirm value doesn't match the calculated compare value +#define SMP_PAIRING_FAILED_NOT_SUPPORTED 0x05 //!< Pairing isn't supported by the device +#define SMP_PAIRING_FAILED_ENC_KEY_SIZE 0x06 //!< The resultant encryption key size is insufficient for the security requirements of this device. +#define SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED 0x07 //!< The SMP command received is not supported on this device. +#define SMP_PAIRING_FAILED_UNSPECIFIED 0x08 //!< Pairing failed due to an unspecified reason +#define SMP_PAIRING_FAILED_REPEATED_ATTEMPTS 0x09 //!< Pairing or authenication procedure is disallowed because too little time has elapsed since the last pairing request or security request. +/** @} End SMP_PAIRING_FAILED_DEFINES */ + +/** @defgroup GAPBOND_BONDING_FAILURE_DEFINES Bonding Failure Actions + @{ +*/ +#define GAPBOND_FAIL_NO_ACTION 0x00 //!< Take no action upon unsuccessful bonding +#define GAPBOND_FAIL_INITIATE_PAIRING 0x01 //!< Initiate pairing upon unsuccessful bonding +#define GAPBOND_FAIL_TERMINATE_LINK 0x02 //!< Terminate link upon unsuccessful bonding +#define GAPBOND_FAIL_TERMINATE_ERASE_BONDS 0x03 //!< Terminate link and erase all existing bonds on device upon unsuccessful bonding +/** @} End GAPBOND_BONDING_FAILURE_DEFINES */ + +/* ------------------------------------------------------------------- + TYPEDEFS +*/ + + +/** + Passcode Callback Function +*/ +typedef void (*pfnPasscodeCB_t) +( + uint8* deviceAddr, //!< address of device to pair with, and could be either public or random. + uint16 connectionHandle, //!< Connection handle + uint8 uiInputs, //!< Pairing User Interface Inputs - Ask user to input passcode + uint8 uiOutputs //!< Pairing User Interface Outputs - Display passcode +); + +/** + Pairing State Callback Function +*/ +typedef void (*pfnPairStateCB_t) +( + uint16 connectionHandle, //!< Connection handle + uint8 state, //!< Pairing state @ref GAPBOND_PAIRING_STATE_DEFINES + uint8 status //!< Pairing status +); + +/** + Callback Registration Structure +*/ +typedef struct +{ + pfnPasscodeCB_t passcodeCB; //!< Passcode callback + pfnPairStateCB_t pairStateCB; //!< Pairing state callback +} gapBondCBs_t; + +/* ------------------------------------------------------------------- + MACROS +*/ + +/* ------------------------------------------------------------------- + API FUNCTIONS +*/ + +/** + @defgroup GAPROLES_BONDMGR_API GAP Bond Manager API Functions + + @{ +*/ + +/** + @brief Set a GAP Bond Manager parameter. + + NOTE: You can call this function with a GAP Parameter ID and it will set the + GAP Parameter. GAP Parameters are defined in (gap.h). Also, + the "len" field must be set to the size of a "uint16" and the + "pValue" field must point to a "uint16". + + @param param - Profile parameter ID: @ref GAPBOND_PROFILE_PARAMETERS + @param len - length of data to write + @param pValue - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return SUCCESS or INVALIDPARAMETER (invalid paramID) +*/ +extern bStatus_t GAPBondMgr_SetParameter( uint16 param, uint8 len, void* pValue ); + +/** + @brief Get a GAP Bond Manager parameter. + + NOTE: You can call this function with a GAP Parameter ID and it will get a + GAP Parameter. GAP Parameters are defined in (gap.h). Also, the + "pValue" field must point to a "uint16". + + @param param - Profile parameter ID: @ref GAPBOND_PROFILE_PARAMETERS + @param pValue - pointer to location to get the value. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return SUCCESS or INVALIDPARAMETER (invalid paramID) +*/ +extern bStatus_t GAPBondMgr_GetParameter( uint16 param, void* pValue ); + +/** + @brief Notify the Bond Manager that a connection has been made. + + NOTE: The GAP Peripheral/Central Role profile will + call this function, if they are included in the project. + + @param addrType - device's address type. Reference GAP_ADDR_TYPE_DEFINES in gap.h + @param pDevAddr - device's address + @param connHandle - connection handle + @param role - master or slave role. Reference GAP_PROFILE_ROLE_DEFINES in gap.h + + @return SUCCESS, otherwise failure +*/ +extern bStatus_t GAPBondMgr_LinkEst( uint8 addrType, uint8* pDevAddr, uint16 connHandle, uint8 role ); + +/** + @brief Resolve an address from bonding information. + + @param addrType - device's address type. Reference GAP_ADDR_TYPE_DEFINES in gap.h + @param pDevAddr - device's address + @param pResolvedAddr - pointer to buffer to put the resolved address + + @return bonding index (0 - (GAP_BONDINGS_MAX-1) if found, + GAP_BONDINGS_MAX if not found +*/ +extern uint8 GAPBondMgr_ResolveAddr( uint8 addrType, uint8* pDevAddr, uint8* pResolvedAddr ); + +/** + @brief Set/clear the service change indication in a bond record. + + @param connectionHandle - connection handle of the connected device or 0xFFFF + if all devices in database. + @param setParam - TRUE to set the service change indication, FALSE to clear it. + + @return SUCCESS - bond record found and changed,
+ bleNoResources - bond record not found (for 0xFFFF connectionHandle),
+ bleNotConnected - connection not found - connectionHandle is invalid (for non-0xFFFF connectionHandle). +*/ +extern bStatus_t GAPBondMgr_ServiceChangeInd( uint16 connectionHandle, uint8 setParam ); + +/** + @brief Update the Characteristic Configuration in a bond record. + + @param connectionHandle - connection handle of the connected device or 0xFFFF + if all devices in database. + @param attrHandle - attribute handle. + @param value - characteristic configuration value. + + @return SUCCESS - bond record found and changed,
+ bleNoResources - bond record not found (for 0xFFFF connectionHandle),
+ bleNotConnected - connection not found - connectionHandle is invalid (for non-0xFFFF connectionHandle). +*/ +extern bStatus_t GAPBondMgr_UpdateCharCfg( uint16 connectionHandle, uint16 attrHandle, uint16 value ); + +/** + @brief Register callback functions with the bond manager. + + NOTE: There is no need to register a passcode callback function + if the passcode will be handled with the GAPBOND_DEFAULT_PASSCODE parameter. + + @param pCB - pointer to callback function structure. + + @return none +*/ +extern void GAPBondMgr_Register( gapBondCBs_t* pCB ); + +/** + @brief Respond to a passcode request. + + @param connectionHandle - connection handle of the connected device or 0xFFFF + if all devices in database. + @param status - SUCCESS if passcode is available, otherwise see @ref SMP_PAIRING_FAILED_DEFINES. + @param passcode - integer value containing the passcode. + + @return SUCCESS - bond record found and changed,
+ bleIncorrectMode - Link not found. +*/ +extern bStatus_t GAPBondMgr_PasscodeRsp( uint16 connectionHandle, uint8 status, uint32 passcode ); + +/** + @brief This is a bypass mechanism to allow the bond manager to process + GAP messages. + + NOTE: This is an advanced feature and shouldn't be called unless + the normal GAP Bond Manager task ID registration is overridden. + + @param pMsg - GAP event message + + @return TRUE if safe to deallocate incoming GAP message, FALSE otherwise. +*/ +extern uint8 GAPBondMgr_ProcessGAPMsg( gapEventHdr_t* pMsg ); + +/** + @brief This function will check the length of a Bond Manager NV Item. + + @param id - NV ID. + @param len - lengths in bytes of item. + + @return SUCCESS or FAILURE +*/ +extern uint8 GAPBondMgr_CheckNVLen( uint8 id, uint8 len ); + +/** + @} End GAPROLES_BONDMGR_API +*/ + + + +/* ------------------------------------------------------------------- + TASK FUNCTIONS - Don't call these. These are system functions. +*/ + +/** + @internal + + @brief Initialization function for the GAP Bond Manager Task. + This is called during initialization and should contain + any application specific initialization (ie. hardware + initialization/setup, table initialization, power up + notificaiton ... ). + + @param the ID assigned by OSAL. This ID should be + used to send messages and set timers. + + @return void +*/ +extern void GAPBondMgr_Init( uint8 task_id ); + +/** + @internal + + @brief GAP Bond Manager Task event processor. + This function is called to process all events for the task. + Events include timers, messages and any other user defined + events. + + @param task_id - The OSAL assigned task ID. + @param events - events to process. This is a bit map and can + contain more than one event. + + @return events not processed +*/ +extern uint16 GAPBondMgr_ProcessEvent( uint8 task_id, uint16 events ); + +/* ------------------------------------------------------------------- + -------------------------------------------------------------------*/ + +#ifdef __cplusplus +} +#endif + +#endif /* GAPBONDMGR_H */ diff --git a/src/components/profiles/Roles/gapgattserver.c b/src/components/profiles/Roles/gapgattserver.c new file mode 100644 index 0000000..91899e2 --- /dev/null +++ b/src/components/profiles/Roles/gapgattserver.c @@ -0,0 +1,957 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: gapgattserver.c + Revised: + Revision: + + Description: GAP Attribute Server + + +**************************************************************************************************/ + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "gap.h" +#include "gapgattserver.h" +#include "att.h" +#include "gatt.h" +#include "gatt_uuid.h" +#include "gattservapp.h" +#include "simpleBLEPeripheral.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ +// Position of device name in attribute table +#define GAP_DEVICE_NAME_POS 2 +#define GAP_APPEARANCE_POS 4 +#define GAP_PRIVACY_FLAG_POS 6 + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ +static const ggsAppCBs_t* ggs_AppCBs = NULL; + +#if defined ( TESTMODES ) + static uint16 paramValue = 0; +#endif + +/********************************************************************* + Profile Attributes - variables +*/ + +// GAP Service +static CONST gattAttrType_t gapService = { ATT_BT_UUID_SIZE, gapServiceUUID }; + +// Device Name Characteristic Properties +static uint8 deviceNameCharProps = GATT_PROP_READ; + +// Device Name attribute (0 - 248 octets) - extra octet for null-terminate char +static uint8 deviceName[GAP_DEVICE_NAME_LEN+1] = { 0 }; + +// Appearance Characteristic Properties +static uint8 appearanceCharProps = GATT_PROP_READ; + +// Appearance attribute (2-octet enumerated value as defined by Bluetooth Assigned Numbers document) +static uint16 appearance = GAP_APPEARE_GENERIC_THERMOMETER; + +#if ( HOST_CONFIG & PERIPHERAL_CFG ) + +#if defined (GAP_PRIVACY) || defined (GAP_PRIVACY_RECONNECT) + + // Peripheral Privacy Flag Characteristic Properties + static uint8 periPrivacyFlagCharProps = GATT_PROP_READ; + + // Peripheral Privacy Flag attribute (1 octet) + static uint8 periPrivacyFlag = GAP_PRIVACY_DISABLED; + +#endif // GAP_PRIVACY || GAP_PRIVACY_RECONNECT + +#if defined (GAP_PRIVACY_RECONNECT) + +// Reconnection Address Characteristic Properties +static uint8 reconnectAddrCharProps = GATT_PROP_WRITE; + +// Reconnection Address attribute (6 octets) +static uint8 reconnectAddr[B_ADDR_LEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +#endif // GAP_PRIVACY_RECONNECT + +// Peripheral Preferred Connection Parameters Characteristic Properties +static uint8 periConnParamCharProps = GATT_PROP_READ; + +// Peripheral Preferred Connection Parameters attribute (8 octets) +gapPeriConnectParams_t periConnParameters = +{ + DEFAULT_DESIRED_MIN_CONN_INTERVAL, + DEFAULT_DESIRED_MAX_CONN_INTERVAL, + DEFAULT_DESIRED_SLAVE_LATENCY, + DEFAULT_DESIRED_CONN_TIMEOUT }; + +#endif // PERIPHERAL_CFG + +/********************************************************************* + Profile Attributes - Table +*/ + +// GAP Attribute Table +static gattAttribute_t gapAttrTbl[] = +{ + // Generic Access Profile + { + { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */ + GATT_PERMIT_READ, /* permissions */ + 0, /* handle */ + (uint8*)& gapService /* pValue */ + }, + + // Characteristic Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &deviceNameCharProps + }, + + // Device Name attribute + { + { ATT_BT_UUID_SIZE, deviceNameUUID }, + GATT_PERMIT_READ, + 0, + deviceName + }, + + // Characteristic Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &appearanceCharProps + }, + + // Icon attribute + { + { ATT_BT_UUID_SIZE, appearanceUUID }, + GATT_PERMIT_READ, + 0, + (uint8*)& appearance + }, + + #if ( HOST_CONFIG & PERIPHERAL_CFG ) + + #if defined (GAP_PRIVACY) || defined (GAP_PRIVACY_RECONNECT) + + // Characteristic Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &periPrivacyFlagCharProps + }, + + // Peripheral Privacy Flag attribute + { + { ATT_BT_UUID_SIZE, periPrivacyFlagUUID }, + GATT_PERMIT_READ, + 0, + (uint8*)& periPrivacyFlag + }, + + #endif // GAP_PRIVACY || GAP_PRIVACY_RECONNECT + + #if defined (GAP_PRIVACY_RECONNECT) + + // Characteristic Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &reconnectAddrCharProps + }, + + // Reconnection Address attribute + { + { ATT_BT_UUID_SIZE, reconnectAddrUUID }, + GATT_PERMIT_AUTHEN_WRITE, + 0, + reconnectAddr + }, + + #endif // GAP_PRIVACY_RECONNECT + + // Characteristic Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &periConnParamCharProps + }, + + // Peripheral Preferred Connection Parameters attribute + { + { ATT_BT_UUID_SIZE, periConnParamUUID }, + GATT_PERMIT_READ, + 0, + (uint8*)& periConnParameters + }, + + #endif // PERIPHERAL_CFG +}; + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static void ggs_SetAttrWPermit( uint8 wPermit, uint8* pPermissions, uint8* pCharProps ); + +/********************************************************************* + PUBLIC FUNCTIONS +*/ +// GGS Callback functions +static uint8 ggs_ReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ); +static bStatus_t ggs_WriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ); + +/********************************************************************* + PROFILE CALLBACKS +*/ +// GAP Service Callbacks +CONST gattServiceCBs_t gapServiceCBs = +{ + ggs_ReadAttrCB, // Read callback function pointer + ggs_WriteAttrCB, // Write callback function pointer + NULL // Authorization callback function pointer +}; + +/********************************************************************* + @fn GGS_SetParameter + + @brief Set a GAP GATT Server parameter. + + @param param - Profile parameter ID + @param len - length of data to right + @param value - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t GGS_SetParameter( uint8 param, uint8 len, void* value ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case GGS_DEVICE_NAME_ATT: + + // Always leave room for null-terminate char + if ( len <= GAP_DEVICE_NAME_LEN ) + { + VOID osal_memset( deviceName, 0, GAP_DEVICE_NAME_LEN+1 ); + VOID osal_memcpy( deviceName, value, len ); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GGS_APPEARANCE_ATT: + if ( len == sizeof ( uint16 ) ) + { + appearance = *((uint16*)value); + } + else + { + ret = bleInvalidRange; + } + + break; + #if ( HOST_CONFIG & PERIPHERAL_CFG ) + #if defined (GAP_PRIVACY) || defined (GAP_PRIVACY_RECONNECT) + + case GGS_PERI_PRIVACY_FLAG_ATT: + if ( len == sizeof ( uint8 ) ) + { + periPrivacyFlag = *((uint8*)value); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GGS_PERI_PRIVACY_FLAG_PROPS: + if ( len == sizeof ( uint8 ) ) + { + periPrivacyFlagCharProps = *((uint8*)value); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GGS_W_PERMIT_PRIVACY_FLAG_ATT: + if ( len == sizeof ( uint8 ) ) + { + uint8 wPermit = *(uint8*)value; + + // Optionally Writeable with Authentication + if ( !gattPermitWrite( wPermit ) ) + { + ggs_SetAttrWPermit( wPermit, + &(gapAttrTbl[GAP_PRIVACY_FLAG_POS].permissions), + gapAttrTbl[GAP_PRIVACY_FLAG_POS-1].pValue ); + } + else + { + ret = bleInvalidRange; + } + } + else + { + ret = bleInvalidRange; + } + + break; + #endif // GAP_PRIVACY || GAP_PRIVACY_RECONNECT + #if defined (GAP_PRIVACY_RECONNECT) + + case GGS_RECONNCT_ADDR_ATT: + if ( len == B_ADDR_LEN ) + { + VOID osal_memcpy( reconnectAddr, value, len ); + } + else + { + ret = bleInvalidRange; + } + + break; + #endif // GAP_PRIVACY_RECONNECT + + case GGS_PERI_CONN_PARAM_ATT: + if ( len == sizeof(gapPeriConnectParams_t) ) + { + periConnParameters = *((gapPeriConnectParams_t*)(value)); + } + else + { + ret = bleInvalidRange; + } + + break; + #endif // PERIPHERAL_CFG + + case GGS_W_PERMIT_DEVICE_NAME_ATT: + if ( len == sizeof ( uint8 ) ) + { + // Optionally Writeable + ggs_SetAttrWPermit( *(uint8*)value, + &(gapAttrTbl[GAP_DEVICE_NAME_POS].permissions), + gapAttrTbl[GAP_DEVICE_NAME_POS-1].pValue ); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GGS_W_PERMIT_APPEARANCE_ATT: + if ( len == sizeof ( uint8 ) ) + { + // Optionally Writeable + ggs_SetAttrWPermit( *(uint8*)value, + &(gapAttrTbl[GAP_APPEARANCE_POS].permissions), + gapAttrTbl[GAP_APPEARANCE_POS-1].pValue ); + } + else + { + ret = bleInvalidRange; + } + + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn GGS_GetParameter + + @brief Get a GAP GATT Server parameter. + + @param param - Profile parameter ID + @param value - pointer to data to put. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t GGS_GetParameter( uint8 param, void* value ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case GGS_DEVICE_NAME_ATT: + VOID osal_memcpy( value, deviceName, GAP_DEVICE_NAME_LEN ); + break; + + case GGS_APPEARANCE_ATT: + *((uint16*)value) = appearance; + break; +#if ( HOST_CONFIG & PERIPHERAL_CFG ) +#if defined (GAP_PRIVACY) || defined (GAP_PRIVACY_RECONNECT) + + case GGS_PERI_PRIVACY_FLAG_ATT: + *((uint8*)value) = periPrivacyFlag; + break; + + case GGS_PERI_PRIVACY_FLAG_PROPS: + *((uint8*)value) = periPrivacyFlagCharProps; + break; +#endif // GAP_PRIVACY || GAP_PRIVACY_RECONNECT +#if defined (GAP_PRIVACY_RECONNECT) + + case GGS_RECONNCT_ADDR_ATT: + VOID osal_memcpy( value, reconnectAddr, B_ADDR_LEN ); + break; +#endif // GAP_PRIVACY_RECONNECT + + case GGS_PERI_CONN_PARAM_ATT: + *((gapPeriConnectParams_t*)(value)) = periConnParameters; + break; +#endif // PERIPHERAL_CFG + + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn GGS_SetParamValue + + @brief Set a GGS Parameter value. Use this function to change + the default GGS parameter values. + + @param value - new GGS param value + + @return void +*/ +void GGS_SetParamValue( uint16 value ) +{ + #if defined ( TESTMODES ) + uint8 wpermit; + paramValue = value; + + switch ( value ) + { + case GGS_TESTMODE_OFF: + wpermit = 0; + VOID GGS_SetParameter( GGS_W_PERMIT_DEVICE_NAME_ATT, sizeof( uint8 ), (void*)&wpermit ); + VOID GGS_SetParameter( GGS_W_PERMIT_APPEARANCE_ATT, sizeof( uint8 ), (void*)&wpermit ); + VOID GGS_SetParameter( GGS_W_PERMIT_PRIVACY_FLAG_ATT, sizeof( uint8 ), (void*)&wpermit ); + break; + + case GGS_TESTMODE_W_PERMIT_DEVICE_NAME: + wpermit = GATT_PERMIT_WRITE; + VOID GGS_SetParameter( GGS_W_PERMIT_DEVICE_NAME_ATT, sizeof( uint8 ), (void*)&wpermit ); + break; + + case GGS_TESTMODE_W_PERMIT_APPEARANCE: + wpermit = GATT_PERMIT_WRITE; + VOID GGS_SetParameter( GGS_W_PERMIT_APPEARANCE_ATT, sizeof( uint8 ), (void*)&wpermit ); + break; + + case GGS_TESTMODE_W_PERMIT_PRIVACY_FLAG: + wpermit = GATT_PERMIT_AUTHEN_WRITE; + VOID GGS_SetParameter( GGS_W_PERMIT_PRIVACY_FLAG_ATT, sizeof( uint8 ), (void*)&wpermit ); + break; + + default: + break; + } + + #else + VOID value; + #endif +} + +/********************************************************************* + @fn GGS_GetParamValue + + @brief Get a GGS Parameter value. + + @param none + + @return GGS Parameter value +*/ +uint16 GGS_GetParamValue( void ) +{ + #if defined ( TESTMODES ) + return ( paramValue ); + #else + return ( 0 ); + #endif +} + +/********************************************************************* + LOCAL FUNCTION PROTOTYPES +*/ + +/********************************************************************* + @fn GGS_AddService + + @brief Add function for the GAP GATT Service. + + @param services - services to add. This is a bit map and can + contain more than one service. + + @return SUCCESS: Service added successfully. + INVALIDPARAMETER: Invalid service field. + FAILURE: Not enough attribute handles available. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t GGS_AddService( uint32 services ) +{ + uint8 status = SUCCESS; + + if ( services & GAP_SERVICE ) + { + // Register GAP attribute list and CBs with GATT Server Server App + status = GATTServApp_RegisterService( gapAttrTbl, GATT_NUM_ATTRS( gapAttrTbl ), + &gapServiceCBs ); + } + + return ( status ); +} + +/****************************************************************************** + @fn GATTServApp_DelService + + @brief Delete function for the GAP GATT Service. + + @param services - services to delete. This is a bit map and can + contain more than one service. + + @return SUCCESS: Service deleted successfully. + FAILURE: Service not found. +*/ +bStatus_t GGS_DelService( uint32 services ) +{ + uint8 status = SUCCESS; + + if ( services & GAP_SERVICE ) + { + // Deregister GAP attribute list and CBs from GATT Server Application + status = GATTServApp_DeregisterService( GATT_SERVICE_HANDLE( gapAttrTbl ), NULL ); + } + + return ( status ); +} + +/********************************************************************* + @fn GGS_RegisterAppCBs + + @brief Registers the application callback function. + + Note: Callback registration is needed only when the + Device Name is made writable. The application + will be notified when the Device Name is changed + over the air. + + @param appCallbacks - pointer to application callbacks. + + @return none +*/ +void GGS_RegisterAppCBs( ggsAppCBs_t* appCallbacks ) +{ + ggs_AppCBs = appCallbacks; +} + +/********************************************************************* + @fn ggs_SetAttrWPermit + + @brief Update attribute Write access permissions and characteristic + properties for over-the-air write operations. + + @param wPermit - write acces permissions + @param pPermissions - pointer to attribute permissions + @param pCharProps - pointer to characteristic properties + + @return none +*/ +static void ggs_SetAttrWPermit( uint8 wPermit, uint8* pPermissions, uint8* pCharProps ) +{ + // Update attribute Write access permissions + if ( gattPermitWrite( wPermit ) ) + { + *pPermissions |= GATT_PERMIT_WRITE; + } + else + { + *pPermissions &= ~GATT_PERMIT_WRITE; + } + + if ( gattPermitAuthenWrite( wPermit ) ) + { + *pPermissions |= GATT_PERMIT_AUTHEN_WRITE; + } + else + { + *pPermissions &= ~GATT_PERMIT_AUTHEN_WRITE; + } + + if ( gattPermitAuthorWrite( wPermit ) ) + { + *pPermissions |= GATT_PERMIT_AUTHOR_WRITE; + } + else + { + *pPermissions &= ~GATT_PERMIT_AUTHOR_WRITE; + } + + // Update attribute Write characteristic properties + if ( gattPermitWrite( wPermit ) || + gattPermitAuthenWrite( wPermit ) || + gattPermitAuthorWrite( wPermit ) ) + { + *pCharProps |= (GATT_PROP_WRITE_NO_RSP | GATT_PROP_WRITE); + } + else if ( wPermit == 0 ) + { + // Attribute not Writable + *pCharProps &= ~(GATT_PROP_WRITE_NO_RSP | GATT_PROP_WRITE); + } +} + +/********************************************************************* + @fn ggs_ReadAttrCB + + @brief Read an attribute. + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be read + @param pLen - length of data to be read + @param offset - offset of the first octet to be read + @param maxLen - maximum length of data to be read + + @return Success or Failure +*/ +static uint8 ggs_ReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ) +{ + uint16 uuid; + bStatus_t status = SUCCESS; + VOID connHandle; // Not needed for now! + + // Make sure it's not a blob operation + if ( offset > 0 ) + { + return ( ATT_ERR_ATTR_NOT_LONG ); + } + + if ( pAttr->type.len == ATT_BT_UUID_SIZE ) + { + // 16-bit UUID + uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + switch ( uuid ) + { + case DEVICE_NAME_UUID: + { + uint8 len = osal_strlen( (char*)(pAttr->pValue) ); + + // If the attribute value is longer than maxLen then maxLen + // octets shall be included in this response. + if ( len > maxLen ) + { + len = maxLen; + } + + *pLen = len; + VOID osal_memcpy( pValue, pAttr->pValue, len ); + } + break; + + case APPEARANCE_UUID: + { + uint16 value = *((uint16*)(pAttr->pValue)); + *pLen = 2; + pValue[0] = LO_UINT16( value ); + pValue[1] = HI_UINT16( value ); + } + break; + + case RECONNECT_ADDR_UUID: + *pLen = B_ADDR_LEN; + VOID osal_memcpy( pValue, pAttr->pValue, B_ADDR_LEN ); + break; + + case PERI_PRIVACY_FLAG_UUID: + *pLen = 1; + *pValue = *pAttr->pValue; + break; + + case PERI_CONN_PARAM_UUID: + if ( pAttr->pValue != NULL ) + { + gapPeriConnectParams_t* pConnectParam = (gapPeriConnectParams_t*)(pAttr->pValue); + *pLen = 8; + pValue[0] = LO_UINT16( pConnectParam->intervalMin ); + pValue[1] = HI_UINT16( pConnectParam->intervalMin ); + pValue[2] = LO_UINT16( pConnectParam->intervalMax ); + pValue[3] = HI_UINT16( pConnectParam->intervalMax ); + pValue[4] = LO_UINT16( pConnectParam->latency ); + pValue[5] = HI_UINT16( pConnectParam->latency ); + pValue[6] = LO_UINT16( pConnectParam->timeout ); + pValue[7] = HI_UINT16( pConnectParam->timeout ); + } + else + { + *pLen = 0; + } + + break; + + default: + // Should never get here! + *pLen = 0; + status = ATT_ERR_INVALID_HANDLE; + break; + } + } + else + { + // 128-bit UUID + *pLen = 0; + status = ATT_ERR_INVALID_HANDLE; + } + + return ( status ); +} + +/********************************************************************* + @fn ggs_ValidateWriteAttrCB + + @brief Validate and Write attribute data + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be written + @param len - length of data + @param offset - offset of the first octet to be written + + @return Success or Failure +*/ +static bStatus_t ggs_WriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ) +{ + bStatus_t status = SUCCESS; + VOID connHandle; // Not needed for now! + + if ( pAttr->type.len == ATT_BT_UUID_SIZE ) + { + // 16-bit UUID + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + switch ( uuid ) + { + case DEVICE_NAME_UUID: + // Validate the long value + { + uint8 curLen = osal_strlen( (char*)(pAttr->pValue) ); + + // If the value offset is greater than the current length of the + // attribute value then an Error Response shall be sent with the + // error code Invalid Offset. + if ( offset <= curLen ) + { + // Always leave room for null-terminate char + if ( ( offset + len ) > GAP_DEVICE_NAME_LEN ) + { + // Appliction error + status = ATT_ERR_INVALID_VALUE_SIZE; + } + } + else + { + status = ATT_ERR_INVALID_OFFSET; + } + } + + // Write the long value + if ( status == SUCCESS ) + { + VOID osal_memcpy( &(pAttr->pValue[offset]), pValue, len ); + offset += len; + pAttr->pValue[offset] = '\0'; + + // Notify application + if ( ggs_AppCBs && ggs_AppCBs->pfnAttrValueChange ) + { + ggs_AppCBs->pfnAttrValueChange( GGS_DEVICE_NAME_ID ); + } + } + + break; + + case APPEARANCE_UUID: + + // Validate the value + if ( offset == 0 ) + { + if ( len != 2 ) + { + status = ATT_ERR_INVALID_VALUE_SIZE; + } + } + else + { + status = ATT_ERR_ATTR_NOT_LONG; + } + + // Write the value + if ( status == SUCCESS ) + { + uint16* pCurValue = (uint16*)pAttr->pValue; + *pCurValue = BUILD_UINT16( pValue[0], pValue[1] ); + + // Notify application + if ( ggs_AppCBs && ggs_AppCBs->pfnAttrValueChange ) + { + ggs_AppCBs->pfnAttrValueChange( GGS_APPEARANCE_ID ); + } + } + + break; + + case RECONNECT_ADDR_UUID: + // Validate the value - writable by a bonded device + #if ( HOST_CONFIG & PERIPHERAL_CFG ) + #if defined (GAP_PRIVACY) || defined (GAP_PRIVACY_RECONNECT) + if ( periPrivacyFlag == GAP_PRIVACY_DISABLED ) + { + status = ATT_ERR_WRITE_NOT_PERMITTED; + } + else + #endif // GAP_PRIVACY || GAP_PRIVACY_RECONNECT + #endif // PERIPHERAL_CFG + if ( offset == 0 ) + { + if ( len != B_ADDR_LEN ) + { + status = ATT_ERR_INVALID_VALUE_SIZE; + } + } + else + { + status = ATT_ERR_ATTR_NOT_LONG; + } + + // Write the value + if ( status == SUCCESS ) + { + VOID osal_memcpy( pAttr->pValue, pValue, B_ADDR_LEN ); + } + + break; + + case PERI_PRIVACY_FLAG_UUID: + // Validate the value - writable by a bonded device + #if ( HOST_CONFIG & PERIPHERAL_CFG ) + #if defined (GAP_PRIVACY) || defined (GAP_PRIVACY_RECONNECT) + if ( (periPrivacyFlagCharProps & GATT_PROP_WRITE) == 0 ) + { + status = ATT_ERR_WRITE_NOT_PERMITTED; + } + else + #endif // GAP_PRIVACY || GAP_PRIVACY_RECONNECT + #endif // PERIPHERAL_CFG + if ( offset == 0 ) + { + if ( len == 1 ) + { + // Validate characteristic configuration bit field + if ( ( *pValue != GAP_PRIVACY_DISABLED ) && + ( *pValue != GAP_PRIVACY_ENABLED ) ) + { + status = ATT_ERR_INVALID_VALUE; + } + } + else + { + status = ATT_ERR_INVALID_VALUE_SIZE; + } + } + else + { + status = ATT_ERR_ATTR_NOT_LONG; + } + + // Write the value + if ( status == SUCCESS ) + { + *pAttr->pValue = *pValue; + } + + break; + + default: + // Should never get here! + status = ATT_ERR_INVALID_HANDLE; + } + } + else + { + // 128-bit UUID + status = ATT_ERR_INVALID_HANDLE; + } + + return ( status ); +} + +/********************************************************************* +*********************************************************************/ diff --git a/src/components/profiles/Roles/observer.c b/src/components/profiles/Roles/observer.c new file mode 100644 index 0000000..fb38580 --- /dev/null +++ b/src/components/profiles/Roles/observer.c @@ -0,0 +1,278 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "osal_cbtimer.h" +#include "osal_snv.h" +#include "hci_tl.h" +#include "gap.h" + +#include "observer.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +// Task ID +static uint8 gapObserverRoleTaskId; + +// App callbacks +static gapObserverRoleCB_t* pGapObserverRoleCB; + +/********************************************************************* + Profile Parameters - reference GAPCENTRALROLE_PROFILE_PARAMETERS for + descriptions +*/ + +static uint8 gapObserverRoleBdAddr[B_ADDR_LEN]; +static uint8 gapObserverRoleMaxScanRes = 0; + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static void gapObserverRole_ProcessOSALMsg( osal_event_hdr_t* pMsg ); +static void gapObserverRole_ProcessGAPMsg( gapEventHdr_t* pMsg ); + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/** + @brief Start the device in Observer role. This function is typically + called once during system startup. + + Public function defined in observer.h. +*/ +bStatus_t GAPObserverRole_StartDevice( gapObserverRoleCB_t* pAppCallbacks ) +{ + if ( pAppCallbacks ) + { + pGapObserverRoleCB = pAppCallbacks; + } + + return GAP_DeviceInit( gapObserverRoleTaskId, GAP_PROFILE_OBSERVER, + gapObserverRoleMaxScanRes, NULL, NULL, NULL ); +} + +/** + @brief Set a parameter in the Observer Profile. + + Public function defined in observer.h. +*/ +bStatus_t GAPObserverRole_SetParameter( uint16 param, uint8 len, void* pValue ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case GAPOBSERVERROLE_MAX_SCAN_RES: + if ( len == sizeof ( uint8 ) ) + { + gapObserverRoleMaxScanRes = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ret; +} + +/** + @brief Get a parameter in the Observer Profile. + + Public function defined in observer.h. +*/ +bStatus_t GAPObserverRole_GetParameter( uint16 param, void* pValue ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case GAPOBSERVERROLE_BD_ADDR: + VOID osal_memcpy( pValue, gapObserverRoleBdAddr, B_ADDR_LEN ) ; + break; + + case GAPOBSERVERROLE_MAX_SCAN_RES: + *((uint8*)pValue) = gapObserverRoleMaxScanRes; + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ret; +} + +/** + @brief Start a device discovery scan. + + Public function defined in observer.h. +*/ +bStatus_t GAPObserverRole_StartDiscovery( uint8 mode, uint8 activeScan, uint8 whiteList ) +{ + gapDevDiscReq_t params; + params.taskID = gapObserverRoleTaskId; + params.mode = mode; + params.activeScan = activeScan; + params.whiteList = whiteList; + return GAP_DeviceDiscoveryRequest( ¶ms ); +} + +/** + @brief Cancel a device discovery scan. + + Public function defined in observer.h. +*/ +bStatus_t GAPObserverRole_CancelDiscovery( void ) +{ + return GAP_DeviceDiscoveryCancel( gapObserverRoleTaskId ); +} + +/** + @brief Observer Profile Task initialization function. + + @param taskId - Task ID. + + @return void +*/ +void GAPObserverRole_Init( uint8 taskId ) +{ + gapObserverRoleTaskId = taskId; + // Register for HCI messages (for RSSI) + GAP_RegisterForHCIMsgs( taskId ); +} + +/** + @brief Observer Profile Task event processing function. + + @param taskId - Task ID + @param events - Events. + + @return events not processed +*/ +uint16 GAPObserverRole_ProcessEvent( uint8 taskId, uint16 events ) +{ + if ( events & SYS_EVENT_MSG ) + { + uint8* pMsg; + + if ( (pMsg = osal_msg_receive( gapObserverRoleTaskId )) != NULL ) + { + gapObserverRole_ProcessOSALMsg( (osal_event_hdr_t*) pMsg ); + // Release the OSAL message + VOID osal_msg_deallocate( pMsg ); + } + + // return unprocessed events + return (events ^ SYS_EVENT_MSG); + } + + // Discard unknown events + return 0; +} + +/********************************************************************* + @fn gapObserverRole_ProcessOSALMsg + + @brief Process an incoming task message. + + @param pMsg - message to process + + @return none +*/ +static void gapObserverRole_ProcessOSALMsg( osal_event_hdr_t* pMsg ) +{ + switch ( pMsg->event ) + { + case HCI_GAP_EVENT_EVENT: + if ( pMsg->status == HCI_COMMAND_COMPLETE_EVENT_CODE ) + { + //hciEvt_CmdComplete_t *pPkt = (hciEvt_CmdComplete_t *) pMsg; + } + + break; + + case GAP_MSG_EVENT: + gapObserverRole_ProcessGAPMsg( (gapEventHdr_t*) pMsg ); + break; + + default: + break; + } +} + +/********************************************************************* + @fn gapObserverRole_ProcessGAPMsg + + @brief Process an incoming task message from GAP. + + @param pMsg - message to process + + @return none +*/ +static void gapObserverRole_ProcessGAPMsg( gapEventHdr_t* pMsg ) +{ + switch ( pMsg->opcode ) + { + case GAP_DEVICE_INIT_DONE_EVENT: + { + gapDeviceInitDoneEvent_t* pPkt = (gapDeviceInitDoneEvent_t*) pMsg; + + if ( pPkt->hdr.status == SUCCESS ) + { + // Save off the information + VOID osal_memcpy( gapObserverRoleBdAddr, pPkt->devAddr, B_ADDR_LEN ); + } + } + break; + + default: + break; + } + + // Pass event to app + if ( pGapObserverRoleCB && pGapObserverRoleCB->eventCB ) + { + pGapObserverRoleCB->eventCB( (gapObserverRoleEvent_t*) pMsg ); + } +} + +/********************************************************************* +*********************************************************************/ diff --git a/src/components/profiles/Roles/observer.h b/src/components/profiles/Roles/observer.h new file mode 100644 index 0000000..6616064 --- /dev/null +++ b/src/components/profiles/Roles/observer.h @@ -0,0 +1,193 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ +#ifndef OBSERVER_H +#define OBSERVER_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "gap.h" + +/********************************************************************* + CONSTANTS +*/ + +/** @defgroup GAPOBSERVERROLE_PROFILE_PARAMETERS GAP Observer Role Parameters + @{ +*/ +#define GAPOBSERVERROLE_BD_ADDR 0x400 //!< Device's Address. Read Only. Size is uint8[B_ADDR_LEN]. This item is read from the controller. +#define GAPOBSERVERROLE_MAX_SCAN_RES 0x401 //!< Maximum number of discover scan results to receive. Default is 0 = unlimited. +/** @} End GAPOBSERVERROLE_PROFILE_PARAMETERS */ + +/********************************************************************* + VARIABLES +*/ + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/** + Observer Event Structure +*/ +typedef union +{ + gapEventHdr_t gap; //!< GAP_MSG_EVENT and status. + gapDeviceInitDoneEvent_t initDone; //!< GAP initialization done. + gapDeviceInfoEvent_t deviceInfo; //!< Discovery device information event structure. + gapDevDiscEvent_t discCmpl; //!< Discovery complete event structure. +} gapObserverRoleEvent_t; + +/** + RSSI Read Callback Function +*/ +typedef void (*pfnGapObserverRoleRssiCB_t) +( + uint16 connHandle, //!< Connection handle. + int8 rssi //!< New RSSI value. +); + +/** + Observer Event Callback Function +*/ +typedef void (*pfnGapObserverRoleEventCB_t) +( + gapObserverRoleEvent_t* pEvent //!< Pointer to event structure. +); + +/** + Observer Callback Structure +*/ +typedef struct +{ + pfnGapObserverRoleRssiCB_t rssiCB; //!< RSSI callback. + pfnGapObserverRoleEventCB_t eventCB; //!< Event callback. +} gapObserverRoleCB_t; + +/********************************************************************* + VARIABLES +*/ + +/********************************************************************* + API FUNCTIONS +*/ + +/* ------------------------------------------------------------------- + Observer Profile Public APIs +*/ + +/** + @defgroup OBSERVER_PROFILE_API Observer Profile API Functions + + @{ +*/ + +/** + @brief Start the device in Observer role. This function is typically + called once during system startup. + + @param pAppCallbacks - pointer to application callbacks + + @return SUCCESS: Operation successful.
+ bleAlreadyInRequestedMode: Device already started.
+*/ +extern bStatus_t GAPObserverRole_StartDevice( gapObserverRoleCB_t* pAppCallbacks ); + +/** + @brief Set a parameter in the Observer Profile. + + @param param - profile parameter ID: @ref GAPOBSERVERROLE_PROFILE_PARAMETERS + @param len - length of data to write + @param pValue - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type. + + @return SUCCESS: Operation successful.
+ INVALIDPARAMETER: Invalid parameter ID.
+*/ +extern bStatus_t GAPObserverRole_SetParameter( uint16 param, uint8 len, void* pValue ); + +/** + @brief Get a parameter in the Observer Profile. + + @param param - profile parameter ID: @ref GAPOBSERVERROLE_PROFILE_PARAMETERS + @param pValue - pointer to buffer to contain the read data + + @return SUCCESS: Operation successful.
+ INVALIDPARAMETER: Invalid parameter ID.
+*/ +extern bStatus_t GAPObserverRole_GetParameter( uint16 param, void* pValue ); + +/** + @brief Start a device discovery scan. + + @param mode - discovery mode: @ref GAP_DEVDISC_MODE_DEFINES + @param activeScan - TRUE to perform active scan + @param whiteList - TRUE to only scan for devices in the white list + + @return SUCCESS: Discovery scan started.
+ bleIncorrectMode: Invalid profile role.
+ bleAlreadyInRequestedMode: Not available.
+*/ +extern bStatus_t GAPObserverRole_StartDiscovery( uint8 mode, uint8 activeScan, uint8 whiteList ); + +/** + @brief Cancel a device discovery scan. + + @return SUCCESS: Cancel started.
+ bleInvalidTaskID: Not the task that started discovery.
+ bleIncorrectMode: Not in discovery mode.
+*/ +extern bStatus_t GAPObserverRole_CancelDiscovery( void ); + +/** + @} +*/ + +/* ------------------------------------------------------------------- + TASK API - These functions must only be called by OSAL. +*/ + +/** + @internal + + @brief Observer Profile Task initialization function. + + @param taskId - Task ID. + + @return void +*/ +extern void GAPObserverRole_Init( uint8 taskId ); + +/** + @internal + + @brief Observer Profile Task event processing function. + + @param taskId - Task ID + @param events - Events. + + @return events not processed +*/ +extern uint16 GAPObserverRole_ProcessEvent( uint8 taskId, uint16 events ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* OBSERVER_H */ diff --git a/src/components/profiles/Roles/peripheral.c b/src/components/profiles/Roles/peripheral.c new file mode 100644 index 0000000..256d7db --- /dev/null +++ b/src/components/profiles/Roles/peripheral.c @@ -0,0 +1,1589 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: peripheral.c + Revised: + Revision: + + Description: GAP Peripheral Role + + +**************************************************************************************************/ + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "hci_tl.h" +#include "l2cap.h" +#include "gap.h" +#include "linkdb.h" +#include "att.h" +#include "gatt.h" +#include "osal_snv.h" +#include "peripheral.h" +#include "gapbondmgr.h" + +#ifdef EXT_ADV_ENABLE + #include "rf_phy_driver.h" +#endif + +#ifndef DEF_GAPBOND_MGR_ENABLE + #define DEF_GAPBOND_MGR_ENABLE 1 +#endif +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ +// Profile Events +#define START_ADVERTISING_EVT 0x0001 // Start Advertising +#define RSSI_READ_EVT 0x0002 // Read RSSI +#define START_CONN_UPDATE_EVT 0x0004 // Start Connection Update Procedure +#define CONN_PARAM_TIMEOUT_EVT 0x0008 // Connection Parameters Update Timeout + +#ifdef EXT_ADV_ENABLE + #define START_SECOND_ADVERTISING_EVENT 0x0010 +#endif + + +#define DEFAULT_ADVERT_OFF_TIME 30000 // 30 seconds + +#define RSSI_NOT_AVAILABLE 127 + +#define DEFAULT_MIN_CONN_INTERVAL 0x0006 // 100 milliseconds +#define DEFAULT_MAX_CONN_INTERVAL 0x0C80 // 4 seconds + +#define MIN_CONN_INTERVAL 0x0006 +#define MAX_CONN_INTERVAL 0x0C80 + +#define DEFAULT_TIMEOUT_MULTIPLIER 1000 + +#define CONN_INTERVAL_MULTIPLIER 6 + +#define MIN_SLAVE_LATENCY 0 +#define MAX_SLAVE_LATENCY 500 + +#define MIN_TIMEOUT_MULTIPLIER 0x000a +#define MAX_TIMEOUT_MULTIPLIER 0x0c80 + +#define MAX_TIMEOUT_VALUE 0xFFFF + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ +uint8 gapRole_TaskID; // Task ID for internal task/event processing + +gaprole_States_t gapRole_state; + +/********************************************************************* + Profile Parameters - reference GAPROLE_PROFILE_PARAMETERS for + descriptions +*/ + +static uint8 gapRole_profileRole; +static uint8 gapRole_IRK[KEYLEN]; +static uint8 gapRole_SRK[KEYLEN]; +static uint32 gapRole_signCounter; +static uint8 gapRole_bdAddr[B_ADDR_LEN]; +uint8 gapRole_AdvEnabled = FALSE; +#ifdef EXT_ADV_ENABLE + static uint8 gapRole_ExtAdvEnabled = FALSE; +#endif +static uint16 gapRole_AdvertOffTime = DEFAULT_ADVERT_OFF_TIME; +static uint8 gapRole_AdvertDataLen = 3; +uint8 gapRole_AdvertData[B_MAX_ADV_LEN] = +{ + 0x02, // length of this data + GAP_ADTYPE_FLAGS, // AD Type = Flags + // Limited Discoverable & BR/EDR not supported + (GAP_ADTYPE_FLAGS_GENERAL | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED), + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +}; +static uint8 gapRole_ScanRspDataLen = 0; +static uint8 gapRole_ScanRspData[B_MAX_ADV_LEN] = {0}; +uint8 gapRole_AdvEventType; +uint8 gapRole_AdvDirectType; +uint8 gapRole_AdvDirectAddr[B_ADDR_LEN] = {0}; +uint8 gapRole_AdvChanMap; +uint8 gapRole_AdvFilterPolicy; + +static uint16 gapRole_ConnectionHandle = INVALID_CONNHANDLE; +static uint16 gapRole_ConnectionInterval = 0; +static uint16 gapRole_ConnectionLatency = 0; + +static uint16 gapRole_RSSIReadRate = 0; + +static uint8 gapRole_ConnectedDevAddr[B_ADDR_LEN] = {0}; + +static uint8 gapRole_ParamUpdateEnable = FALSE; +static uint16 gapRole_MinConnInterval = DEFAULT_MIN_CONN_INTERVAL; +static uint16 gapRole_MaxConnInterval = DEFAULT_MAX_CONN_INTERVAL; +static uint16 gapRole_SlaveLatency = MIN_SLAVE_LATENCY; +static uint16 gapRole_TimeoutMultiplier = DEFAULT_TIMEOUT_MULTIPLIER; + +static uint16 gapRole_ConnInterval = 0; +static uint16 gapRole_ConnSlaveLatency = 0; +static uint16 gapRole_ConnTimeout = 0; + +static uint8 paramUpdateNoSuccessOption = GAPROLE_NO_ACTION; + +// Application callbacks +static gapRolesCBs_t* pGapRoles_AppCGs = NULL; +static gapRolesParamUpdateCB_t* pGapRoles_ParamUpdateCB = NULL; + +/********************************************************************* + Profile Attributes - variables +*/ + +/********************************************************************* + Profile Attributes - Table +*/ + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static void gapRole_ProcessOSALMsg( osal_event_hdr_t* pMsg ); +static void gapRole_ProcessGAPMsg( gapEventHdr_t* pMsg ); +static void gapRole_SetupGAP( void ); +static void gapRole_HandleParamUpdateNoSuccess( void ); +static void gapRole_startConnUpdate( uint8 handleFailure ); + +#ifdef EXT_ADV_ENABLE + extern volatile uint8_t g_rfPhyPktFmt; +#endif +/********************************************************************* + NETWORK LAYER CALLBACKS +*/ + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/********************************************************************* + @brief Set a GAP Role parameter. + + Public function defined in peripheral.h. +*/ +bStatus_t GAPRole_SetParameter( uint16 param, uint8 len, void* pValue ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case GAPROLE_IRK: + if ( len == KEYLEN ) + { + VOID osal_memcpy( gapRole_IRK, pValue, KEYLEN ) ; + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_SRK: + if ( len == KEYLEN ) + { + VOID osal_memcpy( gapRole_SRK, pValue, KEYLEN ) ; + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_SIGNCOUNTER: + if ( len == sizeof ( uint32 ) ) + { + gapRole_signCounter = *((uint32*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADVERT_ENABLED: + if ( len == sizeof( uint8 ) ) + { + uint8 oldAdvEnabled = gapRole_AdvEnabled; + gapRole_AdvEnabled = *((uint8*)pValue); + + if ( (oldAdvEnabled) && (gapRole_AdvEnabled == FALSE) ) + { + // Turn off Advertising + if ( ( gapRole_state == GAPROLE_ADVERTISING ) + || ( gapRole_state == GAPROLE_CONNECTED_ADV ) + || ( gapRole_state == GAPROLE_WAITING_AFTER_TIMEOUT ) ) + { + VOID GAP_EndDiscoverable( gapRole_TaskID ); + } + } + else if ( (oldAdvEnabled == FALSE) && (gapRole_AdvEnabled) ) + { + // Turn on Advertising + if ( (gapRole_state == GAPROLE_STARTED) + || (gapRole_state == GAPROLE_WAITING) + || (gapRole_state == GAPROLE_CONNECTED) + || (gapRole_state == GAPROLE_WAITING_AFTER_TIMEOUT) ) + { + VOID osal_set_event( gapRole_TaskID, START_ADVERTISING_EVT ); + } + } + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADVERT_OFF_TIME: + if ( len == sizeof ( uint16 ) ) + { + gapRole_AdvertOffTime = *((uint16*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADVERT_DATA: + if ( len <= B_MAX_ADV_LEN ) + { + VOID osal_memset( gapRole_AdvertData, 0, B_MAX_ADV_LEN ); + VOID osal_memcpy( gapRole_AdvertData, pValue, len ); + gapRole_AdvertDataLen = len; + // Update the advertising data + ret = GAP_UpdateAdvertisingData( gapRole_TaskID, + TRUE, len, gapRole_AdvertData ); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_SCAN_RSP_DATA: + if ( len <= B_MAX_ADV_LEN ) + { + VOID osal_memset( gapRole_ScanRspData, 0, B_MAX_ADV_LEN ); + VOID osal_memcpy( gapRole_ScanRspData, pValue, len ); + gapRole_ScanRspDataLen = len; + // Update the Response Data + ret = GAP_UpdateAdvertisingData( gapRole_TaskID, + FALSE, gapRole_ScanRspDataLen, gapRole_ScanRspData ); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADV_EVENT_TYPE: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= GAP_ADTYPE_ADV_LDC_DIRECT_IND) ) + { + gapRole_AdvEventType = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADV_DIRECT_TYPE: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= ADDRTYPE_PRIVATE_RESOLVE) ) + { + gapRole_AdvDirectType = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADV_DIRECT_ADDR: + if ( len == B_ADDR_LEN ) + { + VOID osal_memcpy( gapRole_AdvDirectAddr, pValue, B_ADDR_LEN ) ; + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADV_CHANNEL_MAP: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= 0x07) ) + { + gapRole_AdvChanMap = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADV_FILTER_POLICY: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= GAP_FILTER_POLICY_WHITE) ) + { + gapRole_AdvFilterPolicy = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_RSSI_READ_RATE: + if ( len == sizeof ( uint16 ) ) + { + gapRole_RSSIReadRate = *((uint16*)pValue); + + if ( (gapRole_RSSIReadRate) && (gapRole_state == GAPROLE_CONNECTED) ) + { + // Start the RSSI Reads + VOID osal_start_timerEx( gapRole_TaskID, RSSI_READ_EVT, gapRole_RSSIReadRate ); + } + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_PARAM_UPDATE_ENABLE: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= TRUE) ) + { + gapRole_ParamUpdateEnable = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_MIN_CONN_INTERVAL: + { + uint16 newInterval = *((uint16*)pValue); + + if ( len == sizeof ( uint16 ) && + ( newInterval >= MIN_CONN_INTERVAL ) && + ( newInterval <= MAX_CONN_INTERVAL ) ) + { + gapRole_MinConnInterval = newInterval; + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPROLE_MAX_CONN_INTERVAL: + { + uint16 newInterval = *((uint16*)pValue); + + if ( len == sizeof ( uint16 ) && + ( newInterval >= MIN_CONN_INTERVAL) && + ( newInterval <= MAX_CONN_INTERVAL) ) + { + gapRole_MaxConnInterval = newInterval; + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPROLE_SLAVE_LATENCY: + { + uint16 latency = *((uint16*)pValue); + + if ( len == sizeof ( uint16 ) && (latency < MAX_SLAVE_LATENCY) ) + { + gapRole_SlaveLatency = latency; + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPROLE_TIMEOUT_MULTIPLIER: + { + uint16 newTimeout = *((uint16*)pValue); + + if ( len == sizeof ( uint16 ) + && (newTimeout >= MIN_TIMEOUT_MULTIPLIER) && (newTimeout <= MAX_TIMEOUT_MULTIPLIER) ) + { + gapRole_TimeoutMultiplier = newTimeout; + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPROLE_PARAM_UPDATE_REQ: + { + uint8 req = *((uint8*)pValue); + + if ( len == sizeof ( uint8 ) && (req == TRUE) ) + { + // Make sure we don't send an L2CAP Connection Parameter Update Request + // command within TGAP(conn_param_timeout) of an L2CAP Connection Parameter + // Update Response being received. + if ( osal_get_timeoutEx( gapRole_TaskID, CONN_PARAM_TIMEOUT_EVT ) == 0 ) + { + // Start connection update procedure + gapRole_startConnUpdate( GAPROLE_NO_ACTION ); + // Connection update requested by app, cancel such pending procedure (if active) + VOID osal_stop_timerEx( gapRole_TaskID, START_CONN_UPDATE_EVT ); + } + else + { + ret = blePending; + } + } + else + { + ret = bleInvalidRange; + } + } + break; + #ifdef EXT_ADV_ENABLE + + case GAPROLE_EXT_ADVERT_ENABLED: + if ( len == sizeof( uint8 ) ) + { + gapRole_ExtAdvEnabled = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + #endif + + default: + + // The param value isn't part of this profile, try the GAP. + if ( (param < TGAP_PARAMID_MAX) && (len == sizeof ( uint16 )) ) + { + ret = GAP_SetParamValue( param, *((uint16*)pValue) ); + } + else + { + ret = INVALIDPARAMETER; + } + + break; + } + + return ( ret ); +} + +/********************************************************************* + @brief Get a GAP Role parameter. + + Public function defined in peripheral.h. +*/ +bStatus_t GAPRole_GetParameter( uint16 param, void* pValue ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case GAPROLE_PROFILEROLE: + *((uint8*)pValue) = gapRole_profileRole; + break; + + case GAPROLE_IRK: + VOID osal_memcpy( pValue, gapRole_IRK, KEYLEN ) ; + break; + + case GAPROLE_SRK: + VOID osal_memcpy( pValue, gapRole_SRK, KEYLEN ) ; + break; + + case GAPROLE_SIGNCOUNTER: + *((uint32*)pValue) = gapRole_signCounter; + break; + + case GAPROLE_BD_ADDR: + VOID osal_memcpy( pValue, gapRole_bdAddr, B_ADDR_LEN ) ; + break; + + case GAPROLE_ADVERT_ENABLED: + *((uint8*)pValue) = gapRole_AdvEnabled; + break; + + case GAPROLE_ADVERT_OFF_TIME: + *((uint16*)pValue) = gapRole_AdvertOffTime; + break; + + case GAPROLE_ADVERT_DATA: + VOID osal_memcpy( pValue, gapRole_AdvertData, gapRole_AdvertDataLen ); + break; + + case GAPROLE_SCAN_RSP_DATA: + VOID osal_memcpy( pValue, gapRole_ScanRspData, gapRole_ScanRspDataLen ) ; + break; + + case GAPROLE_ADV_EVENT_TYPE: + *((uint8*)pValue) = gapRole_AdvEventType; + break; + + case GAPROLE_ADV_DIRECT_TYPE: + *((uint8*)pValue) = gapRole_AdvDirectType; + break; + + case GAPROLE_ADV_DIRECT_ADDR: + VOID osal_memcpy( pValue, gapRole_AdvDirectAddr, B_ADDR_LEN ) ; + break; + + case GAPROLE_ADV_CHANNEL_MAP: + *((uint8*)pValue) = gapRole_AdvChanMap; + break; + + case GAPROLE_ADV_FILTER_POLICY: + *((uint8*)pValue) = gapRole_AdvFilterPolicy; + break; + + case GAPROLE_CONNHANDLE: + *((uint16*)pValue) = gapRole_ConnectionHandle; + break; + + case GAPROLE_RSSI_READ_RATE: + *((uint16*)pValue) = gapRole_RSSIReadRate; + break; + + case GAPROLE_PARAM_UPDATE_ENABLE: + *((uint16*)pValue) = gapRole_ParamUpdateEnable; + break; + + case GAPROLE_MIN_CONN_INTERVAL: + *((uint16*)pValue) = gapRole_MinConnInterval; + break; + + case GAPROLE_MAX_CONN_INTERVAL: + *((uint16*)pValue) = gapRole_MaxConnInterval; + break; + + case GAPROLE_SLAVE_LATENCY: + *((uint16*)pValue) = gapRole_SlaveLatency; + break; + + case GAPROLE_TIMEOUT_MULTIPLIER: + *((uint16*)pValue) = gapRole_TimeoutMultiplier; + break; + + case GAPROLE_CONN_BD_ADDR: + VOID osal_memcpy( pValue, gapRole_ConnectedDevAddr, B_ADDR_LEN ) ; + break; + + case GAPROLE_CONN_INTERVAL: + *((uint16*)pValue) = gapRole_ConnInterval; + break; + + case GAPROLE_CONN_LATENCY: + *((uint16*)pValue) = gapRole_ConnSlaveLatency; + break; + + case GAPROLE_CONN_TIMEOUT: + *((uint16*)pValue) = gapRole_ConnTimeout; + break; + + case GAPROLE_STATE: + *((uint8*)pValue) = gapRole_state; + break; + + case GAPROLE_CONNECTION_INTERVAL: + *((uint16*)pValue) = gapRole_ConnectionInterval; + break; + + case GAPROLE_CONNECTION_LATENCY: + *((uint16*)pValue) = gapRole_ConnectionLatency; + break; + #ifdef EXT_ADV_ENABLE + + case GAPROLE_EXT_ADVERT_ENABLED: + *((uint8*)pValue) = gapRole_ExtAdvEnabled; + break; + #endif + + default: + + // The param value isn't part of this profile, try the GAP. + if ( param < TGAP_PARAMID_MAX ) + { + *((uint16*)pValue) = GAP_GetParamValue( param ); + } + else + { + ret = INVALIDPARAMETER; + } + + break; + } + + return ( ret ); +} + +/********************************************************************* + @brief Does the device initialization. + + Public function defined in peripheral.h. +*/ +bStatus_t GAPRole_StartDevice( gapRolesCBs_t* pAppCallbacks ) +{ + if ( gapRole_state == GAPROLE_INIT ) + { + // Clear all of the Application callbacks + if ( pAppCallbacks ) + { + pGapRoles_AppCGs = pAppCallbacks; + } + + // Start the GAP + gapRole_SetupGAP(); + return ( SUCCESS ); + } + else + { + return ( bleAlreadyInRequestedMode ); + } +} + +/********************************************************************* + @brief Register application's callbacks. + + Public function defined in peripheral.h. +*/ +void GAPRole_RegisterAppCBs( gapRolesParamUpdateCB_t* pParamUpdateCB ) +{ + if ( pParamUpdateCB != NULL ) + { + pGapRoles_ParamUpdateCB = pParamUpdateCB; + } +} + +/********************************************************************* + @brief Terminates the existing connection. + + Public function defined in peripheral.h. +*/ +bStatus_t GAPRole_TerminateConnection( void ) +{ + if ( gapRole_state == GAPROLE_CONNECTED ) + { + return ( GAP_TerminateLinkReq( gapRole_TaskID, gapRole_ConnectionHandle, + HCI_DISCONNECT_REMOTE_USER_TERM ) ); + } + else + { + return ( bleIncorrectMode ); + } +} + +/********************************************************************* + LOCAL FUNCTION PROTOTYPES +*/ + +/********************************************************************* + @brief Task Initialization function. + + Internal function defined in peripheral.h. +*/ +void GAPRole_Init( uint8 task_id ) +{ + gapRole_TaskID = task_id; + gapRole_state = GAPROLE_INIT; + gapRole_ConnectionHandle = INVALID_CONNHANDLE; + GAP_RegisterForHCIMsgs( gapRole_TaskID ); + // Initialize the Profile Advertising and Connection Parameters + gapRole_profileRole = GAP_PROFILE_PERIPHERAL; + VOID osal_memset( gapRole_IRK, 0, KEYLEN ); + VOID osal_memset( gapRole_SRK, 0, KEYLEN ); + gapRole_signCounter = 0; + gapRole_AdvEventType = GAP_ADTYPE_ADV_IND; + gapRole_AdvDirectType = ADDRTYPE_PUBLIC; + gapRole_AdvChanMap = GAP_ADVCHAN_ALL; + gapRole_AdvFilterPolicy = GAP_FILTER_POLICY_ALL; + // Restore Items from NV +// VOID osal_snv_read( BLE_NVID_IRK, KEYLEN, gapRole_IRK ); +// VOID osal_snv_read( BLE_NVID_CSRK, KEYLEN, gapRole_SRK ); +// VOID osal_snv_read( BLE_NVID_SIGNCOUNTER, sizeof( uint32 ), &gapRole_signCounter ); +} + +/********************************************************************* + @brief Task Event Processor function. + + Internal function defined in peripheral.h. +*/ +uint16 GAPRole_ProcessEvent( uint8 task_id, uint16 events ) +{ + VOID task_id; // OSAL required parameter that isn't used in this function + + if ( events & SYS_EVENT_MSG ) + { + uint8* pMsg; + + if ( (pMsg = osal_msg_receive( gapRole_TaskID )) != NULL ) + { + gapRole_ProcessOSALMsg( (osal_event_hdr_t*)pMsg ); + // Release the OSAL message + VOID osal_msg_deallocate( pMsg ); + } + + // return unprocessed events + return (events ^ SYS_EVENT_MSG); + } + + if ( events & GAP_EVENT_SIGN_COUNTER_CHANGED ) + { + // Sign counter changed, save it to NV + // VOID osal_snv_write( BLE_NVID_SIGNCOUNTER, sizeof( uint32 ), &gapRole_signCounter ); + return ( events ^ GAP_EVENT_SIGN_COUNTER_CHANGED ); + } + + if ( events & START_ADVERTISING_EVT ) + { + if ( gapRole_AdvEnabled ) + { + gapAdvertisingParams_t params; + + // Setup advertisement parameters + if ( gapRole_state == GAPROLE_CONNECTED ) + { + // While in a connection, we can only advertise non-connectable undirected. + params.eventType = GAP_ADTYPE_ADV_NONCONN_IND; + } + else + { + params.eventType = gapRole_AdvEventType; + params.initiatorAddrType = gapRole_AdvDirectType; + VOID osal_memcpy( params.initiatorAddr, gapRole_AdvDirectAddr, B_ADDR_LEN ); + } + + params.channelMap = gapRole_AdvChanMap; + params.filterPolicy = gapRole_AdvFilterPolicy; + uint8 ret = GAP_MakeDiscoverable( gapRole_TaskID, ¶ms ); + + if ( ret != SUCCESS ) + { + gapRole_state = GAPROLE_ERROR; + + // Notify the application with the new state change + if ( pGapRoles_AppCGs && pGapRoles_AppCGs->pfnStateChange ) + { + pGapRoles_AppCGs->pfnStateChange( gapRole_state ); + } + } + } + + return ( events ^ START_ADVERTISING_EVT ); + } + +#ifdef EXT_ADV_ENABLE + + if( events & START_SECOND_ADVERTISING_EVENT) + { + if( gapRole_ExtAdvEnabled ) + { + if( GAP_EXTADV_MAKEDiscoverable(gapRole_TaskID, TRUE) != SUCCESS ) + { + gapRole_state = GAPROLE_ERROR; + + // Notify the application with the new state change + if ( pGapRoles_AppCGs && pGapRoles_AppCGs->pfnStateChange ) + { + pGapRoles_AppCGs->pfnStateChange( gapRole_state ); + } + } + } + + return ( events ^ START_SECOND_ADVERTISING_EVENT ); + } + +#endif + + if ( events & RSSI_READ_EVT ) + { + // Only get RSSI when in a connection + if ( gapRole_state == GAPROLE_CONNECTED ) + { + // Ask for RSSI + VOID HCI_ReadRssiCmd( gapRole_ConnectionHandle ); + + // Setup next event + if ( gapRole_RSSIReadRate ) + { + VOID osal_start_timerEx( gapRole_TaskID, RSSI_READ_EVT, gapRole_RSSIReadRate ); + } + } + + return ( events ^ RSSI_READ_EVT ); + } + + if ( events & START_CONN_UPDATE_EVT ) + { + // Start connection update procedure + gapRole_startConnUpdate( GAPROLE_NO_ACTION ); + return ( events ^ START_CONN_UPDATE_EVT ); + } + + if ( events & CONN_PARAM_TIMEOUT_EVT ) + { + // Unsuccessful in updating connection parameters + gapRole_HandleParamUpdateNoSuccess(); + return ( events ^ CONN_PARAM_TIMEOUT_EVT ); + } + + // Discard unknown events + return 0; +} + +/********************************************************************* + @fn gapRole_ProcessOSALMsg + + @brief Process an incoming task message. + + @param pMsg - message to process + + @return none +*/ +static void gapRole_ProcessOSALMsg( osal_event_hdr_t* pMsg ) +{ + switch ( pMsg->event ) + { + case HCI_GAP_EVENT_EVENT: + + //LOG("GAP EVT[%d]\n", pMsg->status); + if ( pMsg->status == HCI_COMMAND_COMPLETE_EVENT_CODE ) + { + hciEvt_CmdComplete_t* pPkt = (hciEvt_CmdComplete_t*)pMsg; + + if ( pPkt->cmdOpcode == HCI_READ_RSSI ) + { + int8 rssi = (int8)pPkt->pReturnParam[3]; + + if ( (gapRole_state == GAPROLE_CONNECTED) && (rssi != RSSI_NOT_AVAILABLE) ) + { + // Report RSSI to app + if ( pGapRoles_AppCGs && pGapRoles_AppCGs->pfnRssiRead ) + { + pGapRoles_AppCGs->pfnRssiRead( rssi ); + } + } + } + else if(pPkt->cmdOpcode == HCI_LE_SET_DATA_LENGTH) + { + LOG("[HCI DLE]%d %d %d\n",pPkt->pReturnParam[0],pPkt->pReturnParam[1],pPkt->pReturnParam[2]); + } + } + else if(pMsg->status==HCI_COMMAND_STATUS_EVENT_CODE) + { + hciEvt_CommandStatus_t* pPkt = (hciEvt_CommandStatus_t*)pMsg; + + if ( pPkt->cmdOpcode == HCI_LE_SET_PHY ) + { + LOG_DEBUG("[HCI PHY] %2x \n",pPkt->cmdStatus); + } + } + else if(pMsg->status==HCI_LE_EVENT_CODE) + { + hciEvt_BLEEvent_Hdr_t* pPkt = (hciEvt_BLEEvent_Hdr_t*)pMsg; + + if ( pPkt->BLEEventCode == HCI_BLE_DATA_LENGTH_CHANGE_EVENT ) + { +// hciEvt_BLEDataLenChange_t * pkt = (hciEvt_BLEDataLenChange_t *)pMsg; +// LOG_DEBUG("[HCI DLE EVT]%d %d %d %d\n",pkt->MaxRxOctets,pkt->MaxRxTime, +// pkt->MaxTxOctets,pkt->MaxTxTime); + } + else if(pPkt->BLEEventCode == HCI_BLE_PHY_UPDATE_COMPLETE_EVENT ) + { +// hciEvt_BLEPhyUpdateComplete_t * pkt = (hciEvt_BLEPhyUpdateComplete_t *)pMsg; +// LOG_DEBUG("[HCI PHY EVT]s%d r%d t%d\n",pkt->status, pkt->rxPhy,pkt->txPhy); + } + } + + break; + + case GAP_MSG_EVENT: + gapRole_ProcessGAPMsg( (gapEventHdr_t*)pMsg ); + break; + + case L2CAP_SIGNAL_EVENT: + { + l2capSignalEvent_t* pPkt = (l2capSignalEvent_t*)pMsg; + + // Process the Parameter Update Response + if ( pPkt->opcode == L2CAP_PARAM_UPDATE_RSP ) + { + l2capParamUpdateRsp_t* pRsp = (l2capParamUpdateRsp_t*)&(pPkt->cmd.updateRsp); + + if ( ( pRsp->result == L2CAP_CONN_PARAMS_REJECTED ) && + ( paramUpdateNoSuccessOption == GAPROLE_TERMINATE_LINK ) ) + { + // Cancel connection param update timeout timer + VOID osal_stop_timerEx( gapRole_TaskID, CONN_PARAM_TIMEOUT_EVT ); + // Terminate connection immediately + GAPRole_TerminateConnection(); + } + else + { + uint16 timeout = GAP_GetParamValue( TGAP_CONN_PARAM_TIMEOUT ); + // Let's wait for Controller to update connection parameters if they're + // accepted. Otherwise, decide what to do based on no success option. + VOID osal_start_timerEx( gapRole_TaskID, CONN_PARAM_TIMEOUT_EVT, timeout ); + } + } + } + break; + + default: + break; + } +} + +/********************************************************************* + @fn gapRole_ProcessGAPMsg + + @brief Process an incoming task message. + + @param pMsg - message to process + + @return none +*/ +static void gapRole_ProcessGAPMsg( gapEventHdr_t* pMsg ) +{ + uint8 notify = FALSE; // State changed notify the app? (default no) +#ifdef EXT_ADV_ENABLE + uint8 LegacyAdvEnable = FALSE; + uint8 SecondAdvEnable = FALSE; + gapDeviceInitDoneEvent_t* pPktsec = (gapDeviceInitDoneEvent_t*)pMsg; + bStatus_t statsec = pPktsec->hdr.status; + GAPRole_GetParameter(GAPROLE_ADVERT_ENABLED,&LegacyAdvEnable); + GAPRole_GetParameter(GAPROLE_EXT_ADVERT_ENABLED, &SecondAdvEnable); + + if( LegacyAdvEnable ) + { +#endif + + switch ( pMsg->opcode ) + { + case GAP_DEVICE_INIT_DONE_EVENT: + { + gapDeviceInitDoneEvent_t* pPkt = (gapDeviceInitDoneEvent_t*)pMsg; + bStatus_t stat = pPkt->hdr.status; + + if ( stat == SUCCESS ) + { + // Save off the generated keys + // VOID osal_snv_write( BLE_NVID_IRK, KEYLEN, gapRole_IRK ); + // VOID osal_snv_write( BLE_NVID_CSRK, KEYLEN, gapRole_SRK ); + // Save off the information + VOID osal_memcpy( gapRole_bdAddr, pPkt->devAddr, B_ADDR_LEN ); + gapRole_state = GAPROLE_STARTED; + // Update the advertising data + stat = GAP_UpdateAdvertisingData( gapRole_TaskID, + TRUE, gapRole_AdvertDataLen, gapRole_AdvertData ); + } + + if ( stat != SUCCESS ) + { + gapRole_state = GAPROLE_ERROR; + } + + notify = TRUE; + } + break; + + case GAP_ADV_DATA_UPDATE_DONE_EVENT: + { + gapAdvDataUpdateEvent_t* pPkt = (gapAdvDataUpdateEvent_t*)pMsg; + + if ( pPkt->hdr.status == SUCCESS ) + { + if ( pPkt->adType ) + { + // Setup the Response Data + pPkt->hdr.status = GAP_UpdateAdvertisingData( gapRole_TaskID, + FALSE, gapRole_ScanRspDataLen, gapRole_ScanRspData ); + } + else if ( ( gapRole_state != GAPROLE_ADVERTISING ) && + ( osal_get_timeoutEx( gapRole_TaskID, START_ADVERTISING_EVT ) == 0 ) ) + { + // Start advertising + VOID osal_set_event( gapRole_TaskID, START_ADVERTISING_EVT ); + } + } + + if ( pPkt->hdr.status != SUCCESS ) + { + // Set into Error state + gapRole_state = GAPROLE_ERROR; + notify = TRUE; + } + } + break; + + case GAP_MAKE_DISCOVERABLE_DONE_EVENT: + case GAP_END_DISCOVERABLE_DONE_EVENT: + { + gapMakeDiscoverableRspEvent_t* pPkt = (gapMakeDiscoverableRspEvent_t*)pMsg; + + if ( pPkt->hdr.status == SUCCESS ) + { + if ( pMsg->opcode == GAP_MAKE_DISCOVERABLE_DONE_EVENT ) + { + if (gapRole_state == GAPROLE_CONNECTED) + { + gapRole_state = GAPROLE_CONNECTED_ADV; + } + else + { + gapRole_state = GAPROLE_ADVERTISING; + } + } + else // GAP_END_DISCOVERABLE_DONE_EVENT + { + if ( gapRole_AdvertOffTime != 0 ) + { + if ( ( gapRole_AdvEnabled ) ) + { + VOID osal_start_timerEx( gapRole_TaskID, START_ADVERTISING_EVT, gapRole_AdvertOffTime ); + } + } + else + { + // Since gapRole_AdvertOffTime is set to 0, the device should not + // automatically become discoverable again after a period of time. + // Set enabler to FALSE; device will become discoverable again when + // this value gets set to TRUE + gapRole_AdvEnabled = FALSE; + } + + if (gapRole_state == GAPROLE_CONNECTED_ADV) + { + // In the Advertising Off period + gapRole_state = GAPROLE_CONNECTED; + } + else if (gapRole_state == GAPROLE_WAITING_AFTER_TIMEOUT) + { + // Advertising was just turned off after the link disconnected so begin + // advertising again. + gapRole_AdvEnabled = TRUE; + // Turn advertising back on. + VOID osal_set_event( gapRole_TaskID, START_ADVERTISING_EVT ); + } + else + { + // In the Advertising Off period + gapRole_state = GAPROLE_WAITING; + } + } + } + else + { + gapRole_state = GAPROLE_ERROR; + } + + notify = TRUE; + } + break; + + case GAP_LINK_ESTABLISHED_EVENT: + { + gapEstLinkReqEvent_t* pPkt = (gapEstLinkReqEvent_t*)pMsg; + + if ( pPkt->hdr.status == SUCCESS ) + { + VOID osal_memcpy( gapRole_ConnectedDevAddr, pPkt->devAddr, B_ADDR_LEN ); + gapRole_ConnectionHandle = pPkt->connectionHandle; + gapRole_ConnectionInterval = pPkt->connInterval; + gapRole_ConnectionLatency = pPkt->connLatency; + gapRole_state = GAPROLE_CONNECTED; + + //LOG("connect by[%02x%02x%02x%02x%02x%02x] handle[%d] interval[%d] latency[%d] timeout[%d]\n", + // gapRole_ConnectedDevAddr[0], gapRole_ConnectedDevAddr[1], gapRole_ConnectedDevAddr[2], + // gapRole_ConnectedDevAddr[3],gapRole_ConnectedDevAddr[4], gapRole_ConnectedDevAddr[5], + // pPkt->connectionHandle, pPkt->connInterval,pPkt->connLatency, pPkt->connTimeout); + if ( gapRole_RSSIReadRate ) + { + // Start the RSSI Reads + VOID osal_start_timerEx( gapRole_TaskID, RSSI_READ_EVT, gapRole_RSSIReadRate ); + } + + // Store connection information + gapRole_ConnInterval = pPkt->connInterval; + gapRole_ConnSlaveLatency = pPkt->connLatency; + gapRole_ConnTimeout = pPkt->connTimeout; + + // Check whether update parameter request is enabled + if ( gapRole_ParamUpdateEnable == TRUE ) + { + // Get the minimum time upon connection establishment before the + // peripheral can start a connection update procedure. + uint16 timeout = GAP_GetParamValue( TGAP_CONN_PAUSE_PERIPHERAL ); + osal_start_timerEx( gapRole_TaskID, START_CONN_UPDATE_EVT, timeout*1000 ); + } + + // Notify the Bond Manager to the connection + #if(DEF_GAPBOND_MGR_ENABLE == TRUE) + VOID GAPBondMgr_LinkEst( pPkt->devAddrType, pPkt->devAddr, pPkt->connectionHandle, GAP_PROFILE_PERIPHERAL ); + #endif + // Set enabler to FALSE; device will become discoverable again when + // this value gets set to TRUE + gapRole_AdvEnabled = FALSE; + } + else if ( pPkt->hdr.status == bleGAPConnNotAcceptable ) + { + // Set enabler to FALSE; device will become discoverable again when + // this value gets set to TRUE + gapRole_AdvEnabled = FALSE; + // Go to WAITING state, and then start advertising + gapRole_state = GAPROLE_WAITING; + } + else + { + gapRole_state = GAPROLE_ERROR; + } + + notify = TRUE; + } + break; + + case GAP_LINK_TERMINATED_EVENT: + { + gapTerminateLinkEvent_t* pPkt = (gapTerminateLinkEvent_t*)pMsg; + // VOID GAPBondMgr_ProcessGAPMsg( (gapEventHdr_t *)pMsg ); + osal_memset( gapRole_ConnectedDevAddr, 0, B_ADDR_LEN ); + // Erase connection information + gapRole_ConnInterval = 0; + gapRole_ConnSlaveLatency = 0; + gapRole_ConnTimeout = 0; + // Cancel all connection parameter update timers (if any active) + VOID osal_stop_timerEx( gapRole_TaskID, START_CONN_UPDATE_EVT ); + VOID osal_stop_timerEx( gapRole_TaskID, CONN_PARAM_TIMEOUT_EVT ); + + // Go to WAITING state, and then start advertising + if( pPkt->reason == LL_SUPERVISION_TIMEOUT_TERM ) + { + gapRole_state = GAPROLE_WAITING_AFTER_TIMEOUT; + } + else + { + gapRole_state = GAPROLE_WAITING; + } + + LOG_DEBUG("[DISC].reason %02x\n",pPkt->reason); + notify = TRUE; + + //LOG("disconnected reason[%d]!\n", pPkt->reason); + // Check if still advertising from within last connection. + if ( gapRole_AdvEnabled) + { + // End advertising so we can restart advertising in order + // to change to connectable advertising from nonconnectable. + VOID GAP_EndDiscoverable( gapRole_TaskID ); + } + else // Turn advertising back on. + { + gapRole_AdvEnabled = TRUE; + VOID osal_set_event( gapRole_TaskID, START_ADVERTISING_EVT); + } + + gapRole_ConnectionHandle = INVALID_CONNHANDLE; + } + break; + + case GAP_LINK_PARAM_UPDATE_EVENT: + { + gapLinkUpdateEvent_t* pPkt = (gapLinkUpdateEvent_t*)pMsg; + // Cancel connection param update timeout timer (if active) + VOID osal_stop_timerEx( gapRole_TaskID, CONN_PARAM_TIMEOUT_EVT ); + + if ( pPkt->hdr.status == SUCCESS ) + { + // Store new connection parameters + gapRole_ConnInterval = pPkt->connInterval; + gapRole_ConnSlaveLatency = pPkt->connLatency; + gapRole_ConnTimeout = pPkt->connTimeout; + + // Make sure there's no pending connection update procedure + if ( osal_get_timeoutEx( gapRole_TaskID, START_CONN_UPDATE_EVT ) == 0 ) + { + // Notify the application with the new connection parameters + if ( pGapRoles_ParamUpdateCB != NULL ) + { + (*pGapRoles_ParamUpdateCB)( gapRole_ConnInterval, + gapRole_ConnSlaveLatency, + gapRole_ConnTimeout ); + } + } + } + } + break; + + default: + break; + } + + #ifdef EXT_ADV_ENABLE + } + else if( SecondAdvEnable ) + { + switch ( pMsg->opcode ) + { + case GAP_DEVICE_INIT_DONE_EVENT: + if ( statsec == SUCCESS ) + { + // Save off the information + VOID osal_memcpy( gapRole_bdAddr, pPktsec->devAddr, B_ADDR_LEN ); + gapRole_state = GAPROLE_STARTED; + GapAdv_UpdateParameter(gapRole_bdAddr); + VOID osal_set_event( gapRole_TaskID, START_SECOND_ADVERTISING_EVENT ); + } + + if ( statsec != SUCCESS ) + { + gapRole_state = GAPROLE_ERROR; + } + + notify = TRUE; + break; + + case GAP_LINK_ESTABLISHED_EVENT: + gapRole_state = GAPROLE_CONNECTED; + g_rfPhyPktFmt = PKT_FMT_BLR125K; + notify = TRUE; + break; + + case GAP_LINK_TERMINATED_EVENT: + { + gapTerminateLinkEvent_t* pPkt = (gapTerminateLinkEvent_t*)pMsg; + g_rfPhyPktFmt = PKT_FMT_BLR125K; + // VOID GAPBondMgr_ProcessGAPMsg( (gapEventHdr_t *)pMsg ); + osal_memset( gapRole_ConnectedDevAddr, 0, B_ADDR_LEN ); + // Erase connection information + gapRole_ConnInterval = 0; + gapRole_ConnSlaveLatency = 0; + gapRole_ConnTimeout = 0; + // Cancel all connection parameter update timers (if any active) + VOID osal_stop_timerEx( gapRole_TaskID, START_CONN_UPDATE_EVT ); + VOID osal_stop_timerEx( gapRole_TaskID, CONN_PARAM_TIMEOUT_EVT ); + + // Go to WAITING state, and then start advertising + if( pPkt->reason == LL_SUPERVISION_TIMEOUT_TERM ) + { + gapRole_state = GAPROLE_WAITING_AFTER_TIMEOUT; + } + else + { + gapRole_state = GAPROLE_WAITING; + } + + LOG_DEBUG("[DISC].reason %02x\n",pPkt->reason); + notify = TRUE; + //LOG("disconnected reason[%d]!\n", pPkt->reason); + // Check if still advertising from within last connection. + // = FALSE , should set in GAP_END_DISCOVERABLE_DONE_EVENT , follow-up + gapRole_ExtAdvEnabled = FALSE; + + if ( gapRole_ExtAdvEnabled) + { + // End advertising so we can restart advertising in order + // to change to connectable advertising from nonconnectable. + VOID GAP_EndDiscoverable( gapRole_TaskID ); + } + else // Turn advertising back on. + { + gapRole_ExtAdvEnabled = TRUE; + VOID osal_set_event( gapRole_TaskID, START_SECOND_ADVERTISING_EVENT); + } + + gapRole_ConnectionHandle = INVALID_CONNHANDLE; + } + break; + + case GAP_LINK_PARAM_UPDATE_EVENT: + { + gapLinkUpdateEvent_t* pPkt = (gapLinkUpdateEvent_t*)pMsg; + // Cancel connection param update timeout timer (if active) + VOID osal_stop_timerEx( gapRole_TaskID, CONN_PARAM_TIMEOUT_EVT ); + + if ( pPkt->hdr.status == SUCCESS ) + { + // Store new connection parameters + gapRole_ConnInterval = pPkt->connInterval; + gapRole_ConnSlaveLatency = pPkt->connLatency; + gapRole_ConnTimeout = pPkt->connTimeout; + + // Make sure there's no pending connection update procedure + if ( osal_get_timeoutEx( gapRole_TaskID, START_CONN_UPDATE_EVT ) == 0 ) + { + // Notify the application with the new connection parameters + if ( pGapRoles_ParamUpdateCB != NULL ) + { + (*pGapRoles_ParamUpdateCB)( gapRole_ConnInterval, + gapRole_ConnSlaveLatency, + gapRole_ConnTimeout ); + } + } + } + } + break; + + default: + break; + } + } + +//LOG_DEBUG(" SecondAdvEnable notify %d,pMsg->opcode %d,gapRole_state %d\n ",notify,pMsg->opcode,gapRole_state); + #endif + + if ( notify == TRUE ) + { + // Notify the application with the new state change + if ( pGapRoles_AppCGs && pGapRoles_AppCGs->pfnStateChange ) + { + pGapRoles_AppCGs->pfnStateChange( gapRole_state ); + } + } +} + +/********************************************************************* + @fn gapRole_SetupGAP + + @brief Call the GAP Device Initialization function using the + Profile Parameters. + + @param none + + @return none +*/ +static void gapRole_SetupGAP( void ) +{ + VOID GAP_DeviceInit( gapRole_TaskID, + gapRole_profileRole, 0, + gapRole_IRK, gapRole_SRK, + &gapRole_signCounter ); +} + +/********************************************************************* + @fn gapRole_HandleParamUpdateNoSuccess + + @brief Handle unsuccessful connection parameters update. + + @param none + + @return none +*/ +static void gapRole_HandleParamUpdateNoSuccess( void ) +{ + // See which option was choosen for unsuccessful updates + switch ( paramUpdateNoSuccessOption ) + { + case GAPROLE_RESEND_PARAM_UPDATE: + GAPRole_SendUpdateParam( gapRole_MinConnInterval, gapRole_MaxConnInterval, + gapRole_SlaveLatency, gapRole_TimeoutMultiplier, + GAPROLE_RESEND_PARAM_UPDATE ); + break; + + case GAPROLE_TERMINATE_LINK: + GAPRole_TerminateConnection(); + break; + + case GAPROLE_NO_ACTION: + + // fall through + default: + //do nothing + break; + } +} + +/******************************************************************** + @fn gapRole_startConnUpdate + + @brief Start the connection update procedure + + @param handleFailure - what to do if the update does not occur. + Method may choose to terminate connection, try again, or take no action + + @return none +*/ +static void gapRole_startConnUpdate( uint8 handleFailure ) +{ + // First check the current connection parameters versus the configured parameters + if ( (gapRole_ConnInterval < gapRole_MinConnInterval) || + (gapRole_ConnInterval > gapRole_MaxConnInterval) || + (gapRole_ConnSlaveLatency != gapRole_SlaveLatency) || + (gapRole_ConnTimeout != gapRole_TimeoutMultiplier) ) + { + l2capParamUpdateReq_t updateReq; + uint16 timeout = GAP_GetParamValue( TGAP_CONN_PARAM_TIMEOUT ); + updateReq.intervalMin = gapRole_MinConnInterval; + updateReq.intervalMax = gapRole_MaxConnInterval; + updateReq.slaveLatency = gapRole_SlaveLatency; + updateReq.timeoutMultiplier = gapRole_TimeoutMultiplier; + L2CAP_ConnParamUpdateReq( gapRole_ConnectionHandle, &updateReq, gapRole_TaskID ); + paramUpdateNoSuccessOption = handleFailure; + // Let's wait for L2CAP Connection Parameters Update Response + VOID osal_start_timerEx( gapRole_TaskID, CONN_PARAM_TIMEOUT_EVT, timeout ); + } +} + +/******************************************************************** + @fn GAPRole_SendUpdateParam + + @brief Update the parameters of an existing connection + + @param minConnInterval - the new min connection interval + @param maxConnInterval - the new max connection interval + @param latency - the new slave latency + @param connTimeout - the new timeout value + @param handleFailure - what to do if the update does not occur. + Method may choose to terminate connection, try again, or take no action + + @return SUCCESS, bleNotConnected, or bleInvalidRange +*/ +bStatus_t GAPRole_SendUpdateParam( uint16 minConnInterval, uint16 maxConnInterval, + uint16 latency, uint16 connTimeout, uint8 handleFailure ) +{ + // If there is no existing connection no update need be sent + if ( gapRole_state != GAPROLE_CONNECTED ) + { + return ( bleNotConnected ); + } + + // Check that all parameters are in range before sending request + if ( ( minConnInterval >= DEFAULT_MIN_CONN_INTERVAL ) && + ( minConnInterval < DEFAULT_MAX_CONN_INTERVAL ) && + ( maxConnInterval >= DEFAULT_MIN_CONN_INTERVAL ) && + ( maxConnInterval < DEFAULT_MAX_CONN_INTERVAL ) && + ( latency < MAX_SLAVE_LATENCY ) && + ( connTimeout >= MIN_TIMEOUT_MULTIPLIER ) && + ( connTimeout < MAX_TIMEOUT_MULTIPLIER ) ) + { + gapRole_MinConnInterval = minConnInterval; + gapRole_MaxConnInterval = maxConnInterval; + gapRole_SlaveLatency = latency; + gapRole_TimeoutMultiplier = connTimeout; + // Start connection update procedure + gapRole_startConnUpdate( handleFailure ); + // Connection update requested by app, cancel such pending procedure (if active) + VOID osal_stop_timerEx( gapRole_TaskID, START_CONN_UPDATE_EVT ); + return ( SUCCESS ); + } + + return ( bleInvalidRange ); +} + +#ifdef EXT_ADV_ENABLE +// exdended advertising +bStatus_t GapAdv_create(pfnGapCB_t* cb, Gap_ExtAdv_Param* advParam,uint8* advHandle) +{ + return(HCI_LE_SetExtAdvParamCmd(advParam)); +} + +bStatus_t GapAdv_loadByHandle(uint8 handle, GapAdv_dataTypes_t dataType,uint16 len, uint8* pBuf) +{ + switch (dataType) + { + case GAP_ADV_DATA_TYPE_ADV: + HCI_LE_SetExtAdvDataCmd(handle,len,pBuf); + break; + + case GAP_ADV_DATA_TYPE_SCAN_RSP: + HCI_LE_SetExtScanRspDataCmd(handle,len,pBuf); + break; + + default: + break; + } + + return HCI_SUCCESS; +} + +bStatus_t GapAdv_setEventMask(uint8 handle, GapAdv_eventMaskFlags_t mask) +{ + return HCI_SUCCESS; +} + +bStatus_t GapAdv_enable(uint8 handle, + GapAdv_enableOptions_t enableOptions, + uint16 durationOrMaxEvents) +{ + Gap_ExtAdv_EnableParam param; + param.Enable = TRUE; + param.AdvHandle = handle; + + switch (enableOptions) + { + case GAP_ADV_ENABLE_OPTIONS_USE_MAX: + param.Duration = enableOptions; + param.MaxExtAdv_Events = durationOrMaxEvents; + break; + + case GAP_ADV_ENABLE_OPTIONS_USE_DURATION: + break; + + case GAP_ADV_ENABLE_OPTIONS_USE_MAX_EVENTS: + break; + + default: + break; + } + + HCI_LE_SetExtAdvEnableCmd(¶m); + return HCI_SUCCESS; +} + +#endif + +/********************************************************************* +*********************************************************************/ diff --git a/src/components/profiles/Roles/peripheral.h b/src/components/profiles/Roles/peripheral.h new file mode 100644 index 0000000..00e9c01 --- /dev/null +++ b/src/components/profiles/Roles/peripheral.h @@ -0,0 +1,406 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/** + @headerfile: peripheral.h + $Date: + $Revision: + + + + This GAP profile advertises and allows connections. + + +*/ + +#ifndef PERIPHERAL_H +#define PERIPHERAL_H + +#ifdef EXT_ADV_ENABLE + #include "rflib_LR.h" +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* ------------------------------------------------------------------- + INCLUDES +*/ + +/* ------------------------------------------------------------------- + CONSTANTS +*/ + +/** @defgroup GAPROLE_PROFILE_PARAMETERS GAP Role Parameters + @{ +*/ +#define GAPROLE_PROFILEROLE 0x300 //!< Reading this parameter will return GAP Role type. Read Only. Size is uint8. +#define GAPROLE_IRK 0x301 //!< Identity Resolving Key. Read/Write. Size is uint8[KEYLEN]. Default is all 0, which means that the IRK will be randomly generated. +#define GAPROLE_SRK 0x302 //!< Signature Resolving Key. Read/Write. Size is uint8[KEYLEN]. Default is all 0, which means that the SRK will be randomly generated. +#define GAPROLE_SIGNCOUNTER 0x303 //!< Sign Counter. Read/Write. Size is uint32. Default is 0. +#define GAPROLE_BD_ADDR 0x304 //!< Device's Address. Read Only. Size is uint8[B_ADDR_LEN]. This item is read from the controller. +#define GAPROLE_ADVERT_ENABLED 0x305 //!< Enable/Disable Advertising. Read/Write. Size is uint8. Default is TRUE=Enabled. +#define GAPROLE_ADVERT_OFF_TIME 0x306 //!< Advertising Off Time for Limited advertisements (in milliseconds). Read/Write. Size is uint16. Default is 30 seconds. +#define GAPROLE_ADVERT_DATA 0x307 //!< Advertisement Data. Read/Write. Max size is uint8[B_MAX_ADV_LEN]. Default is "02:01:01", which means that it is a Limited Discoverable Advertisement. +#define GAPROLE_SCAN_RSP_DATA 0x308 //!< Scan Response Data. Read/Write. Max size is uint8[B_MAX_ADV_LEN]. Defaults to all 0. +#define GAPROLE_ADV_EVENT_TYPE 0x309 //!< Advertisement Type. Read/Write. Size is uint8. Default is GAP_ADTYPE_ADV_IND (defined in GAP.h). +#define GAPROLE_ADV_DIRECT_TYPE 0x30A //!< Direct Advertisement Address Type. Read/Write. Size is uint8. Default is ADDRTYPE_PUBLIC (defined in GAP.h). +#define GAPROLE_ADV_DIRECT_ADDR 0x30B //!< Direct Advertisement Address. Read/Write. Size is uint8[B_ADDR_LEN]. Default is NULL. +#define GAPROLE_ADV_CHANNEL_MAP 0x30C //!< Which channels to advertise on. Read/Write Size is uint8. Default is GAP_ADVCHAN_ALL (defined in GAP.h) +#define GAPROLE_ADV_FILTER_POLICY 0x30D //!< Filter Policy. Ignored when directed advertising is used. Read/Write. Size is uint8. Default is GAP_FILTER_POLICY_ALL (defined in GAP.h). +#define GAPROLE_CONNHANDLE 0x30E //!< Connection Handle. Read Only. Size is uint16. +#define GAPROLE_RSSI_READ_RATE 0x30F //!< How often to read the RSSI during a connection. Read/Write. Size is uint16. The value is in milliseconds. Default is 0 = OFF. +#define GAPROLE_PARAM_UPDATE_ENABLE 0x310 //!< Slave Connection Parameter Update Enable. Read/Write. Size is uint8. If TRUE then automatic connection parameter update request is sent. Default is FALSE. +#define GAPROLE_MIN_CONN_INTERVAL 0x311 //!< Minimum Connection Interval to allow (n * 1.25ms). Range: 7.5 msec to 4 seconds (0x0006 to 0x0C80). Read/Write. Size is uint16. Default is 7.5 milliseconds (0x0006). +#define GAPROLE_MAX_CONN_INTERVAL 0x312 //!< Maximum Connection Interval to allow (n * 1.25ms). Range: 7.5 msec to 4 seconds (0x0006 to 0x0C80). Read/Write. Size is uint16. Default is 4 seconds (0x0C80). +#define GAPROLE_SLAVE_LATENCY 0x313 //!< Update Parameter Slave Latency. Range: 0 - 499. Read/Write. Size is uint16. Default is 0. +#define GAPROLE_TIMEOUT_MULTIPLIER 0x314 //!< Update Parameter Timeout Multiplier (n * 10ms). Range: 100ms to 32 seconds (0x000a - 0x0c80). Read/Write. Size is uint16. Default is 1000. +#define GAPROLE_CONN_BD_ADDR 0x315 //!< Address of connected device. Read only. Size is uint8[B_MAX_ADV_LEN]. Set to all zeros when not connected. +#define GAPROLE_CONN_INTERVAL 0x316 //!< Current connection interval. Read only. Size is uint16. Range is 7.5ms to 4 seconds (0x0006 to 0x0C80). Default is 0 (no connection). +#define GAPROLE_CONN_LATENCY 0x317 //!< Current slave latency. Read only. Size is uint16. Range is 0 to 499. Default is 0 (no slave latency or no connection). +#define GAPROLE_CONN_TIMEOUT 0x318 //!< Current timeout value. Read only. size is uint16. Range is 100ms to 32 seconds. Default is 0 (no connection). +#define GAPROLE_PARAM_UPDATE_REQ 0x319 //!< Slave Connection Parameter Update Request. Write. Size is uint8. If TRUE then connection parameter update request is sent. +#define GAPROLE_STATE 0x31A //!< Reading this parameter will return GAP Peripheral Role State. Read Only. Size is uint8. + +#define GAPROLE_CONNECTION_INTERVAL 0x31B +#define GAPROLE_CONNECTION_LATENCY 0x31C + +#ifdef EXT_ADV_ENABLE +#define GAPROLE_EXT_ADVERT_ENABLED 0x0320 +#define GAPROLE_EXT_ADVERT_DATA 0x0321 +#define GAPROLE_EXT_SCAN_RSP_DATA 0x0322 +#define GAPROLE_EXT_ADV_EVENT_TYPE 0x0323 +#endif + +/** @} End GAPROLE_PROFILE_PARAMETERS */ + +/* ------------------------------------------------------------------- + TYPEDEFS +*/ + +/** + GAP Peripheral Role States. +*/ +typedef enum +{ + GAPROLE_INIT = 0, //!< Waiting to be started + GAPROLE_STARTED, //!< Started but not advertising + GAPROLE_ADVERTISING, //!< Currently Advertising + GAPROLE_WAITING, //!< Device is started but not advertising, is in waiting period before advertising again + GAPROLE_WAITING_AFTER_TIMEOUT, //!< Device just timed out from a connection but is not yet advertising, is in waiting period before advertising again + GAPROLE_CONNECTED, //!< In a connection + GAPROLE_CONNECTED_ADV, //!< In a connection + advertising + GAPROLE_ERROR //!< Error occurred - invalid state +} gaprole_States_t; + +/** + Possible actions the peripheral device may take if an unsuccessful parameter + update is received. + + Parameters for GAPRole_SendUpdateParam() only +*/ + +#define GAPROLE_NO_ACTION 0 // Take no action upon unsuccessful parameter updates +#define GAPROLE_RESEND_PARAM_UPDATE 1 // Continue to resend request until successful update +#define GAPROLE_TERMINATE_LINK 2 // Terminate link upon unsuccessful parameter updates + +/* ------------------------------------------------------------------- + MACROS +*/ + +/* ------------------------------------------------------------------- + Profile Callbacks +*/ +// Profile Events +#define START_ADVERTISING_EVT 0x0001 // Start Advertising +#define RSSI_READ_EVT 0x0002 // Read RSSI +#define START_CONN_UPDATE_EVT 0x0004 // Start Connection Update Procedure +#define CONN_PARAM_TIMEOUT_EVT 0x0008 // Connection Parameters Update Timeout +/** + Callback when the connection parameteres are updated. +*/ +typedef void (*gapRolesParamUpdateCB_t)( uint16 connInterval, + uint16 connSlaveLatency, + uint16 connTimeout ); + +/** + Callback when the device has been started. Callback event to + the Notify of a state change. +*/ +typedef void (*gapRolesStateNotify_t)( gaprole_States_t newState ); + +/** + Callback when the device has read an new RSSI value during a connection. +*/ +typedef void (*gapRolesRssiRead_t)( int8 newRSSI ); + +/** + Callback structure - must be setup by the application and used when gapRoles_StartDevice() is called. +*/ +typedef struct +{ + gapRolesStateNotify_t pfnStateChange; //!< Whenever the device changes state + gapRolesRssiRead_t pfnRssiRead; //!< When a valid RSSI is read from controller +} gapRolesCBs_t; + +/* ------------------------------------------------------------------- + API FUNCTIONS +*/ +#ifdef EXT_ADV_ENABLE +// extended advertising +typedef unsigned int uintptr_t; +typedef void (*pfnGapCB_t) +( + uint32_t event, //!< see @ref GapAdvScan_Event_IDs and GapAdvScan_Event_IDs + void* pBuf, //!< data potentially accompanying event + uintptr_t arg //!< custom application argument that can be return through this callback +); +typedef enum +{ + GAP_ADV_DATA_TYPE_ADV, //!< Advertising data + GAP_ADV_DATA_TYPE_SCAN_RSP //!< Scan response data +} GapAdv_dataTypes_t; +#endif +/** + @defgroup GAPROLES_PERIPHERAL_API GAP Peripheral Role API Functions + + @{ +*/ + +/** + @brief Set a GAP Role parameter. + + NOTE: You can call this function with a GAP Parameter ID and it will set the + GAP Parameter. GAP Parameters are defined in (gap.h). Also, + the "len" field must be set to the size of a "uint16" and the + "pValue" field must point to a "uint16". + + @param param - Profile parameter ID: @ref GAPROLE_PROFILE_PARAMETERS + @param len - length of data to write + @param pValue - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return SUCCESS or INVALIDPARAMETER (invalid paramID) +*/ +extern bStatus_t GAPRole_SetParameter( uint16 param, uint8 len, void* pValue ); + +/** + @brief Get a GAP Role parameter. + + NOTE: You can call this function with a GAP Parameter ID and it will get a + GAP Parameter. GAP Parameters are defined in (gap.h). Also, the + "pValue" field must point to a "uint16". + + @param param - Profile parameter ID: @ref GAPROLE_PROFILE_PARAMETERS + @param pValue - pointer to location to get the value. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return SUCCESS or INVALIDPARAMETER (invalid paramID) +*/ +extern bStatus_t GAPRole_GetParameter( uint16 param, void* pValue ); +#ifdef EXT_ADV_ENABLE +extern bStatus_t GapRoleAdv_loadByHandle(uint8 handle, GapAdv_dataTypes_t dataType, + uint16 len, uint8* pBuf); + +#endif + +/** + @brief Does the device initialization. Only call this function once. + + @param pAppCallbacks - pointer to application callbacks. + + @return SUCCESS or bleAlreadyInRequestedMode +*/ +extern bStatus_t GAPRole_StartDevice( gapRolesCBs_t* pAppCallbacks ); + +/** + @brief Terminates the existing connection. + + @return SUCCESS or bleIncorrectMode +*/ +extern bStatus_t GAPRole_TerminateConnection( void ); + +/** + @brief Update the parameters of an existing connection + + @param connInterval - the new connection interval + @param latency - the new slave latency + @param connTimeout - the new timeout value + @param handleFailure - what to do if the update does not occur. + Method may choose to terminate connection, try again, or take no action + + @return SUCCESS, bleNotConnected or bleInvalidRange +*/ +extern bStatus_t GAPRole_SendUpdateParam( uint16 minConnInterval, uint16 maxConnInterval, + uint16 latency, uint16 connTimeout, uint8 handleFailure ); + +/** + @brief Register application's callbacks. + + @param pParamUpdateCB - pointer to param update callback. + + @return none +*/ +extern void GAPRole_RegisterAppCBs( gapRolesParamUpdateCB_t* pParamUpdateCB ); + +/** + @} End GAPROLES_PERIPHERAL_API +*/ + + +/* ------------------------------------------------------------------- + TASK FUNCTIONS - Don't call these. These are system functions. +*/ + +/** + @internal + + @brief Initialization function for the GAP Role Task. + This is called during initialization and should contain + any application specific initialization (ie. hardware + initialization/setup, table initialization, power up + notificaiton ... ). + + @param the ID assigned by OSAL. This ID should be + used to send messages and set timers. + + @return void +*/ +extern void GAPRole_Init( uint8 task_id ); + +/** + @internal + + @brief GAP Role Task event processor. + This function is called to process all events for the task. + Events include timers, messages and any other user defined + events. + + @param task_id - The OSAL assigned task ID. + @param events - events to process. This is a bit map and can + contain more than one event. + + @return events not processed +*/ +extern uint16 GAPRole_ProcessEvent( uint8 task_id, uint16 events ); + +/* ------------------------------------------------------------------- + -------------------------------------------------------------------*/ +#ifdef EXT_ADV_ENABLE +extern bStatus_t GAP_UpdateExtAdvertisingData( uint8 taskID, uint16_t adType, + uint8 dataLen, uint8* pAdvertData ); + + + + + +/** + GAP Advertiser bitfields to enable / disable callback events + + These are used in @ref GapAdv_setEventMask + The events that that these flags control are defined in + @ref GapAdvScan_Event_IDs +*/ +// Advertising Scan Request Notification Flag +#define AE_NOTIFY_DISABLE_SCAN_REQUEST ~BV(0) +#define AE_NOTIFY_ENABLE_SCAN_REQUEST BV(0) +#define AE_NOTIFY +#define AE_NOTIFY_DISABLE_ADV_SET_START ~BV(4) +#define AE_NOTIFY_ENABLE_ADV_SET_START BV(4) +#define AE_NOTIFY_DISABLE_ADV_START ~BV(5) +#define AE_NOTIFY_ENABLE_ADV_START BV(5) +#define AE_NOTIFY_DISABLE_ADV_END ~BV(6) +#define AE_NOTIFY_ENABLE_ADV_END BV(6) +#define AE_NOTIFY_DISABLE_ADV_SET_END ~BV(7) +#define AE_NOTIFY_ENABLE_ADV_SET_END BV(7) + +typedef enum +{ + /** + Enables / disables the @ref GAP_EVT_SCAN_REQ_RECEIVED event + */ + GAP_ADV_EVT_MASK_SCAN_REQ_NOTI = AE_NOTIFY_ENABLE_SCAN_REQUEST, + /** + Enables / disables the @ref GAP_EVT_ADV_SET_TERMINATED event + */ + GAP_ADV_EVT_MASK_SET_TERMINATED = BV(1), + /** + Enables / disables the @ref GAP_EVT_ADV_START_AFTER_ENABLE event + */ + GAP_ADV_EVT_MASK_START_AFTER_ENABLE = AE_NOTIFY_ENABLE_ADV_SET_START, + /** + Enables / disables the @ref GAP_EVT_ADV_START event + */ + GAP_ADV_EVT_MASK_START = AE_NOTIFY_ENABLE_ADV_START, + /** + Enables / disables the @ref GAP_EVT_ADV_END event + */ + GAP_ADV_EVT_MASK_END = AE_NOTIFY_ENABLE_ADV_END, + /** + Enables / disables the @ref GAP_EVT_ADV_END_AFTER_DISABLE event + */ + GAP_ADV_EVT_MASK_END_AFTER_DISABLE = AE_NOTIFY_ENABLE_ADV_SET_END, + /** + Mask to enables / disable all advertising events + */ + GAP_ADV_EVT_MASK_ALL = GAP_ADV_EVT_MASK_SCAN_REQ_NOTI | + GAP_ADV_EVT_MASK_START_AFTER_ENABLE | + GAP_ADV_EVT_MASK_START | + GAP_ADV_EVT_MASK_END | + GAP_ADV_EVT_MASK_END_AFTER_DISABLE | + GAP_ADV_EVT_MASK_SET_TERMINATED, +/// @cond NODOC + /** + Used to set this to 16 bits for future events + */ + GAP_ADV_EVT_MASK_RESERVED = BV(15) +/// @endcond // NODOC +} GapAdv_eventMaskFlags_t; + +/// Enable options for @ref GapAdv_enable +typedef enum +{ + /** + Use the maximum possible value. This is the spec-defined maximum for + directed advertising and infinite advertising for all other types + */ + GAP_ADV_ENABLE_OPTIONS_USE_MAX, + /** + Use the user-specified duration + */ + GAP_ADV_ENABLE_OPTIONS_USE_DURATION, + /** + Use the user-specified maximum number of events + */ + GAP_ADV_ENABLE_OPTIONS_USE_MAX_EVENTS, +} GapAdv_enableOptions_t; + + + +extern bStatus_t GapAdv_create(pfnGapCB_t* cb, Gap_ExtAdv_Param* advParam, + uint8* advHandle); + +bStatus_t GapAdv_loadByHandle(uint8 handle, GapAdv_dataTypes_t dataType, + uint16 len, uint8* pBuf); + +extern bStatus_t GapAdv_setEventMask(uint8 handle, GapAdv_eventMaskFlags_t mask); + +extern bStatus_t GapAdv_enable(uint8 handle, + GapAdv_enableOptions_t enableOptions, + uint16 durationOrMaxEvents); + +extern bStatus_t GapAdv_UpdateParameter(uint8* pBuf); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* PERIPHERAL_H */ diff --git a/src/components/profiles/Roles/peripheral.h~RF5afb64a.TMP b/src/components/profiles/Roles/peripheral.h~RF5afb64a.TMP new file mode 100644 index 0000000..f148f6f --- /dev/null +++ b/src/components/profiles/Roles/peripheral.h~RF5afb64a.TMP @@ -0,0 +1,402 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/** + @headerfile: peripheral.h + $Date: + $Revision: + + + + This GAP profile advertises and allows connections. + + +*/ + +#ifndef PERIPHERAL_H +#define PERIPHERAL_H + +#ifdef EXT_ADV_ENABLE + #include "rflib_LR.h" +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* ------------------------------------------------------------------- + INCLUDES +*/ + +/* ------------------------------------------------------------------- + CONSTANTS +*/ + +/** @defgroup GAPROLE_PROFILE_PARAMETERS GAP Role Parameters + @{ +*/ +#define GAPROLE_PROFILEROLE 0x300 //!< Reading this parameter will return GAP Role type. Read Only. Size is uint8. +#define GAPROLE_IRK 0x301 //!< Identity Resolving Key. Read/Write. Size is uint8[KEYLEN]. Default is all 0, which means that the IRK will be randomly generated. +#define GAPROLE_SRK 0x302 //!< Signature Resolving Key. Read/Write. Size is uint8[KEYLEN]. Default is all 0, which means that the SRK will be randomly generated. +#define GAPROLE_SIGNCOUNTER 0x303 //!< Sign Counter. Read/Write. Size is uint32. Default is 0. +#define GAPROLE_BD_ADDR 0x304 //!< Device's Address. Read Only. Size is uint8[B_ADDR_LEN]. This item is read from the controller. +#define GAPROLE_ADVERT_ENABLED 0x305 //!< Enable/Disable Advertising. Read/Write. Size is uint8. Default is TRUE=Enabled. +#define GAPROLE_ADVERT_OFF_TIME 0x306 //!< Advertising Off Time for Limited advertisements (in milliseconds). Read/Write. Size is uint16. Default is 30 seconds. +#define GAPROLE_ADVERT_DATA 0x307 //!< Advertisement Data. Read/Write. Max size is uint8[B_MAX_ADV_LEN]. Default is "02:01:01", which means that it is a Limited Discoverable Advertisement. +#define GAPROLE_SCAN_RSP_DATA 0x308 //!< Scan Response Data. Read/Write. Max size is uint8[B_MAX_ADV_LEN]. Defaults to all 0. +#define GAPROLE_ADV_EVENT_TYPE 0x309 //!< Advertisement Type. Read/Write. Size is uint8. Default is GAP_ADTYPE_ADV_IND (defined in GAP.h). +#define GAPROLE_ADV_DIRECT_TYPE 0x30A //!< Direct Advertisement Address Type. Read/Write. Size is uint8. Default is ADDRTYPE_PUBLIC (defined in GAP.h). +#define GAPROLE_ADV_DIRECT_ADDR 0x30B //!< Direct Advertisement Address. Read/Write. Size is uint8[B_ADDR_LEN]. Default is NULL. +#define GAPROLE_ADV_CHANNEL_MAP 0x30C //!< Which channels to advertise on. Read/Write Size is uint8. Default is GAP_ADVCHAN_ALL (defined in GAP.h) +#define GAPROLE_ADV_FILTER_POLICY 0x30D //!< Filter Policy. Ignored when directed advertising is used. Read/Write. Size is uint8. Default is GAP_FILTER_POLICY_ALL (defined in GAP.h). +#define GAPROLE_CONNHANDLE 0x30E //!< Connection Handle. Read Only. Size is uint16. +#define GAPROLE_RSSI_READ_RATE 0x30F //!< How often to read the RSSI during a connection. Read/Write. Size is uint16. The value is in milliseconds. Default is 0 = OFF. +#define GAPROLE_PARAM_UPDATE_ENABLE 0x310 //!< Slave Connection Parameter Update Enable. Read/Write. Size is uint8. If TRUE then automatic connection parameter update request is sent. Default is FALSE. +#define GAPROLE_MIN_CONN_INTERVAL 0x311 //!< Minimum Connection Interval to allow (n * 1.25ms). Range: 7.5 msec to 4 seconds (0x0006 to 0x0C80). Read/Write. Size is uint16. Default is 7.5 milliseconds (0x0006). +#define GAPROLE_MAX_CONN_INTERVAL 0x312 //!< Maximum Connection Interval to allow (n * 1.25ms). Range: 7.5 msec to 4 seconds (0x0006 to 0x0C80). Read/Write. Size is uint16. Default is 4 seconds (0x0C80). +#define GAPROLE_SLAVE_LATENCY 0x313 //!< Update Parameter Slave Latency. Range: 0 - 499. Read/Write. Size is uint16. Default is 0. +#define GAPROLE_TIMEOUT_MULTIPLIER 0x314 //!< Update Parameter Timeout Multiplier (n * 10ms). Range: 100ms to 32 seconds (0x000a - 0x0c80). Read/Write. Size is uint16. Default is 1000. +#define GAPROLE_CONN_BD_ADDR 0x315 //!< Address of connected device. Read only. Size is uint8[B_MAX_ADV_LEN]. Set to all zeros when not connected. +#define GAPROLE_CONN_INTERVAL 0x316 //!< Current connection interval. Read only. Size is uint16. Range is 7.5ms to 4 seconds (0x0006 to 0x0C80). Default is 0 (no connection). +#define GAPROLE_CONN_LATENCY 0x317 //!< Current slave latency. Read only. Size is uint16. Range is 0 to 499. Default is 0 (no slave latency or no connection). +#define GAPROLE_CONN_TIMEOUT 0x318 //!< Current timeout value. Read only. size is uint16. Range is 100ms to 32 seconds. Default is 0 (no connection). +#define GAPROLE_PARAM_UPDATE_REQ 0x319 //!< Slave Connection Parameter Update Request. Write. Size is uint8. If TRUE then connection parameter update request is sent. +#define GAPROLE_STATE 0x31A //!< Reading this parameter will return GAP Peripheral Role State. Read Only. Size is uint8. + +#define GAPROLE_CONNECTION_INTERVAL 0x31B +#define GAPROLE_CONNECTION_LATENCY 0x31C + +#ifdef EXT_ADV_ENABLE +#define GAPROLE_EXT_ADVERT_ENABLED 0x0320 +#define GAPROLE_EXT_ADVERT_DATA 0x0321 +#define GAPROLE_EXT_SCAN_RSP_DATA 0x0322 +#define GAPROLE_EXT_ADV_EVENT_TYPE 0x0323 +#endif + +/** @} End GAPROLE_PROFILE_PARAMETERS */ + +/* ------------------------------------------------------------------- + TYPEDEFS +*/ + +/** + GAP Peripheral Role States. +*/ +typedef enum +{ + GAPROLE_INIT = 0, //!< Waiting to be started + GAPROLE_STARTED, //!< Started but not advertising + GAPROLE_ADVERTISING, //!< Currently Advertising + GAPROLE_WAITING, //!< Device is started but not advertising, is in waiting period before advertising again + GAPROLE_WAITING_AFTER_TIMEOUT, //!< Device just timed out from a connection but is not yet advertising, is in waiting period before advertising again + GAPROLE_CONNECTED, //!< In a connection + GAPROLE_CONNECTED_ADV, //!< In a connection + advertising + GAPROLE_ERROR //!< Error occurred - invalid state +} gaprole_States_t; + +/** + Possible actions the peripheral device may take if an unsuccessful parameter + update is received. + + Parameters for GAPRole_SendUpdateParam() only +*/ + +#define GAPROLE_NO_ACTION 0 // Take no action upon unsuccessful parameter updates +#define GAPROLE_RESEND_PARAM_UPDATE 1 // Continue to resend request until successful update +#define GAPROLE_TERMINATE_LINK 2 // Terminate link upon unsuccessful parameter updates + +/* ------------------------------------------------------------------- + MACROS +*/ + +/* ------------------------------------------------------------------- + Profile Callbacks +*/ + +/** + Callback when the connection parameteres are updated. +*/ +typedef void (*gapRolesParamUpdateCB_t)( uint16 connInterval, + uint16 connSlaveLatency, + uint16 connTimeout ); + +/** + Callback when the device has been started. Callback event to + the Notify of a state change. +*/ +typedef void (*gapRolesStateNotify_t)( gaprole_States_t newState ); + +/** + Callback when the device has read an new RSSI value during a connection. +*/ +typedef void (*gapRolesRssiRead_t)( int8 newRSSI ); + +/** + Callback structure - must be setup by the application and used when gapRoles_StartDevice() is called. +*/ +typedef struct +{ + gapRolesStateNotify_t pfnStateChange; //!< Whenever the device changes state + gapRolesRssiRead_t pfnRssiRead; //!< When a valid RSSI is read from controller +} gapRolesCBs_t; + +/* ------------------------------------------------------------------- + API FUNCTIONS +*/ +#ifdef EXT_ADV_ENABLE +// extended advertising +typedef unsigned int uintptr_t; +typedef void (*pfnGapCB_t) +( + uint32_t event, //!< see @ref GapAdvScan_Event_IDs and GapAdvScan_Event_IDs + void* pBuf, //!< data potentially accompanying event + uintptr_t arg //!< custom application argument that can be return through this callback +); +typedef enum +{ + GAP_ADV_DATA_TYPE_ADV, //!< Advertising data + GAP_ADV_DATA_TYPE_SCAN_RSP //!< Scan response data +} GapAdv_dataTypes_t; +#endif +/** + @defgroup GAPROLES_PERIPHERAL_API GAP Peripheral Role API Functions + + @{ +*/ + +/** + @brief Set a GAP Role parameter. + + NOTE: You can call this function with a GAP Parameter ID and it will set the + GAP Parameter. GAP Parameters are defined in (gap.h). Also, + the "len" field must be set to the size of a "uint16" and the + "pValue" field must point to a "uint16". + + @param param - Profile parameter ID: @ref GAPROLE_PROFILE_PARAMETERS + @param len - length of data to write + @param pValue - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return SUCCESS or INVALIDPARAMETER (invalid paramID) +*/ +extern bStatus_t GAPRole_SetParameter( uint16 param, uint8 len, void* pValue ); + +/** + @brief Get a GAP Role parameter. + + NOTE: You can call this function with a GAP Parameter ID and it will get a + GAP Parameter. GAP Parameters are defined in (gap.h). Also, the + "pValue" field must point to a "uint16". + + @param param - Profile parameter ID: @ref GAPROLE_PROFILE_PARAMETERS + @param pValue - pointer to location to get the value. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return SUCCESS or INVALIDPARAMETER (invalid paramID) +*/ +extern bStatus_t GAPRole_GetParameter( uint16 param, void* pValue ); +#ifdef EXT_ADV_ENABLE +extern bStatus_t GapRoleAdv_loadByHandle(uint8 handle, GapAdv_dataTypes_t dataType, + uint16 len, uint8* pBuf); + +#endif + +/** + @brief Does the device initialization. Only call this function once. + + @param pAppCallbacks - pointer to application callbacks. + + @return SUCCESS or bleAlreadyInRequestedMode +*/ +extern bStatus_t GAPRole_StartDevice( gapRolesCBs_t* pAppCallbacks ); + +/** + @brief Terminates the existing connection. + + @return SUCCESS or bleIncorrectMode +*/ +extern bStatus_t GAPRole_TerminateConnection( void ); + +/** + @brief Update the parameters of an existing connection + + @param connInterval - the new connection interval + @param latency - the new slave latency + @param connTimeout - the new timeout value + @param handleFailure - what to do if the update does not occur. + Method may choose to terminate connection, try again, or take no action + + @return SUCCESS, bleNotConnected or bleInvalidRange +*/ +extern bStatus_t GAPRole_SendUpdateParam( uint16 minConnInterval, uint16 maxConnInterval, + uint16 latency, uint16 connTimeout, uint8 handleFailure ); + +/** + @brief Register application's callbacks. + + @param pParamUpdateCB - pointer to param update callback. + + @return none +*/ +extern void GAPRole_RegisterAppCBs( gapRolesParamUpdateCB_t* pParamUpdateCB ); + +/** + @} End GAPROLES_PERIPHERAL_API +*/ + + +/* ------------------------------------------------------------------- + TASK FUNCTIONS - Don't call these. These are system functions. +*/ + +/** + @internal + + @brief Initialization function for the GAP Role Task. + This is called during initialization and should contain + any application specific initialization (ie. hardware + initialization/setup, table initialization, power up + notificaiton ... ). + + @param the ID assigned by OSAL. This ID should be + used to send messages and set timers. + + @return void +*/ +extern void GAPRole_Init( uint8 task_id ); + +/** + @internal + + @brief GAP Role Task event processor. + This function is called to process all events for the task. + Events include timers, messages and any other user defined + events. + + @param task_id - The OSAL assigned task ID. + @param events - events to process. This is a bit map and can + contain more than one event. + + @return events not processed +*/ +extern uint16 GAPRole_ProcessEvent( uint8 task_id, uint16 events ); + +/* ------------------------------------------------------------------- + -------------------------------------------------------------------*/ +#ifdef EXT_ADV_ENABLE +extern bStatus_t GAP_UpdateExtAdvertisingData( uint8 taskID, uint16_t adType, + uint8 dataLen, uint8* pAdvertData ); + + + + + +/** + GAP Advertiser bitfields to enable / disable callback events + + These are used in @ref GapAdv_setEventMask + The events that that these flags control are defined in + @ref GapAdvScan_Event_IDs +*/ +// Advertising Scan Request Notification Flag +#define AE_NOTIFY_DISABLE_SCAN_REQUEST ~BV(0) +#define AE_NOTIFY_ENABLE_SCAN_REQUEST BV(0) +#define AE_NOTIFY +#define AE_NOTIFY_DISABLE_ADV_SET_START ~BV(4) +#define AE_NOTIFY_ENABLE_ADV_SET_START BV(4) +#define AE_NOTIFY_DISABLE_ADV_START ~BV(5) +#define AE_NOTIFY_ENABLE_ADV_START BV(5) +#define AE_NOTIFY_DISABLE_ADV_END ~BV(6) +#define AE_NOTIFY_ENABLE_ADV_END BV(6) +#define AE_NOTIFY_DISABLE_ADV_SET_END ~BV(7) +#define AE_NOTIFY_ENABLE_ADV_SET_END BV(7) + +typedef enum +{ + /** + Enables / disables the @ref GAP_EVT_SCAN_REQ_RECEIVED event + */ + GAP_ADV_EVT_MASK_SCAN_REQ_NOTI = AE_NOTIFY_ENABLE_SCAN_REQUEST, + /** + Enables / disables the @ref GAP_EVT_ADV_SET_TERMINATED event + */ + GAP_ADV_EVT_MASK_SET_TERMINATED = BV(1), + /** + Enables / disables the @ref GAP_EVT_ADV_START_AFTER_ENABLE event + */ + GAP_ADV_EVT_MASK_START_AFTER_ENABLE = AE_NOTIFY_ENABLE_ADV_SET_START, + /** + Enables / disables the @ref GAP_EVT_ADV_START event + */ + GAP_ADV_EVT_MASK_START = AE_NOTIFY_ENABLE_ADV_START, + /** + Enables / disables the @ref GAP_EVT_ADV_END event + */ + GAP_ADV_EVT_MASK_END = AE_NOTIFY_ENABLE_ADV_END, + /** + Enables / disables the @ref GAP_EVT_ADV_END_AFTER_DISABLE event + */ + GAP_ADV_EVT_MASK_END_AFTER_DISABLE = AE_NOTIFY_ENABLE_ADV_SET_END, + /** + Mask to enables / disable all advertising events + */ + GAP_ADV_EVT_MASK_ALL = GAP_ADV_EVT_MASK_SCAN_REQ_NOTI | + GAP_ADV_EVT_MASK_START_AFTER_ENABLE | + GAP_ADV_EVT_MASK_START | + GAP_ADV_EVT_MASK_END | + GAP_ADV_EVT_MASK_END_AFTER_DISABLE | + GAP_ADV_EVT_MASK_SET_TERMINATED, +/// @cond NODOC + /** + Used to set this to 16 bits for future events + */ + GAP_ADV_EVT_MASK_RESERVED = BV(15) +/// @endcond // NODOC +} GapAdv_eventMaskFlags_t; + +/// Enable options for @ref GapAdv_enable +typedef enum +{ + /** + Use the maximum possible value. This is the spec-defined maximum for + directed advertising and infinite advertising for all other types + */ + GAP_ADV_ENABLE_OPTIONS_USE_MAX, + /** + Use the user-specified duration + */ + GAP_ADV_ENABLE_OPTIONS_USE_DURATION, + /** + Use the user-specified maximum number of events + */ + GAP_ADV_ENABLE_OPTIONS_USE_MAX_EVENTS, +} GapAdv_enableOptions_t; + + + +extern bStatus_t GapAdv_create(pfnGapCB_t* cb, Gap_ExtAdv_Param* advParam, + uint8* advHandle); + +bStatus_t GapAdv_loadByHandle(uint8 handle, GapAdv_dataTypes_t dataType, + uint16 len, uint8* pBuf); + +extern bStatus_t GapAdv_setEventMask(uint8 handle, GapAdv_eventMaskFlags_t mask); + +extern bStatus_t GapAdv_enable(uint8 handle, + GapAdv_enableOptions_t enableOptions, + uint16 durationOrMaxEvents); + +extern bStatus_t GapAdv_UpdateParameter(uint8* pBuf); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* PERIPHERAL_H */ diff --git a/src/components/profiles/Roles/peripheralBroadcaster.c b/src/components/profiles/Roles/peripheralBroadcaster.c new file mode 100644 index 0000000..28351a5 --- /dev/null +++ b/src/components/profiles/Roles/peripheralBroadcaster.c @@ -0,0 +1,1095 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "hci.h" +#include "l2cap.h" +#include "gap.h" +#include "linkdb.h" +#include "att.h" +#include "gatt.h" +#include "osal_snv.h" +#include "hci_tl.h" + +#include "peripheralBroadcaster.h" +#include "gapbondmgr.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ +// Profile Events +#define START_ADVERTISING_EVT 0x0001 +#define RSSI_READ_EVT 0x0002 +#define UPDATE_PARAMS_TIMEOUT_EVT 0x0004 + +#define DEFAULT_ADVERT_OFF_TIME 30000 // 30 seconds + +#define RSSI_NOT_AVAILABLE 127 + +#define DEFAULT_MIN_CONN_INTERVAL 0x0006 // 100 milliseconds +#define DEFAULT_MAX_CONN_INTERVAL 0x0C80 // 4 seconds + +#define MIN_CONN_INTERVAL 0x0006 +#define MAX_CONN_INTERVAL 0x0C80 + +#define DEFAULT_SLAVE_LATENCY 0 +#define DEFAULT_TIMEOUT_MULTIPLIER 1000 + +#define CONN_INTERVAL_MULTIPLIER 6 + +#define MAX_SLAVE_LATENCY 500 +#define MIN_TIMEOUT_MULTIPLIER 0x000a +#define MAX_TIMEOUT_MULTIPLIER 0x0c80 + +#define MAX_TIMEOUT_VALUE 0xFFFF + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ +static uint8 gapRole_TaskID; // Task ID for internal task/event processing + +static gaprole_States_t gapRole_state; + +/********************************************************************* + Profile Parameters - reference GAPROLE_PROFILE_PARAMETERS for + descriptions +*/ + +static uint8 gapRole_profileRole; +static uint8 gapRole_IRK[KEYLEN]; +static uint8 gapRole_SRK[KEYLEN]; +static uint32 gapRole_signCounter; +static uint8 gapRole_bdAddr[B_ADDR_LEN]; +static uint8 gapRole_AdvEnabled = TRUE; +static uint16 gapRole_AdvertOffTime = DEFAULT_ADVERT_OFF_TIME; +static uint8 gapRole_AdvertDataLen = 3; +static uint8 gapRole_AdvertData[B_MAX_ADV_LEN] = +{ + 0x02, // length of this data + GAP_ADTYPE_FLAGS, // AD Type = Flags + // Limited Discoverable & BR/EDR not supported + (GAP_ADTYPE_FLAGS_GENERAL | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED), + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +}; +static uint8 gapRole_ScanRspDataLen = 0; +static uint8 gapRole_ScanRspData[B_MAX_ADV_LEN] = {0}; +static uint8 gapRole_AdvEventType; +static uint8 gapRole_AdvDirectType; +static uint8 gapRole_AdvDirectAddr[B_ADDR_LEN] = {0}; +static uint8 gapRole_AdvChanMap; +static uint8 gapRole_AdvFilterPolicy; + +static uint16 gapRole_ConnectionHandle = INVALID_CONNHANDLE; +static uint16 gapRole_RSSIReadRate = 0; + +static gapRolesCBs_t* pGapRoles_AppCGs = NULL; +static uint8 gapRole_ConnectedDevAddr[B_ADDR_LEN] = {0}; + +static uint8 gapRole_ParamUpdateEnable = FALSE; +static uint16 gapRole_MinConnInterval = DEFAULT_MIN_CONN_INTERVAL; +static uint16 gapRole_MaxConnInterval = DEFAULT_MAX_CONN_INTERVAL; +static uint16 gapRole_SlaveLatency = DEFAULT_SLAVE_LATENCY; +static uint16 gapRole_TimeoutMultiplier = DEFAULT_TIMEOUT_MULTIPLIER; + + +/********************************************************************* + Profile Attributes - variables +*/ + +/********************************************************************* + Profile Attributes - Table +*/ + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static void gapRole_ProcessOSALMsg( osal_event_hdr_t* pMsg ); +static void gapRole_ProcessGAPMsg( gapEventHdr_t* pMsg ); +static void gapRole_SetupGAP( void ); +static void gapRole_SendUpdateParam( uint16 connInterval, uint16 connLatency ); + +/********************************************************************* + NETWORK LAYER CALLBACKS +*/ + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/********************************************************************* + @brief Set a GAP Role parameter. + + Public function defined in peripheral.h. +*/ +bStatus_t GAPRole_SetParameter( uint16 param, uint8 len, void* pValue ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case GAPROLE_IRK: + if ( len == KEYLEN ) + { + VOID osal_memcpy( gapRole_IRK, pValue, KEYLEN ) ; + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_SRK: + if ( len == KEYLEN ) + { + VOID osal_memcpy( gapRole_SRK, pValue, KEYLEN ) ; + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_SIGNCOUNTER: + if ( len == sizeof ( uint32 ) ) + { + gapRole_signCounter = *((uint32*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADVERT_ENABLED: + if ( len == sizeof( uint8 ) ) + { + if ( (gapRole_state == GAPROLE_CONNECTED) || (gapRole_state == GAPROLE_CONNECTED_ADV) ) + { + uint8 advEnabled = *((uint8*)pValue); + + if ( (gapRole_state == GAPROLE_CONNECTED) && (advEnabled == TRUE) ) + { + // Turn on advertising + osal_set_event( gapRole_TaskID, START_ADVERTISING_EVT ); + } + else if ( (gapRole_state == GAPROLE_CONNECTED_ADV) && (advEnabled == FALSE) ) + { + // Turn off Advertising + GAP_EndDiscoverable( gapRole_TaskID ); + } + } + else + { + uint8 oldAdvEnabled = gapRole_AdvEnabled; + gapRole_AdvEnabled = *((uint8*)pValue); + + if ( (oldAdvEnabled) && (gapRole_AdvEnabled == FALSE) ) + { + // Turn off Advertising + VOID GAP_EndDiscoverable( gapRole_TaskID ); + } + else if ( (oldAdvEnabled == FALSE) && (gapRole_AdvEnabled) ) + { + // Turn on Advertising + if ( (gapRole_state == GAPROLE_STARTED) + || (gapRole_state == GAPROLE_WAITING ) + || (gapRole_state == GAPROLE_WAITING_AFTER_TIMEOUT) ) + { + VOID osal_set_event( gapRole_TaskID, START_ADVERTISING_EVT ); + } + } + } + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADVERT_OFF_TIME: + if ( len == sizeof ( uint16 ) ) + { + gapRole_AdvertOffTime = *((uint16*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADVERT_DATA: + if ( len <= B_MAX_ADV_LEN ) + { + VOID osal_memset( gapRole_AdvertData, 0, B_MAX_ADV_LEN ); + VOID osal_memcpy( gapRole_AdvertData, pValue, len ); + gapRole_AdvertDataLen = len; + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_SCAN_RSP_DATA: + if ( len <= B_MAX_ADV_LEN ) + { + VOID osal_memset( gapRole_ScanRspData, 0, B_MAX_ADV_LEN ); + VOID osal_memcpy( gapRole_ScanRspData, pValue, len ); + gapRole_ScanRspDataLen = len; + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADV_EVENT_TYPE: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= GAP_ADTYPE_ADV_LDC_DIRECT_IND) ) + { + gapRole_AdvEventType = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADV_DIRECT_TYPE: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= ADDRTYPE_PRIVATE_RESOLVE) ) + { + gapRole_AdvDirectType = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADV_DIRECT_ADDR: + if ( len == B_ADDR_LEN ) + { + VOID osal_memcpy( gapRole_AdvDirectAddr, pValue, B_ADDR_LEN ) ; + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADV_CHANNEL_MAP: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= 0x07) ) + { + gapRole_AdvChanMap = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_ADV_FILTER_POLICY: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= GAP_FILTER_POLICY_WHITE) ) + { + gapRole_AdvFilterPolicy = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_RSSI_READ_RATE: + if ( len == sizeof ( uint16 ) ) + { + gapRole_RSSIReadRate = *((uint16*)pValue); + + if ( (gapRole_RSSIReadRate) && (gapRole_state == GAPROLE_CONNECTED) ) + { + // Start the RSSI Reads + VOID osal_start_timerEx( gapRole_TaskID, RSSI_READ_EVT, gapRole_RSSIReadRate ); + } + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_PARAM_UPDATE_ENABLE: + if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= TRUE) ) + { + gapRole_ParamUpdateEnable = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + + break; + + case GAPROLE_MIN_CONN_INTERVAL: + { + uint16 newInterval = *((uint16*)pValue); + + if ( len == sizeof ( uint16 ) && + ( newInterval >= MIN_CONN_INTERVAL ) && + ( newInterval <= MAX_CONN_INTERVAL ) ) + { + gapRole_MinConnInterval = newInterval; + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPROLE_MAX_CONN_INTERVAL: + { + uint16 newInterval = *((uint16*)pValue); + + if ( len == sizeof ( uint16 ) && + ( newInterval >= MIN_CONN_INTERVAL) && + ( newInterval <= MAX_CONN_INTERVAL) ) + { + gapRole_MaxConnInterval = newInterval; + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPROLE_SLAVE_LATENCY: + { + uint16 latency = *((uint16*)pValue); + + if ( len == sizeof ( uint16 ) && (latency < MAX_SLAVE_LATENCY) ) + { + gapRole_SlaveLatency = latency; + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPROLE_TIMEOUT_MULTIPLIER: + { + uint16 newTimeout = *((uint16*)pValue); + + if ( len == sizeof ( uint16 ) + && (newTimeout >= MIN_TIMEOUT_MULTIPLIER) && (newTimeout <= MAX_TIMEOUT_MULTIPLIER) ) + { + gapRole_TimeoutMultiplier = newTimeout; + } + else + { + ret = bleInvalidRange; + } + } + break; + + default: + + // The param value isn't part of this profile, try the GAP. + if ( (param < TGAP_PARAMID_MAX) && (len == sizeof ( uint16 )) ) + { + ret = GAP_SetParamValue( param, *((uint16*)pValue) ); + } + else + { + ret = INVALIDPARAMETER; + } + + break; + } + + return ( ret ); +} + +/********************************************************************* + @brief Get a GAP Role parameter. + + Public function defined in peripheral.h. +*/ +bStatus_t GAPRole_GetParameter( uint16 param, void* pValue ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case GAPROLE_PROFILEROLE: + *((uint8*)pValue) = gapRole_profileRole; + break; + + case GAPROLE_IRK: + VOID osal_memcpy( pValue, gapRole_IRK, KEYLEN ) ; + break; + + case GAPROLE_SRK: + VOID osal_memcpy( pValue, gapRole_SRK, KEYLEN ) ; + break; + + case GAPROLE_SIGNCOUNTER: + *((uint32*)pValue) = gapRole_signCounter; + break; + + case GAPROLE_BD_ADDR: + VOID osal_memcpy( pValue, gapRole_bdAddr, B_ADDR_LEN ) ; + break; + + case GAPROLE_ADVERT_ENABLED: + *((uint8*)pValue) = gapRole_AdvEnabled; + break; + + case GAPROLE_ADVERT_OFF_TIME: + *((uint16*)pValue) = gapRole_AdvertOffTime; + break; + + case GAPROLE_ADVERT_DATA: + VOID osal_memcpy( pValue, gapRole_AdvertData, gapRole_AdvertDataLen ); + break; + + case GAPROLE_SCAN_RSP_DATA: + VOID osal_memcpy( pValue, gapRole_ScanRspData, gapRole_ScanRspDataLen ) ; + break; + + case GAPROLE_ADV_EVENT_TYPE: + *((uint8*)pValue) = gapRole_AdvEventType; + break; + + case GAPROLE_ADV_DIRECT_TYPE: + *((uint8*)pValue) = gapRole_AdvDirectType; + break; + + case GAPROLE_ADV_DIRECT_ADDR: + VOID osal_memcpy( pValue, gapRole_AdvDirectAddr, B_ADDR_LEN ) ; + break; + + case GAPROLE_ADV_CHANNEL_MAP: + *((uint8*)pValue) = gapRole_AdvChanMap; + break; + + case GAPROLE_ADV_FILTER_POLICY: + *((uint8*)pValue) = gapRole_AdvFilterPolicy; + break; + + case GAPROLE_CONNHANDLE: + *((uint16*)pValue) = gapRole_ConnectionHandle; + break; + + case GAPROLE_RSSI_READ_RATE: + *((uint16*)pValue) = gapRole_RSSIReadRate; + break; + + case GAPROLE_PARAM_UPDATE_ENABLE: + *((uint16*)pValue) = gapRole_ParamUpdateEnable; + break; + + case GAPROLE_MIN_CONN_INTERVAL: + *((uint16*)pValue) = gapRole_MinConnInterval; + break; + + case GAPROLE_MAX_CONN_INTERVAL: + *((uint16*)pValue) = gapRole_MaxConnInterval; + break; + + case GAPROLE_SLAVE_LATENCY: + *((uint16*)pValue) = gapRole_SlaveLatency; + break; + + case GAPROLE_TIMEOUT_MULTIPLIER: + *((uint16*)pValue) = gapRole_TimeoutMultiplier; + break; + + case GAPROLE_CONN_BD_ADDR: + VOID osal_memcpy( pValue, gapRole_ConnectedDevAddr, B_ADDR_LEN ) ; + break; + + default: + + // The param value isn't part of this profile, try the GAP. + if ( param < TGAP_PARAMID_MAX ) + { + *((uint16*)pValue) = GAP_GetParamValue( param ); + } + else + { + ret = INVALIDPARAMETER; + } + + break; + } + + return ( ret ); +} + +/********************************************************************* + @brief Does the device initialization. + + Public function defined in peripheral.h. +*/ +bStatus_t GAPRole_StartDevice( gapRolesCBs_t* pAppCallbacks ) +{ + if ( gapRole_state == GAPROLE_INIT ) + { + // Clear all of the Application callbacks + if ( pAppCallbacks ) + { + pGapRoles_AppCGs = pAppCallbacks; + } + + // Start the GAP + gapRole_SetupGAP(); + return ( SUCCESS ); + } + else + { + return ( bleAlreadyInRequestedMode ); + } +} + +/********************************************************************* + @brief Terminates the existing connection. + + Public function defined in peripheral.h. +*/ +bStatus_t GAPRole_TerminateConnection( void ) +{ + if ( (gapRole_state == GAPROLE_CONNECTED) + || (gapRole_state == GAPROLE_CONNECTED_ADV) ) + { + return ( GAP_TerminateLinkReq( gapRole_TaskID, gapRole_ConnectionHandle, + HCI_DISCONNECT_REMOTE_USER_TERM ) ); + } + else + { + return ( bleIncorrectMode ); + } +} + +/********************************************************************* + LOCAL FUNCTION PROTOTYPES +*/ + +/********************************************************************* + @brief Task Initialization function. + + Internal function defined in peripheral.h. +*/ +void GAPRole_Init( uint8 task_id ) +{ + gapRole_TaskID = task_id; + gapRole_state = GAPROLE_INIT; + gapRole_ConnectionHandle = INVALID_CONNHANDLE; + GAP_RegisterForHCIMsgs( gapRole_TaskID ); + // Initialize the Profile Advertising and Connection Parameters + gapRole_profileRole = (GAP_PROFILE_PERIPHERAL | GAP_PROFILE_BROADCASTER); + VOID osal_memset( gapRole_IRK, 0, KEYLEN ); + VOID osal_memset( gapRole_SRK, 0, KEYLEN ); + gapRole_signCounter = 0; + gapRole_AdvEventType = GAP_ADTYPE_ADV_IND; + gapRole_AdvDirectType = ADDRTYPE_PUBLIC; + gapRole_AdvChanMap = GAP_ADVCHAN_ALL; + gapRole_AdvFilterPolicy = GAP_FILTER_POLICY_ALL; + // Restore Items from NV + VOID osal_snv_read( BLE_NVID_IRK, KEYLEN, gapRole_IRK ); + VOID osal_snv_read( BLE_NVID_CSRK, KEYLEN, gapRole_SRK ); + VOID osal_snv_read( BLE_NVID_SIGNCOUNTER, sizeof( uint32 ), &gapRole_signCounter ); +} + +/********************************************************************* + @brief Task Event Processor function. + + Internal function defined in peripheral.h. +*/ +uint16 GAPRole_ProcessEvent( uint8 task_id, uint16 events ) +{ + VOID task_id; // OSAL required parameter that isn't used in this function + + if ( events & SYS_EVENT_MSG ) + { + uint8* pMsg; + + if ( (pMsg = osal_msg_receive( gapRole_TaskID )) != NULL ) + { + gapRole_ProcessOSALMsg( (osal_event_hdr_t*)pMsg ); + // Release the OSAL message + VOID osal_msg_deallocate( pMsg ); + } + + // return unprocessed events + return (events ^ SYS_EVENT_MSG); + } + + if ( events & GAP_EVENT_SIGN_COUNTER_CHANGED ) + { + // Sign counter changed, save it to NV + VOID osal_snv_write( BLE_NVID_SIGNCOUNTER, sizeof( uint32 ), &gapRole_signCounter ); + return ( events ^ GAP_EVENT_SIGN_COUNTER_CHANGED ); + } + + if ( events & START_ADVERTISING_EVT ) + { + if ( gapRole_AdvEnabled ) + { + gapAdvertisingParams_t params; + + // Setup advertisement parameters + if ( gapRole_state == GAPROLE_CONNECTED ) + { + // While in a connection, we can only advertise non-connectable undirected. + params.eventType = GAP_ADTYPE_ADV_NONCONN_IND; + } + else + { + params.eventType = gapRole_AdvEventType; + params.initiatorAddrType = gapRole_AdvDirectType; + VOID osal_memcpy( params.initiatorAddr, gapRole_AdvDirectAddr, B_ADDR_LEN ); + } + + params.channelMap = gapRole_AdvChanMap; + params.filterPolicy = gapRole_AdvFilterPolicy; + + if ( GAP_MakeDiscoverable( gapRole_TaskID, ¶ms ) != SUCCESS ) + { + gapRole_state = GAPROLE_ERROR; + + if ( pGapRoles_AppCGs && pGapRoles_AppCGs->pfnStateChange ) + { + pGapRoles_AppCGs->pfnStateChange( gapRole_state ); + } + } + } + + return ( events ^ START_ADVERTISING_EVT ); + } + + if ( events & RSSI_READ_EVT ) + { + // Only get RSSI when in a connection + if ( (gapRole_state == GAPROLE_CONNECTED) + || (gapRole_state == GAPROLE_CONNECTED_ADV) ) + { + // Ask for RSSI + VOID HCI_ReadRssiCmd( gapRole_ConnectionHandle ); + + // Setup next event + if ( gapRole_RSSIReadRate ) + { + VOID osal_start_timerEx( gapRole_TaskID, RSSI_READ_EVT, gapRole_RSSIReadRate ); + } + } + + return ( events ^ RSSI_READ_EVT ); + } + + if ( events & UPDATE_PARAMS_TIMEOUT_EVT ) + { + // Clear an existing timeout + if ( osal_get_timeoutEx( gapRole_TaskID, UPDATE_PARAMS_TIMEOUT_EVT ) ) + { + VOID osal_stop_timerEx( gapRole_TaskID, UPDATE_PARAMS_TIMEOUT_EVT ); + } + + // The Update Parameters Timeout occurred - Terminate connection + VOID GAP_TerminateLinkReq( gapRole_TaskID, gapRole_ConnectionHandle, + HCI_DISCONNECT_REMOTE_USER_TERM ); + return ( events ^ UPDATE_PARAMS_TIMEOUT_EVT ); + } + + // Discard unknown events + return 0; +} + +/********************************************************************* + @fn gapRole_ProcessOSALMsg + + @brief Process an incoming task message. + + @param pMsg - message to process + + @return none +*/ +static void gapRole_ProcessOSALMsg( osal_event_hdr_t* pMsg ) +{ + switch ( pMsg->event ) + { + case HCI_GAP_EVENT_EVENT: + if ( pMsg->status == HCI_COMMAND_COMPLETE_EVENT_CODE ) + { + hciEvt_CmdComplete_t* pPkt = (hciEvt_CmdComplete_t*)pMsg; + + if ( pPkt->cmdOpcode == HCI_READ_RSSI ) + { + int8 rssi = (int8)pPkt->pReturnParam[3]; + + if ( ((gapRole_state == GAPROLE_CONNECTED) + || (gapRole_state == GAPROLE_CONNECTED_ADV)) + && (rssi != RSSI_NOT_AVAILABLE) ) + { + // Report RSSI to app + if ( pGapRoles_AppCGs && pGapRoles_AppCGs->pfnRssiRead ) + { + pGapRoles_AppCGs->pfnRssiRead( rssi ); + } + } + } + } + + break; + + case GAP_MSG_EVENT: + gapRole_ProcessGAPMsg( (gapEventHdr_t*)pMsg ); + break; + + case L2CAP_SIGNAL_EVENT: + { + l2capSignalEvent_t* pPkt = (l2capSignalEvent_t*)pMsg; + + // Process the Parameter Update Response + if ( pPkt->opcode == L2CAP_PARAM_UPDATE_RSP ) + { + l2capParamUpdateRsp_t* pRsp = (l2capParamUpdateRsp_t*)&(pPkt->cmd.updateRsp); + + if ( pRsp->result == SUCCESS ) + { + // All is good stop Update Parameters timeout + VOID osal_stop_timerEx( gapRole_TaskID, UPDATE_PARAMS_TIMEOUT_EVT ); + } + } + } + break; + + default: + break; + } +} + +/********************************************************************* + @fn gapRole_ProcessGAPMsg + + @brief Process an incoming task message. + + @param pMsg - message to process + + @return none +*/ +static void gapRole_ProcessGAPMsg( gapEventHdr_t* pMsg ) +{ + uint8 notify = FALSE; // State changed notify the app? (default no) + + switch ( pMsg->opcode ) + { + case GAP_DEVICE_INIT_DONE_EVENT: + { + gapDeviceInitDoneEvent_t* pPkt = (gapDeviceInitDoneEvent_t*)pMsg; + bStatus_t stat = pPkt->hdr.status; + + if ( stat == SUCCESS ) + { + // Save off the generated keys + VOID osal_snv_write( BLE_NVID_IRK, KEYLEN, gapRole_IRK ); + VOID osal_snv_write( BLE_NVID_CSRK, KEYLEN, gapRole_SRK ); + // Save off the information + VOID osal_memcpy( gapRole_bdAddr, pPkt->devAddr, B_ADDR_LEN ); + gapRole_state = GAPROLE_STARTED; + // Update the advertising data + stat = GAP_UpdateAdvertisingData( gapRole_TaskID, + TRUE, gapRole_AdvertDataLen, gapRole_AdvertData ); + } + + if ( stat != SUCCESS ) + { + gapRole_state = GAPROLE_ERROR; + } + + notify = TRUE; + } + break; + + case GAP_ADV_DATA_UPDATE_DONE_EVENT: + { + gapAdvDataUpdateEvent_t* pPkt = (gapAdvDataUpdateEvent_t*)pMsg; + + if ( pPkt->hdr.status == SUCCESS ) + { + if ( pPkt->adType ) + { + // Setup the Response Data + pPkt->hdr.status = GAP_UpdateAdvertisingData( gapRole_TaskID, + FALSE, gapRole_ScanRspDataLen, gapRole_ScanRspData ); + } + else + { + // Start advertising + VOID osal_set_event( gapRole_TaskID, START_ADVERTISING_EVT ); + } + } + + if ( pPkt->hdr.status != SUCCESS ) + { + // Set into Error state + gapRole_state = GAPROLE_ERROR; + notify = TRUE; + } + } + break; + + case GAP_MAKE_DISCOVERABLE_DONE_EVENT: + case GAP_END_DISCOVERABLE_DONE_EVENT: + { + gapMakeDiscoverableRspEvent_t* pPkt = (gapMakeDiscoverableRspEvent_t*)pMsg; + + if ( pPkt->hdr.status == SUCCESS ) + { + if ( pMsg->opcode == GAP_MAKE_DISCOVERABLE_DONE_EVENT ) + { + if ( gapRole_state == GAPROLE_CONNECTED ) + { + gapRole_state = GAPROLE_CONNECTED_ADV; + } + else + { + gapRole_state = GAPROLE_ADVERTISING; + } + } + else // GAP_END_DISCOVERABLE_DONE_EVENT + { + if ( gapRole_AdvertOffTime != 0 ) + { + if ( ( gapRole_AdvEnabled ) ) + { + VOID osal_start_timerEx( gapRole_TaskID, START_ADVERTISING_EVT, gapRole_AdvertOffTime ); + } + } + else + { + // Since gapRole_AdvertOffTime is set to 0, the device should not + // automatically become discoverable again after a period of time. + // Set enabler to FALSE; device will become discoverable again when + // this value gets set to TRUE + gapRole_AdvEnabled = FALSE; + } + + // In the Advertising Off period + gapRole_state = GAPROLE_WAITING; + } + } + else + { + gapRole_state = GAPROLE_ERROR; + } + + notify = TRUE; + } + break; + + case GAP_LINK_ESTABLISHED_EVENT: + { + gapEstLinkReqEvent_t* pPkt = (gapEstLinkReqEvent_t*)pMsg; + + if ( pPkt->hdr.status == SUCCESS ) + { + VOID osal_memcpy( gapRole_ConnectedDevAddr, pPkt->devAddr, B_ADDR_LEN ); + gapRole_ConnectionHandle = pPkt->connectionHandle; + gapRole_state = GAPROLE_CONNECTED; + + if ( gapRole_RSSIReadRate ) + { + // Start the RSSI Reads + VOID osal_start_timerEx( gapRole_TaskID, RSSI_READ_EVT, gapRole_RSSIReadRate ); + } + + // Check whether update parameter request is enabled, and check the connection parameters + if ( ( gapRole_ParamUpdateEnable == TRUE ) && + ( (pPkt->connInterval < gapRole_MinConnInterval) || + (pPkt->connInterval > gapRole_MaxConnInterval) || + (pPkt->connLatency != gapRole_SlaveLatency) || + (pPkt->connTimeout != gapRole_TimeoutMultiplier) )) + { + gapRole_SendUpdateParam( pPkt->connInterval, pPkt->connLatency ); + } + + // Notify the Bond Manager to the connection + VOID GAPBondMgr_LinkEst( pPkt->devAddrType, pPkt->devAddr, pPkt->connectionHandle, GAP_PROFILE_PERIPHERAL ); + } + else + { + gapRole_state = GAPROLE_ERROR; + } + + notify = TRUE; + } + break; + + case GAP_LINK_TERMINATED_EVENT: + { + VOID GAPBondMgr_ProcessGAPMsg( (gapEventHdr_t*)pMsg ); + osal_memset( gapRole_ConnectedDevAddr, 0, B_ADDR_LEN ); + + if ( gapRole_state == GAPROLE_CONNECTED_ADV ) + { + // End the non-connectable advertising + GAP_EndDiscoverable( gapRole_TaskID ); + gapRole_state = GAPROLE_CONNECTED; + } + else + { + gapTerminateLinkEvent_t* pPkt = (gapTerminateLinkEvent_t*)pMsg; + + if( pPkt->reason == LL_SUPERVISION_TIMEOUT_TERM ) + { + gapRole_state = GAPROLE_WAITING_AFTER_TIMEOUT; + } + else + { + gapRole_state = GAPROLE_WAITING; + } + + notify = TRUE; + VOID osal_set_event( gapRole_TaskID, START_ADVERTISING_EVT ); + } + + gapRole_ConnectionHandle = INVALID_CONNHANDLE; + } + break; + + case GAP_LINK_PARAM_UPDATE_EVENT: + { + gapLinkUpdateEvent_t* pPkt = (gapLinkUpdateEvent_t*)pMsg; + + if ( (pPkt->hdr.status != SUCCESS) + || (pPkt->connInterval < gapRole_MinConnInterval) + || (pPkt->connInterval > gapRole_MaxConnInterval) ) + { + // Ask to change the interval + gapRole_SendUpdateParam( pPkt->connInterval, pPkt->connLatency ); + } + else + { + // All is good stop Update Parameters timeout + VOID osal_stop_timerEx( gapRole_TaskID, UPDATE_PARAMS_TIMEOUT_EVT ); + } + } + break; + + default: + break; + } + + if ( notify == TRUE ) + { + // Notify the application + if ( pGapRoles_AppCGs && pGapRoles_AppCGs->pfnStateChange ) + { + pGapRoles_AppCGs->pfnStateChange( gapRole_state ); + } + } +} + +/********************************************************************* + @fn gapRole_SetupGAP + + @brief Call the GAP Device Initialization function using the + Profile Parameters. + + @param none + + @return none +*/ +static void gapRole_SetupGAP( void ) +{ + VOID GAP_DeviceInit( gapRole_TaskID, + gapRole_profileRole, 0, + gapRole_IRK, gapRole_SRK, + &gapRole_signCounter ); +} + +/********************************************************************* + @fn gapRole_SendUpdateParam + + @brief Send an Update Connection Parameters. + + @param connInterval - current connection interval + @param connLatency - current connection latency + + @return none +*/ +static void gapRole_SendUpdateParam( uint16 connInterval, uint16 connLatency ) +{ + l2capParamUpdateReq_t updateReq; // Space for Conn Update parameters + uint32 timeout; // Calculated response timeout + // Calculate the current interval + uint16 effectiveOldInterval = (connInterval * (connLatency + 1)); + // Calculate the interval we want + uint16 effectiveNewMaxInterval = (gapRole_MaxConnInterval * (gapRole_SlaveLatency + 1)); + // Fill in the wanted parameters + updateReq.intervalMin = gapRole_MinConnInterval; + updateReq.intervalMax = gapRole_MaxConnInterval; + updateReq.slaveLatency = gapRole_SlaveLatency; + updateReq.timeoutMultiplier = gapRole_TimeoutMultiplier; + VOID L2CAP_ConnParamUpdateReq( gapRole_ConnectionHandle, &updateReq, gapRole_TaskID ); + + // Set up the timeout for expected response + if( effectiveOldInterval > effectiveNewMaxInterval ) + { + timeout = (uint32)(effectiveOldInterval) * CONN_INTERVAL_MULTIPLIER; + } + else + { + timeout = (uint32)(effectiveNewMaxInterval) * CONN_INTERVAL_MULTIPLIER; + } + + if( timeout > MAX_TIMEOUT_VALUE ) + { + timeout = MAX_TIMEOUT_VALUE; + } + + VOID osal_start_timerEx( gapRole_TaskID, UPDATE_PARAMS_TIMEOUT_EVT, (uint16)(timeout) ); +} + +/********************************************************************* +*********************************************************************/ diff --git a/src/components/profiles/Roles/peripheralBroadcaster.h b/src/components/profiles/Roles/peripheralBroadcaster.h new file mode 100644 index 0000000..23299e2 --- /dev/null +++ b/src/components/profiles/Roles/peripheralBroadcaster.h @@ -0,0 +1,206 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#ifndef PERIPHERAL_BROADCASTER_H +#define PERIPHERAL_BROADCASTER_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* ------------------------------------------------------------------- + INCLUDES +*/ + +/* ------------------------------------------------------------------- + CONSTANTS +*/ + +/** @defgroup GAPROLE_PROFILE_PARAMETERS GAP Role Parameters + @{ +*/ +#define GAPROLE_PROFILEROLE 0x300 //!< Reading this parameter will return GAP Role type. Read Only. Size is uint8. +#define GAPROLE_IRK 0x301 //!< Identity Resolving Key. Read/Write. Size is uint8[KEYLEN]. Default is all 0, which means that the IRK will be randomly generated. +#define GAPROLE_SRK 0x302 //!< Signature Resolving Key. Read/Write. Size is uint8[KEYLEN]. Default is all 0, which means that the SRK will be randomly generated. +#define GAPROLE_SIGNCOUNTER 0x303 //!< Sign Counter. Read/Write. Size is uint32. Default is 0. +#define GAPROLE_BD_ADDR 0x304 //!< Device's Address. Read Only. Size is uint8[B_ADDR_LEN]. This item is read from the controller. +#define GAPROLE_ADVERT_ENABLED 0x305 //!< Enable/Disable Advertising. Read/Write. Size is uint8. Default is TRUE=Enabled. During a connection, this will enable and display advertising (non-connectable undirected). Setting this variable during a connection does not change the permanent state of the parameter. +#define GAPROLE_ADVERT_OFF_TIME 0x306 //!< Advertising Off Time for Limited advertisements (in milliseconds). Read/Write. Size is uint16. Default is 30 seconds. +#define GAPROLE_ADVERT_DATA 0x307 //!< Advertisement Data. Read/Write. Max size is uint8[B_MAX_ADV_LEN]. Default is "02:01:01", which means that it is a Limited Discoverable Advertisement. +#define GAPROLE_SCAN_RSP_DATA 0x308 //!< Scan Response Data. Read/Write. Max size is uint8[B_MAX_ADV_LEN]. Defaults to all 0. +#define GAPROLE_ADV_EVENT_TYPE 0x309 //!< Advertisement Type. Read/Write. Size is uint8. Default is GAP_ADTYPE_ADV_IND (defined in GAP.h). +#define GAPROLE_ADV_DIRECT_TYPE 0x30A //!< Direct Advertisement Address Type. Read/Write. Size is uint8. Default is ADDRTYPE_PUBLIC (defined in GAP.h). +#define GAPROLE_ADV_DIRECT_ADDR 0x30B //!< Direct Advertisement Address. Read/Write. Size is uint8[B_ADDR_LEN]. Default is NULL. +#define GAPROLE_ADV_CHANNEL_MAP 0x30C //!< Which channels to advertise on. Read/Write Size is uint8. Default is GAP_ADVCHAN_ALL (defined in GAP.h) +#define GAPROLE_ADV_FILTER_POLICY 0x30D //!< Filter Policy. Ignored when directed advertising is used. Read/Write. Size is uint8. Default is GAP_FILTER_POLICY_ALL (defined in GAP.h). +#define GAPROLE_CONNHANDLE 0x30E //!< Connection Handle. Read Only. Size is uint16. +#define GAPROLE_RSSI_READ_RATE 0x30F //!< How often to read the RSSI during a connection. Read/Write. Size is uint16. The value is in milliseconds. Default is 0 = OFF. +#define GAPROLE_PARAM_UPDATE_ENABLE 0x310 //!< Slave Connection Parameter Update Enable. Read/Write. Size is uint8. If TRUE then automatic connection parameter update request is sent. Default is FALSE. +#define GAPROLE_MIN_CONN_INTERVAL 0x311 //!< Minimum Connection Interval to allow (n * 1.25ms). Range: 7.5 msec to 4 seconds (0x0006 to 0x0C80). Read/Write. Size is uint16. Default is 7.5 milliseconds (0x0006). +#define GAPROLE_MAX_CONN_INTERVAL 0x312 //!< Maximum Connection Interval to allow (n * 1.25ms). Range: 7.5 msec to 4 seconds (0x0006 to 0x0C80). Read/Write. Size is uint16. Default is 4 seconds (0x0C80). +#define GAPROLE_SLAVE_LATENCY 0x313 //!< Update Parameter Slave Latency. Range: 0 - 499. Read/Write. Size is uint16. Default is 0. +#define GAPROLE_TIMEOUT_MULTIPLIER 0x314 //!< Update Parameter Timeout Multiplier (n * 10ms). Range: 100ms to 32 seconds (0x000a - 0x0c80). Read/Write. Size is uint16. Default is 1000. +#define GAPROLE_CONN_BD_ADDR 0x315 //!< Address of connected device. Read only. Size is uint8[B_MAX_ADV_LEN]. Set to all zeros when not connected. +/** @} End GAPROLE_PROFILE_PARAMETERS */ + +/* ------------------------------------------------------------------- + TYPEDEFS +*/ + +/** + GAP Peripheral + Broadcaster Role States. +*/ +typedef enum +{ + GAPROLE_INIT = 0, //!< Waiting to be started + GAPROLE_STARTED, //!< Started but not advertising + GAPROLE_ADVERTISING, //!< Currently Advertising + GAPROLE_WAITING, //!< Device is started but not advertising, is in waiting period before advertising again + GAPROLE_WAITING_AFTER_TIMEOUT, //!< Device just timed out from a connection but is not yet advertising, is in waiting period before advertising again + GAPROLE_CONNECTED, //!< In a connection + GAPROLE_CONNECTED_ADV, //!< In a connection and advertising + GAPROLE_ERROR //!< Error occurred - invalid state +} gaprole_States_t; + +/* ------------------------------------------------------------------- + MACROS +*/ + +/* ------------------------------------------------------------------- + Profile Callbacks +*/ + +/** + Callback when the device has been started. Callback event to + the Notify of a state change. +*/ +typedef void (*gapRolesStateNotify_t)( gaprole_States_t newState ); + +/** + Callback when the device has read an new RSSI value during a connection. +*/ +typedef void (*gapRolesRssiRead_t)( int8 newRSSI ); + +/** + Callback structure - must be setup by the application and used when gapRoles_StartDevice() is called. +*/ +typedef struct +{ + gapRolesStateNotify_t pfnStateChange; //!< Whenever the device changes state + gapRolesRssiRead_t pfnRssiRead; //!< When a valid RSSI is read from controller +} gapRolesCBs_t; + +/* ------------------------------------------------------------------- + API FUNCTIONS +*/ + +/** + @defgroup GAPROLES_PERIPHERAL_BROADCASTER_API GAP Peripheral + Broadcaster Role API Functions + + @{ +*/ + +/** + @brief Set a GAP Role parameter. + + NOTE: You can call this function with a GAP Parameter ID and it will set the + GAP Parameter. GAP Parameters are defined in (gap.h). Also, + the "len" field must be set to the size of a "uint16" and the + "pValue" field must point to a "uint16". + + @param param - Profile parameter ID: @ref GAPROLE_PROFILE_PARAMETERS + @param len - length of data to write + @param pValue - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return SUCCESS or INVALIDPARAMETER (invalid paramID) +*/ +extern bStatus_t GAPRole_SetParameter( uint16 param, uint8 len, void* pValue ); + +/** + @brief Get a GAP Role parameter. + + NOTE: You can call this function with a GAP Parameter ID and it will get a + GAP Parameter. GAP Parameters are defined in (gap.h). Also, the + "pValue" field must point to a "uint16". + + @param param - Profile parameter ID: @ref GAPROLE_PROFILE_PARAMETERS + @param pValue - pointer to location to get the value. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return SUCCESS or INVALIDPARAMETER (invalid paramID) +*/ +extern bStatus_t GAPRole_GetParameter( uint16 param, void* pValue ); + +/** + @brief Does the device initialization. Only call this function once. + + @param pAppCallbacks - pointer to application callbacks. + + @return SUCCESS or bleAlreadyInRequestedMode +*/ +extern bStatus_t GAPRole_StartDevice( gapRolesCBs_t* pAppCallbacks ); + +/** + @brief Terminates the existing connection. + + @return SUCCESS or bleIncorrectMode +*/ +extern bStatus_t GAPRole_TerminateConnection( void ); + +/** + @} End GAPROLES_PERIPHERAL_BROADCASTER_API +*/ + + +/* ------------------------------------------------------------------- + TASK FUNCTIONS - Don't call these. These are system functions. +*/ + +/** + @internal + + @brief Initialization function for the GAP Role Task. + This is called during initialization and should contain + any application specific initialization (ie. hardware + initialization/setup, table initialization, power up + notificaiton ... ). + + @param the ID assigned by OSAL. This ID should be + used to send messages and set timers. + + @return void +*/ +extern void GAPRole_Init( uint8 task_id ); + +/** + @internal + + @brief GAP Role Task event processor. + This function is called to process all events for the task. + Events include timers, messages and any other user defined + events. + + @param task_id - The OSAL assigned task ID. + @param events - events to process. This is a bit map and can + contain more than one event. + + @return events not processed +*/ +extern uint16 GAPRole_ProcessEvent( uint8 task_id, uint16 events ); + +/* ------------------------------------------------------------------- + -------------------------------------------------------------------*/ + +#ifdef __cplusplus +} +#endif + +#endif /* PERIPHERAL_BROADCASTER_H */ diff --git a/src/components/profiles/ScanParam/scanparamservice.c b/src/components/profiles/ScanParam/scanparamservice.c new file mode 100644 index 0000000..9c51e60 --- /dev/null +++ b/src/components/profiles/ScanParam/scanparamservice.c @@ -0,0 +1,406 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "att.h" +#include "gatt.h" +#include "gatt_uuid.h" +#include "gattservapp.h" +#include "gatt_profile_uuid.h" +#include "gapbondmgr.h" +#include "linkdb.h" +#include "scanparamservice.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ +// Scan parameters service +CONST uint8 scanParamServUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(SCAN_PARAM_SERV_UUID), HI_UINT16(SCAN_PARAM_SERV_UUID) +}; + +// Scan interval window characteristic +CONST uint8 scanIntervalWindowUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(SCAN_INTERVAL_WINDOW_UUID), HI_UINT16(SCAN_INTERVAL_WINDOW_UUID) +}; + +// Scan parameter refresh characteristic +CONST uint8 scanParamRefreshUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(SCAN_REFRESH_UUID), HI_UINT16(SCAN_REFRESH_UUID) +}; + + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +// Application callback +static scanParamServiceCB_t scanParamServiceCB; + +/********************************************************************* + Profile Attributes - variables +*/ + +// Scan Parameters Service attribute +static CONST gattAttrType_t scanParamService = { ATT_BT_UUID_SIZE, scanParamServUUID }; + +// Scan Interval Window characteristic +static uint8 scanIntervalWindowProps = GATT_PROP_WRITE_NO_RSP; +static uint8 scanIntervalWindow[SCAN_INTERVAL_WINDOW_CHAR_LEN]; + +// Scan Parameter Refresh characteristic +static uint8 scanParamRefreshProps = GATT_PROP_NOTIFY; +static uint8 scanParamRefresh[SCAN_PARAM_REFRESH_LEN]; +static gattCharCfg_t scanParamRefreshClientCharCfg[GATT_MAX_NUM_CONN]; + +/********************************************************************* + Profile Attributes - Table +*/ + +static gattAttribute_t scanParamAttrTbl[] = +{ + // Scan Parameters Service attribute + { + { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */ + GATT_PERMIT_READ, /* permissions */ + 0, /* handle */ + (uint8*)& scanParamService /* pValue */ + }, + + // Scan Interval Window declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &scanIntervalWindowProps + }, + + // Scan Interval Window characteristic + { + { ATT_BT_UUID_SIZE, scanIntervalWindowUUID }, + GATT_PERMIT_ENCRYPT_WRITE, + 0, + scanIntervalWindow + }, + + // Scan Parameter Refresh declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &scanParamRefreshProps + }, + + // Scan Parameter Refresh characteristic + { + { ATT_BT_UUID_SIZE, scanParamRefreshUUID }, + 0, + 0, + scanParamRefresh + }, + + // Scan Parameter Refresh characteristic client characteristic configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_ENCRYPT_WRITE, + 0, + (uint8*)& scanParamRefreshClientCharCfg + } +}; + +// Attribute index enumeration-- these indexes match array elements above +enum +{ + SCAN_PARAM_SERVICE_IDX, // Scan Parameters Service + SCAN_PARAM_INTERVAL_DECL_IDX, // Scan Interval Window declaration + SCAN_PARAM_INTERVAL_IDX, // Scan Interval Window characteristic + SCAN_PARAM_REFRESH_DECL_IDX, // Scan Parameter Refresh declaration + SCAN_PARAM_REFRESH_IDX, // Scan Parameter Refresh characteristic + SCAN_PARAM_REFRESH_CCCD_IDX // Scan Parameter Refresh characteristic client characteristic configuration +}; + + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static bStatus_t scanParamWriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ); +static uint8 scanParamReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ); + +/********************************************************************* + PROFILE CALLBACKS +*/ + +// Service Callbacks +CONST gattServiceCBs_t scanParamCBs = +{ + scanParamReadAttrCB, // Read callback function pointer + scanParamWriteAttrCB, // Write callback function pointer + NULL // Authorization callback function pointer +}; + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/********************************************************************* + @fn ScanParam_AddService + + @brief Initializes the Battery Service by registering + GATT attributes with the GATT server. + + @return Success or Failure +*/ +bStatus_t ScanParam_AddService( void ) +{ + uint8 status = SUCCESS; + // Initialize Client Characteristic Configuration attributes + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, scanParamRefreshClientCharCfg ); + // Register GATT attribute list and CBs with GATT Server App + status = GATTServApp_RegisterService( scanParamAttrTbl, GATT_NUM_ATTRS( scanParamAttrTbl ), + &scanParamCBs ); + return ( status ); +} + +/********************************************************************* + @fn ScanParam_Register + + @brief Register a callback function with the Battery Service. + + @param pfnServiceCB - Callback function. + + @return None. +*/ +extern void ScanParam_Register( scanParamServiceCB_t pfnServiceCB ) +{ + scanParamServiceCB = pfnServiceCB; +} + +/********************************************************************* + @fn ScanParam_SetParameter + + @brief Set a Battery Service parameter. + + @param param - Profile parameter ID + @param len - length of data to right + @param value - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t ScanParam_SetParameter( uint8 param, uint8 len, void* value ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn ScanParam_GetParameter + + @brief Get a Battery Service parameter. + + @param param - Profile parameter ID + @param value - pointer to data to get. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t ScanParam_GetParameter( uint8 param, void* value ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case SCAN_PARAM_PARAM_INTERVAL: + *((uint16*)value) = BUILD_UINT16(scanIntervalWindow[0], + scanIntervalWindow[1]); + break; + + case SCAN_PARAM_PARAM_WINDOW: + *((uint16*)value) = BUILD_UINT16(scanIntervalWindow[2], + scanIntervalWindow[3]); + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn ScanParam_RefreshNotify + + @brief Notify the peer to refresh the scan parameters. + + @param connHandle - connection handle + + @return None +*/ +void ScanParam_RefreshNotify( uint16 connHandle ) +{ + attHandleValueNoti_t noti; + uint16 value; + value = GATTServApp_ReadCharCfg( connHandle, scanParamRefreshClientCharCfg ); + + if ( value & GATT_CLIENT_CFG_NOTIFY ) + { + // send notification + noti.handle = scanParamAttrTbl[SCAN_PARAM_REFRESH_CCCD_IDX].handle; + noti.len = SCAN_PARAM_REFRESH_LEN; + noti.value[0] = SCAN_PARAM_REFRESH_REQ; + GATT_Notification( connHandle, ¬i, FALSE ); + } +} + +/********************************************************************* + @fn scanParamReadAttrCB + + @brief GATT read callback. + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be read + @param pLen - length of data to be read + @param offset - offset of the first octet to be read + @param maxLen - maximum length of data to be read + + @return Success or Failure +*/ +static uint8 scanParamReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ) +{ + bStatus_t status = SUCCESS; + return ( status ); +} + +/********************************************************************* + @fn scanParamWriteAttrCB + + @brief Validate attribute data prior to a write operation + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be written + @param len - length of data + @param offset - offset of the first octet to be written + + @return Success or Failure +*/ +static bStatus_t scanParamWriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ) +{ + bStatus_t status = SUCCESS; + + // Make sure it's not a blob operation (no attributes in the profile are long) + if ( offset > 0 ) + { + return ( ATT_ERR_ATTR_NOT_LONG ); + } + + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + // Only one writeable attribute + if ( uuid == SCAN_INTERVAL_WINDOW_UUID ) + { + if ( len == SCAN_INTERVAL_WINDOW_CHAR_LEN ) + { + uint16 interval = BUILD_UINT16( pValue[0], pValue[1] ); + uint16 window = BUILD_UINT16( pValue[0], pValue[1] ); + + // Validate values + if ( window <= interval ) + { + osal_memcpy( pAttr->pValue, pValue, len ); + (*scanParamServiceCB)( SCAN_INTERVAL_WINDOW_SET ); + } + else + { + status = ATT_ERR_INVALID_VALUE; + } + } + else + { + status = ATT_ERR_INVALID_VALUE_SIZE; + } + } + else if ( uuid == GATT_CLIENT_CHAR_CFG_UUID ) + { + status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len, + offset, GATT_CLIENT_CFG_NOTIFY ); + } + else + { + status = ATT_ERR_ATTR_NOT_FOUND; + } + + return ( status ); +} + +/********************************************************************* + @fn ScanParam_HandleConnStatusCB + + @brief Service link status change handler function. + + @param connHandle - connection handle + @param changeType - type of change + + @return none +*/ +void ScanParam_HandleConnStatusCB( uint16 connHandle, uint8 changeType ) +{ + // Make sure this is not loopback connection + if ( connHandle != LOOPBACK_CONNHANDLE ) + { + // Reset Client Char Config if connection has dropped + if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) || + ( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && + ( !linkDB_Up( connHandle ) ) ) ) + { + GATTServApp_InitCharCfg( connHandle, scanParamRefreshClientCharCfg ); + } + } +} diff --git a/src/components/profiles/ScanParam/scanparamservice.h b/src/components/profiles/ScanParam/scanparamservice.h new file mode 100644 index 0000000..14ba9d6 --- /dev/null +++ b/src/components/profiles/ScanParam/scanparamservice.h @@ -0,0 +1,137 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#ifndef SCANPARAMSERVICE_H +#define SCANPARAMSERVICE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + CONSTANTS +*/ + +// Scan Characteristic Lengths +#define SCAN_INTERVAL_WINDOW_CHAR_LEN 4 +#define SCAN_PARAM_REFRESH_LEN 1 + +// Scan Parameter Refresh Values +#define SCAN_PARAM_REFRESH_REQ 0x00 + +// Callback events +#define SCAN_INTERVAL_WINDOW_SET 1 + +// Get/Set parameters +#define SCAN_PARAM_PARAM_INTERVAL 0 +#define SCAN_PARAM_PARAM_WINDOW 1 + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + Profile Callbacks +*/ + +// Scan Parameters Service callback function +typedef void (*scanParamServiceCB_t)( uint8 event ); + +/********************************************************************* + API FUNCTIONS +*/ + +/********************************************************************* + @fn ScanParam_AddService + + @brief Initializes the Service by registering + GATT attributes with the GATT server. + + @return Success or Failure +*/ +extern bStatus_t ScanParam_AddService( void ); + +/********************************************************************* + @fn ScanParam_Register + + @brief Register a callback function with the Scan Parameters Service. + + @param pfnServiceCB - Callback function. + + @return None. +*/ +extern void ScanParam_Register( scanParamServiceCB_t pfnServiceCB ); + +/********************************************************************* + @fn ScanParam_SetParameter + + @brief Set a Scan Parameters Service parameter. + + @param param - Profile parameter ID + @param len - length of data to right + @param value - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +extern bStatus_t ScanParam_SetParameter( uint8 param, uint8 len, void* value ); + +/********************************************************************* + @fn ScanParam_GetParameter + + @brief Get a Scan Parameters Service parameter. + + @param param - Profile parameter ID + @param value - pointer to data to get. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +extern bStatus_t ScanParam_GetParameter( uint8 param, void* value ); + +/********************************************************************* + @fn ScanParam_RefreshNotify + + @brief Notify the peer to refresh the scan parameters. + + @param connHandle - connection handle + + @return None +*/ +extern void ScanParam_RefreshNotify( uint16 connHandle ); + +/********************************************************************* + @fn ScanParam_HandleConnStatusCB + + @brief Service link status change handler function. + + @param connHandle - connection handle + @param changeType - type of change + + @return none +*/ +void ScanParam_HandleConnStatusCB( uint16 connHandle, uint8 changeType ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* SCANPARAMSERVICE_H */ diff --git a/src/components/profiles/SimpleProfile/simpleGATTprofile_ota.c b/src/components/profiles/SimpleProfile/simpleGATTprofile_ota.c new file mode 100644 index 0000000..92ce160 --- /dev/null +++ b/src/components/profiles/SimpleProfile/simpleGATTprofile_ota.c @@ -0,0 +1,874 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: simpleGATTprofile_ota.c + Revised: + Revision: + + Description: This file contains the Simple GATT profile sample GATT service + profile for use with the BLE sample application. + + +**************************************************************************************************/ + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "linkdb.h" +#include "att.h" +#include "gatt.h" +#include "gatt_uuid.h" +#include "gattservapp.h" +#include "gapbondmgr.h" + +#include "simpleGATTprofile_ota.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +#define SERVAPP_NUM_ATTR_SUPPORTED 21 + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ +// Simple GATT Profile Service UUID: 0xFFF0 +CONST uint8 simpleProfileServUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(SIMPLEPROFILE_SERV_UUID), HI_UINT16(SIMPLEPROFILE_SERV_UUID) +}; + +// Characteristic 1 UUID: 0xFFF1 +CONST uint8 simpleProfilechar1UUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(SIMPLEPROFILE_CHAR1_UUID), HI_UINT16(SIMPLEPROFILE_CHAR1_UUID) +}; + +// Characteristic 2 UUID: 0xFFF2 +CONST uint8 simpleProfilechar2UUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(SIMPLEPROFILE_CHAR2_UUID), HI_UINT16(SIMPLEPROFILE_CHAR2_UUID) +}; + +// Characteristic 3 UUID: 0xFFF3 +CONST uint8 simpleProfilechar3UUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(SIMPLEPROFILE_CHAR3_UUID), HI_UINT16(SIMPLEPROFILE_CHAR3_UUID) +}; + +// Characteristic 4 UUID: 0xFFF4 +CONST uint8 simpleProfilechar4UUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(SIMPLEPROFILE_CHAR4_UUID), HI_UINT16(SIMPLEPROFILE_CHAR4_UUID) +}; + +// Characteristic 5 UUID: 0xFFF5 +CONST uint8 simpleProfilechar5UUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(SIMPLEPROFILE_CHAR5_UUID), HI_UINT16(SIMPLEPROFILE_CHAR5_UUID) +}; + +// Characteristic 6 UUID: 0xFFF6 +CONST uint8 simpleProfilechar6UUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(SIMPLEPROFILE_CHAR6_UUID), HI_UINT16(SIMPLEPROFILE_CHAR6_UUID) +}; + + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +static simpleProfileCBs_t* simpleProfile_AppCBs = NULL; + +/********************************************************************* + Profile Attributes - variables +*/ + +// Simple Profile Service attribute +static CONST gattAttrType_t simpleProfileService = { ATT_BT_UUID_SIZE, simpleProfileServUUID }; + + +// Simple Profile Characteristic 1 Properties +static uint8 simpleProfileChar1Props = GATT_PROP_READ | GATT_PROP_WRITE; + +// Characteristic 1 Value +static uint8 simpleProfileChar1[IBEACON_UUID_LEN];// = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; + +// Simple Profile Characteristic 1 User Description +static uint8 simpleProfileChar1UserDesp[] = "UUID\0"; + + +// Simple Profile Characteristic 2 Properties +static uint8 simpleProfileChar2Props = GATT_PROP_READ | GATT_PROP_WRITE; + +// Characteristic 2 Value +static uint16 simpleProfileChar2 = 0; + +// Simple Profile Characteristic 2 User Description +static uint8 simpleProfileChar2UserDesp[] = "Major\0"; + + +// Simple Profile Characteristic 3 Properties +static uint8 simpleProfileChar3Props = GATT_PROP_READ | GATT_PROP_WRITE; + +// Characteristic 3 Value +static uint16 simpleProfileChar3 = 0; + +// Simple Profile Characteristic 3 User Description +static uint8 simpleProfileChar3UserDesp[] = "Minor\0"; + + +// Simple Profile Characteristic 4 Properties +static uint8 simpleProfileChar4Props = GATT_PROP_READ | GATT_PROP_WRITE; + +// Characteristic 4 Value +static uint8 simpleProfileChar4 = 0; + +// Simple Profile Characteristic 4 Configuration Each client has its own +// instantiation of the Client Characteristic Configuration. Reads of the +// Client Characteristic Configuration only shows the configuration for +// that client and writes only affect the configuration of that client. +static gattCharCfg_t simpleProfileChar4Config[GATT_MAX_NUM_CONN]; + +// Simple Profile Characteristic 4 User Description +static uint8 simpleProfileChar4UserDesp[] = "Power\0"; + + +// Simple Profile Characteristic 5 Properties +static uint8 simpleProfileChar5Props = GATT_PROP_READ | GATT_PROP_WRITE; // to change to write only, HZF + +// Characteristic 5 Value +static uint8 simpleProfileChar5 = 0; + +// Simple Profile Characteristic 5 User Description +static uint8 simpleProfileChar5UserDesp[] = "Reset\0"; + +// Simple Profile Characteristic 6 Properties +static uint8 simpleProfileChar6Props = GATT_PROP_READ | GATT_PROP_NOTIFY; + +// Characteristic 6 Value +static uint8 simpleProfileChar6[20]; + +// Simple Profile Characteristic 6 User Description +static uint8 simpleProfileChar6UserDesp[] = "NOTIFY\0"; +// Simple Profile Characteristic 1 Configuration Each client has its own +// instantiation of the Client Characteristic Configuration. Reads of the +// Client Characteristic Configuration only shows the configuration for +// that client and writes only affect the configuration of that client. +static gattCharCfg_t simpleProfileChar6Config[GATT_MAX_NUM_CONN]; + + +/********************************************************************* + Profile Attributes - Table +*/ + +static gattAttribute_t simpleProfileAttrTbl[SERVAPP_NUM_ATTR_SUPPORTED] = +{ + // Simple Profile Service + { + { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */ + GATT_PERMIT_READ, /* permissions */ + 0, /* handle */ + (uint8*)& simpleProfileService /* pValue */ + }, + + // Characteristic 1 Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &simpleProfileChar1Props + }, + + // Characteristic Value 1 + { + { ATT_BT_UUID_SIZE, simpleProfilechar1UUID }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + &simpleProfileChar1[0] + }, + + // Characteristic 1 User Description + { + { ATT_BT_UUID_SIZE, charUserDescUUID }, + GATT_PERMIT_READ, + 0, + simpleProfileChar1UserDesp + }, + + // Characteristic 2 Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &simpleProfileChar2Props + }, + + // Characteristic Value 2 + { + { ATT_BT_UUID_SIZE, simpleProfilechar2UUID }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8*)& simpleProfileChar2 + }, + + // Characteristic 2 User Description + { + { ATT_BT_UUID_SIZE, charUserDescUUID }, + GATT_PERMIT_READ, + 0, + simpleProfileChar2UserDesp + }, + + // Characteristic 3 Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &simpleProfileChar3Props + }, + + // Characteristic Value 3 + { + { ATT_BT_UUID_SIZE, simpleProfilechar3UUID }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8*)& simpleProfileChar3 + }, + + // Characteristic 3 User Description + { + { ATT_BT_UUID_SIZE, charUserDescUUID }, + GATT_PERMIT_READ, + 0, + simpleProfileChar3UserDesp + }, + + // Characteristic 4 Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &simpleProfileChar4Props + }, + + // Characteristic Value 4 + { + { ATT_BT_UUID_SIZE, simpleProfilechar4UUID }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8*)& simpleProfileChar4 + }, + + // Characteristic 4 User Description + { + { ATT_BT_UUID_SIZE, charUserDescUUID }, + GATT_PERMIT_READ, + 0, + simpleProfileChar4UserDesp + }, + + // Characteristic 5 Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &simpleProfileChar5Props + }, + + // Characteristic Value 5 + { + { ATT_BT_UUID_SIZE, simpleProfilechar5UUID }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + &simpleProfileChar5 + }, + + // Characteristic 5 User Description + { + { ATT_BT_UUID_SIZE, charUserDescUUID }, + GATT_PERMIT_READ, + 0, + simpleProfileChar5UserDesp + }, + + // ---------------------------------------------------------------------- + // Characteristic 6 Declaration, NOTify + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &simpleProfileChar6Props + }, + + // Characteristic Value 6 + { + { ATT_BT_UUID_SIZE, simpleProfilechar6UUID }, + GATT_PERMIT_READ, + 0, + (uint8*)& simpleProfileChar6 + }, + + // Characteristic 6 configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8*)simpleProfileChar6Config + }, + + // Characteristic 6 User Description + { + { ATT_BT_UUID_SIZE, charUserDescUUID }, + GATT_PERMIT_READ, + 0, + simpleProfileChar6UserDesp + }, + + + +}; + + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static uint8 simpleProfile_ReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ); +static bStatus_t simpleProfile_WriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ); + +static void simpleProfile_HandleConnStatusCB( uint16 connHandle, uint8 changeType ); + + +/********************************************************************* + PROFILE CALLBACKS +*/ +// Simple Profile Service Callbacks +CONST gattServiceCBs_t simpleProfileCBs = +{ + simpleProfile_ReadAttrCB, // Read callback function pointer + simpleProfile_WriteAttrCB, // Write callback function pointer + NULL // Authorization callback function pointer +}; + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/********************************************************************* + @fn SimpleProfile_AddService + + @brief Initializes the Simple Profile service by registering + GATT attributes with the GATT server. + + @param services - services to add. This is a bit map and can + contain more than one service. + + @return Success or Failure +*/ +bStatus_t SimpleProfile_AddService( uint32 services ) +{ + uint8 status = SUCCESS; + // Initialize Client Characteristic Configuration attributes + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, simpleProfileChar6Config ); + // Register with Link DB to receive link status change callback + VOID linkDB_Register( simpleProfile_HandleConnStatusCB ); + + if ( services & SIMPLEPROFILE_SERVICE ) + { + // Register GATT attribute list and CBs with GATT Server App + status = GATTServApp_RegisterService( simpleProfileAttrTbl, + GATT_NUM_ATTRS( simpleProfileAttrTbl ), + &simpleProfileCBs ); + } + + return ( status ); +} + + +/********************************************************************* + @fn SimpleProfile_RegisterAppCBs + + @brief Registers the application callback function. Only call + this function once. + + @param callbacks - pointer to application callbacks. + + @return SUCCESS or bleAlreadyInRequestedMode +*/ +bStatus_t SimpleProfile_RegisterAppCBs( simpleProfileCBs_t* appCallbacks ) +{ + if ( appCallbacks ) + { + simpleProfile_AppCBs = appCallbacks; + return ( SUCCESS ); + } + else + { + return ( bleAlreadyInRequestedMode ); + } +} + + +/********************************************************************* + @fn SimpleProfile_SetParameter + + @brief Set a Simple Profile parameter. + + @param param - Profile parameter ID + @param len - length of data to right + @param value - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t SimpleProfile_SetParameter( uint8 param, uint8 len, void* value ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case SIMPLEPROFILE_CHAR1: + if ( len <= IBEACON_UUID_LEN ) + { + osal_memcpy(simpleProfileChar1, value, len); + } + else + { + ret = bleInvalidRange; + } + + break; + + case SIMPLEPROFILE_CHAR2: + if ( len == sizeof ( uint16 ) ) + { + simpleProfileChar2 = (*(uint8*)value) << 8 | *((uint8*)value + 1); + } + else + { + ret = bleInvalidRange; + } + + break; + + case SIMPLEPROFILE_CHAR3: + if ( len == sizeof ( uint16 ) ) + { + simpleProfileChar3 = (*(uint8*)value) << 8 | *((uint8*)value + 1); + } + else + { + ret = bleInvalidRange; + } + + break; + + case SIMPLEPROFILE_CHAR4: + if ( len == sizeof ( uint8 ) ) + { + simpleProfileChar4 = *((uint8*)value); + // See if Notification has been enabled + //GATTServApp_ProcessCharCfg( simpleProfileChar4Config, &simpleProfileChar4, FALSE, + // simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ), + // INVALID_TASK_ID ); + } + else + { + ret = bleInvalidRange; + } + + break; + + case SIMPLEPROFILE_CHAR5: + if ( len == sizeof ( uint8 ) ) + { + simpleProfileChar5 = *((uint8*)value); + } + else + { + ret = bleInvalidRange; + } + + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn SimpleProfile_GetParameter + + @brief Get a Simple Profile parameter. + + @param param - Profile parameter ID + @param value - pointer to data to put. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t SimpleProfile_GetParameter( uint8 param, void* value ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case SIMPLEPROFILE_CHAR1: + VOID osal_memcpy( value, simpleProfileChar1, IBEACON_UUID_LEN ); + break; + + case SIMPLEPROFILE_CHAR2: + *((uint16*)value) = simpleProfileChar2; + break; + + case SIMPLEPROFILE_CHAR3: + *((uint16*)value) = simpleProfileChar3; + break; + + case SIMPLEPROFILE_CHAR4: + *((uint8*)value) = simpleProfileChar4; + //*((uint16*)value) = simpleProfileChar4; + break; + + case SIMPLEPROFILE_CHAR5: + *((uint8*)value) = simpleProfileChar5; + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn simpleProfile_ReadAttrCB + + @brief Read an attribute. + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be read + @param pLen - length of data to be read + @param offset - offset of the first octet to be read + @param maxLen - maximum length of data to be read + + @return Success or Failure +*/ +static uint8 simpleProfile_ReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ) +{ + bStatus_t status = SUCCESS; + + // If attribute permissions require authorization to read, return error + if ( gattPermitAuthorRead( pAttr->permissions ) ) + { + // Insufficient authorization + return ( ATT_ERR_INSUFFICIENT_AUTHOR ); + } + + // Make sure it's not a blob operation (no attributes in the profile are long) + if ( offset > 0 ) + { + return ( ATT_ERR_ATTR_NOT_LONG ); + } + + if ( pAttr->type.len == ATT_BT_UUID_SIZE ) + { + // 16-bit UUID + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + switch ( uuid ) + { + // No need for "GATT_SERVICE_UUID" or "GATT_CLIENT_CHAR_CFG_UUID" cases; + // gattserverapp handles those reads + case SIMPLEPROFILE_CHAR1_UUID: + *pLen = IBEACON_UUID_LEN; + VOID osal_memcpy( pValue, pAttr->pValue, IBEACON_UUID_LEN ); + break; + + case SIMPLEPROFILE_CHAR2_UUID: + case SIMPLEPROFILE_CHAR3_UUID: + //case SIMPLEPROFILE_CHAR4_UUID: + *pLen = 2; + VOID osal_memcpy( pValue, pAttr->pValue, *pLen ); + break; + + case SIMPLEPROFILE_CHAR4_UUID: + case SIMPLEPROFILE_CHAR5_UUID: + *pLen = 1; + pValue[0] = *pAttr->pValue; + break; + + case SIMPLEPROFILE_CHAR6_UUID: + *pLen = sizeof(simpleProfileChar6); + VOID osal_memcpy( pValue, pAttr->pValue, *pLen ); + break; + + default: + // Should never get here! (characteristics 3 and 4 do not have read permissions) + *pLen = 0; + status = ATT_ERR_ATTR_NOT_FOUND; + break; + } + } + else + { + // 128-bit UUID + *pLen = 0; + status = ATT_ERR_INVALID_HANDLE; + } + + return ( status ); +} + +/********************************************************************* + @fn simpleProfile_WriteAttrCB + + @brief Validate attribute data prior to a write operation + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be written + @param len - length of data + @param offset - offset of the first octet to be written + + @return Success or Failure +*/ +// TODO: test this function +static bStatus_t simpleProfile_WriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ) +{ + bStatus_t status = SUCCESS; + uint8 notifyApp = 0xFF; + + // If attribute permissions require authorization to write, return error + if ( gattPermitAuthorWrite( pAttr->permissions ) ) + { + // Insufficient authorization + return ( ATT_ERR_INSUFFICIENT_AUTHOR ); + } + + if ( pAttr->type.len == ATT_BT_UUID_SIZE ) + { + // 16-bit UUID + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + switch ( uuid ) + { + case SIMPLEPROFILE_CHAR1_UUID: + + //Validate the value + // Make sure it's not a blob oper + if ( offset == 0 ) + { + if ( len != IBEACON_UUID_LEN ) + { + status = ATT_ERR_INVALID_VALUE_SIZE; + } + } + else + { + status = ATT_ERR_ATTR_NOT_LONG; + } + + //Write the value + if ( status == SUCCESS ) + { + uint8* pCurValue = (uint8*)pAttr->pValue; + VOID osal_memcpy( pCurValue, pValue, IBEACON_UUID_LEN ); + notifyApp = SIMPLEPROFILE_CHAR1; + } + + break; + + case SIMPLEPROFILE_CHAR2_UUID: + case SIMPLEPROFILE_CHAR3_UUID: + + //Validate the value + // Make sure it's not a blob oper + if ( offset == 0 ) + { + if ( len != 2 ) + { + status = ATT_ERR_INVALID_VALUE_SIZE; + } + } + else + { + status = ATT_ERR_ATTR_NOT_LONG; + } + + //Write the value + if ( status == SUCCESS ) + { + uint8* pCurValue = (uint8*)pAttr->pValue; + *pCurValue = pValue[0]; + *(pCurValue + 1 ) = pValue[1]; + + if( uuid == SIMPLEPROFILE_CHAR2_UUID) + { + notifyApp = SIMPLEPROFILE_CHAR2; + } + else + { + notifyApp = SIMPLEPROFILE_CHAR3; + } + } + + break; + + case SIMPLEPROFILE_CHAR4_UUID: + case SIMPLEPROFILE_CHAR5_UUID: + + //Validate the value + // Make sure it's not a blob oper + if ( offset == 0 ) + { + if ( len != 1 ) + { + status = ATT_ERR_INVALID_VALUE_SIZE; + } + } + else + { + status = ATT_ERR_ATTR_NOT_LONG; + } + + //Write the value + if ( status == SUCCESS ) + { + uint8* pCurValue = (uint8*)pAttr->pValue; + *pCurValue = pValue[0]; + + if( uuid == SIMPLEPROFILE_CHAR4_UUID ) + { + notifyApp = SIMPLEPROFILE_CHAR4; + } + else + { + notifyApp = SIMPLEPROFILE_CHAR5; + } + } + + break; + + case GATT_CLIENT_CHAR_CFG_UUID: + status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len, + offset, GATT_CLIENT_CFG_NOTIFY ); + break; + + default: + // Should never get here! (characteristics 2 and 4 do not have write permissions) + status = ATT_ERR_ATTR_NOT_FOUND; + break; + } + } + else + { + // 128-bit UUID + status = ATT_ERR_INVALID_HANDLE; + } + + // If a charactersitic value changed then callback function to notify application of change + if ( (notifyApp != 0xFF ) && simpleProfile_AppCBs && simpleProfile_AppCBs->pfnSimpleProfileChange ) + { + simpleProfile_AppCBs->pfnSimpleProfileChange( notifyApp ); + } + + return ( status ); +} + +/********************************************************************* + @fn simpleProfile_HandleConnStatusCB + + @brief Simple Profile link status change handler function. + + @param connHandle - connection handle + @param changeType - type of change + + @return none +*/ +static void simpleProfile_HandleConnStatusCB( uint16 connHandle, uint8 changeType ) +{ + // Make sure this is not loopback connection + if ( connHandle != LOOPBACK_CONNHANDLE ) + { + // Reset Client Char Config if connection has dropped + if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) || + ( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && + ( !linkDB_Up( connHandle ) ) ) ) + { + GATTServApp_InitCharCfg( connHandle, simpleProfileChar4Config ); + } + } +} + + +bStatus_t simpleProfile_Notify( uint8 param, uint8 len, void* value ) +{ + bStatus_t ret = SUCCESS; + uint16 notfEnable; + + switch ( param ) + { + case SIMPLEPROFILE_CHAR6: + notfEnable = GATTServApp_ReadCharCfg( 0, simpleProfileChar6Config ); + + // If notifications enabled + if ( notfEnable & GATT_CLIENT_CFG_NOTIFY ) + { + VOID osal_memcpy( simpleProfileChar6, value, len ); + ret=GATTServApp_ProcessCharCfg( simpleProfileChar6Config, simpleProfileChar6, FALSE, + simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ), + INVALID_TASK_ID ); + } + else + { + ret = bleNotReady; + } + + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + + +/********************************************************************* +*********************************************************************/ diff --git a/src/components/profiles/SimpleProfile/simpleGATTprofile_ota.h b/src/components/profiles/SimpleProfile/simpleGATTprofile_ota.h new file mode 100644 index 0000000..1f8ff26 --- /dev/null +++ b/src/components/profiles/SimpleProfile/simpleGATTprofile_ota.h @@ -0,0 +1,134 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: simpleGATTprofile.h + Revised: + Revision: + + Description: This file contains the Simple GATT profile definitions and + prototypes. + + **************************************************************************************************/ + +#ifndef SIMPLEGATTPROFILE_OTA_H +#define SIMPLEGATTPROFILE_OTA_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + CONSTANTS +*/ + +// Profile Parameters +#define SIMPLEPROFILE_CHAR1 0 // RW uint8 - Profile Characteristic 1 value +#define SIMPLEPROFILE_CHAR2 1 // RW uint8 - Profile Characteristic 2 value +#define SIMPLEPROFILE_CHAR3 2 // RW uint8 - Profile Characteristic 3 value +#define SIMPLEPROFILE_CHAR4 3 // RW uint8 - Profile Characteristic 4 value +#define SIMPLEPROFILE_CHAR5 4 // RW uint8 - Profile Characteristic 4 value +#define SIMPLEPROFILE_CHAR6 5 // RW uint8 - Profile Characteristic 4 value + +// Simple Profile Service UUID +#define SIMPLEPROFILE_SERV_UUID 0xFFF0 + +// Key Pressed UUID +#define SIMPLEPROFILE_CHAR1_UUID 0xFFF1 +#define SIMPLEPROFILE_CHAR2_UUID 0xFFF2 +#define SIMPLEPROFILE_CHAR3_UUID 0xFFF3 +#define SIMPLEPROFILE_CHAR4_UUID 0xFFF4 +#define SIMPLEPROFILE_CHAR5_UUID 0xFFF5 +#define SIMPLEPROFILE_CHAR6_UUID 0xFFF6 + +// Simple Keys Profile Services bit fields +#define SIMPLEPROFILE_SERVICE 0x00000001 + +// Length of Characteristic 5 in bytes +//#define SIMPLEPROFILE_CHAR5_LEN 5 +#define IBEACON_UUID_LEN 16 + +/********************************************************************* + TYPEDEFS +*/ + + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + Profile Callbacks +*/ + +// Callback when a characteristic value has changed +typedef void (*simpleProfileChange_t)( uint8 paramID ); + +typedef struct +{ + simpleProfileChange_t pfnSimpleProfileChange; // Called when characteristic value changes +} simpleProfileCBs_t; + + + +/********************************************************************* + API FUNCTIONS +*/ + + +/* + SimpleProfile_AddService- Initializes the Simple GATT Profile service by registering + GATT attributes with the GATT server. + + @param services - services to add. This is a bit map and can + contain more than one service. +*/ + +extern bStatus_t SimpleProfile_AddService( uint32 services ); + +/* + SimpleProfile_RegisterAppCBs - Registers the application callback function. + Only call this function once. + + appCallbacks - pointer to application callbacks. +*/ +extern bStatus_t SimpleProfile_RegisterAppCBs( simpleProfileCBs_t* appCallbacks ); + +/* + SimpleProfile_SetParameter - Set a Simple GATT Profile parameter. + + param - Profile parameter ID + len - length of data to right + value - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). +*/ +extern bStatus_t SimpleProfile_SetParameter( uint8 param, uint8 len, void* value ); + +/* + SimpleProfile_GetParameter - Get a Simple GATT Profile parameter. + + param - Profile parameter ID + value - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). +*/ +extern bStatus_t SimpleProfile_GetParameter( uint8 param, void* value ); + +extern bStatus_t simpleProfile_Notify( uint8 param, uint8 len, void* value ); +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* SIMPLEGATTPROFILE_H */ diff --git a/src/components/profiles/aliGenie/ali_genie_profile.c b/src/components/profiles/aliGenie/ali_genie_profile.c new file mode 100644 index 0000000..51c2fb7 --- /dev/null +++ b/src/components/profiles/aliGenie/ali_genie_profile.c @@ -0,0 +1,155 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/******************************************************************************* + @file ali_genie_profile.c + @brief Contains all functions support for ali genie profile + @version 1.0 + @date 28. Feb. 2019 + @author Zhongqi Yang + + + +*******************************************************************************/ +#include "sha256.h" +#include "flash.h" + +#include +#include +#include +#include "ali_genie_profile.h" + +#define ALI_GENIE_PID_LEN 4 +#define ALI_GENIE_SEC_LEN 16 + + +#define VENDOR_PRODUCT_ID_ADDR 0x4030 +#define VENDOR_PRODUCT_SECRERT_ADDR 0x4010 +#define VENDOR_PRODUCT_MAC_ADDR 0x4000 + + + + +unsigned char ali_genie_pid[4] = {0x00}; +unsigned char ali_genie_mac[6] = {0x00}; +unsigned char ali_genie_macStr[12]; + +unsigned char ali_genie_sec[16] = {0x00}; +unsigned char ali_genie_auth[16]= {0x00}; + +void hex2Str( unsigned char* pIn,unsigned char* pOut,int len,int reverse) +{ + int i; + unsigned char hex[] = "0123456789abcdef"; + + // Start from end of addr + if(reverse) + { + pIn += len; + + for ( i = len; i > 0; i-- ) + { + *pOut++ = hex[*--pIn >> 4]; + *pOut++ = hex[*pIn & 0x0F]; + } + } + else + { + for ( i = 0; i > 4]; + *pOut++ = hex[*pIn++ & 0x0F]; + } + } +} + + + +int gen_aligenie_auth_val(void) +{ + int i, buflen, ret = 0; + //unsigned char buf[]="000293e2,abcdf0f1f2f3,53daed805bc534a4a93c825ed20a7063"; + unsigned char buf[54]; +// unsigned char pidStr[8]; +// unsigned char macAddrStr[12]; +// unsigned char secStr[32]; + unsigned char sha256sum[32]; + mbedtls_sha256_context ctx; + + //load ProductID + for(i=0; i<4; i++) + hal_flash_read(VENDOR_PRODUCT_ID_ADDR+i,ali_genie_pid+i,1); + +// ali_genie_pid[i]=(uint8_t)ReadFlash(VENDOR_PRODUCT_ID_ADDR+i); + hex2Str(ali_genie_pid,buf,4,0); + printf("\n === PID === \n"); + + for(i=0; i<4; i++) + printf("%02X ",ali_genie_pid[i]); + + printf("\n"); + buf[8]=0x2c; + //load MAC + uint32 address = VENDOR_PRODUCT_MAC_ADDR; + hal_flash_read(address ++,&ali_genie_mac[3],1); + hal_flash_read(address ++,&ali_genie_mac[2],1); + hal_flash_read(address ++,&ali_genie_mac[1],1); + hal_flash_read(address ++,&ali_genie_mac[0],1); + hal_flash_read(address ++,&ali_genie_mac[5],1); + hal_flash_read(address ++,&ali_genie_mac[4],1); + printf("\n === MAC === \n"); + + for(i=0; i<6; i++) + printf("%02X ",ali_genie_mac[5-i]); + + printf("\n"); + //hex2Str(ali_genie_mac,buf+9,6,1); + hex2Str(ali_genie_mac,ali_genie_macStr,6,1); + + for(i=0; i<12; i++) + buf[9+i]=ali_genie_macStr[i]; + + buf[21]=0x2c; + + //load secert + for(i=0; i<16; i++) + hal_flash_read(VENDOR_PRODUCT_SECRERT_ADDR+i,ali_genie_sec+i,1); + +// ali_genie_sec[i]=(uint8_t)ReadFlash(VENDOR_PRODUCT_SECRERT_ADDR+i); + hex2Str(ali_genie_sec,buf+22,16,0); + mbedtls_sha256_init( &ctx ); + + if( ( ret = mbedtls_sha256_starts_ret( &ctx, 0 ) ) != 0 ) + goto fail; + + buflen = 54; + +// printf("\n input %d ",buflen); +// for(i=0;i +#include + + + + + +/******************************************************************************* + Global Var +*/ +extern unsigned char ali_genie_pid[4]; +extern unsigned char ali_genie_mac[6]; +extern unsigned char ali_genie_macStr[12]; +extern unsigned char ali_genie_sec[16]; +extern unsigned char ali_genie_auth[16]; + + +/******************************************************************************* + MACRO +*/ + +int gen_aligenie_auth_val( void ); + + +#endif diff --git a/src/components/profiles/ancs/ancs_attr.c b/src/components/profiles/ancs/ancs_attr.c new file mode 100644 index 0000000..5fe5dfe --- /dev/null +++ b/src/components/profiles/ancs/ancs_attr.c @@ -0,0 +1,619 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#include "bcomdef.h" +#include "linkdb.h" +#include "osal.h" +#include "gatt.h" +#include "gapgattserver.h" +#include "gattservapp.h" +#include "peripheral.h" +#include "gapbondmgr.h" +#include "gatt_profile_uuid.h" +#include "ble_ancs.h" +#include "ancs_attr.h" +#include "log.h" + + + + +static bool all_req_attrs_parsed(ancs_ctx_t* p_ancs) +{ + if (p_ancs->parse_info.expected_number_of_attrs == 0) + { + return TRUE; + } + + return FALSE; +} + +static bool attr_is_requested(ancs_ctx_t* p_ancs, ancs_attr_evt_t* pattr) +{ + if(p_ancs->parse_info.p_attr_list[pattr->attr_id].en == TRUE) + { + return TRUE; + } + + return FALSE; +} + + +static ancs_parse_state_t command_id_parse(ancs_ctx_t* p_ancs, const uint8_t* p_data_src, uint32_t* index) +{ + ancs_parse_state_t parse_state; + p_ancs->parse_info.command_id = (ancs_cmd_id_val_t) p_data_src[(*index)++]; + p_ancs->attr_rsp_evt.msg = (void*)(&(p_ancs->attr_evt_msg)); + + switch (p_ancs->parse_info.command_id) + { + case ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES: + p_ancs->attr_rsp_evt.type = BLE_ANCS_EVT_NOTIF_ATTRIBUTE; + p_ancs->parse_info.p_attr_list = p_ancs->notif_attr_list; + p_ancs->parse_info.nb_of_attr = ANCS_NB_OF_NOTIF_ATTR; + parse_state = NOTIF_UID; + break; + + case ANCS_COMMAND_ID_GET_APP_ATTRIBUTES: + p_ancs->attr_rsp_evt.type = BLE_ANCS_EVT_APP_ATTRIBUTE; + p_ancs->parse_info.p_attr_list = p_ancs->app_attr_list; + p_ancs->parse_info.nb_of_attr = ANCS_NB_OF_APP_ATTR; + parse_state = APP_ID; + break; + + default: + //no valid command_id, abort the rest of the parsing procedure. + LOG("Invalid Command ID"); + parse_state = DONE; + break; + } + + return parse_state; +} + + +static ancs_parse_state_t notif_uid_parse(ancs_ctx_t* p_ancs, + const uint8_t* p_data_src, + uint32_t* index) +{ + p_ancs->attr_evt_msg.notif_uid = BUILD_UINT32(p_data_src[*index],p_data_src[*index+1],p_data_src[*index+2],p_data_src[*index+3]); + *index += sizeof(uint32_t); + return ATTR_ID; +} + +static ancs_parse_state_t app_id_parse(ancs_ctx_t* p_ancs, + const uint8_t* p_data_src, + uint32_t* index) +{ + p_ancs->attr_evt_msg.app_id[p_ancs->parse_info.current_app_id_index] = p_data_src[(*index)++]; + + if(p_ancs->attr_evt_msg.app_id[p_ancs->parse_info.current_app_id_index] != '\0') + { + p_ancs->parse_info.current_app_id_index++; + return APP_ID; + } + else + { + return ATTR_ID; + } +} + +static ancs_parse_state_t attr_id_parse(ancs_ctx_t* p_ancs, + const uint8_t* p_data_src, + uint32_t* index) +{ + p_ancs->attr_evt_msg.attr_id = p_data_src[(*index)++]; + + if (p_ancs->attr_evt_msg.attr_id >= p_ancs->parse_info.nb_of_attr) + { + LOG("Attribute ID Invalid.\r\n"); + return DONE; + } + + p_ancs->attr_evt_msg.p_attr_data = p_ancs->parse_info.p_attr_list[p_ancs->attr_evt_msg.attr_id].p_attr_data; + + if (all_req_attrs_parsed(p_ancs)) + { + LOG("All requested attributes received. \r\n"); + return DONE; + } + else + { + if (attr_is_requested(p_ancs, &(p_ancs->attr_evt_msg))) + { + p_ancs->parse_info.expected_number_of_attrs--; + } + + LOG("Attribute ID %i \r\n", p_ancs->attr_evt_msg.attr_id); + return ATTR_LEN1; + } +} + + +static ancs_parse_state_t attr_len1_parse(ancs_ctx_t* p_ancs, const uint8_t* p_data_src, uint32_t* index) +{ + p_ancs->attr_evt_msg.attr_len = p_data_src[(*index)++]; + return ATTR_LEN2; +} + +static ancs_parse_state_t attr_len2_parse(ancs_ctx_t* p_ancs, const uint8_t* p_data_src, uint32_t* index) +{ + p_ancs->attr_evt_msg.attr_len |= (p_data_src[(*index)++] << 8); + p_ancs->parse_info.current_attr_index = 0; + + if (p_ancs->attr_evt_msg.attr_len != 0) + { + //If the attribute has a length but there is no allocated space for this attribute + if((p_ancs->parse_info.p_attr_list[p_ancs->attr_evt_msg.attr_id].attr_len == 0) || + (p_ancs->parse_info.p_attr_list[p_ancs->attr_evt_msg.attr_id].p_attr_data == NULL)) + { + return ATTR_SKIP; + } + else + { + return ATTR_DATA; + } + } + else + { + LOG("Attribute LEN %i \r\n", p_ancs->attr_evt_msg.attr_len); + + if(attr_is_requested(p_ancs, &(p_ancs->attr_evt_msg))) + { + p_ancs->callback(&p_ancs->attr_rsp_evt); + } + + if(all_req_attrs_parsed(p_ancs)) + { + return DONE; + } + else + { + return ATTR_ID; + } + } +} + + +static ancs_parse_state_t attr_data_parse(ancs_ctx_t* p_ancs, + const uint8_t* p_data_src, + uint32_t* index) +{ + // We have not reached the end of the attribute, nor our max allocated internal size. + // Proceed with copying data over to our buffer. + if ( (p_ancs->parse_info.current_attr_index < p_ancs->parse_info.p_attr_list[p_ancs->attr_evt_msg.attr_id].attr_len) + && (p_ancs->parse_info.current_attr_index < p_ancs->attr_evt_msg.attr_len)) + { + //LOG("Byte copied to buffer: %c\r\n", p_data_src[(*index)]); // Un-comment this line to see every byte of an attribute as it is parsed. Commented out by default since it can overflow the uart buffer. + p_ancs->attr_evt_msg.p_attr_data[p_ancs->parse_info.current_attr_index++] = p_data_src[(*index)++]; + } + + // We have reached the end of the attribute, or our max allocated internal size. + // Stop copying data over to our buffer. NUL-terminate at the current index. + if ( (p_ancs->parse_info.current_attr_index == p_ancs->attr_evt_msg.attr_len) || + (p_ancs->parse_info.current_attr_index == p_ancs->parse_info.p_attr_list[p_ancs->attr_evt_msg.attr_id].attr_len - 1)) + { + if (attr_is_requested(p_ancs, &(p_ancs->attr_evt_msg))) + { + p_ancs->attr_evt_msg.p_attr_data[p_ancs->parse_info.current_attr_index] = '\0'; + } + + // If our max buffer size is smaller than the remaining attribute data, we must + // increase index to skip the data until the start of the next attribute. + if (p_ancs->parse_info.current_attr_index < p_ancs->attr_evt_msg.attr_len) + { + return ATTR_SKIP; + } + + LOG("Attribute finished!\r\n"); + + if(attr_is_requested(p_ancs, &(p_ancs->attr_evt_msg))) + { + p_ancs->callback(&p_ancs->attr_rsp_evt); + } + + if(all_req_attrs_parsed(p_ancs)) + { + return DONE; + } + else + { + return ATTR_ID; + } + } + + return ATTR_DATA; +} + + +static ancs_parse_state_t attr_skip(ancs_ctx_t* p_ancs, const uint8_t* p_data_src, uint32_t* index) +{ + // We have not reached the end of the attribute, nor our max allocated internal size. + // Proceed with copying data over to our buffer. + if (p_ancs->parse_info.current_attr_index < p_ancs->attr_evt_msg.attr_len) + { + p_ancs->parse_info.current_attr_index++; + (*index)++; + } + + // At the end of the attribute, determine if it should be passed to event handler and + // continue parsing the next attribute ID if we are not done with all the attributes. + if (p_ancs->parse_info.current_attr_index == p_ancs->attr_evt_msg.attr_len) + { + if(attr_is_requested(p_ancs, &(p_ancs->attr_evt_msg))) + { + p_ancs->callback(&p_ancs->attr_rsp_evt); + } + + if(all_req_attrs_parsed(p_ancs)) + { + return DONE; + } + else + { + return ATTR_ID; + } + } + + return ATTR_SKIP; +} + +static void print_hex (const uint8* data, uint16 len) +{ + uint16 i; + + for (i = 0; i < len - 1; i++) + { + LOG("%x,",data[i]); + LOG(" "); + } + + LOG("%d\n",data[i]); +} + +void ancs_parse_get_attrs_response(ancs_ctx_t* p_ancs, const uint8_t* p_data_src, uint8_t hvx_data_len) +{ + uint32_t index; + LOG("ancs_parse_get_attrs_response:\n"); + print_hex(p_data_src, hvx_data_len); + + for (index = 0; index < hvx_data_len;) + { + switch (p_ancs->parse_info.parse_state) + { + case COMMAND_ID: + p_ancs->parse_info.parse_state = command_id_parse(p_ancs, p_data_src, &index); + break; + + case NOTIF_UID: + p_ancs->parse_info.parse_state = notif_uid_parse(p_ancs, p_data_src, &index); + break; + + case APP_ID: + p_ancs->parse_info.parse_state = app_id_parse(p_ancs, p_data_src, &index); + break; + + case ATTR_ID: + p_ancs->parse_info.parse_state = attr_id_parse(p_ancs, p_data_src, &index); + break; + + case ATTR_LEN1: + p_ancs->parse_info.parse_state = attr_len1_parse(p_ancs, p_data_src, &index); + break; + + case ATTR_LEN2: + p_ancs->parse_info.parse_state = attr_len2_parse(p_ancs, p_data_src, &index); + break; + + case ATTR_DATA: + p_ancs->parse_info.parse_state = attr_data_parse(p_ancs, p_data_src, &index); + break; + + case ATTR_SKIP: + p_ancs->parse_info.parse_state = attr_skip(p_ancs, p_data_src, &index); + break; + + case DONE: + LOG("Parse state: Done %s\r\n", p_ancs->attr_evt_msg.p_attr_data); + index = hvx_data_len; + break; + + default: + // Default case will never trigger intentionally. Go to the DONE state to minimize the consequences. + p_ancs->parse_info.parse_state = DONE; + break; + } + } +} + + + + + + +static bool app_attr_is_requested(ancs_ctx_t* p_ancs, uint32_t attr_id) +{ + if(p_ancs->app_attr_list[attr_id].en == TRUE) + { + return TRUE; + } + + return false; +} + + +static uint32_t app_attr_nb_to_get(ancs_ctx_t* p_ancs) +{ + uint32_t attr_nb_to_get = 0; + + for(uint32_t i = 0; i < (sizeof(p_ancs->app_attr_list)/sizeof(ancs_attr_list_t)); i++) + { + if(app_attr_is_requested(p_ancs,i)) + { + attr_nb_to_get++; + } + } + + return attr_nb_to_get; +} + + + +static encode_app_attr_t app_attr_encode_cmd_id(ancs_ctx_t* p_ancs, + uint32_t* index, + uint8_t* tx_buf) +{ + LOG("Encoding Command ID\r\n"); + // Encode Command ID. + tx_buf[(*index)++] = ANCS_COMMAND_ID_GET_APP_ATTRIBUTES; + return APP_ATTR_APP_ID; +} + + +static encode_app_attr_t app_attr_encode_app_id(ancs_ctx_t* p_ancs, + uint32_t* p_index, + uint16_t* p_offset, + uint8_t* tx_buf, + const uint8_t* p_app_id, + const uint32_t app_id_len, + uint32_t* p_app_id_bytes_encoded_count) +{ + LOG("Encoding APP ID\r\n"); + + //Encode App Identifier. + if(*p_app_id_bytes_encoded_count == app_id_len) + { + tx_buf[(*p_index)++] = '\0'; + (*p_app_id_bytes_encoded_count)++; + } + + LOG("%c\r\n", p_app_id[(*p_app_id_bytes_encoded_count)]); + + if(*p_app_id_bytes_encoded_count < app_id_len) + { + tx_buf[(*p_index)++] = p_app_id[(*p_app_id_bytes_encoded_count)++]; + } + + if(*p_app_id_bytes_encoded_count > app_id_len) + { + return APP_ATTR_ATTR_ID; + } + + return APP_ATTR_APP_ID; +} + + +static encode_app_attr_t app_attr_encode_attr_id(ancs_ctx_t* p_ancs, + uint32_t* p_index, + uint16_t* p_offset, + uint8_t* tx_buf, + uint32_t* p_attr_count, + uint32_t* attr_get_total_nb) +{ + LOG("Encoding Attribute ID\r\n"); + + //Encode Attribute ID. + if (*p_attr_count < ANCS_NB_OF_APP_ATTR) + { + if (app_attr_is_requested(p_ancs, *p_attr_count)) + { + tx_buf[(*p_index)] = *p_attr_count; + (*p_index)++; + LOG("offset %i\r\n", *p_offset); + } + + (*p_attr_count)++; + } + + if (*p_attr_count == ANCS_NB_OF_APP_ATTR) + { + return APP_ATTR_DONE; + } + + return APP_ATTR_APP_ID; +} + + + +bStatus_t app_attrs_get(ancs_ctx_t* p_ancs, const uint8_t* p_app_id, uint8_t app_id_len) +{ + ancs_service_t* pservice = &(p_ancs->ancs_service); + uint32_t index = 0; + uint32_t attr_bytes_encoded_count = 0; + uint16_t offset = 0; + uint32_t app_id_bytes_encoded_count = 0; + encode_app_attr_t state = APP_ATTR_COMMAND_ID; + bStatus_t status; + p_ancs->parse_info.parse_state = COMMAND_ID; + uint32_t attr_get_total_nb = app_attr_nb_to_get(p_ancs); + uint8_t* tx_buf = p_ancs->app_attr_tx_buf; + + if(app_id_len == 0) + { + return INVALIDPARAMETER; + } + + if(p_app_id[app_id_len] != '\0') // App id to be requestes must be NULL terminated + { + return INVALIDPARAMETER; + } + + osal_memset(tx_buf, 0, sizeof(ANCS_APP_ATTR_TX_SIZE)); + + while(state != APP_ATTR_DONE) + { + switch(state) + { + case APP_ATTR_COMMAND_ID: + state = app_attr_encode_cmd_id(p_ancs, + &index, + tx_buf); + break; + + case APP_ATTR_APP_ID: + state = app_attr_encode_app_id(p_ancs, + &index, + &offset, + tx_buf, + p_app_id, + app_id_len, + &app_id_bytes_encoded_count); + break; + + case APP_ATTR_ATTR_ID: + state = app_attr_encode_attr_id(p_ancs, + &index, + &offset, + tx_buf, + &attr_bytes_encoded_count, + &attr_get_total_nb); + break; + + case APP_ATTR_DONE: + break; + + default: + break; + } + } + + p_ancs->parse_info.expected_number_of_attrs = ANCS_NB_OF_APP_ATTR; + + if(index > 20) + { + gattPrepareWriteReq_t lreq; + lreq.pValue = osal_mem_alloc(index); + osal_memcpy(lreq.pValue, tx_buf, index); + lreq.handle = pservice->chars_hdl[ANCS_CTRL_POINT_HDL_START]; + lreq.len = index; + status = GATT_WriteLongCharValue(pservice->conn_hdl, &lreq, p_ancs->app_task_ID); + + if (status != SUCCESS) + { + // If it fails free the message. + LOG("CP WRITE ERROR:\t%d\n",status); + osal_mem_free(lreq.pValue); + } + } + else + { + attWriteReq_t req; + osal_memcpy(req.value, tx_buf, index); + req.sig = 0; + req.cmd = 0; + req.handle = pservice->chars_hdl[ANCS_CTRL_POINT_HDL_START]; + req.len = index; + status = GATT_WriteCharValue(pservice->conn_hdl, &req, p_ancs->app_task_ID); + + if (status != SUCCESS) + { + // If it fails free the message. + LOG("CP WRITE ERROR:\t%d\n",status); + } + } + + return SUCCESS; +} + + + +bStatus_t notif_attrs_get(ancs_ctx_t* p_ancs,const uint8_t* pNotificationUID) +{ + ancs_service_t* pservice = &(p_ancs->ancs_service); + ancs_attr_list_t* pattrlist = p_ancs->notif_attr_list; + bStatus_t status; + uint8_t* tx_buf = p_ancs->app_attr_tx_buf; + uint8_t number_of_requested_attr = 0; + p_ancs->parse_info.parse_state = COMMAND_ID; + osal_memset(tx_buf, 0, sizeof(ANCS_APP_ATTR_TX_SIZE)); + uint32_t index = 0; + //Encode Command ID. + tx_buf[index++] = ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES; + //Encode Notification UID. + tx_buf[index++] = pNotificationUID[0]; + tx_buf[index++] = pNotificationUID[1]; + tx_buf[index++] = pNotificationUID[2]; + tx_buf[index++] = pNotificationUID[3]; + + //Encode Attribute ID. + for (uint32_t attr = 0; attr < ANCS_NB_OF_NOTIF_ATTR; attr++) + { + if (pattrlist[attr].en == TRUE) + { + tx_buf[index++] = attr; + + if ((attr == BLE_ANCS_NOTIF_ATTR_ID_TITLE) || + (attr == BLE_ANCS_NOTIF_ATTR_ID_SUBTITLE) || + (attr == BLE_ANCS_NOTIF_ATTR_ID_MESSAGE)) + { + //Encode Length field, only applicable for Title, Subtitle and Message + tx_buf[index++] = (uint8_t)(pattrlist[attr].attr_len & 0xff); + tx_buf[index++] = (uint8_t)((pattrlist[attr].attr_len >> 8)&0xff); + } + + number_of_requested_attr++; + } + } + + LOG("notif_attrs_get:\n"); + print_hex(tx_buf, index); + p_ancs->parse_info.expected_number_of_attrs = number_of_requested_attr; + + if(index > 20) + { + gattPrepareWriteReq_t lreq; + lreq.pValue = osal_mem_alloc(index); + osal_memcpy(lreq.pValue, tx_buf, index); + lreq.handle = pservice->chars_hdl[ANCS_CTRL_POINT_HDL_START]; + lreq.len = index; + status = GATT_WriteLongCharValue(pservice->conn_hdl, &lreq, p_ancs->app_task_ID); + + if (status != SUCCESS) + { + // If it fails free the message. + LOG("CP WRITE ERROR:\t%d\n",status); + osal_mem_free(lreq.pValue); + } + } + else + { + attWriteReq_t req; + osal_memcpy(req.value, tx_buf, index); + req.sig = 0; + req.cmd = 0; + req.handle = pservice->chars_hdl[ANCS_CTRL_POINT_HDL_START]; + req.len = index; + status = GATT_WriteCharValue(pservice->conn_hdl, &req, p_ancs->app_task_ID); + + if (status != SUCCESS) + { + // If it fails free the message. + LOG("CP WRITE ERROR:\t%d\n",status); + } + } + + return SUCCESS; +} + + diff --git a/src/components/profiles/ancs/ancs_attr.h b/src/components/profiles/ancs/ancs_attr.h new file mode 100644 index 0000000..333c038 --- /dev/null +++ b/src/components/profiles/ancs/ancs_attr.h @@ -0,0 +1,30 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#ifndef __ANCS_ATTR_H +#define __ANCS_ATTR_H + +#include "ble_ancs.h" + +#define GATTC_OPCODE_SIZE 1 /**< Size of the GATTC OPCODE. */ +#define GATTC_ATTR_HANDLE_SIZE 4 /**< Size of the Attribute handle Size. */ + + +#define ANCS_GATTC_WRITE_PAYLOAD_LEN_MAX (23 - GATTC_OPCODE_SIZE - GATTC_ATTR_HANDLE_SIZE) /**< Maximum Length of the data we can send in one write. */ + +typedef enum +{ + APP_ATTR_COMMAND_ID, /**< Currently encoding the Command ID. */ + APP_ATTR_APP_ID, /**< Currently encoding the App ID. */ + APP_ATTR_ATTR_ID, /**< Currently encoding the Attribute ID. */ + APP_ATTR_DONE /**< Encoding done. */ +} encode_app_attr_t; + +extern void ancs_parse_get_attrs_response(ancs_ctx_t* p_ancs, const uint8_t* p_data_src, uint8_t hvx_data_len); +extern bStatus_t app_attrs_get(ancs_ctx_t* p_ancs, const uint8_t* p_app_id, uint8_t app_id_len); +extern bStatus_t notif_attrs_get(ancs_ctx_t* p_ancs,const uint8_t* pNotificationUID); + +#endif //__ANCS_ATTR_H + diff --git a/src/components/profiles/ancs/ble_ancs.c b/src/components/profiles/ancs/ble_ancs.c new file mode 100644 index 0000000..43fff95 --- /dev/null +++ b/src/components/profiles/ancs/ble_ancs.c @@ -0,0 +1,727 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#include "bcomdef.h" +#include "linkdb.h" +#include "types.h" +#include "gatt.h" +#include "gapgattserver.h" +#include "gattservapp.h" +#include "gatt_uuid.h" +#include "peripheral.h" +#include "gapbondmgr.h" +#include "gatt_profile_uuid.h" +#include "ble_ancs.h" +#include "ancs_attr.h" +#include "log.h" + + +static uint8_t Ancs_CCCDConfig(uint16_t attrHdl, uint8_t isEnable); + +static ancs_ctx_t s_ancs_ctx; + +bStatus_t ble_ancs_attr_add(const ancs_notif_attr_id id, uint8_t* p_data, const uint16_t len) +{ + ancs_attr_list_t* p_ancs_notif_attr_list = s_ancs_ctx.notif_attr_list; + + if(!p_data) + return INVALIDPARAMETER; + + if((len == 0) || (len > ANCS_ATTR_DATA_MAX)) + { + return INVALID_MEM_SIZE; + } + + p_ancs_notif_attr_list[id].en = true; + p_ancs_notif_attr_list[id].attr_len = len; + p_ancs_notif_attr_list[id].p_attr_data = p_data; + return SUCCESS; +} + +static uint8_t figure_out_chars_end_hdl(void) +{ + uint8_t errorcode = 0; + ancs_ctx_t* pctx = &s_ancs_ctx; + ancs_service_t* pservie = &(s_ancs_ctx.ancs_service); + uint16_t* p_chars_hdl = pservie->chars_hdl; + uint16_t ntf, cp, dt; + ntf = p_chars_hdl[ANCS_NOTIF_SCR_HDL_START]; + cp = p_chars_hdl[ANCS_CTRL_POINT_HDL_START]; + dt = p_chars_hdl[ANCS_DATA_SRC_HDL_START]; + + if(ntf < ((cp < dt) ? cp :dt)) + p_chars_hdl[ANCS_NOTIF_SCR_HDL_END] = cp > dt ? dt : cp; + else if(ntf < ((cp < dt) ? dt :cp)) + p_chars_hdl[ANCS_NOTIF_SCR_HDL_END] = cp > dt ? cp : dt; + else + p_chars_hdl[ANCS_NOTIF_SCR_HDL_END] = pservie->service_hdl[1]; + + if(cp < ((ntf < dt) ? ntf:dt)) + p_chars_hdl[ANCS_CTRL_POINT_HDL_END] = ntf > dt ? dt : ntf; + else if(cp < ((ntf < dt) ? dt :ntf)) + p_chars_hdl[ANCS_CTRL_POINT_HDL_END] = ntf > dt ? ntf : dt; + else + p_chars_hdl[ANCS_CTRL_POINT_HDL_END] = pservie->service_hdl[1]; + + if(dt < ((ntf < cp) ? ntf :cp)) + p_chars_hdl[ANCS_DATA_SRC_HDL_END] = ntf > cp ? cp : ntf; + else if(dt < ((ntf < cp) ? cp :ntf)) + p_chars_hdl[ANCS_DATA_SRC_HDL_END] = ntf > cp ? ntf : cp; + else + p_chars_hdl[ANCS_DATA_SRC_HDL_END] = pservie->service_hdl[1]; + + // Sanity check to ensure that each start handle is valid and + // less than each respective end handle. + if(p_chars_hdl[ANCS_NOTIF_SCR_HDL_START] != 0 && + p_chars_hdl[ANCS_CTRL_POINT_HDL_START] != 0 && + p_chars_hdl[ANCS_DATA_SRC_HDL_START] != 0) + { + if(p_chars_hdl[ANCS_NOTIF_SCR_HDL_START] < p_chars_hdl[ANCS_NOTIF_SCR_HDL_END] && + p_chars_hdl[ANCS_CTRL_POINT_HDL_START] < p_chars_hdl[ANCS_CTRL_POINT_HDL_END] && + p_chars_hdl[ANCS_DATA_SRC_HDL_START] < p_chars_hdl[ANCS_DATA_SRC_HDL_END]) + { + LOG("All chars discoveried\n"); + } + else + { + LOG("ANCS_STORE_CHARS_HANDLES FAILURE\n"); + pctx->disc_state = ANCS_DISC_FAILED; + errorcode = 4; + } + } + // Throw an error if the handles are invalid. + else + { + LOG("ANCS_STORE_CHARS_HANDLES FAILURE\n"); + pctx->disc_state = ANCS_DISC_FAILED; + errorcode = 5; + } + + return errorcode; +} + + +static bStatus_t ble_disc_service(gattMsgEvent_t* pMsg) +{ + ancs_ctx_t* pctx = &s_ancs_ctx; + ancs_service_t* pservie = &(pctx->ancs_service); + // Stores the error code, should the discovery process fail at any state. + uint8_t errorcode = 0; + + //if(pMsg){ + // LOG("ble_disc_service->pMsg->method: 0x%x\n",pMsg->method); + //} + // Enter the state machine. + switch (pctx->disc_state) + { + case ANCS_UNINIT: + LOG("Discovery Progress:\t1\n"); + return FAILURE; + + // Perform a GATT Discover Primary Service By Service UUID to located the ANCS + // handles. + case ANCS_DISC_SERVICE: + { + LOG("Discovery Progress:\t2\n"); + LOG("Discovery State:\tDiscover the ANCS\n"); + // Initialize the ANCS handles to zero. + pservie->service_hdl[0] = 0; + pservie->service_hdl[1] = 0; + // Store the ANCS UUID for GATT request. + uint8_t uuid[ATT_UUID_SIZE] = {ANCSAPP_ANCS_SVC_UUID}; + // Discover the ANCS by UUID. + bStatus_t ret = GATT_DiscPrimaryServiceByUUID(pservie->conn_hdl, uuid, ATT_UUID_SIZE, pctx->app_task_ID); + + // If successfully discovered proceed, throw error if not. + if(ret == SUCCESS) + { + pctx->disc_state = ANCS_STORE_SERVICE_HANDLES; + pservie->expect_type_value_num = 0; + //ancsAppState = ANCS_STATE_READY; + } + else + { + LOG("ANCS_DISC_SERVICE FAILURE, Error code:\t%d\n", ret); + pctx->disc_state = ANCS_DISC_FAILED; + errorcode = 1; + } + } + break; + + // Store the ANCS handles requested in the previous state. + case ANCS_STORE_SERVICE_HANDLES: + { + LOG("Discovery Progress:\t3\n"); + LOG("Discovery State:\tStore the ANCS handles %d\n",pMsg->method); + + // Did the application receive a response from the GATT Disc Primary Service? + if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP ) + { + LOG("found :%d\n",pMsg->msg.findByTypeValueRsp.numInfo); + + // Check if the ANCS was found. + if (pMsg->msg.findByTypeValueRsp.numInfo > 0) + { + // Found the ANCS, so store the handles and proceed. + pservie->service_hdl[0] = pMsg->msg.findByTypeValueRsp.handlesInfo[0].handle; + pservie->service_hdl[1] = pMsg->msg.findByTypeValueRsp.handlesInfo[0].grpEndHandle; + pctx->disc_state = ANCS_DISC_CHARS; + //for(i = 0; i< pMsg->msg.findByTypeValueRsp.numInfo; i++){ + // pservie->service_hdl[pservie->expect_type_value_num] = pMsg->msg.findByTypeValueRsp.handlesInfo[i].handle; + // pservie->expect_type_value_num ++; + // if(pservie->expect_type_value_num == 2){ + // pctx->disc_state = ANCS_DISC_CHARS; + // break; + // } + //} + } + else + { + // The ANCS was not found. + LOG("ANCS_STORE_SERVICE_HANDLES FAILURE\n"); + pctx->disc_state = ANCS_DISC_FAILED; + errorcode = 2; + } + } + else + { + LOG("ble_disc_service->pMsg->method: 0x%x\n",pMsg->method); + LOG("ANCS_STORE_SERVICE_HANDLES FAILURE\n"); + pctx->disc_state = ANCS_DISC_FAILED; + errorcode = 2; + } + } + break; + + // Use the ANCS handles to discovery the ANCS's characteristics' handles. + case ANCS_DISC_CHARS: + { + LOG("Discovery Progress:\t4\n"); + LOG("Discovery State:\tDiscover the ANCS characteristics\n"); + + // Check if service handle discovery event has completed. + if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP ) + { + LOG("ble_disc_service->pMsg->method: 0x%x\n",pMsg->method); + + if(pMsg->hdr.status == bleProcedureComplete) + { + // Sanity check to make sure the handle is valid before proceeding. + if (pservie->service_hdl[0] != 0 && pservie->service_hdl[1] != 0 ) + { + // Discover all characteristics of the ANCS. + bStatus_t ret = GATT_DiscAllChars( + pservie->conn_hdl, + pservie->service_hdl[0], + pservie->service_hdl[1], + pctx->app_task_ID); + pservie->chars_disc_num = 0; + + // If the request was successfully sent, proceed with the discovery process. + if (ret == SUCCESS) + { + pctx->disc_state = ANCS_STORE_CHARS_HANDLES; + } + // If not, throw an error. + else + { + LOG("ANCS_DISC_CHARS FAILURE, Error code:\t%d\n",ret); + pctx->disc_state = ANCS_DISC_FAILED; + errorcode = 3; + } + } + } + } + else + { + LOG("ble_disc_service->pMsg->method: 0x%x\n",pMsg->method); + } + } + break; + + // Store the retrieved ANCS characteristic handles. + case ANCS_STORE_CHARS_HANDLES: + { + LOG("Discovery Progress:\t5\n"); + LOG("Discovery State:\tStore the ANCS characteristics' handles\n"); + + // Wait until GATT "Read by type response" is received, then confirm that the correct number of + // pairs are present, and that their length is correct + if (pMsg->method == ATT_READ_BY_TYPE_RSP ) + { + //if ( (pMsg->msg.readByTypeRsp.numPairs == NUMBER_OF_ANCS_CHARS) && (pMsg->msg.readByTypeRsp.len == CHAR_DESC_HDL_UUID128_LEN) ) + if ((pMsg->msg.readByTypeRsp.len == CHAR_DESC_HDL_UUID128_LEN) ) + { + // Pointer to the pair list data in the GATT response. + uint8_t* pCharPairList; + // Will store the start and end handles of the current pair. + uint16_t charStartHandle; + // Stores to the UUID of the current pair. + uint16_t charUuid; + // Stores what pair the loop is currently processing. + uint8_t currentCharIndex; + // Set the pair pointer to the first pair. + pCharPairList = pMsg->msg.readByTypeRsp.dataList; + + // Iterate through all three pairs found. + for(currentCharIndex = 0; currentCharIndex < pMsg->msg.readByTypeRsp.numPairs ; currentCharIndex++) + { + uint16_t* p_chars_hdl = pservie->chars_hdl; + // Extract the starting handle, ending handle, and UUID of the current characteristic. + charStartHandle = BUILD_UINT16(pCharPairList[3], pCharPairList[4]); + charUuid = BUILD_UINT16(pCharPairList[5], pCharPairList[6]); + LOG("Chars found handle is is %d, uuid is %x\n", charStartHandle, charUuid); + + // Store the start and end handles in the handle cache corresponding to + // their UUID. + switch (charUuid) + { + // If it's the Notification Source. + case ANCSAPP_NOTIF_SRC_CHAR_UUID: + p_chars_hdl[ANCS_NOTIF_SCR_HDL_START] = charStartHandle; + p_chars_hdl[ANCS_NOTIF_SCR_HDL_END] = 0; + break; + + // If it's the Control Point. + case ANCSAPP_CTRL_PT_CHAR_UUID: + p_chars_hdl[ANCS_CTRL_POINT_HDL_START] = charStartHandle; + p_chars_hdl[ANCS_CTRL_POINT_HDL_END] = 0; + break; + + // If it's the Data Source. + case ANCSAPP_DATA_SRC_CHAR_UUID: + p_chars_hdl[ANCS_DATA_SRC_HDL_START] = charStartHandle; + p_chars_hdl[ANCS_DATA_SRC_HDL_END] = 0; + break; + + default: + break; + } + + pservie->chars_disc_num ++; + + // If this is the final characteristic found in the response, + // reset its end handle to the ANCS's end handle. This is because + // there is no next staring handle to use as a reference and subtract one + // from, so instead the ending handle of the ANCS must be used. + if(pservie->chars_disc_num == NUMBER_OF_ANCS_CHARS) + { + errorcode = figure_out_chars_end_hdl(); + pctx->disc_state = (errorcode == 0) ? ANCS_DISC_NS_DESCS : ANCS_DISC_FAILED; + } + + // Increment the pair pointer to the next pair. + pCharPairList += CHAR_DESC_HDL_UUID128_LEN; + } + } + // Throw an error if the length or number of pairs is incorrect. + else + { + LOG("ANCS_STORE_CHARS_HANDLES FAILURE\n"); + pctx->disc_state = ANCS_DISC_FAILED; + errorcode = 6; + } + } + else + { + LOG("ble_disc_service->pMsg->method: 0x%x\n",pMsg->method); + + if(pMsg->method == ATT_ERROR_RSP) + { + attErrorRsp_t* perr = &(pMsg->msg.errorRsp); + LOG("ATT_ERROR_RSP 0x%x, 0x%x, 0x%x\n", perr->errCode, perr->handle, perr->reqOpcode); + } + } + } + break; + + // Discover the Notification Source's descriptors (namely, the CCCD) using the start + // and end handle stored in the handle cache. + case ANCS_DISC_NS_DESCS: + { + LOG("Discovery Progress:\t6\n"); + LOG("Discovery State:\tDiscover the Notification Source's CCCD\n"); + + // Wait until the characteristic handle discovery has finished. + if ( (pMsg->method == ATT_READ_BY_TYPE_RSP) && (pMsg->hdr.status == bleProcedureComplete) ) + { + // Discover the ANCS Notification Source descriptors. + bStatus_t ret = GATT_DiscAllCharDescs(pservie->conn_hdl, + pservie->chars_hdl[ANCS_NOTIF_SCR_HDL_START], + pservie->chars_hdl[ANCS_NOTIF_SCR_HDL_END]-1, + pctx->app_task_ID); + + // If the discovery was successful, proceed. + if ( ret == SUCCESS ) + pctx->disc_state = ANCS_STORE_NS_DESCS_HANDLES; + // If not, throw an error and invalidate the CCCD handle in the handle cache. + else + { + LOG("ANCS_DISC_NS_DESCS FAILURE\n"); + pservie->chars_hdl[ANCS_NOTIF_SCR_HDL_START] = 0; + pctx->disc_state = ANCS_DISC_FAILED; + errorcode = 7; + } + } + } + break; + + // Store the retrieved Notification Source descriptors (namely, the CCCD). + case ANCS_STORE_NS_DESCS_HANDLES: + { + LOG("Discovery Progress:\t7\n"); + LOG("Discovery State:\tStore the Notification Source's CCCD handle\n"); + + // Wait for the discovery response. + if (pMsg->method == ATT_FIND_INFO_RSP ) + { + // Sanity check to validate that at least one descriptors pair was found, + // and that the pair length is correct. + if ( (pMsg->msg.findInfoRsp.numInfo > 0) && + (pMsg->msg.findInfoRsp.format == ATT_HANDLE_BT_UUID_TYPE) ) + { + // This will keep track of the current pair being processed. + uint8_t currentPair; + + // Iterate through the pair list. + for(currentPair = 0; currentPair < pMsg->msg.findInfoRsp.numInfo; currentPair++) + { + // Check if the pair is a CCCD. + uint16_t uuid = BUILD_UINT16(pMsg->msg.findInfoRsp.info.btPair[currentPair].uuid[0], pMsg->msg.findInfoRsp.info.btPair[currentPair].uuid[1]); + + if (uuid == GATT_CLIENT_CHAR_CFG_UUID) + { + // If so, store the handle in the handle cache, and proceed. + pservie->chars_hdl[ANCS_NOTIF_SCR_HDL_CCCD] = pMsg->msg.findInfoRsp.info.btPair[currentPair].handle; + pctx->disc_state = ANCS_DISC_DS_DESCS; + } + } + } + } + } + break; + + // Discover the Data Source's descriptors (namely, the CCCD) using the start + // and end handle stored in the handle cache. + case ANCS_DISC_DS_DESCS: + { + LOG("Discovery Progress:\t8\n"); + LOG("Discovery State:\tDiscover the Data Source's CCCD\n"); + + // Wait until the Notification Source descriptors discovery has finished. + if ( (pMsg->method == ATT_FIND_INFO_RSP) && (pMsg->hdr.status == bleProcedureComplete) ) + { + // Discover ANCS Notification Source CCCD + uint8_t discCheck = GATT_DiscAllCharDescs(pservie->conn_hdl, + pservie->chars_hdl[ANCS_DATA_SRC_HDL_START] + 1, + pservie->chars_hdl[ANCS_DATA_SRC_HDL_END], + pctx->app_task_ID); + + // If the discovery was successful, proceed. + if (discCheck == SUCCESS ) + pctx->disc_state = ANCS_STORE_DS_DESCS_HANDLES; + // If not, throw an error and invalidate the CCCD handle in the handle cache. + else + { + LOG("ANCS_DISC_DS_DESCS FAILURE\n"); + pservie->chars_hdl[ANCS_DATA_SRC_HDL_CCCD] = 0; + pctx->disc_state = ANCS_DISC_FAILED; + errorcode = 8; + } + } + } + break; + + // Discover the Data Source's descriptors (namely, the CCCD) using the start + // and end handle stored in the handle cache. + case ANCS_STORE_DS_DESCS_HANDLES: + { + LOG("Discovery Progress:\t9\n"); + LOG("Discovery State:\tStore the Data Source's CCCD handle\n"); + + // Wait for the discovery response. + if (pMsg->method == ATT_FIND_INFO_RSP ) + { + bool flg = FALSE; + + // Sanity check to validate that at least one descriptors pair was found, + // and that the pair length is correct. + if ( (pMsg->msg.findInfoRsp.numInfo > 0) && (pMsg->msg.findInfoRsp.format == ATT_HANDLE_BT_UUID_TYPE) ) + { + // This will keep track of the current pair being processed. + uint8_t currentPair; + + // Iterate through the pair list. + for(currentPair = 0; currentPair < pMsg->msg.findInfoRsp.numInfo; currentPair++) + { + // Check if the pair is a CCCD. + uint16_t uuid = BUILD_UINT16(pMsg->msg.findInfoRsp.info.btPair[currentPair].uuid[0], pMsg->msg.findInfoRsp.info.btPair[currentPair].uuid[1]); + + if (uuid == GATT_CLIENT_CHAR_CFG_UUID) + { + // If so, store the handle in the handle cache, and proceed to the subscription process. + pservie->chars_hdl[ANCS_DATA_SRC_HDL_CCCD] = pMsg->msg.findInfoRsp.info.btPair[currentPair].handle; + flg = TRUE; + } + } + + if(flg == FALSE) + { + LOG("ANCS_STORE_DS_DESCS_HANDLES FAILURE\n"); + pservie->chars_hdl[ANCS_DATA_SRC_HDL_CCCD] = 0; + pctx->disc_state = ANCS_DISC_FAILED; + errorcode = 9; + } + else + { + pctx->disc_state = ANCS_ENABLE_NS_CCCD; + } + } + } + } + break; + + case ANCS_ENABLE_NS_CCCD: + { + bStatus_t ret; + + if (pMsg->method == ATT_FIND_INFO_RSP && (pMsg->hdr.status == bleProcedureComplete)) + { + ret = Ancs_CCCDConfig(pservie->chars_hdl[ANCS_NOTIF_SCR_HDL_CCCD], TRUE); + + if(ret != SUCCESS) + { + LOG("ANCS_DATA_SRC_HDL_CCCD FAILURE\n"); + pservie->chars_hdl[ANCS_DATA_SRC_HDL_CCCD] = 0; + pctx->disc_state = ANCS_DISC_FAILED; + errorcode = 10; + break; + } + + pctx->disc_state = ANCS_ENABLE_DS_CCCD; + } + } + + case ANCS_ENABLE_DS_CCCD: + { + bStatus_t ret; + + if (pMsg->method == ATT_WRITE_RSP ) + { + ret = Ancs_CCCDConfig(pservie->chars_hdl[ANCS_DATA_SRC_HDL_CCCD], TRUE); + + if(ret != SUCCESS) + { + LOG("ANCS_DATA_SRC_HDL_CCCD FAILURE\n"); + pservie->chars_hdl[ANCS_DATA_SRC_HDL_CCCD] = 0; + pctx->disc_state = ANCS_DISC_FAILED; + errorcode = 10; + break; + } + + pctx->disc_state = ANCS_DISC_FINISH; + pctx->app_state = ANCS_STATE_READY; + //pctx->disc_state = ANCS_WAIT_CCCD_READY; + } + } + break; + + case ANCS_WAIT_CCCD_READY: + if (pMsg->method == ATT_WRITE_RSP ) + { + pctx->disc_state = ANCS_DISC_FINISH; + pctx->app_state = ANCS_STATE_READY; + LOG("Discovery Progress:\t12\n"); + LOG("Discovery State:\tProcessing notification data\n"); + break; + } + + default: + { + pctx->disc_state = ANCS_DISC_FAILED; + errorcode = 11; + } + break; + } + + if(errorcode != 0) + { + LOG("Discovery State:\tDiscovery Error: %d\n",errorcode); + } + + return errorcode; +} + +static uint8_t Ancs_CCCDConfig(uint16_t attrHdl, uint8_t isEnable) +{ + ancs_ctx_t* pctx = &s_ancs_ctx; + // Declare return variable status. + uint8_t status; + // Stores the GATT write request parameters. + attWriteReq_t req; + LOG("Ancs_CCCDConfig handle %d\n", attrHdl); + // Else, prepare the request. + // Set the data length to 2 ("01" = 2 bytes). + req.len = 2; + + // If we are enabling notifications, set the write data to "01". + if (isEnable == TRUE) + { + req.value[0] = LO_UINT16(GATT_CLIENT_CFG_NOTIFY); + req.value[1] = HI_UINT16(GATT_CLIENT_CFG_NOTIFY); + } + // Else, disable notifications, thus set the write data to "00". + else + { + req.value[0] = 0x00; + req.value[1] = 0x00; + } + + // Signature and command must be set to zero. + req.sig = 0; + req.cmd = 0; + // Set the handle to the passed value (either the Notification Source's CCCD handle + // or the Data Source's CCCD handle). + req.handle = attrHdl; + // Send write request. If it fails, free the memory allocated and + // return a failure. + status = GATT_WriteCharValue(pctx->ancs_service.conn_hdl, &req, pctx->app_task_ID); + + if ( status != SUCCESS) + { + LOG("Ancs_CCCDConfig %d\n", status); + } + + return status; +} + +bStatus_t ble_ancs_start_descovery(uint16_t conn_handle) +{ + ancs_ctx_t* pctx = &s_ancs_ctx; + ancs_service_t* pservie = &(pctx->ancs_service); + pservie->conn_hdl = conn_handle; + pctx->disc_state = ANCS_DISC_SERVICE; + pctx->app_state = ANCS_STATE_DISCOVERY; + ble_disc_service(NULL); + return SUCCESS; +} +static void ble_ancs_process_ds_notify(gattMsgEvent_t* pMsg) +{ + ancs_ctx_t* pctx = &s_ancs_ctx; + ancs_parse_get_attrs_response(pctx, (const uint8_t*)pMsg->msg.handleValueNoti.value, pMsg->msg.handleValueNoti.len); + return; +} + + + +void ble_ancs_process_ns_notify(gattMsgEvent_t* pMsg) +{ + ancs_ctx_t* pctx = &s_ancs_ctx; + ancs_evt_t evt; + ancs_notify_evt_t notify_msg; + uint8_t len = pMsg->msg.handleValueNoti.len; + + if (len != 8) + { + LOG("\n"); + LOG("Error evt len\n"); + return; + } + + // Create pointer to GATT notification data. + uint8_t* packetData = pMsg->msg.handleValueNoti.value; + // Store the ANCS notification's eventID + notify_msg.eventID = packetData[0]; + // Store the ANCS notification's eventFlag + notify_msg.eventFlag = packetData[1]; + // Store the ANCS notification's categoryID + notify_msg.categoryID = packetData[2]; + notify_msg.categoryCount = packetData[3]; + // Notification UID from packetData[4] to packetData[7] + notify_msg.notifUID[0] = packetData[ANCS_NOTIF_UID_LENGTH]; + notify_msg.notifUID[1] = packetData[ANCS_NOTIF_UID_LENGTH+1]; + notify_msg.notifUID[2] = packetData[ANCS_NOTIF_UID_LENGTH+2]; + notify_msg.notifUID[3] = packetData[ANCS_NOTIF_UID_LENGTH+3]; + evt.msg = (void*)(¬ify_msg); + evt.len = sizeof(notify_msg); + evt.type = BLE_ANCS_EVT_NOTIF; + + if(pctx->callback) + { + pctx->callback(&evt); + } +} + + + +bStatus_t ble_ancs_get_notif_attrs(const uint8_t* pNotificationUID) +{ + return notif_attrs_get(&s_ancs_ctx, pNotificationUID); +} + + +bStatus_t ble_ancs_get_app_attrs(const uint8_t* p_app_id, uint8_t app_id_len) +{ + return app_attrs_get(&s_ancs_ctx, p_app_id, app_id_len); +} + + +bStatus_t ble_ancs_handle_gatt_event(gattMsgEvent_t* pMsg) +{ + ancs_ctx_t* pctx = &s_ancs_ctx; + ancs_service_t* pservie = &(pctx->ancs_service); + + if(pctx->app_state == ANCS_STATE_DISCOVERY) + { + ble_disc_service(pMsg); + } + else if (pMsg->method == ATT_HANDLE_VALUE_NOTI || pMsg->method == ATT_HANDLE_VALUE_IND) + { + // If we receive a GATT notification, we can assume it pertains to ANCS + // because we only subscribe to notifications from the Notification Source + // ancs Data Source. + uint8_t notifHandle = pMsg->msg.handleValueNoti.handle; + + if ( notifHandle == pservie->chars_hdl[ANCS_NOTIF_SCR_HDL_START]) + { + ble_ancs_process_ns_notify(pMsg); + } + else if ( notifHandle == pservie->chars_hdl[ANCS_DATA_SRC_HDL_START]) + { + ble_ancs_process_ds_notify(pMsg); + } + } + //If we have received a read or write response, assume that it is related to + //CCCD configuration + else if (pMsg->method == ATT_WRITE_RSP) + { + } + + // It's safe to free the incoming message + return (TRUE); +} + + + +bStatus_t ble_ancs_disconnect(void) +{ + ancs_ctx_t* pctx = &s_ancs_ctx; + uint8_t app_task_ID = pctx->app_task_ID; + ancs_evt_hdl_t callback = pctx->callback; + osal_memset(&s_ancs_ctx, 0, sizeof(s_ancs_ctx)); + pctx->app_task_ID = app_task_ID; + pctx->callback = callback; + return SUCCESS; +} + +bStatus_t ble_ancs_init(ancs_evt_hdl_t evt_hdl, uint8_t task_ID) +{ + ancs_ctx_t* pctx = &s_ancs_ctx; + osal_memset(&s_ancs_ctx, 0, sizeof(s_ancs_ctx)); + pctx->app_task_ID = task_ID; + pctx->callback = evt_hdl; + return SUCCESS; +} + diff --git a/src/components/profiles/ancs/ble_ancs.h b/src/components/profiles/ancs/ble_ancs.h new file mode 100644 index 0000000..c8be6c6 --- /dev/null +++ b/src/components/profiles/ancs/ble_ancs.h @@ -0,0 +1,239 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#ifndef __BLE_ANCS_HD_ +#define __BLE_ANCS_HD_ +#include "stdint.h" + +#define ANCS_ATTR_DATA_MAX 32 +#define ANCS_NB_OF_CATEGORY_ID 12 +#define ANCS_NB_OF_NOTIF_ATTR 8 +#define ANCS_NB_OF_APP_ATTR 1 +#define ANCS_NB_OF_EVT_ID 3 +#define ANCS_APP_ATTR_TX_SIZE (32+16) + +// ANCS: 7905F431-B5CE-4E99-A40F-4B1E122D00D0 +#define ANCSAPP_ANCS_SVC_UUID 0xD0, 0x00, 0x2D, 0x12, 0x1E, 0x4B, 0x0F, 0xA4, 0x99, 0x4E, 0xCE, 0xB5, 0x31, 0xF4, 0x05, 0x79 +// Notification Source: UUID 9FBF120D-6301-42D9-8C58-25E699A21DBD (notifiable) +#define ANCSAPP_NOTIF_SRC_CHAR_UUID 0x1DBD +// Control point: UUID 69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9 (writable with response) +#define ANCSAPP_CTRL_PT_CHAR_UUID 0xD9D9 +// Data Source: UUID 22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB (notifiable) +#define ANCSAPP_DATA_SRC_CHAR_UUID 0x7BFB + +#define CHAR_DESC_HDL_UUID128_LEN 21 // (5 + 16) bytes = 21 bytes. +#define NUMBER_OF_ANCS_CHARS 3 +#define ANCS_NOTIF_UID_LENGTH 4 + + +typedef enum +{ + BLE_ANCS_CATEGORY_ID_OTHER, /**< The iOS notification belongs to the "other" category. */ + BLE_ANCS_CATEGORY_ID_INCOMING_CALL, /**< The iOS notification belongs to the "Incoming Call" category. */ + BLE_ANCS_CATEGORY_ID_MISSED_CALL, /**< The iOS notification belongs to the "Missed Call" category. */ + BLE_ANCS_CATEGORY_ID_VOICE_MAIL, /**< The iOS notification belongs to the "Voice Mail" category. */ + BLE_ANCS_CATEGORY_ID_SOCIAL, /**< The iOS notification belongs to the "Social" category. */ + BLE_ANCS_CATEGORY_ID_SCHEDULE, /**< The iOS notification belongs to the "Schedule" category. */ + BLE_ANCS_CATEGORY_ID_EMAIL, /**< The iOS notification belongs to the "E-mail" category. */ + BLE_ANCS_CATEGORY_ID_NEWS, /**< The iOS notification belongs to the "News" category. */ + BLE_ANCS_CATEGORY_ID_HEALTH_AND_FITNESS, /**< The iOS notification belongs to the "Health and Fitness" category. */ + BLE_ANCS_CATEGORY_ID_BUSINESS_AND_FINANCE, /**< The iOS notification belongs to the "Buisness and Finance" category. */ + BLE_ANCS_CATEGORY_ID_LOCATION, /**< The iOS notification belongs to the "Location" category. */ + BLE_ANCS_CATEGORY_ID_ENTERTAINMENT /**< The iOS notification belongs to the "Entertainment" category. */ +} ancs_notif_category_id; + +/**@brief Event IDs for iOS notifications. */ +typedef enum +{ + BLE_ANCS_EVENT_ID_NOTIFICATION_ADDED, /**< The iOS notification was added. */ + BLE_ANCS_EVENT_ID_NOTIFICATION_MODIFIED, /**< The iOS notification was modified. */ + BLE_ANCS_EVENT_ID_NOTIFICATION_REMOVED /**< The iOS notification was removed. */ +} ancs_notif_evt_id; + +#define EVENT_FLAG_silent (1<<0) //!< If this flag is set, the notification has a low priority. +#define EVENT_FLAG_important (1<<1) //!< If this flag is set, the notification has a high priority. +#define EVENT_FLAG_pre_existing (1<<2) //!< If this flag is set, the notification is pre-existing. +#define EVENT_FLAG_positive_action (1<<3) //!< If this flag is set, the notification has a positive action that can be taken. +#define EVENT_FLAG_negative_action (1<<4) //!< If this flag is set, the notification has a negative action that can be taken. + +#define BLE_ANCS_APP_ATTR_ID_DISPLAY_NAME 0 + +typedef enum +{ + BLE_ANCS_NOTIF_ATTR_ID_APP_IDENTIFIER = 0, /**< Identifies that the attribute data is of an "App Identifier" type. */ + BLE_ANCS_NOTIF_ATTR_ID_TITLE, /**< Identifies that the attribute data is a "Title". */ + BLE_ANCS_NOTIF_ATTR_ID_SUBTITLE, /**< Identifies that the attribute data is a "Subtitle". */ + BLE_ANCS_NOTIF_ATTR_ID_MESSAGE, /**< Identifies that the attribute data is a "Message". */ + BLE_ANCS_NOTIF_ATTR_ID_MESSAGE_SIZE, /**< Identifies that the attribute data is a "Message Size". */ + BLE_ANCS_NOTIF_ATTR_ID_DATE, /**< Identifies that the attribute data is a "Date". */ + BLE_ANCS_NOTIF_ATTR_ID_POSITIVE_ACTION_LABEL, /**< The notification has a "Positive action" that can be executed associated with it. */ + BLE_ANCS_NOTIF_ATTR_ID_NEGATIVE_ACTION_LABEL, /**< The notification has a "Negative action" that can be executed associated with it. */ +} ancs_notif_attr_id; + + + +typedef enum +{ + BLE_ANCS_EVT_DISCOVERY_COMPLETE, + BLE_ANCS_EVT_DISCOVERY_FAILED, + BLE_ANCS_EVT_NOTIF, + BLE_ANCS_EVT_NOTIF_ATTRIBUTE, + BLE_ANCS_EVT_APP_ATTRIBUTE, + BLE_ANCS_EVT_NP_ERROR, +} ancs_evt_type_t; + + +typedef struct +{ + bool en; //enable flag + uint32_t attr_id; + uint16_t attr_len; + uint8_t* p_attr_data; +} ancs_attr_list_t; + + +enum +{ + ANCS_NOTIF_SCR_HDL_START, // ANCS Notification Source characteristic start handle. + ANCS_NOTIF_SCR_HDL_END, // ANCS Notification Source characteristic end handle. + ANCS_NOTIF_SCR_HDL_CCCD, // ANCS Notification Source CCCD handle. + + ANCS_CTRL_POINT_HDL_START, // ANCS Control Point characteristic start handle. + ANCS_CTRL_POINT_HDL_END, // ANCS Control Point characteristic end handle. + + ANCS_DATA_SRC_HDL_START, // ANCS Data Source characteristic start handle. + ANCS_DATA_SRC_HDL_END, // ANCS Data Source characteristic end handle. + ANCS_DATA_SRC_HDL_CCCD, // ANCS Data Source CCCD handle. +}; + +// Cache array length. +#define HDL_CACHE_LEN 8 +enum +{ + ANCS_UNINIT, // uninitial idle state. + ANCS_DISC_SERVICE, // Discover the ANCS service by UUID. + ANCS_STORE_SERVICE_HANDLES, // Store the ANCS service handles in the cache. + ANCS_DISC_CHARS, // Discover the three characteristics: Notification Source, Control Point, and Data Source. + ANCS_STORE_CHARS_HANDLES, // Store the handles of each characteristic in the handle cache. + ANCS_DISC_NS_DESCS, // Discover the descriptors of the Notification Source (Trying to locate the CCCD). + ANCS_STORE_NS_DESCS_HANDLES, // Store the descriptor's handles in the handle cache (ANCS_NOTIF_SCR_HDL_CCCD). + ANCS_DISC_DS_DESCS, // Discover the descriptors of the Data Source (Trying to locate the CCCD). + ANCS_STORE_DS_DESCS_HANDLES, // Store the descriptor's handles in the handle cache (ANCS_DATA_SRC_HDL_CCCD). + ANCS_ENABLE_NS_CCCD, + ANCS_ENABLE_DS_CCCD, + ANCS_WAIT_CCCD_READY, + ANCS_DISC_FINISH, // Final state signifying the end of the discovery process. + + ANCS_DISC_FAILED = 0xFF // A failure state reached only if an error occurs. +}; + +enum +{ + ANCS_STATE_IDLE = 0, + ANCS_STATE_DISCOVERY, + ANCS_STATE_READY, +}; + +typedef struct +{ + uint16_t conn_hdl; + uint8_t expect_type_value_num; + uint16_t service_hdl[2]; + uint8_t chars_disc_num; + uint16_t chars_hdl[HDL_CACHE_LEN]; +} ancs_service_t; +typedef enum +{ + COMMAND_ID, /**< Parsing the command ID. */ + NOTIF_UID, /**< Parsing the notification UID. */ + APP_ID, /**< Parsing app ID. */ + ATTR_ID, /**< Parsing attribute ID. */ + ATTR_LEN1, /**< Parsing the LSB of the attribute length. */ + ATTR_LEN2, /**< Parsing the MSB of the attribute length. */ + ATTR_DATA, /**< Parsing the attribute data. */ + ATTR_SKIP, /**< Parsing is skipped for the rest (or entire) of an attribute. */ + DONE, /**< Parsing for one attribute is done. */ +} ancs_parse_state_t; + +typedef enum +{ + ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES, /**< Requests attributes to be sent from the NP to the NC for a given notification. */ + ANCS_COMMAND_ID_GET_APP_ATTRIBUTES, /**< Requests attributes to be sent from the NP to the NC for a given iOS app. */ + ANCS_COMMAND_ID_GET_PERFORM_NOTIF_ACTION, /**< Requests an action to be performed on a given notification, for example, dismiss an alarm. */ +} ancs_cmd_id_val_t; + + +typedef struct +{ + ancs_attr_list_t* p_attr_list; //!< The current list of attributes being parsed. This field will point to either @ref ble_ancs_c_t::ancs_notif_attr_list or @ref ble_ancs_c_t::ancs_app_attr_list. + uint32_t nb_of_attr; //!< Number of possible attributes. When parsing begins, it is set to either @ref ANCS_NB_OF_NOTIF_ATTR or @ref ANCS_NB_OF_APP_ATTR. + uint32_t expected_number_of_attrs; //!< The number of attributes expected upon receiving attributes. Keeps track of when to stop reading incoming attributes. + ancs_parse_state_t parse_state; //!< ANCS notification attribute parsing state. + ancs_cmd_id_val_t command_id; //!< Variable to keep track of what command type we are currently parsing ( @ref BLE_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES or @ref BLE_ANCS_COMMAND_ID_GET_APP_ATTRIBUTES. + uint8_t* p_data_dest; //!< Attribute that the parsed data will be copied into. + uint16_t current_attr_index; //!< Variable to keep track of how much (for a given attribute) we are done parsing. + uint32_t current_app_id_index; //!< Variable to keep track of how much (for a given app identifier) we are done parsing. +} ble_ancs_parse_fsm_t; + +typedef struct +{ + uint32_t notif_uid; + uint8_t app_id[ANCS_ATTR_DATA_MAX]; + uint16_t attr_len; //!< Length of the received attribute data. + uint32_t attr_id; //!< Classification of the attribute type, for example, title or date. + uint8_t* p_attr_data; //!< Pointer to where the memory is allocated for storing incoming attributes. +} ancs_attr_evt_t; + +typedef struct +{ + uint8_t type; + uint8_t len; + void* msg; +} ancs_evt_t; + +typedef void (*ancs_evt_hdl_t) (ancs_evt_t* p_evt); + +typedef struct +{ + uint8_t app_task_ID; + uint8_t disc_state; + uint8_t app_state; + ancs_attr_list_t notif_attr_list[ANCS_NB_OF_NOTIF_ATTR]; + ancs_attr_list_t app_attr_list[ANCS_NB_OF_APP_ATTR]; + ble_ancs_parse_fsm_t parse_info; + ancs_service_t ancs_service; + ancs_attr_evt_t attr_evt_msg; + ancs_evt_t attr_rsp_evt; + uint8_t app_attr_tx_buf[ANCS_APP_ATTR_TX_SIZE]; + ancs_evt_hdl_t callback; +} ancs_ctx_t; + + + + +typedef struct +{ + uint8_t eventID; + // Store the ANCS notification's eventFlag + uint8_t eventFlag; + // Store the ANCS notification's categoryID + uint8_t categoryID; + uint8_t categoryCount; + + uint8_t notifUID[4]; +} ancs_notify_evt_t; + + +bStatus_t ble_ancs_attr_add(const ancs_notif_attr_id id, uint8_t* p_data, const uint16_t len); +bStatus_t ble_ancs_get_notif_attrs(const uint8_t* pNotificationUID); +bStatus_t ble_ancs_get_app_attrs(const uint8_t* p_app_id, uint8_t app_id_len); +bStatus_t ble_ancs_start_descovery(uint16_t conn_handle); +bStatus_t ble_ancs_handle_gatt_event(gattMsgEvent_t* pMsg); +bStatus_t ble_ancs_init(ancs_evt_hdl_t evt_hdl, uint8_t task_ID); + + +#endif //__BLE_ANCS_HD_ + + diff --git a/src/components/profiles/hrs/heartrateservice.c b/src/components/profiles/hrs/heartrateservice.c new file mode 100644 index 0000000..c84a377 --- /dev/null +++ b/src/components/profiles/hrs/heartrateservice.c @@ -0,0 +1,479 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: heartrateservice.c + Revised: + Revision: + + Description: This file contains the Heart Rate sample service + for use with the Heart Rate sample application. + +**************************************************************************************************/ + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "linkdb.h" +#include "att.h" +#include "gatt.h" +#include "gatt_uuid.h" +#include "gatt_profile_uuid.h" +#include "gattservapp.h" + +#include "heartrateservice.h" +#include "log.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +// Position of heart rate measurement value in attribute array +#define HEARTRATE_MEAS_VALUE_POS 2 + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ +// Heart rate service +CONST uint8 heartRateServUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(HEARTRATE_SERV_UUID), HI_UINT16(HEARTRATE_SERV_UUID) +}; + +// Heart rate measurement characteristic +CONST uint8 heartRateMeasUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(HEARTRATE_MEAS_UUID), HI_UINT16(HEARTRATE_MEAS_UUID) +}; + +// Sensor location characteristic +CONST uint8 heartRateSensLocUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(BODY_SENSOR_LOC_UUID), HI_UINT16(BODY_SENSOR_LOC_UUID) +}; + +// Command characteristic +CONST uint8 heartRateCommandUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(HEARTRATE_CTRL_PT_UUID), HI_UINT16(HEARTRATE_CTRL_PT_UUID) +}; + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +static heartRateServiceCB_t heartRateServiceCB; + +/********************************************************************* + Profile Attributes - variables +*/ + +// Heart Rate Service attribute +static CONST gattAttrType_t heartRateService = { ATT_BT_UUID_SIZE, heartRateServUUID }; + +// Heart Rate Measurement Characteristic +// Note characteristic value is not stored here +static uint8 heartRateMeasProps = GATT_PROP_NOTIFY; +static uint8 heartRateMeas = 0; +static gattCharCfg_t heartRateMeasClientCharCfg[GATT_MAX_NUM_CONN]; + +// Sensor Location Characteristic +static uint8 heartRateSensLocProps = GATT_PROP_READ; +static uint8 heartRateSensLoc = 0; + +// Command Characteristic +static uint8 heartRateCommandProps = GATT_PROP_WRITE; +static uint8 heartRateCommand = 0; + +/********************************************************************* + Profile Attributes - Table +*/ + +static gattAttribute_t heartRateAttrTbl[] = +{ + // Heart Rate Service + { + { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */ + GATT_PERMIT_READ, /* permissions */ + 0, /* handle */ + (uint8*)& heartRateService /* pValue */ + }, + + // Heart Rate Measurement Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &heartRateMeasProps + }, + + // Heart Rate Measurement Value + { + { ATT_BT_UUID_SIZE, heartRateMeasUUID }, + 0, + 0, + &heartRateMeas + }, + + // Heart Rate Measurement Client Characteristic Configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8*)& heartRateMeasClientCharCfg + }, + + // Sensor Location Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &heartRateSensLocProps + }, + + // Sensor Location Value + { + { ATT_BT_UUID_SIZE, heartRateSensLocUUID }, + GATT_PERMIT_READ, + 0, + &heartRateSensLoc + }, + + // Command Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &heartRateCommandProps + }, + + // Command Value + { + { ATT_BT_UUID_SIZE, heartRateCommandUUID }, + GATT_PERMIT_WRITE, + 0, + &heartRateCommand + } +}; + + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static uint8 heartRate_ReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint8* pLen, uint16 offset, uint8 maxLen ); +static bStatus_t heartRate_WriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint8 len, uint16 offset ); + +/********************************************************************* + PROFILE CALLBACKS +*/ +// Heart Rate Service Callbacks +CONST gattServiceCBs_t heartRateCBs = +{ + heartRate_ReadAttrCB, // Read callback function pointer + heartRate_WriteAttrCB, // Write callback function pointer + NULL // Authorization callback function pointer +}; + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/********************************************************************* + @fn HeartRate_AddService + + @brief Initializes the Heart Rate service by registering + GATT attributes with the GATT server. + + @param services - services to add. This is a bit map and can + contain more than one service. + + @return Success or Failure +*/ +bStatus_t HeartRate_AddService( uint32 services ) +{ + uint8 status = SUCCESS; + // Initialize Client Characteristic Configuration attributes + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, heartRateMeasClientCharCfg ); + + if ( services & HEARTRATE_SERVICE ) + { + // Register GATT attribute list and CBs with GATT Server App + status = GATTServApp_RegisterService( heartRateAttrTbl, + GATT_NUM_ATTRS( heartRateAttrTbl ), + &heartRateCBs ); + } + + return ( status ); +} + +/********************************************************************* + @fn HeartRate_Register + + @brief Register a callback function with the Heart Rate Service. + + @param pfnServiceCB - Callback function. + + @return None. +*/ +extern void HeartRate_Register( heartRateServiceCB_t pfnServiceCB ) +{ + heartRateServiceCB = pfnServiceCB; +} + +/********************************************************************* + @fn HeartRate_SetParameter + + @brief Set a Heart Rate parameter. + + @param param - Profile parameter ID + @param len - length of data to right + @param value - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t HeartRate_SetParameter( uint8 param, uint8 len, void* value ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case HEARTRATE_MEAS_CHAR_CFG: + // Need connection handle + //heartRateMeasClientCharCfg.value = *((uint16*)value); + break; + + case HEARTRATE_SENS_LOC: + heartRateSensLoc = *((uint8*)value); + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn HeartRate_GetParameter + + @brief Get a Heart Rate parameter. + + @param param - Profile parameter ID + @param value - pointer to data to get. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t HeartRate_GetParameter( uint8 param, void* value ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case HEARTRATE_MEAS_CHAR_CFG: + // Need connection handle + //*((uint16*)value) = heartRateMeasClientCharCfg.value; + break; + + case HEARTRATE_SENS_LOC: + *((uint8*)value) = heartRateSensLoc; + break; + + case HEARTRATE_COMMAND: + *((uint8*)value) = heartRateCommand; + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn HeartRate_MeasNotify + + @brief Send a notification containing a heart rate + measurement. + + @param connHandle - connection handle + @param pNoti - pointer to notification structure + + @return Success or Failure +*/ +bStatus_t HeartRate_MeasNotify( uint16 connHandle, attHandleValueNoti_t* pNoti ) +{ + uint16 value = GATTServApp_ReadCharCfg( connHandle, heartRateMeasClientCharCfg ); + + // If notifications enabled + if ( value & GATT_CLIENT_CFG_NOTIFY ) + { + // Set the handle + pNoti->handle = heartRateAttrTbl[HEARTRATE_MEAS_VALUE_POS].handle; + // Send the notification + return GATT_Notification( connHandle, pNoti, FALSE ); + } + + return bleIncorrectMode; +} + +/********************************************************************* + @fn heartRate_ReadAttrCB + + @brief Read an attribute. + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be read + @param pLen - length of data to be read + @param offset - offset of the first octet to be read + @param maxLen - maximum length of data to be read + + @return Success or Failure +*/ +static uint8 heartRate_ReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint8* pLen, uint16 offset, uint8 maxLen ) +{ + bStatus_t status = SUCCESS; + + // Make sure it's not a blob operation (no attributes in the profile are long) + if ( offset > 0 ) + { + return ( ATT_ERR_ATTR_NOT_LONG ); + } + + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + if (uuid == BODY_SENSOR_LOC_UUID) + { + *pLen = 1; + pValue[0] = *pAttr->pValue; + } + else + { + status = ATT_ERR_ATTR_NOT_FOUND; + } + + return ( status ); +} + +/********************************************************************* + @fn heartRate_WriteAttrCB + + @brief Validate attribute data prior to a write operation + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be written + @param len - length of data + @param offset - offset of the first octet to be written + + @return Success or Failure +*/ +static bStatus_t heartRate_WriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint8 len, uint16 offset ) +{ + bStatus_t status = SUCCESS; + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + switch ( uuid ) + { + case HEARTRATE_CTRL_PT_UUID: + if ( offset > 0 ) + { + status = ATT_ERR_ATTR_NOT_LONG; + } + else if (len != 1) + { + status = ATT_ERR_INVALID_VALUE_SIZE; + } + else if (*pValue != HEARTRATE_COMMAND_ENERGY_EXP) + { + status = HEARTRATE_ERR_NOT_SUP; + } + else + { + *(pAttr->pValue) = pValue[0]; + (*heartRateServiceCB)(HEARTRATE_COMMAND_SET); + } + + break; + + case GATT_CLIENT_CHAR_CFG_UUID: + status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len, + offset, GATT_CLIENT_CFG_NOTIFY ); + + if ( status == SUCCESS ) + { + uint16 charCfg = BUILD_UINT16( pValue[0], pValue[1] ); + (*heartRateServiceCB)( (charCfg == GATT_CFG_NO_OPERATION) ? + HEARTRATE_MEAS_NOTI_DISABLED : + HEARTRATE_MEAS_NOTI_ENABLED ); + } + + break; + + default: + status = ATT_ERR_ATTR_NOT_FOUND; + break; + } + + return ( status ); +} + +/********************************************************************* + @fn HeartRate_HandleConnStatusCB + + @brief Heart Rate Service link status change handler function. + + @param connHandle - connection handle + @param changeType - type of change + + @return none +*/ +void HeartRate_HandleConnStatusCB( uint16 connHandle, uint8 changeType ) +{ + // Make sure this is not loopback connection + if ( connHandle != LOOPBACK_CONNHANDLE ) + { + // Reset Client Char Config if connection has dropped + if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) || + ( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && + ( !linkDB_Up( connHandle ) ) ) ) + { + GATTServApp_InitCharCfg( connHandle, heartRateMeasClientCharCfg ); + } + } +} + + +/********************************************************************* +*********************************************************************/ diff --git a/src/components/profiles/hrs/heartrateservice.h b/src/components/profiles/hrs/heartrateservice.h new file mode 100644 index 0000000..b370beb --- /dev/null +++ b/src/components/profiles/hrs/heartrateservice.h @@ -0,0 +1,167 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: heartrateservice.h + Revised: + Revision: + + Description: This file contains the Heart Rate service definitions and + prototypes. + +**************************************************************************************************/ + +#ifndef HEARTRATESERVICE_H +#define HEARTRATESERVICE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + CONSTANTS +*/ + + +// Heart Rate Service Parameters +#define HEARTRATE_MEAS 0 +#define HEARTRATE_MEAS_CHAR_CFG 1 +#define HEARTRATE_SENS_LOC 2 +#define HEARTRATE_COMMAND 3 + +// Maximum length of heart rate measurement characteristic +#define HEARTRATE_MEAS_MAX (ATT_MTU_SIZE -5) + +// Values for flags +#define HEARTRATE_FLAGS_FORMAT_UINT16 0x01 +#define HEARTRATE_FLAGS_CONTACT_NOT_SUP 0x00 +#define HEARTRATE_FLAGS_CONTACT_NOT_DET 0x04 +#define HEARTRATE_FLAGS_CONTACT_DET 0x06 +#define HEARTRATE_FLAGS_ENERGY_EXP 0x08 +#define HEARTRATE_FLAGS_RR 0x10 + +// Values for sensor location +#define HEARTRATE_SENS_LOC_OTHER 0x00 +#define HEARTRATE_SENS_LOC_CHEST 0x01 +#define HEARTRATE_SENS_LOC_WRIST 0x02 +#define HEARTRATE_SENS_LOC_FINGER 0x03 +#define HEARTRATE_SENS_LOC_HAND 0x04 +#define HEARTRATE_SENS_LOC_EARLOBE 0x05 +#define HEARTRATE_SENS_LOC_FOOT 0x06 + +// Value for command characteristic +#define HEARTRATE_COMMAND_ENERGY_EXP 0x01 + +// ATT Error code +// Control point value not supported +#define HEARTRATE_ERR_NOT_SUP 0x80 + +// Heart Rate Service bit fields +#define HEARTRATE_SERVICE 0x00000001 + +// Callback events +#define HEARTRATE_MEAS_NOTI_ENABLED 1 +#define HEARTRATE_MEAS_NOTI_DISABLED 2 +#define HEARTRATE_COMMAND_SET 3 + +/********************************************************************* + TYPEDEFS +*/ + +// Heart Rate Service callback function +typedef void (*heartRateServiceCB_t)(uint8 event); + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + Profile Callbacks +*/ + + +/********************************************************************* + API FUNCTIONS +*/ + +/* + HeartRate_AddService- Initializes the Heart Rate service by registering + GATT attributes with the GATT server. + + @param services - services to add. This is a bit map and can + contain more than one service. +*/ + +extern bStatus_t HeartRate_AddService( uint32 services ); + +/* + HeartRate_Register - Register a callback function with the + Heart Rate Service + + @param pfnServiceCB - Callback function. +*/ + +extern void HeartRate_Register( heartRateServiceCB_t pfnServiceCB ); + +/* + HeartRate_SetParameter - Set a Heart Rate parameter. + + param - Profile parameter ID + len - length of data to right + value - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). +*/ +extern bStatus_t HeartRate_SetParameter( uint8 param, uint8 len, void* value ); + +/* + HeartRate_GetParameter - Get a Heart Rate parameter. + + param - Profile parameter ID + value - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). +*/ +extern bStatus_t HeartRate_GetParameter( uint8 param, void* value ); + +/********************************************************************* + @fn HeartRate_MeasNotify + + @brief Send a notification containing a heart rate + measurement. + + @param connHandle - connection handle + @param pNoti - pointer to notification structure + + @return Success or Failure +*/ +extern bStatus_t HeartRate_MeasNotify( uint16 connHandle, attHandleValueNoti_t* pNoti ); + +/********************************************************************* + @fn HeartRate_HandleConnStatusCB + + @brief Heart Rate Service link status change handler function. + + @param connHandle - connection handle + @param changeType - type of change + + @return none +*/ +extern void HeartRate_HandleConnStatusCB( uint16 connHandle, uint8 changeType ); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* HEARTRATESERVICE_H */ diff --git a/src/components/profiles/multiRole/multi.c b/src/components/profiles/multiRole/multi.c new file mode 100644 index 0000000..fa959e4 --- /dev/null +++ b/src/components/profiles/multiRole/multi.c @@ -0,0 +1,2284 @@ +/****************************************************************************** + + @file multi.c + + @brief multi GAPRole profile code + + Group: CMCU, SCS + ******************************************************************************/ + +/********************************************************************* + INCLUDES +*/ +//#include +#include "bcomdef.h" +#include "OSAL.h" +#include "hci_tl.h" +#include "l2cap.h" +#include "gap.h" +#include "linkdb.h" +#include "gatt.h" +#include "osal_snv.h" +#include "gapbondmgr.h" + +/* This Header file contains all BLE API and icall structure definition */ +#include "multi.h" +#include "multi_role.h" +#include "log.h" +#include "flash.h" +#include "multi_timer.h" +#include "multi_schedule.h" + +/********************************************************************* + MACROS +*/ +#define MULTI_ROLE_CENTRAL_HANDLER 0xFE + +// Length of bd addr as a string +#define B_ADDR_STR_LEN 15 + +// default Exchange MTU SIZE +#define DEFAULT_EXCHANGE_MTU_LEN 23 + + +/********************************************************************* + GLOBAL VARIABLES +*/ + +// Link DB maximum number of connections +uint8 linkDBNumConns = MAX_NUM_LL_CONN; // hardcoded, + +/********************************************************************* + EXTERNAL VARIABLES +*/ +extern GAPMultiRoleLinkCtrl_t* g_multiLinkInfo; + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ +extern uint8 gapBond_PairingMode[]; + +/********************************************************************* + LOCAL VARIABLES +*/ +uint8 gapMultiRole_TaskID; +// Application callbacks +static gapMultiRolesCBs_t* pGapRoles_AppCGs = NULL; + +/********************************************************************* + Profile Parameters - reference GAPMULTIROLE_PROFILE_PARAMETERS for + descriptions +*/ +#if (MAX_CONNECTION_MASTER_NUM > 0 ) + // scanner list + static GAPMultiRolScanner_t* g_scanlist = NULL; + GAPMultiRoleCentralDev_t* g_cfgSlaveList = NULL; // devices want to be connected + GAPMultiRoleCentralDev_t* g_mlinkingList = NULL; // devices + GAPMultiRoleCentralAction_t* g_centralAction = NULL; + + multiTimer* g_centralActionTimer = NULL; + + GAPMultiRole_CentralSDP_t* g_centralSDPlist = NULL; +#endif + +// multi-role common info +static GAPMultiRoleParam_t g_multiRoleParam; + +#if(MAX_CONNECTION_SLAVE_NUM > 0 ) + // multi-role as peripheral Info + // max support DEFAULT_SLAVE_CNT slave + multiTimer g_peri_conn_update_timer[MAX_CONNECTION_SLAVE_NUM]; + multiTimer g_pcu_no_success_timer[MAX_CONNECTION_SLAVE_NUM]; + + static uint8 paramUpdateNoSuccessOption = MULTIROLE_NO_ACTION; +#endif + +// parameter update no success actions + +/********************************************************************* + Profile Attributes - variables +*/ + +/********************************************************************* + Profile Attributes - Table +*/ + +/********************************************************************* + EXTERN FUNCTIONS +*/ +#if( MAX_CONNECTION_SLAVE_NUM > 0 ) + extern void multiConfigSchAdv_param(uint8 opcode,uint8 status,uint8 advType ); +#endif +#if( MAX_CONNECTION_MASTER_NUM > 0 ) + extern void multiConfigSchScan_param(void); +#endif +extern GAPMultiLinkInfo_t multiConfigLink_status(uint8 opcode,void* pkt); + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static void MultiPeriodProcessEvent(void); +#if( MAX_CONNECTION_SLAVE_NUM > 0 ) + static void Multi_peripheralUpdateParam(uint16 idx); + static void MultiRole_PeripheralstartConnUpdate( uint8 idx,uint8 handleFailure ); + static void MultiRole_HandleParamUpdateNoSuccess( uint16 idx ); +#endif +#if( MAX_CONNECTION_MASTER_NUM > 0 ) + static void* multiListCreate(GAPMultiListMode_t mode ); + static void* multiListFindTail(GAPMultiListMode_t mode, void** ppnode ); + static void multiListDelNode(GAPMultiListMode_t mode, void** ppnode, void* pvalue ); + static uint8 multiListInsertTail(GAPMultiListMode_t mode, void** ppnode,void* vnode); + static void* multiList_inside(GAPMultiListMode_t mode,void** ppnode, void* pvalue); + static void multiListMemoryFree(GAPMultiListMode_t mode ); + void multi_ScannerInsertDev(gapDeviceInfoEvent_t* pMsg); + static uint8 MultiRole_CancelConn(void); + static void Multi_centralAction(uint16 idx); + static void MultiRole_ProcessSDPInfo(gattMsgEvent_t* pMsg); + static void multilist_free_central_action_actimerlist(uint16 connHandle); + static void multilist_free_sdplist(uint16 connHandle); + +#endif + +static void MultiRole_ProcessParamUpdateInfo(gapLinkUpdateEvent_t* pPkt); +static void MultiRole_ProcessOSALMsg( osal_event_hdr_t* pMsg ); +static uint8 MultiRole_processGAPMsg(gapEventHdr_t* pMsg); +static void multiRoleProcessGATTMsg( gattMsgEvent_t* pMsg ); +static void MultiRole_SetupGAP(uint8* numConns); +static void multiRolePasscodeCB( uint8* deviceAddr, uint16 connectionHandle, + uint8 uiInputs, uint8 uiOutputs ); +static void multiRolePairStateCB( uint16 connHandle, uint8 state, uint8 status ); + + + +// Bond Manager Callbacks +static const gapBondCBs_t multiRoleBondCB = +{ + multiRolePasscodeCB, + multiRolePairStateCB +}; + +/********************************************************************* + @brief Set a GAP Role parameter. + + Public function defined in peripheral.h. +*/ +bStatus_t GAPMultiRole_SetParameter(uint16 param, uint8 len, void* pValue) +{ + bStatus_t ret = SUCCESS; + + switch (param) + { + case GAPMULTIROLE_PROFILEROLE: + { + if (len == sizeof(uint8)) + { + g_multiRoleParam.common.profileRole = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPMULTIROLE_IRK: + { + if (len == KEYLEN) + { + osal_memcpy(g_multiRoleParam.common.IRK, pValue, KEYLEN); + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPMULTIROLE_SRK: + { + if (len == KEYLEN) + { + osal_memcpy(g_multiRoleParam.common.SRK, pValue, KEYLEN); + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPMULTIROLE_SIGNCOUNTER: + { + if (len == sizeof (uint32)) + { + g_multiRoleParam.common.signCounter = *((uint32*)pValue); + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPMULTIROLE_MIN_CONN_INTERVAL: + { + if ( len == sizeof (uint16) ) + { + g_multiRoleParam.common.ExConnIntvMIN = *((uint16*)pValue); + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPMULTIROLE_MAX_CONN_INTERVAL: + { + if ( len == sizeof (uint16) ) + { + g_multiRoleParam.common.ExConnIntvMAX = *((uint16*)pValue); + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPMULTIROLE_SLAVE_LATENCY: + { + if ( len == sizeof (uint16) ) + { + g_multiRoleParam.common.ExLatency = *((uint16*)pValue); + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPMULTIROLE_TIMEOUT_MULTIPLIER: + { + if ( len == sizeof (uint16) ) + { + g_multiRoleParam.common.ExTimeOut = *((uint16*)pValue); + } + else + { + ret = bleInvalidRange; + } + } + break; + #if(MAX_CONNECTION_SLAVE_NUM > 0 ) + + case GAPMULTIROLE_ADV_EVENT_TYPE: + { + if ((len == sizeof (uint8)) && (*((uint8*)pValue) <= GAP_ADTYPE_ADV_LDC_DIRECT_IND) ) + { + g_multiRoleParam.adv.EventType = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPMULTIROLE_ADV_CHANNEL_MAP: + { + if ((len == sizeof (uint8)) && (*((uint8*)pValue) <= 0x07)) + { + g_multiRoleParam.adv.ChanMap = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPMULTIROLE_ADV_FILTER_POLICY: + { + if ((len == sizeof (uint8)) && (*((uint8*)pValue) <= GAP_FILTER_POLICY_WHITE) ) + { + g_multiRoleParam.adv.FilterPolicy = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPMULTIROLE_PARAM_UPDATE_ENABLE: + { + if ( len == sizeof (uint8) ) + { + g_multiRoleParam.adv.UpdateEnable = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + } + break; + #endif + #if (MAX_CONNECTION_MASTER_NUM > 0 ) + + case GAPMULTIROLE_MAX_SCAN_RES: + { + if (len == sizeof (uint8)) + { + g_multiRoleParam.scan.maxScanRes = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPMULTIROLE_SCAN_MODE: + { + if (len == sizeof (uint8)) + { + g_multiRoleParam.scan.scanMode = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPMULTIROLE_ACTIVE_SCAN: + { + if (len == sizeof (uint8)) + { + g_multiRoleParam.scan.activeScan = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPMULTIROLE_SCAN_WHITELIST: + { + if (len == sizeof (uint8)) + { + g_multiRoleParam.scan.whitelist = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPMULTIROLE_LINK_HIGHDUTYCYCLE: + { + if (len == sizeof (uint8)) + { + g_multiRoleParam.link.highDutyCycle = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPMULTIROLE_LINK_WHITELIST: + { + if (len == sizeof (uint8)) + { + g_multiRoleParam.link.whitelist = *((uint8*)pValue); + } + else + { + ret = bleInvalidRange; + } + } + break; + + case GAPMULTIROLE_ACTION_AFTER_LINK: + { + if (len == sizeof (uint16)) + { + g_multiRoleParam.link.actionAfterLink = *((uint16*)pValue); + } + else + { + ret = bleInvalidRange; + } + } + break; + #endif + + default: + { + // The param value isn't part of this profile, try the GAP. + if ((param < TGAP_PARAMID_MAX) && (len == sizeof (uint16))) + { + ret = GAP_SetParamValue(param, *((uint16*)pValue)); + } + else + { + ret = INVALIDPARAMETER; + } + } + break; + } + + return (ret); +} + +/********************************************************************* + @brief Get a GAP Role parameter. + + Public function defined in peripheral.h. +*/ +bStatus_t GAPMultiRole_GetParameter(uint16 param, void* pValue) +{ + bStatus_t ret = SUCCESS; + + switch (param) + { + case GAPMULTIROLE_PROFILEROLE: + *((uint8*)pValue) = g_multiRoleParam.common.profileRole; + break; + + case GAPMULTIROLE_IRK: + osal_memcpy(pValue, g_multiRoleParam.common.IRK, KEYLEN); + break; + + case GAPMULTIROLE_SRK: + osal_memcpy(pValue, g_multiRoleParam.common.SRK, KEYLEN); + break; + + case GAPMULTIROLE_SIGNCOUNTER: + *((uint32*)pValue) = g_multiRoleParam.common.signCounter; + break; + + case GAPMULTIROLE_BD_ADDR: + osal_memcpy(pValue, g_multiRoleParam.common.bdAddr, B_ADDR_LEN); + break; + + case GAPMULTIROLE_MIN_CONN_INTERVAL: + *((uint16*)pValue) = g_multiRoleParam.common.ExConnIntvMIN; + break; + + case GAPMULTIROLE_MAX_CONN_INTERVAL: + *((uint16*)pValue) = g_multiRoleParam.common.ExConnIntvMAX; + break; + + case GAPMULTIROLE_SLAVE_LATENCY: + *((uint16*)pValue) = g_multiRoleParam.common.ExLatency; + break; + + case GAPMULTIROLE_TIMEOUT_MULTIPLIER: + *((uint16*)pValue) = g_multiRoleParam.common.ExTimeOut; + break; + #if(MAX_CONNECTION_SLAVE_NUM > 0 ) + + case GAPMULTIROLE_ADV_EVENT_TYPE: + *((uint8*)pValue) = g_multiRoleParam.adv.EventType; + break; + + case GAPMULTIROLE_ADV_CHANNEL_MAP: + *((uint8*)pValue) = g_multiRoleParam.adv.ChanMap; + break; + + case GAPMULTIROLE_ADV_FILTER_POLICY: + *((uint8*)pValue) = g_multiRoleParam.adv.FilterPolicy; + break; + + case GAPMULTIROLE_PARAM_UPDATE_ENABLE: + *((uint8*)pValue) = g_multiRoleParam.adv.UpdateEnable; + break; + #endif + #if (MAX_CONNECTION_MASTER_NUM > 0 ) + + case GAPMULTIROLE_MAX_SCAN_RES: + *((uint8*)pValue) = g_multiRoleParam.scan.maxScanRes; + break; + #endif + + default: + { + // The param value isn't part of this profile, try the GAP. + if (param < TGAP_PARAMID_MAX) + { + *((uint16*)pValue) = GAP_GetParamValue(param); + } + else + { + ret = INVALIDPARAMETER; + } + } + break; + } + + return (ret); +} + +/********************************************************************* + @brief Does the device initialization. + + Public function defined in peripheral.h. +*/ +bStatus_t GAPMultiRole_StartDevice(gapMultiRolesCBs_t* pAppCallbacks, uint8* numConns) +{ + // Clear all of the Application callbacks + if (pAppCallbacks) + { + pGapRoles_AppCGs = pAppCallbacks; + } + + // Start the GAP + MultiRole_SetupGAP(numConns); + return (SUCCESS); +} + +/********************************************************************* + @brief Terminates the existing connection. + + Public function defined in peripheral.h. +*/ +bStatus_t GAPMultiRole_TerminateConnection(uint16_t Handler) +{ + return (GAP_TerminateLinkReq(gapMultiRole_TaskID, Handler, + HCI_DISCONNECT_REMOTE_USER_TERM)); +} + + + +/********************************************************************* + LOCAL FUNCTION PROTOTYPES +*/ +/********************************************************************* + @fn bdAddr2Str + + @brief Convert Bluetooth address to string. Only needed when + LCD display is used. + + @return none +*/ +char* bdAddr2Str( uint8* pAddr ) +{ + uint8 i; + char hex[] = "0123456789ABCDEF"; + static char str[B_ADDR_STR_LEN]; + char* pStr = str; + *pStr++ = '0'; + *pStr++ = 'x'; + // Start from end of addr + pAddr += B_ADDR_LEN; + + for ( i = B_ADDR_LEN; i > 0; i-- ) + { + *pStr++ = hex[*--pAddr >> 4]; + *pStr++ = hex[*pAddr & 0x0F]; + } + + *pStr = 0; + return str; +} + +/********************************************************************* + @fn gapRole_init + + @brief Initialization function for the GAP Role Task. + + @param none + + @return none +*/ +void GAPMultiRole_Init(uint8 taskId) +{ + gapMultiRole_TaskID = taskId; + multiSchedule_init( gapMultiRole_TaskID ); + osal_memset(&g_multiRoleParam,0,sizeof(GAPMultiRoleParam_t)); + #if(MAX_CONNECTION_MASTER_NUM > 0 ) + // Initialize GATT Client + GATT_InitClient(); + // Register to receive incoming ATT Indications/Notifications + GATT_RegisterForInd( gapMultiRole_TaskID ); + #endif +// Register with bond manager after starting device + GAPBondMgr_Register( (gapBondCBs_t*) &multiRoleBondCB ); +// GAP_RegisterForHCIMsgs( taskId ); +// HCI_PPLUS_AdvEventDoneNoticeCmd(gapMultiRole_TaskID,MULTI_ADV_EVENT_DONE_EVT); + osal_start_reload_timer(gapMultiRole_TaskID, MULTI_PERIOD_EVT, MULTI_PERIOD_TIMING); +} + +/** + @brief Establish a link to a peer device. + + Public function defined in central.h. +*/ +bStatus_t GAPMultiRole_EstablishLink(uint8 highDutyCycle, uint8 whiteList, + uint8 addrTypePeer, uint8* peerAddr) +{ + gapEstLinkReq_t params; + params.taskID = gapMultiRole_TaskID; + params.highDutyCycle = highDutyCycle; + params.whiteList = whiteList; + params.addrTypePeer = addrTypePeer; + osal_memcpy(params.peerAddr, peerAddr, B_ADDR_LEN); + return GAP_EstablishLinkReq(¶ms); +} + + +/********************************************************************* + @fn gapRole_taskFxn + + @brief Task entry point for the GAP Peripheral Role. + + @param a0 - first argument + @param a1 - second argument + + @return none +*/ +uint16 GAPMultiRole_ProcessEvent( uint8 task_id, uint16 events ) +{ + if ( events & SYS_EVENT_MSG ) + { + uint8* pMsg; + + if ( (pMsg = osal_msg_receive( gapMultiRole_TaskID )) != NULL ) + { + MultiRole_ProcessOSALMsg( (osal_event_hdr_t*)pMsg ); + // Release the OSAL message + VOID osal_msg_deallocate( pMsg ); + } + + // return unprocessed events + return (events ^ SYS_EVENT_MSG); + } + + if( events & MULTI_SCHEDULE_EVT) + { + multiScheduleProcess(); + return ( events ^ MULTI_SCHEDULE_EVT ); + } + + if( events & MULTI_ADV_EVENT_DONE_EVT ) + { +// MultiProcessAdvEvent(); + return ( events ^ MULTI_ADV_EVENT_DONE_EVT ); + } + + #if( MAX_CONNECTION_MASTER_NUM > 0 ) + + if( events & CONN_TIMEOUT_EVT ) + { + MultiRole_CancelConn(); + return ( events ^ CONN_TIMEOUT_EVT ); + } + + #endif + + if( events & MULTI_PERIOD_EVT ) + { + MultiPeriodProcessEvent(); + return ( events ^ MULTI_PERIOD_EVT ); + } + + return 0; +} + +/********************************************************************* + @fn gapRole_processStackMsg + + @brief Process an incoming task message. + + @param pMsg - message to process + + @return none +*/ +//static uint8 gapRole_processStackMsg(ICall_Hdr *pMsg) +static void MultiRole_ProcessOSALMsg( osal_event_hdr_t* pMsg ) +{ + // uint8 safeToDealloc = TRUE; + switch (pMsg->event) + { + case GAP_MSG_EVENT: + MultiRole_processGAPMsg((gapEventHdr_t*)pMsg); + break; + + case L2CAP_SIGNAL_EVENT: + { + } + break; + + case GATT_MSG_EVENT: + multiRoleProcessGATTMsg( (gattMsgEvent_t*) pMsg ); + break; + + default: + break; + } +} + + +/********************************************************************* + @fn gapRole_processGAPMsg + + @brief Process an incoming task message. + + @param pMsg - message to process + + @return none +*/ +static uint8 MultiRole_processGAPMsg(gapEventHdr_t* pMsg) +{ + switch (pMsg->opcode) + { + // Device initialized + case GAP_DEVICE_INIT_DONE_EVENT: + { + gapDeviceInitDoneEvent_t* pPkt = (gapDeviceInitDoneEvent_t*)pMsg; + bStatus_t stat = pPkt->hdr.status; + + if (stat == SUCCESS) + { + LOG("Device Init Done \n"); + LOG("BLE Multi-Role Address:" ); + LOG( bdAddr2Str( pPkt->devAddr ) ); + LOG("\n"); + LOG("HCI_LE PKT LEN %d\n",pPkt->dataPktLen); + LOG("HCI_LE NUM TOTAL %d\n",pPkt->numDataPkts); + } + else + { + LOG("Device Init Done ERR_Code 0x%02X\n",stat); + } + } + break; + #if( MAX_CONNECTION_SLAVE_NUM > 0 ) + + // Update advertising done + case GAP_ADV_DATA_UPDATE_DONE_EVENT: + { + gapAdvDataUpdateEvent_t* pPkt = (gapAdvDataUpdateEvent_t*)pMsg; + multiConfigSchAdv_param( pMsg->opcode,pPkt->hdr.status, pPkt->adType); + } + break; + + case GAP_MAKE_DISCOVERABLE_DONE_EVENT: + { + gapMakeDiscoverableRspEvent_t* pPkt = (gapMakeDiscoverableRspEvent_t*)pMsg; + multiConfigSchAdv_param( pMsg->opcode,pPkt->hdr.status, NULL); + } + break; + + case GAP_END_DISCOVERABLE_DONE_EVENT: + { + gapEndDiscoverableRspEvent_t* pPkt = (gapEndDiscoverableRspEvent_t*)pMsg; + multiConfigSchAdv_param( pMsg->opcode,pPkt->hdr.status, NULL); + } + break; + #endif + + // Connection formed + case GAP_LINK_ESTABLISHED_EVENT: + { + GAPMultiLinkInfo_t info; + gapEstLinkReqEvent_t* pPkt = (gapEstLinkReqEvent_t*)pMsg; + + if( pPkt->hdr.status == SUCCESS ) + { + info = multiConfigLink_status(pMsg->opcode,pMsg); + #if( MAX_CONNECTION_SLAVE_NUM > 0 ) + + if( info.value.role == Slave_Role ) + { +// gapBond_PairingMode[ pPkt->connectionHandle ] = GAPBOND_PAIRING_MODE_INITIATE ; + gapBond_PairingMode[ pPkt->connectionHandle ] = GAPBOND_PAIRING_MODE_NO_PAIRING ; + uint8 bondret = GAPBondMgr_LinkEst( pPkt->devAddrType, pPkt->devAddr, pPkt->connectionHandle, GAP_PROFILE_PERIPHERAL ); + LOG("GAPBondMgr_LinkEst SLAVE bondret %d\n",bondret); + // varify if enable connection parameter update? + uint8 param_update_enable = FALSE; + GAPMultiRole_GetParameter(GAPMULTIROLE_PARAM_UPDATE_ENABLE, ¶m_update_enable ); + + if( param_update_enable ) + { + // enable connection parameter update procedure + uint16 Conndelay = 0; + GAPMultiRole_GetParameter(TGAP_CONN_PAUSE_PERIPHERAL, &Conndelay ); + LOG("multitimer_init perIdx %d\n",info.value.perIdx); + multitimer_init(&g_peri_conn_update_timer[info.value.perIdx], Multi_peripheralUpdateParam, \ + Conndelay*1000, 0,info.value.perIdx); + g_peri_conn_update_timer[info.value.perIdx].valid = TRUE; + int ret = multitimer_start(&g_peri_conn_update_timer[info.value.perIdx]); + LOG("multitimer_start RET %d\n",ret); + } + } + + #endif + #if( MAX_CONNECTION_MASTER_NUM > 0 ) + + if( info.value.role == Master_Role ) + { + gapBond_PairingMode[ pPkt->connectionHandle ] = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ ; + osal_stop_timerEx(gapMultiRole_TaskID, CONN_TIMEOUT_EVT ); + multiDelCurrentConnNode(); +// uint8 bondret = GAPBondMgr_LinkEst( pPkt->devAddrType, pPkt->devAddr, pPkt->connectionHandle, GAP_PROFILE_CENTRAL ); +// LOG("GAPBondMgr_LinkEst MASTER bondret %d\n",bondret); + // TODO : read user area flash to check the action after establish success + // action_readFlash shall according different address + uint16 action_readFlash = 0; + uint16 action = g_multiRoleParam.link.actionAfterLink; + uint16 tAction = action ^ action_readFlash; + + // xor value tAction not null , means there's action(s) to be run + if( tAction ) + { + GAPMultiRoleCentralAction_t node; + node.connHandle = info.value.connHandle; + node.action = tAction; + node.busy = FALSE; + node.next = NULL; + + if(multiListInsertTail(MULTI_CONFIG_MASTER_ACTION_MODE,(void**)&g_centralAction,&node) ) + { + multiTimer tim_node; + osal_memset(&tim_node,0,sizeof(multiTimer)); + tim_node.next = NULL; + tim_node.id = info.value.connHandle; + + if(multiListInsertTail( MULTI_CENTRAL_ACTION_TIMER_MODE,(void**)&g_centralActionTimer,&tim_node ) ) + { + multiTimer* entry = multiListFindTail(MULTI_CENTRAL_ACTION_TIMER_MODE,(void**)&g_centralActionTimer); + multitimer_init(entry, Multi_centralAction,500, 1,info.value.connHandle); + multitimer_start(entry); + } + } + } + } + + #endif + } + + if( pGapRoles_AppCGs->pfnEstablish ) + pGapRoles_AppCGs->pfnEstablish(pPkt->hdr.status,info.value.connHandle,\ + ((Master_Role == info.value.role) ? Master_Role:Slave_Role),info.value.perIdx,pPkt->devAddr); + } + break; + + case GAP_LINK_TERMINATED_EVENT: + { + GAPMultiLinkInfo_t info; + gapTerminateLinkEvent_t* pPkt = (gapTerminateLinkEvent_t*)pMsg; + + if( pPkt->hdr.status == SUCCESS ) + { + info = multiConfigLink_status(pMsg->opcode,pMsg); + #if( MAX_CONNECTION_MASTER_NUM > 0 ) + multilist_free_central_action_actimerlist(pPkt->connectionHandle); + // if sdp not success + multilist_free_sdplist(pPkt->connectionHandle); + #endif + #if( MAX_CONNECTION_SLAVE_NUM > 0 ) + multitimer_stop(&g_peri_conn_update_timer[info.value.perIdx]); + multitimer_stop(&g_pcu_no_success_timer[ info.value.perIdx ]); + #endif + } + + if( pGapRoles_AppCGs->pfnTerminate ) + pGapRoles_AppCGs->pfnTerminate(info.value.connHandle,\ + ((Master_Role == info.value.role) ? Master_Role:Slave_Role),info.value.perIdx,pPkt->reason); + } + break; + + // Connection parameter update + case GAP_LINK_PARAM_UPDATE_EVENT: + { + gapLinkUpdateEvent_t* pPkt = (gapLinkUpdateEvent_t*)pMsg; + MultiRole_ProcessParamUpdateInfo(pPkt); + } + break; + #if( MAX_CONNECTION_MASTER_NUM > 0 ) + + case GAP_DEVICE_INFO_EVENT: + { + gapDeviceInfoEvent_t* pPkt = (gapDeviceInfoEvent_t*)pMsg; + multi_ScannerInsertDev( pPkt ); + + if( pGapRoles_AppCGs && pGapRoles_AppCGs->pfnEachScan ) + pGapRoles_AppCGs->pfnEachScan(pPkt); + } + break; + + case GAP_DEVICE_DISCOVERY_EVENT: + { + if( pGapRoles_AppCGs && pGapRoles_AppCGs->pfnScanDone ) + pGapRoles_AppCGs->pfnScanDone(g_scanlist); + + multiListMemoryFree(MULTI_SCAN_MODE); + multiConfigSchScan_param(); + } + break; + + // Security request received from slave + case GAP_SLAVE_REQUESTED_SECURITY_EVENT: + { + LOG("GAP slave requested security event \n"); + // copy from central.c --> temporary walkaround + GAPBondMgr_ProcessGAPMsg( pMsg ); + } + break; + #endif + + default: + break; + } + + return TRUE; +} + + +/********************************************************************* + @fn multiRoleProcessGATTMsg + + @brief Process GATT messages + + @return none +*/ +static void multiRoleProcessGATTMsg( gattMsgEvent_t* pMsg ) +{ + #if( MAX_CONNECTION_MASTER_NUM > 0 ) + uint16 handle = pMsg->connHandle; + + switch( pMsg->method ) + { + case ATT_EXCHANGE_MTU_RSP: + { + LOG("connHand %d,exchangeMTU status %d,rxMTU %d\n", pMsg->connHandle,\ + pMsg->hdr.status,\ + pMsg->msg.exchangeMTURsp.serverRxMTU); + GAPMultiRoleCentralAction_t* action_node = NULL; + action_node = multiList_inside(MULTI_CONFIG_MASTER_ACTION_MODE,(void**)&g_centralAction,&handle); + + if( action_node ) + action_node->busy = FALSE; + } + break; + + case ATT_READ_RSP: + if( pMsg->hdr.status == SUCCESS ) + { + LOG("Read Success Handle %d,len %d ",pMsg->connHandle,pMsg->msg.readRsp.len ); + + for( uint8 i=0; i < pMsg->msg.readRsp.len; i++) + LOG("0x%02X,",pMsg->msg.readRsp.value[i]); + + LOG("\n"); + } + + break; + + case ATT_WRITE_REQ: + if( pMsg->hdr.status == SUCCESS ) + { + LOG( "Write sent connHandle %d\n",pMsg->connHandle ); + } + + break; + + case ATT_HANDLE_VALUE_NOTI: + if( pMsg->hdr.status == SUCCESS ) + { + if( pGapRoles_AppCGs && pGapRoles_AppCGs->dataNotify ) + pGapRoles_AppCGs->dataNotify( pMsg->connHandle, pMsg->msg.handleValueNoti.len, pMsg->msg.handleValueNoti.value ); + } + + break; + + case ATT_READ_BY_GRP_TYPE_RSP: + case ATT_READ_BY_TYPE_RSP: + MultiRole_ProcessSDPInfo(pMsg); + break; + + case ATT_ERROR_RSP: + switch( pMsg->msg.errorRsp.reqOpcode ) + { + case ATT_READ_REQ: + LOG( "Read Error %d\n", pMsg->msg.errorRsp.errCode ); + break; + + case ATT_WRITE_REQ: + LOG( "Write Error: %d\n", pMsg->msg.errorRsp.errCode ); + break; + + case ATT_HANDLE_VALUE_NOTI: + LOG( "Notify Error: %d\n", pMsg->msg.errorRsp.errCode ); + break; + + default: + LOG( "connHandle %d,ATT_ERROR_RSP %d\n", handle,pMsg->msg.errorRsp.reqOpcode ); + break; + } + + break; + + default: + break; + } + + #endif +} + +/********************************************************************* + @fn MultiRole_SetupGAP + + @brief Call the GAP Device Initialization function using the + Profile Parameters. Negotiate the maximum number + of simultaneous connections with the stack. + + @param numConns - desired number of simultaneous connections + + @return none +*/ +static void MultiRole_SetupGAP(uint8* numConns) +{ + // Set number of possible simultaneous connections + *numConns = linkDBNumConns; + uint8 maxScanNum = 0; + #if (MAX_CONNECTION_MASTER_NUM > 0 ) + maxScanNum = g_multiRoleParam.scan.maxScanRes; + LOG("maxScanNum %d\n",maxScanNum); + #endif + bStatus_t ret= GAP_DeviceInit( gapMultiRole_TaskID, g_multiRoleParam.common.profileRole, maxScanNum, + g_multiRoleParam.common.IRK, g_multiRoleParam.common.SRK, + (uint32*)&g_multiRoleParam.common.signCounter); + LOG("%s,ret %d\n",__func__,ret); +} + +void multiRolePasscodeCB( uint8* deviceAddr, uint16 connectionHandle, + uint8 uiInputs, uint8 uiOutputs ) +{ + uint32 passcode = 0; + LOG("pass code CB connHandle 0x%02X,uiInputs:0x%x,uiOutputs:0x%x\n",connectionHandle,uiInputs,uiOutputs); + GAPBondMgr_GetParameter( GAPBOND_DEFAULT_PASSCODE,&passcode); + LOG("passcode %d\n",passcode); +// GAP_PasscodeUpdate(passcode,connectionHandle); + GAPBondMgr_PasscodeRsp(connectionHandle,SUCCESS,passcode); +} +void multiRolePairStateCB( uint16 connHandle, uint8 state, uint8 status ) +{ + LOG("PairStateCB handle 0x%02X,status %d,state 0x%X\n",connHandle,status,state); + + if ( state == GAPBOND_PAIRING_STATE_STARTED ) + { + LOG( "Pairing started connHandle %d\n",connHandle); + } + else if (( state == GAPBOND_PAIRING_STATE_COMPLETE ) || ( state == GAPBOND_PAIRING_STATE_BONDED ) ) + { + if ( status == SUCCESS ) + { + #if( MAX_CONNECTION_MASTER_NUM > 0 ) + LOG( "Pairing & Bonding success,connHandle %d , and start SDP \n",connHandle); + GAPMultiRole_CentralSDP_t sdp_node; + osal_memset(&sdp_node, 0,sizeof(GAPMultiRole_CentralSDP_t)); + sdp_node.connHandle = connHandle; + multiListInsertTail(MULTI_CENTRAL_SDP_MODE,(void**)&g_centralSDPlist,&sdp_node); + #endif + #if( MAX_CONNECTION_SLAVE_NUM > 0 ) + #endif + } + else + { + LOG( "Pairing fail connHandle %d\n",connHandle); + } + } +} + +static void MultiPeriodProcessEvent(void) +{ +// LOG("%s\n",__func__); + multitimer_ticks( MULTI_PERIOD_TIMING ); + multitimer_loop(); +} + +#if( MAX_CONNECTION_SLAVE_NUM > 0 ) + +static void Multi_peripheralUpdateParam(uint16 idx) +{ + LOG("%s idx %d\n",__func__,idx); + MultiRole_PeripheralstartConnUpdate(idx,paramUpdateNoSuccessOption ); +} + +static void MultiRole_PeripheralstartConnUpdate( uint8 idx,uint8 handleFailure ) +{ + LOG("%s idx %d\n",__func__,idx); + l2capParamUpdateReq_t updateReq; + uint16 timeout = GAP_GetParamValue( TGAP_CONN_PARAM_TIMEOUT ); + uint16 desired_min_interval; + uint16 desired_max_interval; + uint16 desired_slave_latency; + uint16 desired_conn_timeout ; + GAPMultiRole_GetParameter( GAPMULTIROLE_MIN_CONN_INTERVAL, &desired_min_interval ); + GAPMultiRole_GetParameter( GAPMULTIROLE_MAX_CONN_INTERVAL, &desired_max_interval ); + GAPMultiRole_GetParameter( GAPMULTIROLE_SLAVE_LATENCY,&desired_slave_latency ); + GAPMultiRole_GetParameter( GAPMULTIROLE_TIMEOUT_MULTIPLIER, &desired_conn_timeout ); + updateReq.intervalMin = desired_min_interval; + updateReq.intervalMax = desired_max_interval; + updateReq.slaveLatency = desired_slave_latency; + updateReq.timeoutMultiplier = desired_conn_timeout; + uint16 connHandle = multiLinkStatusGetSlaveConnHandle( idx ); + LOG("idx %d,connHandle %d\n",idx,connHandle); + L2CAP_ConnParamUpdateReq( connHandle, &updateReq, gapMultiRole_TaskID ); + multitimer_init(&g_pcu_no_success_timer[idx], MultiRole_HandleParamUpdateNoSuccess, \ + timeout, 0,idx); + multitimer_start(&g_pcu_no_success_timer[idx]); +} + +static void MultiRole_HandleParamUpdateNoSuccess( uint16 idx ) +{ + LOG("%s\n",__func__); + + // See which option was choosen for unsuccessful updates + switch ( paramUpdateNoSuccessOption ) + { + case MULTIROLE_RESEND_PARAM_UPDATE: + Multi_peripheralUpdateParam( idx ); + break; + + case MULTIROLE_TERMINATE_LINK: + break; + + case MULTIROLE_NO_ACTION: + + // fall through + default: + //do nothing + break; + } +} +#endif + +static void MultiRole_ProcessParamUpdateInfo(gapLinkUpdateEvent_t* pPkt) +{ + if ( pPkt->hdr.status == SUCCESS ) + { + LOG("handle %d,Intv %d,latency %d,TO %d\n", pPkt->connectionHandle,\ + pPkt->connInterval,\ + pPkt->connLatency,\ + pPkt->connTimeout); + #if( MAX_CONNECTION_SLAVE_NUM > 0 ) + // stop no success timer + uint8 perIdx = multiLinkConnParamUpdate( pPkt ); + + if( perIdx < MAX_CONNECTION_SLAVE_NUM ) + multitimer_stop(&g_pcu_no_success_timer[ perIdx ]); + + #endif + #if( MAX_CONNECTION_MASTER_NUM > 0 ) + // for multi-role as master not support parameter update + GAPMultiRoleLinkCtrl_t* LinkInfoTmp = g_multiLinkInfo; + + while( LinkInfoTmp != NULL ) + { + if( ( Master_Role == LinkInfoTmp->RoleState ) && (( LinkInfoTmp->connectionHandle & 0x0fff) == pPkt->connectionHandle )) + { + uint8 bondret = GAPBondMgr_LinkEst( LinkInfoTmp->peerDevAddrType,LinkInfoTmp->peerDevAddr, pPkt->connectionHandle, GAP_PROFILE_CENTRAL ); + break; + } + + LinkInfoTmp = LinkInfoTmp->next; + } + + #endif + } + else + { + LOG("ParamUpdateInfo error status %d\n",pPkt->hdr.status); + } +} + + +#if( MAX_CONNECTION_MASTER_NUM > 0 ) +/** + @brief Start a device discovery scan. + + Public function defined in central.h. +*/ +bStatus_t GAPMultiRole_StartDiscovery(uint8 mode, uint8 activeScan, uint8 whiteList) +{ + gapDevDiscReq_t params; + params.taskID = gapMultiRole_TaskID; + params.mode = mode; + params.activeScan = activeScan; + params.whiteList = whiteList; + return GAP_DeviceDiscoveryRequest(¶ms); +} + +/** + @brief Cancel a device discovery scan. + + Public function defined in central.h. +*/ +bStatus_t GAPMultiRole_CancelDiscovery(void) +{ + return GAP_DeviceDiscoveryCancel(gapMultiRole_TaskID); +} + + +void multiGetScanStrategy(uint8* param,uint8 len) +{ + if( len == 3 ) + { + param[0] = g_multiRoleParam.scan.scanMode; + param[1] = g_multiRoleParam.scan.activeScan; + param[2] = g_multiRoleParam.scan.whitelist; + } +} + +void multiGetLinkStrategy(uint8* param,uint8 len) +{ + if( len == 2 ) + { + param[0] = g_multiRoleParam.link.highDutyCycle; + param[1] = g_multiRoleParam.link.whitelist; + } +} + +void multi_ScannerInsertDev(gapDeviceInfoEvent_t* pMsg) +{ + GAPMultiRolScanner_t* node = (GAPMultiRolScanner_t*)multiList_inside(MULTI_SCAN_MODE,(void**)&g_scanlist, pMsg->addr); + + if( node ) + { + // already in g_scanlist + // update rssi + node->rssi = pMsg->rssi; + + // TODO: there's osal_mem_free will result memory leak ? + if( pMsg->eventType == LL_ADV_RPT_SCAN_RSP ) + { + // update scanner scan response data + if( node->rspData ) + osal_mem_free( node->rspData ); + + node->scanRsplen = pMsg->dataLen; + node->rspData = osal_mem_alloc( node->scanRsplen ); + + if( node->rspData ) + { + osal_memset(node->rspData, 0, node->scanRsplen ); + osal_memcpy( node->rspData,pMsg->pEvtData,node->scanRsplen); + } + } + else + { + // update scanner advertising data + if( node->advData ) + osal_mem_free( node->advData ); + + node->advDatalen = pMsg->dataLen; + node->advData = osal_mem_alloc( node->advDatalen ); + + if( node->advData ) + { + osal_memset(node->advData, 0, node->advDatalen ); + osal_memcpy( node->advData,pMsg->pEvtData,node->advDatalen); + } + } + } + else + { + GAPMultiRolScanner_t pVnode; + osal_memset( &pVnode,0,sizeof(GAPMultiRolScanner_t)); + pVnode.rssi = pMsg->rssi; + pVnode.addrtype = pMsg->addrType; + osal_memcpy(pVnode.addr, pMsg->addr,B_ADDR_LEN); + + // for ADV_IND, shall not necessary , + // consider another type advertising + if( pMsg->eventType == LL_ADV_RPT_SCAN_RSP ) + { + pVnode.scanRsplen = pMsg->dataLen; + pVnode.rspData = osal_mem_alloc( pVnode.scanRsplen ); + + if( pVnode.rspData ) + { + osal_memset(pVnode.rspData, 0, pVnode.scanRsplen ); + osal_memcpy( pVnode.rspData,pMsg->pEvtData,pVnode.scanRsplen); + } + } + else + { + pVnode.advDatalen = pMsg->dataLen; + pVnode.advData = osal_mem_alloc( pVnode.advDatalen ); + + if( pVnode.advData ) + { + osal_memset(pVnode.advData, 0, pVnode.advDatalen ); + osal_memcpy( pVnode.advData,pMsg->pEvtData,pVnode.advDatalen); + } + } + + multiListInsertTail(MULTI_SCAN_MODE,(void**)&g_scanlist,&pVnode); + } +} + +uint8 multiConfigSlaveList( uint8 addrType,uint8* addr) +{ + uint8 resault = FALSE; + + if( NULL == multiList_inside(MULTI_CONFIG_SLAVE_DEV_MODE,(void**)&g_cfgSlaveList,addr) ) + { + GAPMultiRoleCentralDev_t node; + osal_memset(&node,0,sizeof(GAPMultiRoleCentralDev_t)); + node.next = NULL; + node.addrType = addrType; + osal_memcpy(node.addr,addr,B_ADDR_LEN ); + resault = multiListInsertTail(MULTI_CONFIG_SLAVE_DEV_MODE,(void**)&g_cfgSlaveList,&node); + } + + return resault; +} +uint8 multiClearSlaveList( uint8 addrType,uint8* addr) +{ + if( multiList_inside(MULTI_CONFIG_SLAVE_DEV_MODE,(void**)&g_cfgSlaveList,addr) ) + { + multiListDelNode(MULTI_CONFIG_SLAVE_DEV_MODE,(void**)&g_cfgSlaveList,addr); + } + + return TRUE; +} + +void multiClearAllSlaveList(void) +{ + GAPMultiRoleCentralDev_t* node = g_cfgSlaveList; + + while( node != NULL ) + { + g_cfgSlaveList = node->next; + osal_mem_free( node ); + node = g_cfgSlaveList; + } +} + +GAPMultiRoleCentralDev_t* multiGetConfigSlaveList(void) +{ + return g_cfgSlaveList; +} + +uint8 multiDevInConfSlaveList(uint8* addr) +{ + uint8 inFlag = FALSE; + GAPMultiRoleCentralDev_t* node = (GAPMultiRoleCentralDev_t*)multiList_inside(MULTI_CONFIG_SLAVE_DEV_MODE,(void**)&g_cfgSlaveList,addr); + + if( node ) + inFlag = TRUE; + + return inFlag; +} + +void multiAddSlaveConnList( uint8 addrType,uint8* addr) +{ + GAPMultiRoleCentralDev_t node; + osal_memset(&node,0,sizeof(GAPMultiRoleCentralDev_t)); + node.next = NULL; + node.addrType = addrType; + osal_memcpy(node.addr,addr,B_ADDR_LEN ); + multiListInsertTail(MULTI_CONFIG_MASTER_LINKING_MODE,(void**)&g_mlinkingList,&node); +} + +void multiDelCurrentConnNode(void) +{ + // use first node + if( g_mlinkingList ) + { + GAPMultiRoleCentralDev_t* node = g_mlinkingList->next; + osal_memset(g_mlinkingList,0,sizeof(GAPMultiRoleCentralDev_t)); + osal_mem_free(g_mlinkingList); + + if( node == NULL ) + { + // only one node + g_mlinkingList = NULL; + } + else + { + g_mlinkingList = node; + } + } +} + +uint8 multi_devInLinkList(uint8* addr) +{ + uint8 inFlag = FALSE; + GAPMultiRoleCentralDev_t* node = multiList_inside(MULTI_CONFIG_MASTER_LINKING_MODE,(void**)&g_mlinkingList,addr); + + if( node ) + inFlag = TRUE; + + return inFlag; +} + +GAPMultiRoleCentralDev_t* multiGetSlaveConnList(void) +{ + return g_mlinkingList; +} + +uint8 MultiRole_CancelConn(void) +{ + uint8 status = GAPMultiRole_TerminateConnection(GAP_CONNHANDLE_INIT); + return SUCCESS; +} + +static void Multi_centralAction(uint16 idx) +{ + multiTimer* atim_node = multiList_inside(MULTI_CENTRAL_ACTION_TIMER_MODE,(void**)&g_centralActionTimer,&idx); + GAPMultiRoleCentralAction_t* action_node = multiList_inside(MULTI_CONFIG_MASTER_ACTION_MODE,(void**)&g_centralAction,&idx); + + if( atim_node && action_node ) + { + if( action_node->busy ) + return; + + if( action_node->action & GAPMULTI_CENTRAL_MTU_EXCHANGE ) + { + ATT_SetMTUSizeMax( DEFAULT_EXCHANGE_MTU_LEN ); + attExchangeMTUReq_t pReq; + pReq.clientRxMTU = DEFAULT_EXCHANGE_MTU_LEN; + uint8 status =GATT_ExchangeMTU( idx,&pReq, gapMultiRole_TaskID ); + + if( status == SUCCESS ) + { + action_node->busy = TRUE; + action_node->action &= ~GAPMULTI_CENTRAL_MTU_EXCHANGE; + } + } + else if( action_node->action & GAPMULTI_CENTRAL_DLE_EXCHANGE ) + { + uint8 status = HCI_LE_SetDataLengthCmd(idx,251, 2120); + + if( status == SUCCESS ) + { + action_node->action &= ~GAPMULTI_CENTRAL_DLE_EXCHANGE; + } + } + else if( action_node->action & GAPMULTI_CENTRAL_SDP ) + { + GAPMultiRole_CentralSDP_t* sdp_node = multiList_inside(MULTI_CENTRAL_SDP_MODE,(void**)&g_centralSDPlist,&idx); + + if( sdp_node ) + { + if( sdp_node->state == DISC_STATE_IDLE ) + { + bStatus_t ret = GATT_DiscAllPrimaryServices(idx,gapMultiRole_TaskID); + + if( ret == SUCCESS ) + { + action_node->busy = TRUE; + sdp_node->state = DISC_STATE_SVC; + } + } + } + } + } +} + +static void MultiRole_ProcessSDPInfo(gattMsgEvent_t* pMsg) +{ + GAPMultiRole_CentralSDP_t* sdp_node = multiList_inside(MULTI_CENTRAL_SDP_MODE,(void**)&g_centralSDPlist,&pMsg->connHandle); + + if( sdp_node ) + { + switch ( pMsg->method ) + { + case ATT_READ_BY_GRP_TYPE_RSP: + { + if( pMsg->msg.readByGrpTypeRsp.numGrps > 0 ) + { + for(uint8 i = 0 ; i < pMsg->msg.readByGrpTypeRsp.numGrps; i++) + { + GATTReadGroupRsp primserv_node; + primserv_node.StHandle = BUILD_UINT16( pMsg->msg.readByGrpTypeRsp.dataList[pMsg->msg.readByGrpTypeRsp.len * i], \ + pMsg->msg.readByGrpTypeRsp.dataList[pMsg->msg.readByGrpTypeRsp.len * i + 1]); + primserv_node.EGHandle = BUILD_UINT16( pMsg->msg.readByGrpTypeRsp.dataList[pMsg->msg.readByGrpTypeRsp.len * i+2], \ + pMsg->msg.readByGrpTypeRsp.dataList[pMsg->msg.readByGrpTypeRsp.len * i + 3]); + primserv_node.uuid_Len = pMsg->msg.readByGrpTypeRsp.len - 4; + osal_memcpy(primserv_node.uuid,\ + &(pMsg->msg.readByGrpTypeRsp.dataList[pMsg->msg.readByGrpTypeRsp.len * i + 4]),\ + primserv_node.uuid_Len); + multiListInsertTail(MULTI_CENTRAL_SDP_PRIMSERV_MODE,(void**)&sdp_node->service.PrimServ,&primserv_node); + } + } + else if( pMsg->hdr.status == bleProcedureComplete ) + { + GATT_DiscAllChars( pMsg->connHandle,sdp_node->service.PrimServ->StHandle,\ + sdp_node->service.PrimServ->EGHandle,gapMultiRole_TaskID ); + } + else if( pMsg->method == ATT_ERROR_RSP ) + { + LOG("SDP primary service error connHandle %d\n",pMsg->connHandle); + } + } + break; + + case ATT_READ_BY_TYPE_RSP: + { + if ( pMsg->msg.readByTypeRsp.numPairs > 0 ) + { + for(uint8 i = 0; i < pMsg->msg.readByTypeRsp.numPairs ; i++) + { + Characteristic char_node; + char_node.charHandle = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[pMsg->msg.readByTypeRsp.len * i], \ + pMsg->msg.readByTypeRsp.dataList[pMsg->msg.readByTypeRsp.len * i + 1]); + char_node.Properties = pMsg->msg.readByTypeRsp.dataList[pMsg->msg.readByTypeRsp.len * i + 2]; + char_node.valueHandle = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[pMsg->msg.readByTypeRsp.len * i+3], \ + pMsg->msg.readByTypeRsp.dataList[pMsg->msg.readByTypeRsp.len * i + 4]); + char_node.uuid_Len = pMsg->msg.readByTypeRsp.len - 5; + osal_memcpy(char_node.uuid,&(pMsg->msg.readByTypeRsp.dataList[pMsg->msg.readByTypeRsp.len * i + 5]),char_node.uuid_Len); + multiListInsertTail(MULTI_CENTRAL_SDP_CHARAC_MODE,(void**)&sdp_node->service.Charac,&char_node); + sdp_node->sdpCharHandle = char_node.valueHandle; + } + } + else if( pMsg->hdr.status == bleProcedureComplete ) + { + GATTReadGroupRsp* next_prim_node = multiList_inside(MULTI_CENTRAL_SDP_PRIMSERV_MODE,(void**)&sdp_node->service.PrimServ, &sdp_node->sdpCharHandle); + + if( next_prim_node ) + { + GATT_DiscAllChars( pMsg->connHandle,next_prim_node->StHandle,\ + next_prim_node->EGHandle,gapMultiRole_TaskID ); + } +// else if( sdp_node->sdpCharHandle < 0xFFFF) + else + { + LOG("All Characteristic Discover Success pMsg->connHandle %d\n",pMsg->connHandle); + + if( pGapRoles_AppCGs && pGapRoles_AppCGs->SDPNotify ) + pGapRoles_AppCGs->SDPNotify( sdp_node ); + + multilist_free_central_action_actimerlist( pMsg->connHandle ); + multilist_free_sdplist(pMsg->connHandle); + } + } + else if( pMsg->method == ATT_ERROR_RSP ) + { + LOG("SDP Characteristic error connHandle %d\n",pMsg->connHandle); + } + } + + default: + break; + } + } +} + +static void multilist_free_central_action_actimerlist( uint16 connHandle ) +{ + multiListDelNode( MULTI_CONFIG_MASTER_ACTION_MODE, (void**)&g_centralAction,&connHandle ); + // + multiTimer* entry = multiList_inside(MULTI_CENTRAL_ACTION_TIMER_MODE,(void**)&g_centralActionTimer, &connHandle ); + multitimer_stop( entry ); + multiListDelNode( MULTI_CENTRAL_ACTION_TIMER_MODE, (void**)&g_centralActionTimer,&connHandle ); +} + +static void multilist_free_sdplist(uint16 connHandle) +{ + multiListDelNode( MULTI_CENTRAL_SDP_MODE, (void**)&g_centralSDPlist,&connHandle); +} + +static void* multiListCreate(GAPMultiListMode_t mode ) +{ + void* node = NULL ; + + switch( mode ) + { + case MULTI_SCAN_MODE: + { + GAPMultiRolScanner_t* tnode = (GAPMultiRolScanner_t*)osal_mem_alloc( sizeof( GAPMultiRolScanner_t ) ); + + if( tnode ) + { + osal_memset( tnode, 0, sizeof( sizeof( GAPMultiRolScanner_t ) ) ); + // TODO: tnode->next can not clear to zero after osal_memset, why? + tnode->next = NULL; + } + + node = (GAPMultiRolScanner_t*)tnode; + } + break; + + case MULTI_CONFIG_SLAVE_DEV_MODE: + case MULTI_CONFIG_MASTER_LINKING_MODE: + { + GAPMultiRoleCentralDev_t* tnode = (GAPMultiRoleCentralDev_t*)osal_mem_alloc( sizeof( GAPMultiRoleCentralDev_t ) ); + + if( tnode ) + { + osal_memset( tnode, 0, sizeof( sizeof( GAPMultiRoleCentralDev_t ) ) ); + // TODO: tnode->next can not clear to zero after osal_memset, why? + tnode->next = NULL; + } + + node = (GAPMultiRoleCentralDev_t*)tnode; + } + break; + + case MULTI_CONFIG_MASTER_ACTION_MODE: + { + GAPMultiRoleCentralAction_t* tnode = (GAPMultiRoleCentralAction_t*)osal_mem_alloc( sizeof( GAPMultiRoleCentralAction_t ) ); + + if( tnode ) + { + osal_memset( tnode, 0, sizeof( sizeof( GAPMultiRoleCentralAction_t ) ) ); + // TODO: tnode->next can not clear to zero after osal_memset, why? + tnode->next = NULL; + } + + node = (GAPMultiRoleCentralAction_t*)tnode; + } + break; + + case MULTI_CENTRAL_ACTION_TIMER_MODE: + { + multiTimer* tnode = (multiTimer*)osal_mem_alloc( sizeof( multiTimer ) ); + + if( tnode ) + { + osal_memset( tnode, 0, sizeof( sizeof( multiTimer ) ) ); + // TODO: tnode->next can not clear to zero after osal_memset, why? + tnode->next = NULL; + } + + node = (multiTimer*)tnode; + } + break; + + case MULTI_CENTRAL_SDP_MODE: + { + GAPMultiRole_CentralSDP_t* tnode = (GAPMultiRole_CentralSDP_t*)osal_mem_alloc( sizeof( GAPMultiRole_CentralSDP_t ) ); + + if( tnode ) + { + osal_memset( tnode, 0, sizeof( sizeof( GAPMultiRole_CentralSDP_t ) ) ); + // TODO: tnode->next can not clear to zero after osal_memset, why? + tnode->next = NULL; + } + + node = (GAPMultiRole_CentralSDP_t*)tnode; + } + break; + + case MULTI_CENTRAL_SDP_PRIMSERV_MODE: + { + GATTReadGroupRsp* tnode = (GATTReadGroupRsp*)osal_mem_alloc( sizeof( GATTReadGroupRsp ) ); + + if( tnode ) + { + osal_memset( tnode, 0, sizeof( sizeof( GATTReadGroupRsp ) ) ); + // TODO: tnode->next can not clear to zero after osal_memset, why? + tnode->next = NULL; + } + + node = (GATTReadGroupRsp*)tnode; + } + break; + + case MULTI_CENTRAL_SDP_CHARAC_MODE: + { + Characteristic* tnode = (Characteristic*)osal_mem_alloc( sizeof( Characteristic ) ); + + if( tnode ) + { + osal_memset( tnode, 0, sizeof( sizeof( Characteristic ) ) ); + // TODO: tnode->next can not clear to zero after osal_memset, why? + tnode->next = NULL; + } + + node = (Characteristic*)tnode; + } + break; + + default: + break; + } + + return node; +} + +static void* multiListFindTail(GAPMultiListMode_t mode, void** ppnode) +{ + // TODO : ppnode shall not be NULL , + void* node = NULL ; + + switch( mode ) + { + case MULTI_SCAN_MODE: + { + GAPMultiRolScanner_t* entry = *(GAPMultiRolScanner_t**)ppnode; + + while( entry ) + { + if(entry->next == NULL ) + break; + + entry = entry->next; + } + + node = entry; + } + break; + + case MULTI_CONFIG_SLAVE_DEV_MODE: + case MULTI_CONFIG_MASTER_LINKING_MODE: + { + GAPMultiRoleCentralDev_t* entry = *(GAPMultiRoleCentralDev_t**)ppnode; + + while( entry ) + { + if(entry->next == NULL ) + break; + + entry = entry->next; + } + + node = entry; + } + break; + + case MULTI_CONFIG_MASTER_ACTION_MODE: + { + GAPMultiRoleCentralAction_t* entry = *(GAPMultiRoleCentralAction_t**)ppnode; + + while( entry ) + { + if(entry->next == NULL ) + break; + + entry = entry->next; + } + + node = entry; + } + break; + + case MULTI_CENTRAL_ACTION_TIMER_MODE: + { + multiTimer* entry = *(multiTimer**)ppnode; + + while( entry ) + { + if(entry->next == NULL ) + break; + + entry = entry->next; + } + + node = entry; + } + break; + + case MULTI_CENTRAL_SDP_MODE: + { + GAPMultiRole_CentralSDP_t* entry = *(GAPMultiRole_CentralSDP_t**)ppnode; + + while( entry ) + { + if(entry->next == NULL ) + break; + + entry = entry->next; + } + + node = entry; + } + break; + + case MULTI_CENTRAL_SDP_PRIMSERV_MODE: + { + GATTReadGroupRsp* entry = *(GATTReadGroupRsp**)ppnode; + + while( entry ) + { + if(entry->next == NULL ) + break; + + entry = entry->next; + } + + node = entry; + } + break; + + case MULTI_CENTRAL_SDP_CHARAC_MODE: + { + Characteristic* entry = *(Characteristic**)ppnode; + + while( entry ) + { + if(entry->next == NULL ) + break; + + entry = entry->next; + } + + node = entry; + } + break; + + default: + break; + } + + return node; +} + +static void multiListDelNode(GAPMultiListMode_t mode, void** ppnode, void* pvalue ) +{ + switch( mode ) + { + case MULTI_CONFIG_SLAVE_DEV_MODE: + { + for( GAPMultiRoleCentralDev_t** curr = (GAPMultiRoleCentralDev_t**)ppnode; *curr;) + { + GAPMultiRoleCentralDev_t* entry = *curr; + + if( osal_memcmp(entry->addr,(uint8*)pvalue,B_ADDR_LEN) == TRUE ) + { + *curr = entry->next; + osal_mem_free( entry ); + break; + } + else + curr = &entry->next; + } + } + break; + + case MULTI_CONFIG_MASTER_ACTION_MODE: + { + for( GAPMultiRoleCentralAction_t** curr = (GAPMultiRoleCentralAction_t**)ppnode; *curr;) + { + GAPMultiRoleCentralAction_t* entry = *curr; + + if( entry == NULL ) + break; + + if( entry->connHandle == *(uint16*)pvalue ) + { + *curr = entry->next; + osal_mem_free( entry ); + break; + } + else + curr = &entry->next; + } + } + break; + + case MULTI_CENTRAL_ACTION_TIMER_MODE: + { + for( multiTimer** curr = (multiTimer**)ppnode; *curr;) + { + multiTimer* entry = *curr; + + if( entry == NULL ) + break; + + if( entry->id == *(uint16*)pvalue ) + { + *curr = entry->next; + osal_mem_free( entry ); + break; + } + else + curr = &entry->next; + } + } + break; + + case MULTI_CENTRAL_SDP_MODE: + { + for( GAPMultiRole_CentralSDP_t** curr = (GAPMultiRole_CentralSDP_t**)ppnode; *curr;) + { + GAPMultiRole_CentralSDP_t* entry = *curr; + + if( entry == NULL ) + break; + + if( entry->connHandle == *(uint16*)pvalue ) + { + *curr = entry->next; + GATTReadGroupRsp* primservice = entry->service.PrimServ; + + while( primservice ) + { + osal_mem_free( primservice ); + primservice = primservice->next; + } + + Characteristic* charac = entry->service.Charac; + + while( charac ) + { + osal_mem_free( charac ); + charac = charac->next; + } + + osal_mem_free( entry ); + break; + } + else + curr = &entry->next; + } + } + break; + + default: + break; + } +} + +static uint8 multiListInsertTail(GAPMultiListMode_t mode, void** ppnode,void* vnode) +{ + volatile uint8 ret = FALSE; + + switch( mode ) + { + case MULTI_SCAN_MODE: + { + GAPMultiRolScanner_t** curr = (GAPMultiRolScanner_t**)ppnode; + GAPMultiRolScanner_t* new_node = multiListCreate( mode ); + + if( new_node ) + { + osal_memcpy( new_node, (GAPMultiRolScanner_t*)vnode, sizeof( GAPMultiRolScanner_t ) ); + new_node->next = NULL; + GAPMultiRolScanner_t* entry = multiListFindTail(mode,(void**)ppnode); + + if( entry == NULL ) + { + *curr = new_node; + } + else + { + entry->next = new_node; + } + + ret = TRUE; + } + } + break; + + case MULTI_CONFIG_SLAVE_DEV_MODE: + case MULTI_CONFIG_MASTER_LINKING_MODE: + { + GAPMultiRoleCentralDev_t** curr = (GAPMultiRoleCentralDev_t**)ppnode; + GAPMultiRoleCentralDev_t* new_node = multiListCreate( mode ); + + if( new_node ) + { + osal_memcpy( new_node, (GAPMultiRoleCentralDev_t*)vnode, sizeof( GAPMultiRoleCentralDev_t ) ); + new_node->next = NULL; + GAPMultiRoleCentralDev_t* entry = multiListFindTail(mode,(void**)ppnode); + + if( entry == NULL ) + { + *curr = new_node; + } + else + { + entry->next = new_node; + } + + ret = TRUE; + } + } + break; + + case MULTI_CONFIG_MASTER_ACTION_MODE: + { + GAPMultiRoleCentralAction_t** curr = (GAPMultiRoleCentralAction_t**)ppnode; + GAPMultiRoleCentralAction_t* new_node = multiListCreate( mode ); + + if( new_node ) + { + osal_memcpy( new_node, (GAPMultiRoleCentralAction_t*)vnode, sizeof( GAPMultiRoleCentralAction_t ) ); + new_node->next = NULL; + GAPMultiRoleCentralAction_t* entry = multiListFindTail(mode,(void**)ppnode); + + if( entry == NULL ) + { + *curr = new_node; + } + else + { + entry->next = new_node; + } + + ret = TRUE; + } + } + break; + + case MULTI_CENTRAL_ACTION_TIMER_MODE: + { + multiTimer** curr = (multiTimer**)ppnode; + multiTimer* new_node = multiListCreate( mode ); + + if( new_node ) + { + osal_memcpy( new_node, (multiTimer*)vnode, sizeof( multiTimer ) ); + new_node->next = NULL; + multiTimer* entry = multiListFindTail(mode,(void**)ppnode); + + if( entry == NULL ) + { + *curr = new_node; + } + else + { + entry->next = new_node; + } + + ret = TRUE; + } + } + break; + + case MULTI_CENTRAL_SDP_MODE: + { + GAPMultiRole_CentralSDP_t** curr = (GAPMultiRole_CentralSDP_t**)ppnode; + GAPMultiRole_CentralSDP_t* new_node = multiListCreate( mode ); + + if( new_node ) + { + osal_memcpy( new_node, (GAPMultiRole_CentralSDP_t*)vnode, sizeof( GAPMultiRole_CentralSDP_t ) ); + new_node->next = NULL; + GAPMultiRole_CentralSDP_t* entry = multiListFindTail(mode,(void**)ppnode); + + if( entry == NULL ) + { + *curr = new_node; + } + else + { + entry->next = new_node; + } + + ret = TRUE; + } + } + break; + + case MULTI_CENTRAL_SDP_PRIMSERV_MODE: + { + GATTReadGroupRsp** curr = (GATTReadGroupRsp**)ppnode; + GATTReadGroupRsp* new_node = multiListCreate( mode ); + + if( new_node ) + { + osal_memcpy( new_node, (GATTReadGroupRsp*)vnode, sizeof( GATTReadGroupRsp ) ); + new_node->next = NULL; + GATTReadGroupRsp* entry = multiListFindTail(mode,(void**)ppnode); + + if( entry == NULL ) + { + *curr = new_node; + } + else + { + entry->next = new_node; + } + + ret = TRUE; + } + } + break; + + case MULTI_CENTRAL_SDP_CHARAC_MODE: + { + Characteristic** curr = (Characteristic**)ppnode; + Characteristic* new_node = multiListCreate( mode ); + + if( new_node ) + { + osal_memcpy( new_node, (Characteristic*)vnode, sizeof( Characteristic ) ); + new_node->next = NULL; + Characteristic* entry = multiListFindTail(mode,(void**)ppnode); + + if( entry == NULL ) + { + *curr = new_node; + } + else + { + entry->next = new_node; + } + + ret = TRUE; + } + } + break; + + default: + break; + } + + return ret; +} + +static void* multiList_inside(GAPMultiListMode_t mode,void** ppnode, void* pvalue) +{ + void* node = NULL; + + switch( mode ) + { + case MULTI_SCAN_MODE: + { + GAPMultiRolScanner_t* entry = *(GAPMultiRolScanner_t**)ppnode; + + while( entry ) + { + // scan mode, detect MAC addr + if( osal_memcmp(entry->addr,(uint8*)pvalue,B_ADDR_LEN) == TRUE ) + break; + + entry = entry->next; + } + + // not in scan list , tail node tnode = NULL + node = (GAPMultiRolScanner_t*)entry; + } + break; + + case MULTI_CONFIG_SLAVE_DEV_MODE: + case MULTI_CONFIG_MASTER_LINKING_MODE: + { + GAPMultiRoleCentralDev_t* entry = *(GAPMultiRoleCentralDev_t**)ppnode; + + while( entry ) + { + // scan mode, detect MAC addr + if( osal_memcmp(entry->addr,(uint8*)pvalue,B_ADDR_LEN) == TRUE ) + break; + + entry = entry->next; + } + + node = (GAPMultiRoleCentralDev_t*)entry; + } + break; + + case MULTI_CONFIG_MASTER_ACTION_MODE: + { + GAPMultiRoleCentralAction_t* entry = *(GAPMultiRoleCentralAction_t**)ppnode; + + while( entry ) + { + if( entry->connHandle== *(uint16*)pvalue ) + break; + + entry = entry->next; + } + + node = (GAPMultiRoleCentralAction_t*)entry; + } + break; + + case MULTI_CENTRAL_ACTION_TIMER_MODE: + { + multiTimer* entry = *(multiTimer**)ppnode; + + while( entry ) + { + if( entry->id == *(uint8*)pvalue ) + break; + + entry = entry->next; + } + + node = (multiTimer*)entry; + } + break; + + case MULTI_CENTRAL_SDP_MODE: + { + GAPMultiRole_CentralSDP_t* entry = *(GAPMultiRole_CentralSDP_t**)ppnode; + + while( entry ) + { + if( entry->connHandle == *(uint16*)pvalue ) + break; + + entry = entry->next; + } + + node = (GAPMultiRole_CentralSDP_t*)entry; + } + break; + + case MULTI_CENTRAL_SDP_PRIMSERV_MODE: + { + GATTReadGroupRsp* entry = *(GATTReadGroupRsp**)ppnode; + + while( entry ) + { + if( entry->StHandle > *(uint16*)pvalue ) + break; + + entry = entry->next; + } + + node = (GATTReadGroupRsp*)entry; + } + break; + + default: + node = (uint8*)NULL; + break; + } + + return node; +} + +static void multiListMemoryFree(GAPMultiListMode_t mode ) +{ + switch( mode ) + { + case MULTI_SCAN_MODE: + { + #if( MAX_CONNECTION_MASTER_NUM > 0 ) + GAPMultiRolScanner_t* node = g_scanlist; + + while( node != NULL ) + { + g_scanlist = node->next; + + if( node->advData != NULL ) + osal_mem_free(node->advData); + + if( node->rspData != NULL ) + osal_mem_free(node->rspData); + + osal_mem_free( node ); + node = g_scanlist; + } + + #endif + } + break; + + default: + break; + } +} +#endif + + + + diff --git a/src/components/profiles/multiRole/multi.h b/src/components/profiles/multiRole/multi.h new file mode 100644 index 0000000..9fb61a4 --- /dev/null +++ b/src/components/profiles/multiRole/multi.h @@ -0,0 +1,955 @@ +/** + @defgroup Multi GAPRole (Multi) + @brief This module implements the Multi GAP Role + For a detailed usage section describing how to send these commands and receive events, + see the
GAPRole Section of the + User's Guide. + @{ + @file multi.h + @brief Multi layer interface +*/ + +#ifndef MULTI_H +#define MULTI_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* ------------------------------------------------------------------- + INCLUDES +*/ +#include "gap.h" +#include "att.h" + +/* ------------------------------------------------------------------- + CONSTANTS +*/ + +/** @defgroup Multi_Constants Multi GAPRole Constants + @{ +*/ +#define MAX_CONNECTION_NUM 2 ///5// +#define MAX_CONNECTION_SLAVE_NUM 1 ///3// +#define MAX_CONNECTION_MASTER_NUM ( (MAX_CONNECTION_NUM >= MAX_CONNECTION_SLAVE_NUM)?\ + (MAX_CONNECTION_NUM - MAX_CONNECTION_SLAVE_NUM):0) +#if( MAX_CONNECTION_NUM < MAX_CONNECTION_SLAVE_NUM ) +#error ("max connection num is less than slave num") +#endif +//// Multi-role Event +#define MULTI_SCHEDULE_EVT 0x0001 +#define MULTI_ADV_EVENT_DONE_EVT 0x0002 +#define MULTI_PERIOD_EVT 0x0004 +#define CONN_TIMEOUT_EVT 0X0008 + +#define MULTI_PERIOD_TIMING 500 //ms + +/** @defgroup Multi_Params Multi GAPRole Parameters + @{ + Parameters set via @ref GAPRole_SetParameter +*/ + +/** + @brief This parameter will return GAP Role type (Read-only) + + size: uint8 + + range: @ref GAP_Profile_Roles +*/ +#define GAPMULTIROLE_PROFILEROLE 0x300 + +/** + @brief Identity Resolving Key (Read/Write) Size is uint8[KEYLEN]. + + @note If this is set to all 0x00's, the IRK will be randomly generated + + size: uint8[16] + + default: 0x00000000000000000000000000000000 + + range: 0x00000000000000000000000000000000 - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +*/ +#define GAPMULTIROLE_IRK 0x301 + +/** + @brief Signature Resolving Key (Read/Write) + + @note If this is set to all 0x00's, the SRK will be randomly generated + + size: uint8[16] + + default: 0x00000000000000000000000000000000 + + range: 0x00000000000000000000000000000000 - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +*/ +#define GAPMULTIROLE_SRK 0x302 + +/** + @brief Sign Counter (Read/Write) + + size: uint32 + + default: 0x0000 + + range: 0x0000 - 0xFFFF +*/ +#define GAPMULTIROLE_SIGNCOUNTER 0x303 + +/** + @brief Device Address read from the controller (Read-only) + + The BDADDR is read, in increasing order of priortiy, from the info page, + secondary address from flash, or set from @ref HCI_ReadBDADDRCmd + + size: uint8[6] + + default: BDADDR from info page + + range: 0x000000000000 - 0xFFFFFFFFFFFE +*/ +#define GAPMULTIROLE_BD_ADDR 0x304 + +/** + @brief Enable/Disable Connectable Advertising (Read/Write) + + @warning @ref GAPMULTIROLE_ADV_NONCONN_ENABLED must be set to FALSE in order to enable this + + size: uint8 + + default: TRUE + + range: TRUE (enabled) or FALSE (disabled) +*/ +#define GAPMULTIROLE_ADVERT_ENABLED 0x305 + +/** + @brief How long to remain off (in sec) after advertising stops before starting again (Read/Write) + + If set to 0, advertising will not start again. + + size: uint16 + + default: 30 + + range: 0-65535 +*/ +#define GAPMULTIROLE_ADVERT_OFF_TIME 0x306 + +/** + @brief Advertisement data (Read/Write) + + @note The third byte sets limited / general advertising as defined in Vol 3, Part C, section 11.1.3 + of the BT 4.2 Core Spec. + + size: a uint8 array of up to 31 bytes + + default: 02:01:01 (general advertising) +*/ +#define GAPMULTIROLE_ADVERT_DATA 0x307 + +/** + @brief Scan Response Data (Read/Write) + + @note This should be formatted as define d in Vol 3, Part C, section 11.1.3 of the BT 4.2 Core Spec. + + size: a uint8 array of up to 31 bytes + + default: all 0x00's +*/ +#define GAPMULTIROLE_SCAN_RSP_DATA 0x308 + +/** + @brief Advertisement Types (Read/Write) + + size: uint8 + + default: @ref GAP_ADTYPE_ADV_IND + + range: @ref GAP_Adv_Types +*/ +#define GAPMULTIROLE_ADV_EVENT_TYPE 0x309 + +/** + @brief Direct Advertisement Type (Read/Write) + + size: uint8 + + default: @ref ADDRMODE_PUBLIC + + range: @ref Gap_Addr_Modes +*/ +#define GAPMULTIROLE_ADV_DIRECT_TYPE 0x30A + +/** + @brief Direct Advertisement Address (Read/Write) + + size: uint8[6] + + default: NULL + + range: 0x000000000000 - 0xFFFFFFFFFFFE +*/ +#define GAPMULTIROLE_ADV_DIRECT_ADDR 0x30B + +/** + @brief Which channels to advertise on (Read/Write) + + Multiple channels can be selected by ORing the bit values below. + + size: uint8 + + default: @ref GAP_ADVCHAN_ALL + + range: @ref GAP_Adv_Chans +*/ +#define GAPMULTIROLE_ADV_CHANNEL_MAP 0x30C + +/** + @brief Policy for filtering advertisements (Read/Write) + + @note This is ignored for direct advertising. + + size: uint8 + + default: @ref GAP_FILTER_POLICY_ALL + + range: @ref GAP_Adv_Filter_Policices +*/ +#define GAPMULTIROLE_ADV_FILTER_POLICY 0x30D + + +#define GAPMULTIROLE_PARAM_UPDATE_ENABLE 0x310 + +/** + @brief Minimum connection interval (n * 1.25 ms) to use when performing param update (Read/Write) + + size: uint16 + + default: 6 + + range: 6 - @ref GAPMULTIROLE_MAX_CONN_INTERVAL +*/ +#define GAPMULTIROLE_MIN_CONN_INTERVAL 0x311 + +/** + @brief Maximum connection interval (n * 1.25 ms) to use when performing param update (Read/Write) + + size: uint16 + + default: 3200 + + range: @ref GAPMULTIROLE_MIN_CONN_INTERVAL - 3200 +*/ +#define GAPMULTIROLE_MAX_CONN_INTERVAL 0x312 + +/** + @brief Slave latency to use when performing param update (Read/Write) + + size: uint16 + + default: 0 + + range: 0 - 499 +*/ +#define GAPMULTIROLE_SLAVE_LATENCY 0x313 + +/** + @brief Supervision timeout (n x 10 ms) to use when performing param update (Read/Write) + + size: uint16 + + default: 1000 + + range: 10-3200 +*/ +#define GAPMULTIROLE_TIMEOUT_MULTIPLIER 0x314 + +/** + @brief Enable / Disable non-connectable advertising (Read/Write) + + @warning @ref GAPMULTIROLE_ADVERT_ENABLED must be set to FALSE in order to enable this + + size: uint8 + + default: FALSE + + range: TRUE (enable) or FALSE (disable) +*/ +#define GAPMULTIROLE_ADV_NONCONN_ENABLED 0x31B + +/** + @brief Maximmum number of scan reports to store from @ref GAPCentralRole_StartDiscovery (Read/Write) + + size: uint8 + + default: 8 + + range: 0-256 but this will be constrained by available RAM +*/ +#define GAPMULTIROLE_MAX_SCAN_RES 0x404 +#define GAPMULTIROLE_SCAN_MODE 0x405 +#define GAPMULTIROLE_ACTIVE_SCAN 0x406 +#define GAPMULTIROLE_SCAN_WHITELIST 0x407 +#define GAPMULTIROLE_LINK_HIGHDUTYCYCLE 0x408 +#define GAPMULTIROLE_LINK_WHITELIST 0x409 +#define GAPMULTIROLE_ACTION_AFTER_LINK 0x40A + + + +/** + @brief Advertising off time Units:ms + + size: uint8 + + default: 10(ms) + + range: 0-256 : +*/ +#define GAPMULTIROLE_ADV_OFF_UNITS + +/** @} End Multi_Params */ + +/** @defgroup Multi_Param_Update_Fail_Actions Failed Parameter Update Actions + @{ + Possible actions the device may take if an unsuccessful parameter + update is received. +*/ +#define MULTIROLE_NO_ACTION 0 //!< Take no action upon unsuccessful parameter updates +#define MULTIROLE_RESEND_PARAM_UPDATE 1 //!< Continue to resend request until successful update +#define MULTIROLE_TERMINATE_LINK 2 //!< Terminate link upon unsuccessful parameter updates +/** @} End Multi_Param_Update_Fail_Actions */ + + +/** @defgroup Multi_Param_Update_Options Parameter Update Options + @{ + Possible actions the device may take when it receives a + Connection Parameter Update Request. +*/ +#define GAPMULTIROLE_LINK_PARAM_UPDATE_ACCEPT 0 //!< Accept all parameter update requests +#define GAPMULTIROLE_LINK_PARAM_UPDATE_REJECT 1 //!< Reject all parameter update requests +#define GAPMULTIROLE_LINK_PARAM_UPDATE_APP_DECIDES 2 //!< Notify app for it to decide +#define GAPMULTIROLE_LINK_PARAM_UPDATE_NUM_OPTIONS 3 //!< Number of options. Used for parameter checking. + +/** @} End Multi_Param_Update_Options */ + + +/* ------------------------------------------------------------------- + macro define -- multi advertising schedule data update info config + uint8 bit.Number £º meaning + bit7-bit6:if set means advertising data or + sacn response data shall be updated before + make discoverable + 7 shall update advertising data + 6 : shall update scan response data + + bit1-bit0:if set,means advertising data already updated + 1 : advertising data already updated, + 0 : scan response data already updated +*/ +#define GAPMULTI_UPDATEADV_FLAG 0x80 +#define GAPMULTI_UPDATESRD_FLAG 0x40 +#define GAPMULTI_ADV_UPDATED 0x02 +#define GAPMULTI_SRD_UPDATED 0x01 + +#define GAPMULTI_CENTRAL_SMP 0x01 + +#define GAPMULTI_CENTRAL_MTU_EXCHANGE 0x0001 +#define GAPMULTI_CENTRAL_DLE_EXCHANGE 0x0002 +#define GAPMULTI_CENTRAL_SDP 0x0004 + + + + +/** @} End Multi_Constants */ + + +/** @defgroup Multi_Structs Multi GAPRole Structures + @{ +*/ + + +/// @brief Multi GAPRole Event Structure + +/** + GAP multi-gap Role States. +*/ +typedef enum +{ + GAPMULTIROLE_INIT = 0, //!< Waiting to be started + GAPMULTIROLE_STARTED, //!< Started but not advertising + GAPMULTIROLE_ADVERTISING, //!< Currently Advertising + GAPMULTIROLE_SCANING, //!< Currently scaning + GAPMULTIROLE_CONNECTING, //!< Currently scaning + GAPMULTIROLE_WAITING, //!< Device is started but not advertising, is in waiting period before advertising again + GAPMULTIROLE_WAITING_AFTER_TIMEOUT, //!< Device just timed out from a connection but is not yet advertising, is in waiting period before advertising again + GAPMULTIROLE_CONNECTED, //!< In a connection + GAPMULTIROLE_TERMINATED, + GAPMULTIROLE_CONNECTED_ADV, //!< In a connection + advertising + GAPMULTIROLE_CONNECTED_SCAN, //!< In a connection + scan + GAPMULTIROLE_ERROR //!< Error occurred - invalid state +} GAPMultiRole_states_t; + +typedef union +{ + gapEventHdr_t gap; //!< @ref GAP_MSG_EVENT and status. + gapDeviceInitDoneEvent_t initDone; //!< GAP initialization done. + gapDeviceInfoEvent_t deviceInfo; //!< Discovery device information event structure. + gapDevDiscEvent_t discCmpl; //!< Discovery complete event structure. + gapEstLinkReqEvent_t linkCmpl; //!< Link complete event structure. + gapLinkUpdateEvent_t linkUpdate; //!< Link update event structure. + gapTerminateLinkEvent_t linkTerminate; //!< Link terminated event structure. +} gapMultiRoleEvent_t; + +/// @brief Multi GAPRole Parameter Update Structure +typedef struct +{ + uint8 paramUpdateEnable; //!< @ref Multi_Param_Update_Options + uint16 connHandle; //!< connection handle + uint16 minConnInterval; //!< minimum connection interval + uint16 maxConnInterval; //!< maximum connection interval + uint16 slaveLatency; //!< slave latency + uint16 timeoutMultiplier; //!< supervision timeout +} gapRole_updateConnParams_t; + + +// Service and Characteristic +typedef struct Characteristic +{ + uint16 charHandle; + uint8 Properties; + uint16 valueHandle; + uint8 uuid_Len; + uint8 uuid[16]; + struct Characteristic* next; +} Characteristic; +typedef struct GATTReadGroupRsp +{ + uint16 StHandle; // start handler + uint16 EGHandle; // End_Group_Handle + uint8 uuid_Len; + uint8 uuid[16]; + struct GATTReadGroupRsp* next; +} GATTReadGroupRsp; +typedef struct +{ + GATTReadGroupRsp* PrimServ; //ServerGroupService + Characteristic* Charac; +} GattMultiRoleScanServeice; + +// Discovery states +typedef enum +{ + DISC_STATE_IDLE, + DISC_STATE_SVC, + DISC_STATE_CHAR, // Service discovery + DISC_STATE_DONE +} MultiRole_discState_t; + +typedef struct centralSDP +{ + uint16 connHandle; + uint16 sdpCharHandle; + // exchange + MultiRole_discState_t state; + // service + GattMultiRoleScanServeice service; + struct centralSDP* next; +} GAPMultiRole_CentralSDP_t; + +/********************************************************************* + TYPEDEFS +*/ +typedef struct +{ + struct + { + uint8 profileRole; + uint8 IRK[KEYLEN]; + uint8 SRK[KEYLEN]; + uint32 signCounter; + uint8 bdAddr[B_ADDR_LEN]; + + // expiry connection parameter + uint16 ExConnIntvMIN; + uint16 ExConnIntvMAX; + uint16 ExLatency; + uint16 ExTimeOut; + } common; + #if( MAX_CONNECTION_SLAVE_NUM > 0 ) + struct + { + uint8 EventType; + uint8 ChanMap; + uint8 FilterPolicy; + uint8 UpdateEnable; + } adv; + #endif + #if( MAX_CONNECTION_MASTER_NUM > 0 ) + struct + { + uint8 maxScanRes; + uint8 scanMode; + uint8 activeScan; + uint8 whitelist; + } scan; + struct + { + uint8 highDutyCycle; + uint8 whitelist; + + // bit value + uint16 actionAfterLink; + } link; + #endif +} GAPMultiRoleParam_t; + +typedef enum +{ + Idle_Role = 0xFF, + Slave_Role = 0x0, + Master_Role = 0x3 +} GAPMultiRole_State_t; + +typedef struct link_T +{ + uint16 connectionHandle; + GAPMultiRole_State_t RoleState; + uint8 peerDevAddrType; + uint8 peerDevAddr[B_ADDR_LEN]; + uint16 connInterval; + uint16 connLatency; + uint16 connTimeout; + struct link_T* next; +} GAPMultiRoleLinkCtrl_t; + +typedef struct multiScan +{ + int8 rssi; + uint8 addrtype; + uint8 addr[B_ADDR_LEN]; + uint8 advDatalen; + uint8* advData; + uint8 scanRsplen; + uint8* rspData; + struct multiScan* next; +} GAPMultiRolScanner_t; + +typedef struct mCentralDev +{ + uint8 addrType; + uint8 addr[B_ADDR_LEN]; + struct mCentralDev* next; +} GAPMultiRoleCentralDev_t; + +typedef struct mCentralAction +{ + uint16 connHandle; + uint16 action; + uint8 busy; + struct mCentralAction* next; +} GAPMultiRoleCentralAction_t; + +typedef enum +{ + MULTI_SCAN_MODE = 0, + MULTI_CONFIG_SLAVE_DEV_MODE, + MULTI_CONFIG_MASTER_LINKING_MODE, + MULTI_CONFIG_MASTER_ACTION_MODE, + MULTI_CENTRAL_ACTION_TIMER_MODE, + MULTI_CENTRAL_SDP_MODE, + MULTI_CENTRAL_SDP_PRIMSERV_MODE, + MULTI_CENTRAL_SDP_CHARAC_MODE +} GAPMultiListMode_t; + +typedef union +{ + uint16 info; + struct + { + uint16 connHandle : 4; + uint16 role : 4; + uint16 perIdx : 4; + uint16 rfu : 4; + } value; +} GAPMultiLinkInfo_t; + +#define GAPMULTILIST_MULTI_SCAN_MODE GAPMultiRolScanner_t +#define GAPMULTILIST_MULTI_CONFIG_SLAVE_DEV_MODE GAPMultiRoleCentralDev_t + +#define _GAPMULTILIST_mode(x) GAPMULTILIST_##x +#define GAPMULTILIST_mode(x) _GAPMULTILIST_mode(x) +/** @} End Multi_Structs */ + +/* ------------------------------------------------------------------- + MACROS +*/ + +/* ------------------------------------------------------------------- + Profile Callbacks +*/ + +/** + Callback when the device has been started. Callback event to + the Notify of a state change. +*/ +typedef void (*gapRolesEachScan_t)( gapDeviceInfoEvent_t* pPkt ); +typedef void (*gapRolesScanDone_t)(GAPMultiRolScanner_t* pPkt); +typedef void (*gapRolesEstablish_t)( uint8 status,uint16 connHandle,GAPMultiRole_State_t role,uint8 perIdx,uint8* addr ); +typedef void (*gapRolesTerminate_t)( uint16 connHandle,GAPMultiRole_State_t role,uint8 perIdx,uint8 reason ); + +/** + Callback when the device has read an new RSSI value during a connection. +*/ +typedef void (*gapRolesRssiRead_t)( uint16 connHandle,int8 newRSSI ); + +/** + Callback when SDP done during a connection. +*/ +typedef void (*gapRolesSDPNotify_t)( void* msg); + +typedef void (*gapRolesDataNotify_t)( uint16 connHandle,uint16 len,uint8* data); + +typedef struct +{ + #if( MAX_CONNECTION_MASTER_NUM > 0) + gapRolesEachScan_t pfnEachScan; + gapRolesScanDone_t pfnScanDone; + gapRolesSDPNotify_t SDPNotify; //!< Event callback. + gapRolesDataNotify_t dataNotify; + #endif + gapRolesEstablish_t pfnEstablish; //!< Whenever the device changes state + gapRolesTerminate_t pfnTerminate; +} gapMultiRolesCBs_t; + +/** @defgroup Multi_CBs Multi GAPRole Callbacks + @{ + These are functions whose pointers are passed from the application + to the GAPRole so that the GAPRole can send events to the application +*/ + +/** + @brief Multi Event Callback Function + + This callback is used by the Multi GAPRole to forward GAP_Events to the + application. + + If the message is successfully queued to the application for later processing, + FALSE is returned because the application deallocates it later. Consider the + following state change event from multi_role as an example of this: + + @code{.c} + static void multi_role_processAppMsg(mrEvt_t *pMsg) + { + switch (pMsg->event) + { + case MR_STATE_CHANGE_EVT: + multi_role_processStackMsg((ICall_Hdr *)pMsg->pData); + // Free the stack message + ICall_freeMsg(pMsg->pData); + break; + @endcode + + If the message is not successfully queued to the application, TRUE is returned + so that the GAPRole can deallocate the message. If the heap has enough room, + the message must always be successfully enqueued. + + @param pEvent Pointer to event structure + + @return TRUE if safe to deallocate event message + @return FALSE otherwise +*/ +typedef uint8 (*passThroughToApp_t) +( + gapMultiRoleEvent_t* pEvent +); + +/** + @brief Callback for the app to decide on a parameter update request + + This callback will be used if the @ref GAP_UPDATE_LINK_PARAM_REQ_EVENT parameter + is set to @ref GAPMULTIROLE_LINK_PARAM_UPDATE_APP_DECIDES + + @param pReq Pointer to param update request + @param pRsp Pointer to param update response. +*/ +typedef void (*paramUpdateAppDecision_t) +( + gapUpdateLinkParamReq_t* pReq +// gapUpdateLinkParamReqReply_t *pRsp +); + +/** + @brief Multi GAPRole Callback structure + + This must be setup by the application and passed to the GAPRole when + @ref GAPRole_StartDevice is called. +*/ +typedef struct +{ + passThroughToApp_t pfnPassThrough; //!< When the event should be processed by the app instead of the GAP Role + paramUpdateAppDecision_t pfnParamUpdateAppDecision; //!< When the app should decide on a param update request +} gapRolesCBs_t; + +/** @} End Multi_Structs */ + +/* ------------------------------------------------------------------- + API FUNCTIONS +*/ + +/** + @brief Set a GAP Role parameter. + + @note + The "len" field must be set to the size of a "uint16" and the + "pValue" field must point to a "uint16". + + @param param @ref Multi_Params + @param len length of data to write + @param pValue pointer to data to write. This is dependent on + the parameter ID and will be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + @param connHandle connection handle + + @return @ref SUCCESS + @return @ref INVALIDPARAMETER + @return @ref bleInvalidRange : len is invalid for the given param +*/ +extern bStatus_t GAPMultiRole_SetParameter(uint16 param, uint8 len, void* pValue); + +/** + @brief Get a GAP Role parameter. + + @note + The "pValue" field must point to a "uint16". + + @param param @ref Multi_Params + @param pValue pointer to location to get the value. This is dependent on + the parameter ID and will be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + @param connHandle connection handle + + @return @ref SUCCESS + @return @ref INVALIDPARAMETER +*/ +extern bStatus_t GAPMultiRole_GetParameter(uint16 param, void* pValue); + +/** + @brief Initialize the GAP layer. + + @warning Only call this function once. + + @param pAppCallbacks @ref gapRolesCBs_t + @param numConns a pointer to the desired number of connections that the + application wants is passed in with this parameter. the GAPRole + will use this value to negotiate with the amount of connections + that the stack supports and place the negotiated value in this + memory location for return to the app. + + @return @ref SUCCESS + @return @ref bleAlreadyInRequestedMode : Device already started. +*/ +bStatus_t GAPMultiRole_StartDevice(gapMultiRolesCBs_t* pAppCallbacks, uint8* numConns); + +/** + @brief Terminates the existing connection. + + @param connHandle handle of connection to terminate + + @return @ref SUCCESS + @return @ref bleIncorrectMode + @return @ref HCI_ERROR_CODE_CONTROLLER_BUSY : terminate procedure has already started +*/ +extern bStatus_t GAPMultiRole_TerminateConnection(uint16 connHandle); + +/** + @brief Start a device discovery scan. + + @param mode discovery mode: @ref GAP_Discovery + @param activeScan TRUE to perform active scan + @param whiteList TRUE to only scan for devices in the white list + + @return @ref SUCCESS : Discovery discovery has started. + @return @ref bleIncorrectMode : Invalid profile role. + @return @ref bleAlreadyInRequestedMode : Device discovery already started + @return @ref HCI_ERROR_CODE_INVALID_HCI_CMD_PARAMS : bad parameter +*/ +extern bStatus_t GAPMultiRole_StartDiscovery(uint8 mode, uint8 activeScan, uint8 whiteList); + +/** + @brief Cancel a device discovery scan. + + @return @ref SUCCESS : Cancel started. + @return @ref bleInvalidTaskID : Not the task that started discovery. + @return @ref bleIncorrectMode : Not in discovery mode. +*/ +extern bStatus_t GAPMultiRole_CancelDiscovery(void); + +/** + @brief Establish a link to a peer device. + + @param highDutyCycle TRUE to high duty cycle scan, FALSE if not + @param whiteList determines use of the white list: @ref GAP_Whitelist + @param addrTypePeer @ref Addr_type + @param peerAddr peer device address + + @return @ref SUCCESS : started establish link process + @return @ref bleIncorrectMode : invalid profile role + @return @ref bleNotReady : a scan is in progress + @return @ref bleAlreadyInRequestedMode : can�t process now + @return @ref bleNoResources : too many links +*/ +extern bStatus_t GAPMultiRole_EstablishLink(uint8 highDutyCycle, uint8 whiteList, + uint8 addrTypePeer, uint8* peerAddr); + + +/** + @brief Send a connection parameter update to a connected device + + @param handleFailure @ref Multi_Param_Update_Fail_Actions + @param pConnParams pointer to connection parameters + + @return @ref SUCCESS : operation was successful. + @return @ref INVALIDPARAMETER : Data can not fit into one packet. + @return @ref MSG_BUFFER_NOT_AVAIL : No HCI buffer is available. + @return @ref bleInvalidRange : params do not satisfy spec + @return @ref bleIncorrectMode : invalid profile role. + @return @ref bleAlreadyInRequestedMode : already updating link parameters. + @return @ref bleNotConnected : Connection is down + @return @ref bleMemAllocError : Memory allocation error occurred. + @return @ref bleNoResources : No available resource +*/ +extern bStatus_t GAPMultiRole_connUpdate(uint8 handleFailure, + gapRole_updateConnParams_t* pConnParams); + + +// === from peripheral.c +/** + @brief Update the parameters of an existing connection + + @param connInterval - the new connection interval + @param latency - the new slave latency + @param connTimeout - the new timeout value + @param handleFailure - what to do if the update does not occur. + Method may choose to terminate connection, try again, or take no action + + @return SUCCESS, bleNotConnected or bleInvalidRange +*/ +extern bStatus_t GAPMultiRole_SendUpdateParam( uint16 minConnInterval, uint16 maxConnInterval, + uint16 latency, uint16 connTimeout, uint8 handleFailure ); +/// @cond NODOC + +/* ------------------------------------------------------------------- + TASK FUNCTIONS - Don't call these. These are system functions. +*/ + +/** + @internal + + @brief Initialization function for the GAP Role Task. + This is called during initialization and should contain + any application specific initialization (ie. hardware + initialization/setup, table initialization, power up + notificaiton ... ). + + @param the ID assigned by OSAL. This ID should be + used to send messages and set timers. + + @return void +*/ +extern void GAPMultiRole_Init( uint8 task_id ); + +/** + @internal + + @brief GAP Role Task event processor. + This function is called to process all events for the task. + Events include timers, messages and any other user defined + events. + + @param task_id - The OSAL assigned task ID. + @param events - events to process. This is a bit map and can + contain more than one event. + + @return events not processed +*/ +extern uint16 GAPMultiRole_ProcessEvent( uint8 task_id, uint16 events ); + +/// @endcond // NODOC + +/* ------------------------------------------------------------------- + -------------------------------------------------------------------*/ + +/** + + @brief GAP MultiRole Init peer address to link + + @param idx - Index of peer address + pAddr-peer device Address + addrType - peer device address type (Public address ...) + + @return None +*/ +extern char* bdAddr2Str( uint8* pAddr ); +//extern uint8 MultiRole_addPeerAddr(uint8* pAddr,uint8 addrType,uint8 en_connect ); +//extern uint8 MultiRole_delPeerAddr(uint8* pAddr ); +//extern uint8 MultiRole_ConnDevLen(); +//extern uint8 MultiRole_isAddr_inlist(uint8* pAddr); + +//extern void GAPMultiRole_enConnPeerAddr(uint8 *pAddr,uint8 en); +//extern GattScanServer* GAPMultiRole_GetSDPIdx( uint16 connHandle ); + +//extern void gapRole_setEvent(uint32 event); + +/******************************************************************************************************* + ******************************************************************************************************* + @ Description : according macro define MAX_CONNECTION_SLAVE_NUM and + MAX_CONNECTION_MASTER_NUM initialization list MultiScehdule *mSche + @ Parameters : + : [IN] pNum:according MAX_CONNECTION_SLAVE_NUM , max peripheral num + cNum:according MAX_CONNECTION_MASTER_NUM, max central num + : [OUT] void + @ Return : None + @ Other : 1.list case : adv --> adv --- + adv --> conn --> adv --> conn --- + adv+adv --> adv+adv --- + adv+scan --> adv+scan --- + + adv+adv+scan --> adv+adv+scan --- + 2.list add priority: adv0 --> adv1 --> scanner --> initiator + Modification History + DATE DESCRIPTION + 2020-11-26 [A] first add + 2020-11-27 [A] add create node priority : advertiser --> scanner --> initiator + ------------------------------------------------------------------------------ + @author : + ******************************************************************************************************* + *******************************************************************************************************/ +//uint8 multiSchedule_Config(uint8 Mode,uint8 flag, uint8 idx ); +//uint8 multiScan_Config(uint8 flag); +//uint8 multiInitiator_Config(uint8 flag); +// +#if( MAX_CONNECTION_MASTER_NUM > 0 ) +void multiGetScanStrategy(uint8* param,uint8 len); +void multiGetLinkStrategy(uint8* param,uint8 len); +uint8 multiConfigSlaveList( uint8 addrType,uint8* addr); +uint8 multiClearSlaveList( uint8 addrType,uint8* addr); +GAPMultiRoleCentralDev_t* multiGetConfigSlaveList(void); +void multiClearAllSlaveList(void); +uint8 multiDevInConfSlaveList(uint8* addr); +uint8 multi_devInLinkList(uint8* addr); +void multiAddSlaveConnList( uint8 addrType,uint8* addr); +GAPMultiRoleCentralDev_t* multiGetSlaveConnList(void); +void multiDelCurrentConnNode(void); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* MULTI_H */ + +/** @} End Multi */ diff --git a/src/components/profiles/multiRole/multiRoleProfile.c b/src/components/profiles/multiRole/multiRoleProfile.c new file mode 100644 index 0000000..9aa8635 --- /dev/null +++ b/src/components/profiles/multiRole/multiRoleProfile.c @@ -0,0 +1,556 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/************************************************************************************************** + Filename: multiRoleProfile.c + Revised: + Revision: + + Description: This file contains the Simple GATT profile sample GATT service + profile for use with the BLE sample application. + + +**************************************************************************************************/ + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "linkdb.h" +#include "att.h" +#include "gatt.h" +#include "gatt_uuid.h" +#include "gattservapp.h" +#include "gapbondmgr.h" +#include "multiRoleProfile.h" +#include "log.h" +#include "multi.h" + + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +#define SERVAPP_NUM_ATTR_SUPPORTED 8 + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ +#if(MAX_CONNECTION_SLAVE_NUM > 0 ) +CONST uint8 multiProfileServUUID[ATT_UUID_SIZE] = +{ + 0x6E, 0x40, 0x00, 0x01, 0xB5, 0xA3, 0xF3, 0x93, 0xE0, 0xA9, 0xE5, 0x0E, 0x24, 0xDC, 0x41,0x79 +}; + +CONST uint8 multiProfilechar1UUID[ATT_UUID_SIZE] = +{ + 0x79, 0x41, 0xDC, 0x24, 0x0E, 0xE5, 0xa9, 0xe0, 0x93, 0xf3, 0xa3, 0xb5, 0x02, 0x00, 0x40,0x6e +}; + +CONST uint8 multiProfilechar2UUID[ATT_UUID_SIZE] = +{ + 0x79, 0x41, 0xDC, 0x24, 0x0E, 0xE5, 0xa9, 0xe0, 0x93, 0xf3, 0xa3, 0xb5, 0x03, 0x00, 0x40,0x6e +}; +#endif + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ +#if(MAX_CONNECTION_SLAVE_NUM > 0 ) + static multiProfileCBs_t* multiProfile_AppCBs = NULL; +#endif +/********************************************************************* + Profile Attributes - variables +*/ +#if(MAX_CONNECTION_SLAVE_NUM > 0 ) +// multi Profile Service attribute +static CONST gattAttrType_t multiProfileService = { ATT_UUID_SIZE, multiProfileServUUID }; + +// multi Profile Characteristic 1 Properties +static uint8 multiProfileChar1Props = GATT_PROP_WRITE; + +// Characteristic 1 Value +static uint8 multiProfileChar1[ATT_MTU_SIZE]; + +// multi Profile Characteristic 1 User Description +static uint8 multiProfileChar1UserDesp[] = "Commmon TXRX\0"; + +// multi Profile Characteristic 1 Properties +static uint8 multiProfileChar2Props = GATT_PROP_READ | GATT_PROP_NOTIFY; + +// Characteristic 2 Value +static uint8 multiProfileChar2[ATT_MTU_SIZE]; +static uint8 multiChar2NotifyLen = 0; + +// multi Profile Characteristic 6 User Description +static uint8 multiProfileChar2UserDesp[] = "NOTIFY\0"; +// multi Profile Characteristic 6 Configuration Each client has its own +// instantiation of the Client Characteristic Configuration. Reads of the +// Client Characteristic Configuration only shows the configuration for +// that client and writes only affect the configuration of that client. +static gattCharCfg_t multiProfileChar2Config[MAX_NUM_LL_CONN]; +#endif + + +/********************************************************************* + Profile Attributes - Table +*/ +#if(MAX_CONNECTION_SLAVE_NUM > 0 ) +static gattAttribute_t multiProfileAttrTbl[SERVAPP_NUM_ATTR_SUPPORTED] = +{ + // multi Profile Service + { + { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */ + GATT_PERMIT_READ, /* permissions */ + 0, /* handle */ + (uint8*)& multiProfileService /* pValue */ + }, + + // Characteristic 1 Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &multiProfileChar1Props + }, + + // Characteristic Value 1 + { + { ATT_UUID_SIZE, multiProfilechar1UUID }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + &multiProfileChar1[0] + }, + + // Characteristic 1 User Description + { + { ATT_BT_UUID_SIZE, charUserDescUUID }, + GATT_PERMIT_READ, + 0, + multiProfileChar1UserDesp + }, + + // ---------------------------------------------------------------------- + // Characteristic 2 Declaration, NOTify + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &multiProfileChar2Props + }, + + // Characteristic Value 2 + { + { ATT_UUID_SIZE, multiProfilechar2UUID }, + GATT_PERMIT_READ, + 0, + (uint8*)& multiProfileChar2 + }, + + // Characteristic 2 configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8*)multiProfileChar2Config + }, + + // Characteristic 2 User Description + { + { ATT_BT_UUID_SIZE, charUserDescUUID }, + GATT_PERMIT_READ, + 0, + multiProfileChar2UserDesp + }, +}; + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static uint8 multiProfile_ReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ); +static bStatus_t multiProfile_WriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ); + +static void multiProfile_HandleConnStatusCB( uint16 connHandle, uint8 changeType ); + + +/********************************************************************* + PROFILE CALLBACKS +*/ +// multi Profile Service Callbacks +CONST gattServiceCBs_t multiProfileCBs = +{ + multiProfile_ReadAttrCB, // Read callback function pointer + multiProfile_WriteAttrCB, // Write callback function pointer + NULL // Authorization callback function pointer +}; +#endif + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/********************************************************************* + @fn multiProfile_AddService + + @brief Initializes the multi Profile service by registering + GATT attributes with the GATT server. + + @param services - services to add. This is a bit map and can + contain more than one service. + + @return Success or Failure +*/ +#if(MAX_CONNECTION_SLAVE_NUM > 0 ) +bStatus_t MultiProfile_AddService( uint32 services ) +{ + uint8 status = SUCCESS; + // Initialize Client Characteristic Configuration attributes + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, multiProfileChar2Config ); + // Register with Link DB to receive link status change callback + linkDB_Register( multiProfile_HandleConnStatusCB ); + // Register GATT attribute list and CBs with GATT Server App + status = GATTServApp_RegisterService( multiProfileAttrTbl, + GATT_NUM_ATTRS( multiProfileAttrTbl ), + &multiProfileCBs ); + return ( status ); +} + + +/********************************************************************* + @fn multiProfile_RegisterAppCBs + + @brief Registers the application callback function. Only call + this function once. + + @param callbacks - pointer to application callbacks. + + @return SUCCESS or bleAlreadyInRequestedMode +*/ +bStatus_t MultiProfile_RegisterAppCBs( multiProfileCBs_t* appCallbacks ) +{ + if ( appCallbacks ) + { + multiProfile_AppCBs = appCallbacks; + return ( SUCCESS ); + } + else + { + return ( bleAlreadyInRequestedMode ); + } +} + + +/********************************************************************* + @fn multiProfile_SetParameter + + @brief Set a multi Profile parameter. + + @param param - Profile parameter ID + @param len - length of data to right + @param value - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t MultiProfile_SetParameter( uint8 param, uint8 len, void* value ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case MULTIPROFILE_CHAR1: + { + if ( len <= ATT_MTU_SIZE ) + { + osal_memcpy(multiProfileChar1, value, len); + } + else + { + ret = bleInvalidRange; + } + } + break; + + case MULTIPROFILE_CHAR2: + { + if ( len <= ATT_MTU_SIZE ) + { + osal_memcpy(multiProfileChar2, value, len); + } + else + { + ret = bleInvalidRange; + } + } + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn multiProfile_GetParameter + + @brief Get a multi Profile parameter. + + @param param - Profile parameter ID + @param value - pointer to data to put. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t MultiProfile_GetParameter( uint16 connHandle,uint8 param, void* value ) +{ + bStatus_t ret = SUCCESS; + + switch ( param ) + { + case MULTIPROFILE_CHAR1: + VOID osal_memcpy( value, multiProfileChar1, ATT_GetCurrentMTUSize( connHandle )-3 ); + break; + + case MULTIPROFILE_CHAR2: + VOID osal_memcpy( value, multiProfileChar2, ATT_GetCurrentMTUSize( connHandle )-3 ); + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn multiProfile_ReadAttrCB + + @brief Read an attribute. + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be read + @param pLen - length of data to be read + @param offset - offset of the first octet to be read + @param maxLen - maximum length of data to be read + + @return Success or Failure +*/ +static uint8 multiProfile_ReadAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ) +{ + bStatus_t status = SUCCESS; + +// LOG("%s connHandle %d,pAttr->type.len %d\n",__func__,connHandle,pAttr->type.len); + // If attribute permissions require authorization to read, return error + if ( gattPermitAuthorRead( pAttr->permissions ) ) + { + // Insufficient authorization + return ( ATT_ERR_INSUFFICIENT_AUTHOR ); + } + + // Make sure it's not a blob operation (no attributes in the profile are long) + if ( offset > 0 ) + { + return ( ATT_ERR_ATTR_NOT_LONG ); + } + + // 16B UUID + if ( pAttr->type.len == ATT_UUID_SIZE ) + { + switch ( pAttr->type.uuid[ ATT_UUID_SIZE - 4 ] ) + { + // No need for "GATT_SERVICE_UUID" or "GATT_CLIENT_CHAR_CFG_UUID" cases; + // gattserverapp handles those reads + case MULTIPROFILE_CHAR1: + case MULTIPROFILE_CHAR2: + *pLen = multiChar2NotifyLen; + VOID osal_memcpy( pValue, pAttr->pValue, ATT_MTU_SIZE ); + break; + + default: + // Should never get here! (characteristics 3 and 4 do not have read permissions) + *pLen = 0; + status = ATT_ERR_ATTR_NOT_FOUND; + break; + } + } + + return ( status ); +} + +/********************************************************************* + @fn multiProfile_WriteAttrCB + + @brief Validate attribute data prior to a write operation + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be written + @param len - length of data + @param offset - offset of the first octet to be written + + @return Success or Failure +*/ +// TODO: test this function +static bStatus_t multiProfile_WriteAttrCB( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ) +{ + bStatus_t status = SUCCESS; + uint8 notifyApp = 0xFF; + + // If attribute permissions require authorization to write, return error + if ( gattPermitAuthorWrite( pAttr->permissions ) ) + { + // Insufficient authorization + return ( ATT_ERR_INSUFFICIENT_AUTHOR ); + } + + if ( pAttr->type.len == ATT_UUID_SIZE ) + { + switch ( pAttr->type.uuid[ ATT_UUID_SIZE - 4 ] ) + { + case MULTIPROFILE_CHAR1: + osal_memcpy(multiProfileChar1, pValue, len); + notifyApp = MULTIPROFILE_CHAR1; + break; + } + } + else if( pAttr->type.len == ATT_BT_UUID_SIZE ) + { + // 16-bit UUID + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + switch ( uuid ) + { + case GATT_CLIENT_CHAR_CFG_UUID: + { + status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len, + offset, GATT_CLIENT_CFG_NOTIFY ); + osal_memcpy(multiProfileChar2, pValue, len); + + if ( status == SUCCESS ) + { + notifyApp = MULTIPROFILE_CHAR2; + } + } + break; + } + } + + // If a charactersitic value changed then callback function to notify application of change + if ( (notifyApp != 0xFF ) && multiProfile_AppCBs && multiProfile_AppCBs->pfnMultiProfileChange ) + { + multiProfile_AppCBs->pfnMultiProfileChange(connHandle,notifyApp,len ); + } + + return status; +} + +/********************************************************************* + @fn multiProfile_HandleConnStatusCB + + @brief multi Profile link status change handler function. + + @param connHandle - connection handle + @param changeType - type of change + + @return none +*/ +static void multiProfile_HandleConnStatusCB( uint16 connHandle, uint8 changeType ) +{ + // Make sure this is not loopback connection + if ( connHandle != LOOPBACK_CONNHANDLE ) + { + // Reset Client Char Config if connection has dropped + if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) || + ( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && + ( !linkDB_Up( connHandle ) ) ) ) + { + GATTServApp_InitCharCfg( connHandle, multiProfileChar2Config ); + } + } +} + + +bStatus_t MultiProfile_Notify(uint16 connHandle,uint8 param, uint16 len, void* value ) +{ + bStatus_t ret = SUCCESS; + uint16 notfEnable = FALSE; + uint16 notfConnHandle = INVALID_CONNHANDLE; + + switch ( param ) + { + case MULTIPROFILE_CHAR2: + { + for(uint8 i=0; iCTRL0 = 0x02; \ + AP_PCR->CACHE_RST = 0x02;\ + AP_PCR->CACHE_BYPASS = 1; \ + }while(0); + + +#define OTA_FLASH_CACHE_EXIT_BYPASS_SECTION() do{ \ + AP_CACHE->CTRL0 = 0x00;\ + AP_PCR->CACHE_RST = 0x03;\ + AP_PCR->CACHE_BYPASS = 0;\ + }while(0); + +uint16_t crc16_table[16] __attribute__((section("ota_app_loader_area"))) = +{ + 0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, + 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400 +}; + +uint32_t __attribute__((section("ota_app_loader_area"))) ota_load_flash_addr; +uint32_t __attribute__((section("ota_app_loader_area"))) ota_load_run_addr; +uint32_t __attribute__((section("ota_app_loader_area"))) ota_load_size; +uint32_t __attribute__((section("ota_app_loader_area"))) ota_load_checksum; +uint32_t __attribute__((section("ota_app_loader_area"))) ota_load_crc; +uint32_t __attribute__((section("ota_app_loader_area"))) ota_boot_bypass_crc; +//uint32_t __attribute__((section("ota_app_loader_area"))) ota_load_mic; + +static uint16_t __attribute__((section("ota_app_loader_area"))) crc16_byte(uint16_t crc, uint8_t byte) +{ +// static const uint16_t crc16_table[16] = +// { +// 0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, +// 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400 +// }; + uint16_t temp; + // Compute checksum of lower four bits of a byte. + temp = crc16_table[crc & 0xF]; + crc = (crc >> 4u) & 0x0FFFu; + crc = crc ^ temp ^ crc16_table[byte & 0xF]; + // Now compute checksum of upper four bits of a byte. + temp = crc16_table[crc & 0xF]; + crc = (crc >> 4u) & 0x0FFFu; + crc = crc ^ temp ^ crc16_table[(byte >> 4u) & 0xF]; + return crc; +} + +// uint16_t __attribute__((section("ota_app_loader_area"))) OTA_crc16(uint16_t seed, const volatile void * p_data, uint32_t size) +//{ +// uint8_t * p_block = (uint8_t *)p_data; + +// while (size != 0) +// { +// seed = crc16_byte(seed, *p_block); +// p_block++; +// size--; +// } + +// return seed; +//} +uint16_t __attribute__((section("ota_app_loader_area"))) $Sub$$crc16(uint16_t seed, const volatile void* p_data, uint32_t size) +{ +// OTA_crc16(seed,p_data,size); + uint8_t* p_block = (uint8_t*)p_data; + + while (size != 0) + { + seed = crc16_byte(seed, *p_block); + p_block++; + size--; + } + + return seed; +} + +int __attribute__((section("ota_app_loader_area"))) ota_flash_read(uint32_t* dest, uint32_t addr, uint32_t size) +{ + int i; + uint32_t cb = AP_PCR->CACHE_BYPASS; + + if((((uint32_t)dest)%4) || (addr %4)|| (size%4)) + return PPlus_ERR_DATA_ALIGN; + + if(addr < OTAF_START_ADDR || addr >= OTAF_END_ADDR) + return PPlus_ERR_INVALID_ADDR; + + //read flash addr direct access + //bypass cache + + if(cb == 0) + { + OTA_FLASH_CACHE_ENTER_BYPASS_SECTION(); + } + + for(i = 0; i < size ; i += 4) + *dest++ = read_reg(addr + i); + + if(cb == 0) + { + OTA_FLASH_CACHE_EXIT_BYPASS_SECTION(); + } + + return PPlus_SUCCESS; +} + + +int __attribute__((section("ota_app_loader_area"))) ota_flash_load_app(void) +{ + int i,ret; + bool is_encrypt = FALSE; + uint32_t partition_num = 0; + uint32_t bank_info = 0; + uint32_t bank_addr = 0; +// uint32_t ota_sec_flag = 0; + ota_flash_read(&partition_num, OTAF_2nd_BOOTINFO_ADDR, 4); + + if(partition_num == 0xffffffff) + { + return PPlus_ERR_OTA_NO_APP; + } + + if(partition_num > OTAF_PARTITION_NUM_MAX || partition_num == 0) + { + // LOG("PPlus_ERR_OTA_BAD_DATA - part numb > OTAF_PARTITION_NUM_MAX\r\n"); + return PPlus_ERR_OTA_BAD_DATA; + } + + ota_flash_read(&bank_info, OTAF_2nd_BOOTINFO_ADDR + 4, 4); + + if(bank_info == OTAF_DUAL_BANK_1) + { + // LOG("OTAF_APP_BANK_1_ADDR\r\n"); + bank_addr = OTAF_APP_BANK_1_ADDR; + } + else if(bank_info == OTAF_DUAL_BANK_0 || bank_info == OTAF_SINGLE_BANK) + { + // LOG("OTAF_APP_BANK_0_ADDR\r\n"); + bank_addr = OTAF_APP_BANK_0_ADDR; + } + else + { + // LOG("PPlus_ERR_OTA_BAD_DATA - bank numb > 2\r\n"); + return PPlus_ERR_OTA_BAD_DATA; + } + + is_encrypt = is_crypto_app(); + volatile uint32_t t = 100; + + while(t--) {}; + + ota_flash_read(&ota_boot_bypass_crc, OTAF_2nd_BOOT_FAST_BOOT, 4); + + for(i = 1; i< partition_num+1; i++) + { +// uint32_t flash_addr; +// uint32_t run_addr; +// uint32_t size; +// uint32_t checksum; +// uint16_t crc; + ota_flash_read(&ota_load_flash_addr, OTAF_2nd_BOOTINFO_ADDR + i*4*4, 4); + ota_flash_read(&ota_load_run_addr, OTAF_2nd_BOOTINFO_ADDR + i*4*4 + 4, 4); + ota_flash_read(&ota_load_size, OTAF_2nd_BOOTINFO_ADDR + i*4*4 + 8, 4); + ota_flash_read(&ota_load_checksum, OTAF_2nd_BOOTINFO_ADDR + i*4*4 + 12, 4); + + if((ota_load_flash_addr==0xffffffff) || (ota_load_run_addr == 0xffffffff )||(ota_load_size == 0xffffffff )||(ota_load_checksum == 0xffffffff )) + { + return PPlus_ERR_OTA_NO_APP; + } + + //ota_sec_flag = ota_load_size&0x80000000; + + //case XIP mode, shoud be in single bank and no fct + if(ota_load_run_addr == ota_load_flash_addr) + { + // LOG("XIP MODE >>> "); + if(USE_FCT==0 && CFG_OTA_BANK_MODE==OTA_SINGLE_BANK) + { + // LOG("NEXT PART! \r\n"); + // continue; + if(is_encrypt) + { + flash_check_parition((uint8_t*)ota_load_flash_addr,(int)ota_load_size,NULL,(uint8_t*)&ota_load_crc); + + if ( ota_load_crc!=ota_load_checksum ) + { + write_reg(OTA_MODE_SELECT_REG, OTA_MODE_OTA); + hal_system_soft_reset(); + } + } + else + { + if(ota_boot_bypass_crc!=OTA_FAST_BOOT_MAGIC) + { + // ota_flash_read((uint32_t*)ota_load_run_addr, ota_load_flash_addr + bank_addr, ota_load_size); + ota_load_crc = crc16(0, (const volatile void* )ota_load_flash_addr, ota_load_size); + + if(ota_load_crc != (uint16)ota_load_checksum) + { + //if crc incorrect, reboot to OTA mode + write_reg(OTA_MODE_SELECT_REG, OTA_MODE_OTA); + hal_system_soft_reset(); + } + } + } + + continue; + } + else + { + // LOG("PPlus_ERR_INVALID_DATA\r\n"); + return PPlus_ERR_INVALID_DATA; + } + } + + if((ota_load_run_addr&0xffff0000) == 0xffff0000) + { + continue; + } + + //load binary + if(is_encrypt) + { +// if(ota_sec_flag){ + ret = flash_load_parition((uint8_t*)(ota_load_flash_addr + bank_addr), (int)ota_load_size, (uint8_t*)&ota_load_checksum,(uint8_t*)ota_load_run_addr); + + //LOG("ret=%d\n",ret); + if(ret!=0) + { + //if crc incorrect, reboot to OTA mode + write_reg(OTA_MODE_SELECT_REG, OTA_MODE_OTA); + hal_system_soft_reset(); + } + +// } +// else{ +// flash_check_parition((uint8_t*)(ota_load_flash_addr + bank_addr),(int)ota_load_size&0xffffff,NULL,(uint8_t*)&ota_load_crc); +// if(ota_load_crc!=ota_load_checksum){ +// write_reg(OTA_MODE_SELECT_REG, OTA_MODE_OTA); +// hal_system_soft_reset(); +// } +// ota_flash_read((uint32_t*)ota_load_run_addr, ota_load_flash_addr + bank_addr, ota_load_size); +// } + } + else + { + ota_flash_read((uint32_t*)ota_load_run_addr, ota_load_flash_addr + bank_addr, ota_load_size); + + if(ota_boot_bypass_crc!=OTA_FAST_BOOT_MAGIC) + { + ota_load_crc = crc16(0, (const volatile void* )ota_load_run_addr, ota_load_size); + + if(ota_load_crc != (uint16)ota_load_checksum) + { + //if crc incorrect, reboot to OTA mode + write_reg(OTA_MODE_SELECT_REG, OTA_MODE_OTA); + hal_system_soft_reset(); + } + } + } + } + + // LOG("PPlus_SUCCESS\r\n"); + return PPlus_SUCCESS; +} + +#if(CFG_FLASH >= 512) +int ota_flash_load_fct(void) +{ + return PPlus_SUCCESS; +} +#endif + + + + +int ota_flash_read_bootsector(uint32_t* bank_addr) +{ + uint32_t partition_num = 0; + uint32_t bank_info = 0; + *bank_addr = OTAF_APP_BANK_0_ADDR; + ota_flash_read(&partition_num, OTAF_2nd_BOOTINFO_ADDR, 4); + + if(partition_num == 0xffffffff) + return PPlus_ERR_OTA_NO_APP; + + if(partition_num > OTAF_PARTITION_NUM_MAX) + return PPlus_ERR_OTA_BAD_DATA; + + ota_flash_read(&bank_info, OTAF_2nd_BOOTINFO_ADDR + 4, 4); + + if(bank_info == OTAF_DUAL_BANK_0) + { + *bank_addr = OTAF_APP_BANK_1_ADDR; + } + else if(bank_info == OTAF_DUAL_BANK_1 || bank_info == OTAF_SINGLE_BANK) + { + *bank_addr = OTAF_APP_BANK_0_ADDR; + } + else + { + return PPlus_ERR_OTA_BAD_DATA; + } + + return PPlus_SUCCESS; +} + +int ota_flash_write_partition(uint32 addr, uint32_t* p_sect, uint32_t size) +{ + if(addr % 4) + return PPlus_ERR_DATA_ALIGN; + + size = (size + 3) & 0xfffffffc; + #if 0 + int ret = 0; + uint32_t i; + + for(i = 0; i < size /4; i++) + { + ret = flash_write_word(addr + i*4, p_sect[i]); + + if(ret == PPlus_SUCCESS) + continue; + + ret = flash_write_word(addr + i*4, p_sect[i]); + + if(ret == PPlus_SUCCESS) + continue; + + ret = flash_write_word(addr + i*4, p_sect[i]); + + if(ret == PPlus_SUCCESS) + continue; + + ret = flash_write_word(addr + i*4, p_sect[i]); + + if(ret != PPlus_SUCCESS) + return PPlus_ERR_SPI_FLASH; + } + + return PPlus_SUCCESS; + #endif + return(hal_flash_write_by_dma(addr, (uint8_t*) p_sect, size)); +} + +int ota_flash_write_boot_sector(uint32_t* p_sect, uint32_t size, uint32_t offset) +{ + if(size % 4) + return PPlus_ERR_DATA_ALIGN; + + #if 0 + uint32_t i; + int ret = 0; + + for(i = 0; i < size /4; i++) + { + ret = flash_write_word(OTAF_2nd_BOOTINFO_ADDR + i*4 + offset, p_sect[i]); + + if(ret == PPlus_SUCCESS) + continue; + + ret = flash_write_word(OTAF_2nd_BOOTINFO_ADDR + i*4 + offset, p_sect[i]); + + if(ret == PPlus_SUCCESS) + continue; + + ret = flash_write_word(OTAF_2nd_BOOTINFO_ADDR + i*4 + offset, p_sect[i]); + + if(ret == PPlus_SUCCESS) + continue; + + ret = flash_write_word(OTAF_2nd_BOOTINFO_ADDR + i*4 + offset, p_sect[i]); + + if(ret != PPlus_SUCCESS) + return PPlus_ERR_SPI_FLASH; + } + + return PPlus_SUCCESS; + #endif + return(hal_flash_write_by_dma(OTAF_2nd_BOOTINFO_ADDR+offset, (uint8_t*) p_sect, size)); +} + +int ota_flash_erase(uint32_t bank_addr) +{ + int i; + + if(CFG_OTA_BANK_MODE == OTA_SINGLE_BANK) + { + if(bank_addr != OTAF_APP_BANK_0_ADDR) + return PPlus_ERR_INVALID_PARAM; + + //erase boot sector + hal_flash_erase_sector(OTAF_2nd_BOOTINFO_ADDR); + + for(i = 0; i< OTAF_APP_BANK_SIZE; i+= OTAF_SECTOR_SIZE) + hal_flash_erase_sector(OTAF_APP_BANK_0_ADDR + i); + + return PPlus_SUCCESS; + } + else + { + if(bank_addr == OTAF_APP_BANK_0_ADDR || bank_addr == OTAF_APP_BANK_1_ADDR) + { + //erase application bank + for(i = 0; i< OTAF_APP_BANK_SIZE; i+= OTAF_SECTOR_SIZE) + hal_flash_erase_sector(bank_addr + i); + + return PPlus_SUCCESS; + } + } + + return PPlus_ERR_INVALID_PARAM; +} + + +int ota_flash_erase_area(uint32_t flash_addr, uint32_t size) +{ + int ret = PPlus_ERR_INVALID_ADDR; + int offset; + flash_addr = flash_addr | 0x11000000; + + if(flash_addr >=OTAF_1st_BOOTINFO_ADDR + OTAF_1st_BOOTINFO_SIZE && (flash_addr + size) <= OTAF_2nd_BOOTINFO_ADDR ) + { + ret = PPlus_SUCCESS; + } + + if(flash_addr >=OTAF_2nd_BOOTINFO_ADDR + 4*1024 && (flash_addr + size) <= OTAF_APP_BANK_0_ADDR ) + { + ret = PPlus_SUCCESS; + } + + if((flash_addr + size) <= OTAF_END_ADDR +1) + { + ret = PPlus_SUCCESS; + } + + if(flash_addr & 0xfff || size & 0xfff) + { + ret = PPlus_ERR_DATA_ALIGN; + } + + if(ret) + return ret; + + if((flash_addr & 0xffff == 0 ) && (size & 0xffff == 0)) //case 64K align, erase block + { + for(offset= 0; offset < size; offset += 64*1024) + hal_flash_erase_block64(flash_addr + offset); + } + else //erase sector + { + for(offset = 0; offset< size; offset+= OTAF_SECTOR_SIZE) + hal_flash_erase_sector(flash_addr + offset); + } + + return PPlus_SUCCESS; +} + + + diff --git a/src/components/profiles/ota/ota_flash.h b/src/components/profiles/ota/ota_flash.h new file mode 100644 index 0000000..0f68f82 --- /dev/null +++ b/src/components/profiles/ota/ota_flash.h @@ -0,0 +1,191 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#ifndef _OTA_FLASH_H +#define _OTA_FLASH_H + +#include "types.h" + +#define OTAF_PARTITION_NUM_MAX 32 + +enum +{ + OTAF_SINGLE_BANK = 0, + OTAF_DUAL_BANK_0 = 1, + OTAF_DUAL_BANK_1 = 2 +}; + +#define DBG_BOOT_IO_TOGGLE do{\ + *(volatile unsigned int *)(0x40008004) |= 0x1;\ + *(volatile unsigned int *)(0x40008000) |= 0x1;\ + *(volatile unsigned int *)(0x40008000) &= ~0x1;}while(0) + +#define OTA_MAGIC_CODE 0x32af08cb //random data +#define OTA_FAST_BOOT_MAGIC 0xa5a55a5a //random data + +#define OTAF_SECTOR_SIZE (1024*4) //4k size + +#define OTA_DUMMY_BANK 0 //undefined mode, will report error +#define OTA_SINGLE_BANK 1 +#define OTA_DUAL_BANK 2 + +#ifndef CFG_OTA_BANK_MODE + #define CFG_OTA_BANK_MODE OTA_DUMMY_BANK +#endif + +#ifndef USE_FCT + #define USE_FCT 0 +#endif + +#ifndef CFG_FLASH + #define CFG_FLASH 0 +#endif + +#if(CFG_FLASH == 256 && USE_FCT==0 && CFG_OTA_BANK_MODE==OTA_SINGLE_BANK) + + #define OTAF_BASE_ADDR 0x11000000 + + #define OTAF_1st_BOOTINFO_ADDR 0x11002000 //4k bytes + #define OTAF_1st_BOOTINFO_SIZE 0x1000 //4k bytes + + #define OTAF_2nd_BOOTINFO_ADDR 0x11003000 //4k bytes + #define OTAF_APP_BANK_0_ADDR 0x11011000 //60K bytes + #define OTAF_APP_BANK_1_ADDR OTA_MAGIC_CODE //Dummy + + #define OTAF_APP_BANK_SIZE (1024*60) + + #define OTAF_NVM_ADDR 0x11020000 //8K bytes + + + #define OTAF_APPLICATION_RUN 0x1fff1838 //??? need confirm + + #elif(CFG_FLASH >= 512 && USE_FCT==1 && CFG_OTA_BANK_MODE==OTA_DUAL_BANK) + + #define OTAF_BASE_ADDR 0x11000000 + + #define OTAF_1st_BOOTINFO_ADDR 0x11002000 //4k bytes + #define OTAF_1st_BOOTINFO_SIZE 0x1000 //4k bytes + + #define OTAF_2nd_BOOTINFO_ADDR 0x11009000 //4k bytes + #define OTAF_APP_FCT_ADDR 0x11012000 //120K bytes, first 4k is FCT boot info + #define OTAF_APP_BANK_0_ADDR 0x11030000 //128K bytes + #define OTAF_APP_BANK_1_ADDR 0x11050000 //128K bytes + + #define OTAF_APP_BANK_SIZE (1024*128) + + #define OTAF_NVM_ADDR 0x11070000 //64K bytes + + + #define OTAF_APPLICATION_RUN 0x1fff1838 //??? need confirm + + #elif(CFG_FLASH >= 512 && USE_FCT==0 && CFG_OTA_BANK_MODE==OTA_DUAL_BANK) + + #define OTAF_BASE_ADDR 0x11000000 + + #define OTAF_1st_BOOTINFO_ADDR 0x11002000 //4k bytes + #define OTAF_1st_BOOTINFO_SIZE 0x1000 //4k bytes + + #define OTAF_2nd_BOOTINFO_ADDR 0x11009000 //4k bytes + #define OTAF_APP_BANK_0_ADDR 0x11012000 //128K bytes + #define OTAF_APP_BANK_1_ADDR 0x11032000 //128K bytes + + #define OTAF_APP_BANK_SIZE (1024*128) + + #define OTAF_NVM_ADDR 0x11052000 //64K bytes + + + #define OTAF_APPLICATION_RUN 0x1fff1838 //??? need confirm + + #elif(CFG_FLASH >= 512 && USE_FCT==1 && CFG_OTA_BANK_MODE==OTA_SINGLE_BANK) + + #define OTAF_BASE_ADDR 0x11000000 + + #define OTAF_1st_BOOTINFO_ADDR 0x11002000 //4k bytes + #define OTAF_1st_BOOTINFO_SIZE 0x1000 //4k bytes + + #define OTAF_2nd_BOOTINFO_ADDR 0x11009000 //4k bytes + #define OTAF_APP_FCT_ADDR 0x11012000 //120K bytes, first 4k is FCT boot info + #define OTAF_APP_BANK_0_ADDR 0x11030000 //128K bytes + #define OTAF_APP_BANK_1_ADDR OTA_MAGIC_CODE //Dummy + + #define OTAF_APP_BANK_SIZE (1024*128) + + #define OTAF_NVM_ADDR 0x11050000 //64K bytes + + + #define OTAF_APPLICATION_RUN 0x1fff1838 //??? need confirm + + #elif(CFG_FLASH >= 512 && USE_FCT==0 && CFG_OTA_BANK_MODE==OTA_SINGLE_BANK) + + #define OTAF_BASE_ADDR 0x11000000 + + #define OTAF_1st_BOOTINFO_ADDR 0x11002000 //4k bytes + #define OTAF_1st_BOOTINFO_SIZE 0x1000 //4k bytes + + #define OTAF_2nd_BOOTINFO_ADDR 0x11003000 //4k bytes + #define OTAF_APP_BANK_0_ADDR 0x11011000 //128K bytes + #define OTAF_APP_BANK_1_ADDR OTA_MAGIC_CODE //Dummy + + #define OTAF_APP_BANK_SIZE (1024*60) + + #define OTAF_NVM_ADDR 0x11020000 //64K bytes + + + #define OTAF_APPLICATION_RUN 0x1fff1838 //??? need confirm + + #define OTAF_2nd_BOOT_FAST_BOOT 0x11003ff0 //bypass 2nd boot crc check for fast boot + +#else + #error "unsupported OTA config, please check these micro:CFG_FLASH, USE_FCT,CFG_OTA_BANK_MODE!" +#endif + + +#if(CFG_FLASH == 256) + #define OTAF_START_ADDR 0x11003000 + #define OTAF_END_ADDR 0x1103ffff + #elif(CFG_FLASH == 512) + #define OTAF_START_ADDR 0x11003000 + #define OTAF_END_ADDR 0x1107ffff + #elif(CFG_FLASH == 4096) + #define OTAF_START_ADDR 0x11003000 + #define OTAF_END_ADDR 0x111fffff +#else + #error "unsupported OTA config, please check these micro:CFG_FLASH!" +#endif + +#define MAX_SECT_SUPPORT 32//16 + + +typedef struct +{ + uint32_t flash_addr; + uint32_t run_addr; + uint32_t size; + uint16_t checksum; +} ota_fw_part_t; + +typedef struct +{ + uint8_t part_num; + uint8_t part_current; + uint32_t total_size; + uint32_t total_offset; + uint32_t offset; + ota_fw_part_t part[MAX_SECT_SUPPORT]; +} ota_fw_t; + + +#if(CFG_FLASH >= 512) + int ota_flash_load_fct(void); +#endif +int ota_flash_load_app(void); +int ota_flash_write_partition(uint32 addr, uint32_t* p_sect, uint32_t size); +int ota_flash_write_boot_sector(uint32_t* p_sect, uint32_t size, uint32_t offset); +int ota_flash_erase(uint32_t addr); +int ota_flash_erase_area(uint32_t flash_addr, uint32_t size); +int ota_flash_read_bootsector(uint32_t* bank_addr); + +#endif + diff --git a/src/components/profiles/ota/ota_flash_mesh.c b/src/components/profiles/ota/ota_flash_mesh.c new file mode 100644 index 0000000..666731b --- /dev/null +++ b/src/components/profiles/ota/ota_flash_mesh.c @@ -0,0 +1,244 @@ + +#include "flash.h" +#include "ota_flash.h" +#include "ota_flash_mesh.h" +#include "ota_app_service.h" +#include "ota_protocol.h" +#include "string.h" +#include "error.h" +#include "crc16.h" +#include "log.h" +#include "hal_mcu.h" + + +typedef struct +{ + uint8_t flg; + uint8_t rsv; + uint16_t dev_type; + uint8_t mac[6]; +} otafm_meshinfo_t; + + + +int otafm_write_partition(uint32 addr, uint32_t* p_sect, uint32_t size) +{ + uint32_t i; + int ret = 0; + uint32_t offset = OTAFM_FW_OTA_DATA_ADDR; + + if(addr % 4) + return PPlus_ERR_DATA_ALIGN; + + size = (size + 3) & 0xfffffffc; + + for(i = 0; i < size /4; i++) + { + ret = flash_write_word(offset + addr + i*4, p_sect[i]); + + if(ret == PPlus_SUCCESS) + continue; + + ret = flash_write_word(offset + addr + i*4, p_sect[i]); + + if(ret == PPlus_SUCCESS) + continue; + + ret = flash_write_word(offset + addr + i*4, p_sect[i]); + + if(ret == PPlus_SUCCESS) + continue; + + ret = flash_write_word(offset + addr + i*4, p_sect[i]); + + if(ret != PPlus_SUCCESS) + return PPlus_ERR_SPI_FLASH; + } + + return PPlus_SUCCESS; +} + +int otafm_write_boot_sector(uint32_t* p_sect, uint32_t size, uint32_t offset) +{ + uint32_t i; + int ret = 0; + + if(size % 4) + return PPlus_ERR_DATA_ALIGN; + + for(i = 0; i < size /4; i++) + { + ret = flash_write_word(OTAFM_FW_OTA_ADDR + OTAFM_FW_OTA_INFO_SZ + i*4 + offset, p_sect[i]); + + if(ret == PPlus_SUCCESS) + continue; + + ret = flash_write_word(OTAFM_FW_OTA_ADDR + OTAFM_FW_OTA_INFO_SZ + i*4 + offset, p_sect[i]); + + if(ret == PPlus_SUCCESS) + continue; + + ret = flash_write_word(OTAFM_FW_OTA_ADDR + OTAFM_FW_OTA_INFO_SZ + i*4 + offset, p_sect[i]); + + if(ret == PPlus_SUCCESS) + continue; + + ret = flash_write_word(OTAFM_FW_OTA_ADDR + OTAFM_FW_OTA_INFO_SZ + i*4 + offset, p_sect[i]); + + if(ret != PPlus_SUCCESS) + return PPlus_ERR_SPI_FLASH; + } + + return PPlus_SUCCESS; +} + + + +int otafm_dev_add(otafmesh_dev_t* pdev) +{ + return PPlus_SUCCESS; +} + + + +int otafm_dev_pull(otafmesh_dev_t* pdev) +{ + uint32_t i = 0; + uint32_t faddr = OTAFM_FW_OTA_ADDR; + uint8_t* pdata = (uint8_t*) (faddr); + uint32_t data_u32 = NULL; + otafm_meshinfo_t* pinfo; + uint8_t flg = 0; + + if(!((char)(pdata[0]) == 'M' && (char)(pdata[1]) == 'O' &&(char)(pdata[2]) == 'T'&&(char)(pdata[3]) == 'A')) + { + return PPlus_ERR_INVALID_DATA; + } + + pdata += 0x100; + + for(i = 0; i<240; i++) + { + if(pdata[0] == OTAFM_DEV_FLG_UNINIT) + return PPlus_ERR_NOT_FOUND; + + if(pdata[0] == OTAFM_DEV_FLG_READY|| + pdata[0] == OTAFM_DEV_FLG_FAILED|| + pdata[0] == OTAFM_DEV_FLG_OTAING) + { + pinfo = (otafm_meshinfo_t*) pdata; + pdev->dev_type = pinfo->dev_type; + pdev->dev_addr[0] = pinfo->mac[5]; + pdev->dev_addr[1] = pinfo->mac[4]; + pdev->dev_addr[2] = pinfo->mac[3]; + pdev->dev_addr[3] = pinfo->mac[2]; + pdev->dev_addr[4] = pinfo->mac[1]; + pdev->dev_addr[5] = pinfo->mac[0]; + pdev->index = (uint16_t)i; + flg = pinfo->flg & OTAFM_DEV_FLG_OTAING; + data_u32 = *((uint32_t*)pdata); + data_u32 &= 0xffffff00; + data_u32 |= flg; + flash_write_word((uint32_t)pdata, data_u32); + return PPlus_SUCCESS; + } + + pdata += 16; + } + + return PPlus_ERR_NOT_FOUND; +} + +int otafm_dev_clear(otafmesh_dev_t* pdev) +{ + uint32_t faddr = OTAFM_FW_OTA_ADDR; + uint8_t* pdata = (uint8_t*) (faddr); + otafm_meshinfo_t* pinfo; + uint32_t data_u32; + + if(!((char)(pdata[0]) == 'M' && (char)(pdata[1]) == 'O' &&(char)(pdata[2]) == 'T'&&(char)(pdata[3]) == 'A')) + { + return PPlus_ERR_INVALID_DATA; + } + + pdata += 0x100 + pdev->index * 16; + pinfo = (otafm_meshinfo_t*)pdata; + + if(memcmp(pdev->dev_addr, pinfo->mac, 6) != 0) + { + return PPlus_ERR_INVALID_ADDR; + } + + if(pinfo->flg != OTAFM_DEV_FLG_READY && + pinfo->flg != OTAFM_DEV_FLG_FAILED && + pinfo->flg != OTAFM_DEV_FLG_COMPLETED && + pinfo->flg != OTAFM_DEV_FLG_OTAING + ) + { + return PPlus_ERR_INVALID_FLAGS; + } + + data_u32 = *(uint32_t*)pdata; + data_u32 &= 0xffffff00; + data_u32 |= OTAFM_DEV_FLG_USED; + flash_write_word((uint32_t)pdata, data_u32); + return PPlus_SUCCESS; +} + + +int otafm_fw_load(ota_fw_t* pfw) +{ + uint32_t faddr = OTAFM_FW_OTA_ADDR + OTAFM_FW_OTA_INFO_SZ; + uint8_t* pdata = (uint8_t*) (faddr); + uint32_t* pdata32 = (uint32_t*) pdata; + LOG("load fw %x\n", faddr); + memset((void*)pfw, 0,sizeof(ota_fw_t)); + + if(!((char)(pdata[0]) == 'O' && (char)(pdata[1]) == 'T' &&(char)(pdata[2]) == 'A'&&(char)(pdata[3]) == 'F')) + { + return PPlus_ERR_INVALID_DATA; + } + + pfw->part_num = (uint8_t)(pdata32[1]); + pfw->total_size = 0; + + for (uint8_t i = 0; i < pfw->part_num; i++) + { + uint16_t checksum = 0; + pfw->part[i].flash_addr = pdata32[i*4+4]; + pfw->part[i].run_addr = pdata32[i*4+5]; + pfw->part[i].size = pdata32[i*4+6]; + pfw->part[i].checksum = (uint16_t)(pdata32[i*4+7]); + checksum = crc16(0, (const volatile void* )(pfw->part[i].flash_addr + OTAFM_FW_OTA_DATA_ADDR), pfw->part[i].size); + + if(checksum != pfw->part[i].checksum) + return PPlus_ERR_INVALID_DATA; + + pfw->total_size += pfw->part[i].size; + } + + return PPlus_SUCCESS; +} + +//load data to +int otafm_fw_execute() +{ + return PPlus_SUCCESS; +} + + +int otafm_format(void) +{ + uint32_t i; + + for(i = 0; i< 4; i++) + { + flash_block64_erase(OTAFM_FW_OTA_ADDR + i * OTAF_SECTOR_SIZE); + } + + return PPlus_SUCCESS; +} + + + + diff --git a/src/components/profiles/ota/ota_flash_mesh.h b/src/components/profiles/ota/ota_flash_mesh.h new file mode 100644 index 0000000..88c1484 --- /dev/null +++ b/src/components/profiles/ota/ota_flash_mesh.h @@ -0,0 +1,49 @@ +#ifndef __OTA_MESH_FLASH_ +#define __OTA_MESH_FLASH_ + +#include "ota_flash.h" + + + +#ifndef CFG_OTA_MESH +#error "unsupported OTA_mesh config, please check micro:CFG_OTA_MESH!" +#else + + +#if(CFG_FLASH >= 512) + #define OTAFM_APP_RAMRUN_ADDR 0x11017000 //108K bytes + #define OTAFM_APP_XIP_ADDR 0x11032000 //120K bytes + #define OTAFM_FW_OTA_ADDR 0x11050000 //256K bytes + #define OTAFM_FW_OTA_INFO_SZ 0x1000 //size of ota info, 4K + #define OTAFM_FW_OTA_DATA_OFFSET 0x2000 + #define OTAFM_FW_OTA_DATA_ADDR (OTAFM_FW_OTA_ADDR + OTAFM_FW_OTA_DATA_OFFSET) + +#endif + +#define OTAFM_DEV_FLG_USED 0 +#define OTAFM_DEV_FLG_UNINIT 0xff +#define OTAFM_DEV_FLG_INVALID 0x80 +#define OTAFM_DEV_FLG_READY 0xfe +#define OTAFM_DEV_FLG_OTAING 0xfc +#define OTAFM_DEV_FLG_COMPLETED 0xf8 +#define OTAFM_DEV_FLG_FAILED 0xec + + +typedef struct +{ + uint16_t dev_type; + uint16_t index; + uint8_t dev_addr[6]; +} otafmesh_dev_t; + +int otafm_write_partition(uint32 addr, uint32_t* p_sect, uint32_t size); +int otafm_write_boot_sector(uint32_t* p_sect, uint32_t size, uint32_t offset); +int otafm_dev_add(otafmesh_dev_t* pdev); +int otafm_dev_pull(otafmesh_dev_t* pdev); +int otafm_dev_clear(otafmesh_dev_t* pdev); +int otafm_fw_load(ota_fw_t* pfw); +int otafm_fw_execute(void); +int otafm_format(void); +#endif //CFG_FLASH +#endif //__OTA_MESH_FLASH_ + diff --git a/src/components/profiles/ota/ota_protocol.c b/src/components/profiles/ota/ota_protocol.c new file mode 100644 index 0000000..0a35623 --- /dev/null +++ b/src/components/profiles/ota/ota_protocol.c @@ -0,0 +1,1136 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#include "bcomdef.h" +#include "OSAL.h" +#include "linkdb.h" +#include "att.h" +#include "gatt.h" +#include "gatt_uuid.h" +#include "gatt_profile_uuid.h" +#include "gattservapp.h" + +#include "bus_dev.h" +//#include "ota.h" +#include "ota_service.h" +#include "ota_protocol.h" +#include "ota_flash.h" +#include "flash.h" +#include "crc16.h" +#include "version.h" +#include "log.h" +#include "error.h" +#include "ll_def.h" + +#define OTA_MODE_OTA_APPLICATION 0 +#define OTA_MODE_OTA_FCT 1 +#define OTA_MODE_OTA 2 +#define OTA_MODE_RESOURCE 3 +#define OTA_MODE_OTA_NADDR 6 //ota no address plus + + +#define OTA_MODE_SELECT_REG 0x4000f034 + + +#define OTA_BLOCK_REQ_TIMEOUT 4000 +#define OTA_BLOCK_BURST_TIMEOUT 1000 + + +#define Bytes2U32(u32val, b) {u32val = ((uint32_t)(b[0]&0xff)) | (((uint32_t)(b[1]&0xff))<<8)| (((uint32_t)(b[2]&0xff))<<16)| (((uint32_t)(b[3]&0xff))<<24);} + +#define Bytes2U16(u16val, b) {u16val = ((uint16_t)(b[0]&0xff)) | (((uint16_t)(b[1]&0xff))<<8);} + +enum +{ + + OTA_ST_UNCONNECTED = 0, + OTA_ST_CONNECTED, + //OTA_ST_PARAM, + + OTA_ST_WAIT_PARTITION_INFO, + OTA_ST_DATA, + OTA_ST_COMPLETE, + OTA_ST_CONFIRM, + OTA_ST_CHANGE, + OTA_ST_VERIFY_KEY, + //OTA_ST_VERIFY_INFO, + OTA_ST_ERROR, +}; + + +typedef struct +{ + uint32_t flash_addr; + uint32_t run_addr; + uint32_t size; + uint16_t checksum; + uint32_t mic; +} ota_part_t; + +//typedef struct{ +// uint32_t flash_addr; +// uint32_t run_addr; +// uint32_t size; +// uint32_t mic; +//}ota_sec_part_t; + +typedef struct +{ + uint8_t ota_state; + uint8_t s_random[16]; + uint8_t m_random[16]; + uint8_t s_key[16]; + uint8_t m_key[16]; + uint8_t m_confirm[16]; + uint8_t s_confirm[16]; + uint8_t task_id; + uint16_t tm_evt; + + bool ota_resource; //just upgrade resource data + uint16_t mtu_a; + bool notif_en; + uint8_t part_num; + uint8_t current_part; + + uint8_t bank_mode; //single bank or + + uint32_t bank_addr; + + bool reboot_flag; + //uint8_t param_size; + //uint8_t param_offset; + //uint32_t param_buf[MAX_OTA_PARAM_SIZE/4]; + + ota_part_t part[MAX_SECT_SUPPORT]; + + //ota_sec_part_t sec_part[MAX_SECT_SUPPORT]; + + uint32_t block_offset; + + uint32_t block_offset_retry; + + + uint8_t* partition_buf; +} ota_context_t; + +#define OTA_PBUF_SIZE (16*1024+16) +uint8_t ota_patition_buffer[OTA_PBUF_SIZE] __attribute__((section("ota_partition_buffer_area"))); + +static uint16_t s_ota_burst_size = 16; + +static bool s_ota_resource = FALSE; +static bool s_ota_address_plus = TRUE; + +static ota_context_t s_ota_ctx; +bool is_crypto_app(void); +extern uint32_t g_ota_sec_key[4]; +int flash_check_parition(unsigned char* pflash, int size, unsigned char* run_addr,unsigned char* micOut); +int flash_load_parition(unsigned char* pflash, int size, unsigned char* micIn,unsigned char* run_addr); +extern void bx_to_application(uint32_t run_addr); +extern bool verify_mic(unsigned char* buf, int size); +extern bool finidv(void); +extern llStatus_t LL_Rand( uint8* randData, + uint8 dataLen ); + +extern void LL_ENC_AES128_Encrypt0( uint8* key,uint8* plaintext,uint8* ciphertext ); +bool is_encrypt = FALSE; + +static void start_timer(uint32_t timeout) +{ + osal_start_timerEx(s_ota_ctx.task_id, s_ota_ctx.tm_evt, (uint32)timeout); +} +static void stop_timer(void) +{ + osal_clear_event(s_ota_ctx.task_id, s_ota_ctx.tm_evt); + osal_stop_timerEx(s_ota_ctx.task_id, s_ota_ctx.tm_evt); +} + + +static void reset_ctx(void) +{ + uint8_t task_id; + uint16_t tm_evt; + task_id = s_ota_ctx.task_id; + tm_evt = s_ota_ctx.tm_evt; + osal_memset(&s_ota_ctx, 0, sizeof(s_ota_ctx)); + s_ota_ctx.bank_mode = CFG_OTA_BANK_MODE; + s_ota_ctx.ota_resource = s_ota_resource; + s_ota_ctx.mtu_a = 20; + s_ota_ctx.task_id = task_id; + s_ota_ctx.tm_evt = tm_evt; +} + +static int sector_crc(void) +{ + uint16 crc = 0; +// int ret = 0; + ota_part_t* ppart = NULL; +// uint32_t mic =0; + ppart = &s_ota_ctx.part[s_ota_ctx.current_part]; +// if(is_encrypt){ +// //flash_check_parition((uint8_t*)(s_ota_ctx.partition_buf),ppart->size,NULL,(uint8_t*)&mic); +// if(ppart->flash_addr != ppart->run_addr){ +// flash_load_parition((uint8_t*)(s_ota_ctx.partition_buf), ppart->size, NULL,(uint8_t*)(s_ota_ctx.partition_buf)); +// flash_check_parition((uint8_t*)(s_ota_ctx.partition_buf),ppart->size-4,(uint8_t*)(s_ota_ctx.partition_buf),(uint8_t*)&mic); +// } +// +// LOG("ret=%d\n",ret); +// if(ret!=0){ +// return PPlus_ERR_OTA_MIC; +// } +// return PPlus_SUCCESS; +// } +// else{ + crc = crc16(0, (void*)s_ota_ctx.partition_buf, ppart->size); + + if(crc != ppart->checksum) + { + #if 0 + LOG("[CRC ERR %04x %04x]\n",crc,ppart->checksum); + + for(int i=0; isize; i++) + { + LOG("%02x ",s_ota_ctx.partition_buf[i]); + + if((i&0x0f)==0) + LOG("\n"); + } + + LOG("\n"); + #endif + return PPlus_ERR_OTA_CRC; + } + + return PPlus_SUCCESS; +// } +} + + + +static int sector_crypto(void) +{ + bool chk = FALSE; + ota_part_t* ppart = NULL; + //uint8_t key[16]; + int ret = -1; + + if(s_ota_ctx.ota_resource)//resource no crypto + return PPlus_SUCCESS; + + if(finidv() == FALSE) + return PPlus_SUCCESS; + + ppart = &s_ota_ctx.part[s_ota_ctx.current_part]; + chk = verify_mic(s_ota_ctx.partition_buf,ppart->size); + + if(chk == FALSE) + return PPlus_ERR_OTA_CRYPTO; + + ppart->size -= 4; //remove MIC when store to flash + + if(is_encrypt) + { + if(ppart->flash_addr == ppart->run_addr) + { + uint32_t mic; + flash_check_parition((uint8_t*)(s_ota_ctx.partition_buf),ppart->size,NULL,(uint8_t*)&mic); + + if(mic!=ppart->mic) + { + return PPlus_ERR_OTA_CRYPTO; + } + } + else + { + ret = flash_load_parition((uint8_t*)(s_ota_ctx.partition_buf), ppart->size,(uint8_t*)&ppart->mic, NULL); + //LOG("ret=%x\n",ret); + + if(ret!=0) + { + return PPlus_ERR_OTA_CRYPTO; + } //flash_check_parition((uint8_t*)(s_ota_ctx.partition_buf),ppart->size, NULL ,(uint8_t*)&ppart->mic); + } + } + else + { + ppart->checksum = (uint32_t)crc16(0, (void*)s_ota_ctx.partition_buf, ppart->size); //figure out new checksum because the data length changed + } + + return PPlus_SUCCESS; +} + + +static void response(int state_cmd, int err) +{ + attHandleValueNoti_t notif; + osal_memset(¬if, 0, sizeof(notif)); + notif.len = 2; + notif.value[0] = (uint8_t)err; + notif.value[1] = (uint8_t)state_cmd; + ota_Notify(¬if); +} + +static void response_param(int state_cmd,uint8_t* data,uint32_t size) +{ + attHandleValueNoti_t notif; + osal_memset(¬if, 0, sizeof(notif)); + notif.len = 1+size; + notif.value[0] = (uint8_t)state_cmd; + + for(int i=0; iflash_addr != 0) + return FALSE; + + if(ppart->run_addr&OTAF_BASE_ADDR != OTAF_BASE_ADDR || ppart->run_addr + ppart->size > OTAF_END_ADDR+1 || ppart->size>OTA_PBUF_SIZE) + return FALSE; + + if(ppart->run_addr < OTAF_1st_BOOTINFO_ADDR + OTAF_1st_BOOTINFO_SIZE) + return FALSE; + } + else if(ppart->run_addr == ppart->flash_addr) + { + //check if address out of flash area + if(ppart->flash_addr > OTAF_END_ADDR || ppart->flash_addr < OTAF_BASE_ADDR||ppart->size>OTA_PBUF_SIZE) + return FALSE; + + //for XIP, only No FCT and single bank allowed + if(USE_FCT && CFG_OTA_BANK_MODE!=OTA_SINGLE_BANK) + return FALSE; + } + else + { + if(ppart->run_addr < SRAM0_BASE_ADDRESS || ppart->run_addr > SRAM0_BASE_ADDRESS + 64*1024 || ppart->size>OTA_PBUF_SIZE) + return FALSE; + + if((ppart->flash_addr | OTAF_BASE_ADDR) + ppart->size > OTAF_END_ADDR+1) + return FALSE; + } + + return TRUE; +} + +static void handle_error(int error) +{ + response_err(error); + + if(s_ota_ctx.notif_en) + { + s_ota_ctx.ota_state = OTA_ST_CONNECTED; + s_ota_ctx.part_num = 0; + s_ota_ctx.partition_buf = ota_patition_buffer; + } + else + { + reset_ctx(); + } +} + +void process_ctrl_cmd(uint8_t* cmdbuf, uint8_t size) +{ + ota_cmd_t cmd; + int ret = PPlus_SUCCESS; + + if(size > sizeof(cmd)) + { + return; + } + + osal_memcpy(&cmd, cmdbuf, size); + is_encrypt = is_crypto_app(); + + switch(cmd.cmd) + { + case OTA_CMD_SEC_CONFIRM: +// if(s_ota_ctx.ota_state != OTA_ST_CONFIRM){ +// //case invalid state +// handle_error_state(); +// break; +// } + s_ota_ctx.ota_state = OTA_ST_CHANGE; + osal_memset(s_ota_ctx.m_key,0,sizeof(s_ota_ctx.m_key)); + osal_memcpy(s_ota_ctx.m_key, cmd.p.ver_key,sizeof(s_ota_ctx.m_key)); + LL_Rand((uint8_t*)s_ota_ctx.s_random, sizeof(s_ota_ctx.s_random)); + LL_ENC_AES128_Encrypt0((uint8_t*)g_ota_sec_key,s_ota_ctx.s_random,s_ota_ctx.s_key); + response_param(OTA_RSP_SEC_CONFIRM,s_ota_ctx.s_key,sizeof(s_ota_ctx.s_key)); + break; + + case OTA_CMD_RND_CHANGE: +// if(s_ota_ctx.ota_state != OTA_ST_CHANGE){ +// //case invalid state +// handle_error_state(); +// break; +// } + s_ota_ctx.ota_state = OTA_ST_VERIFY_KEY; + osal_memset(s_ota_ctx.m_random,0,sizeof(s_ota_ctx.m_random)); + osal_memcpy(s_ota_ctx.m_random,cmd.p.random,sizeof(s_ota_ctx.m_random)); + uint8_t key[16]; + LL_ENC_AES128_Encrypt0((uint8_t*)g_ota_sec_key,s_ota_ctx.m_random,key); + + if(osal_memcmp(key,s_ota_ctx.m_key,sizeof(key))==0) + { + handle_error_fatal(PPlus_ERR_KEY_VERIFY); + } + else + { + response_param(OTA_RSP_RND_CHANGE,s_ota_ctx.s_random,sizeof(s_ota_ctx.s_random)); + } + + break; + + case OTA_CMD_VERIFY_KEY: //app mode start OTA +// if(s_ota_ctx.ota_state != OTA_ST_VERIFY_START){ +// //case invalid state +// handle_error_state(); +// break; +// } + osal_memset(s_ota_ctx.m_confirm,0,sizeof(s_ota_ctx.m_confirm)); + osal_memcpy(s_ota_ctx.m_confirm,cmd.p.confirm,sizeof(s_ota_ctx.m_confirm)); + uint8_t random_key[16]; + LL_ENC_AES128_Encrypt0(s_ota_ctx.m_random,s_ota_ctx.s_random,random_key); + LL_ENC_AES128_Encrypt0((uint8_t*)g_ota_sec_key,random_key,s_ota_ctx.s_confirm); + + if(osal_memcmp(s_ota_ctx.s_confirm,s_ota_ctx.m_confirm,sizeof(s_ota_ctx.s_confirm))==0) + { + handle_error_fatal(PPlus_ERR_DOUBLE_CONFIRM); + } + else + { + response_param(OTA_RSP_VERIFY_KEY,s_ota_ctx.s_confirm,sizeof(s_ota_ctx.s_confirm)); + s_ota_ctx.ota_state = OTA_ST_CONNECTED; + } + + break; + #ifdef CFG_OTA_MESH + + case OTA_CMD_START_OTA: + if(s_ota_ctx.ota_state != OTA_ST_CONNECTED) + { + //case invalid state + handle_error_state(); + break; + } + + if(cmd.p.start.sector_num > MAX_SECT_SUPPORT) + { + //case invalid state + handle_error_fatal(PPlus_ERR_INVALID_PARAM); + break; + } + + s_ota_ctx.bank_mode = CFG_OTA_BANK_MODE; + s_ota_ctx.ota_resource = FALSE; + ota_flash_read_bootsector(&s_ota_ctx.bank_addr); + s_ota_ctx.ota_state = OTA_ST_WAIT_PARTITION_INFO; + s_ota_ctx.part_num = cmd.p.start.sector_num; + //s_ota_ctx.param_size = cmd.p.start.param_size; + s_ota_ctx.partition_buf = ota_patition_buffer; + osal_memset(&(s_ota_ctx.part[0]), 0, sizeof(ota_part_t)*MAX_SECT_SUPPORT); + //osal_memset(&(s_ota_ctx.param_buf[0]), 0xff, MAX_OTA_PARAM_SIZE); + s_ota_burst_size = 16; + + if(cmd.p.start.burst_size > 0) + s_ota_burst_size = cmd.p.start.burst_size; + + if(cmd.p.start.burst_size == 0xff) + s_ota_burst_size = 0xffff; + + AT_LOG("s_ota_burst_size is %x\n", s_ota_burst_size); + ret = otafm_format(); + response(OTA_RSP_START_OTA, ret); + break; + #else + + case OTA_CMD_START_OTA: + if(s_ota_ctx.ota_state != OTA_ST_CONNECTED) + { + //case invalid state + handle_error_state(); + break; + } + + if(cmd.p.start.sector_num > MAX_SECT_SUPPORT) + { + //case invalid state + handle_error_fatal(PPlus_ERR_INVALID_PARAM); + break; + } + + s_ota_ctx.bank_mode = CFG_OTA_BANK_MODE; + s_ota_ctx.ota_resource = s_ota_resource; + ota_flash_read_bootsector(&s_ota_ctx.bank_addr); + s_ota_ctx.ota_state = OTA_ST_WAIT_PARTITION_INFO; + s_ota_ctx.part_num = cmd.p.start.sector_num; + //s_ota_ctx.param_size = cmd.p.start.param_size; + s_ota_ctx.partition_buf = ota_patition_buffer; + osal_memset(&(s_ota_ctx.part[0]), 0, sizeof(ota_part_t)*MAX_SECT_SUPPORT); + //osal_memset(&(s_ota_ctx.param_buf[0]), 0xff, MAX_OTA_PARAM_SIZE); + s_ota_burst_size = 16; + + if(cmd.p.start.burst_size > 0) + s_ota_burst_size = cmd.p.start.burst_size; + + if(cmd.p.start.burst_size == 0xff) + s_ota_burst_size = 0xffff; + + AT_LOG("s_ota_burst_size is %x\n", s_ota_burst_size); + + if(!s_ota_ctx.ota_resource) + { + //if(cmd.p.start.param_size >0) + // s_ota_ctx.ota_state = OTA_ST_PARAM; + uint8_t key[16]= {0}; + + if(is_encrypt) + { + if(osal_memcmp(key,s_ota_ctx.m_confirm,sizeof(s_ota_ctx.m_confirm))==1 || osal_memcmp(0,s_ota_ctx.s_confirm,sizeof(s_ota_ctx.s_confirm))==1) + { + handle_error_state(); + //hal_system_soft_reset(); + break; + } + } + + //ret = ota_flash_erase(s_ota_ctx.bank_addr); + hal_flash_erase_sector(OTAF_2nd_BOOTINFO_ADDR); + } + + response(OTA_RSP_START_OTA, ret); + break; + #endif + + case OTA_CMD_PARTITION_INFO: + { + uint8_t idx = cmd.p.part.index; + ota_part_t* ppart = &s_ota_ctx.part[idx]; + +// ota_sec_part_t* sec_ppart = &s_ota_ctx.sec_part[idx]; + if(s_ota_ctx.ota_state != OTA_ST_WAIT_PARTITION_INFO) + { + //case invalid state + handle_error_state(); + break; + } + + Bytes2U32(ppart->flash_addr,cmd.p.part.flash_addr); + Bytes2U32(ppart->run_addr,cmd.p.part.run_addr); + Bytes2U32(ppart->size,cmd.p.part.size); + + if(is_encrypt) + { + Bytes2U32(ppart->mic,cmd.p.part.checksum); + } + else + { + Bytes2U16(ppart->checksum,cmd.p.part.checksum); + } + + if(!s_ota_ctx.ota_resource) + { + if(ppart->run_addr > OTAF_BASE_ADDR && ppart->run_addr flash_addr = ppart->run_addr; + } + } + + if(!validate_partition_parameter(ppart)) + { + handle_error(PPlus_ERR_INVALID_PARAM); + //hal_system_soft_reset(); + break; + } + + s_ota_ctx.ota_state = OTA_ST_DATA; + s_ota_ctx.current_part = idx; + s_ota_ctx.block_offset = 0; + s_ota_ctx.block_offset_retry = 0; + s_ota_ctx.partition_buf = ota_patition_buffer; + osal_memset(ota_patition_buffer, 0xff, OTA_PBUF_SIZE); + response(OTA_RSP_PARTITION_INFO, PPlus_SUCCESS); + break; + } + + /* case OTA_CMD_BLOCK_INFO: + { + uint8_t b_idx = cmd.p.block.index; + if(s_ota_ctx.ota_state != OTA_ST_WAIT_BLOCK_INFO){ + //case invalid state + handle_error_state(); + return; + } + s_ota_ctx.ota_state = OTA_ST_DATA; + s_ota_ctx.block_idx = b_idx; + s_ota_ctx.block_offset = 0; + s_ota_ctx.block_offset_retry = 0; + Bytes2U16(s_ota_ctx.block_size ,cmd.p.block.size); + response(OTA_RSP_BLOCK_INFO, PPlus_SUCCESS); + start_timer(OTA_BLOCK_REQ_TIMEOUT); + break; + } */ + case OTA_CMD_REBOOT: + { + s_ota_ctx.reboot_flag = FALSE; + + if(size == 1) + { + hal_system_soft_reset(); + } + else if(size == 2) + { + if(cmd.p.reboot_flag == 1) + { + s_ota_ctx.reboot_flag = TRUE; + response(OTA_RSP_REBOOT, PPlus_SUCCESS); + break; + } + } + + response(OTA_RSP_REBOOT, PPlus_ERR_INVALID_PARAM); + break; + } + + case OTA_CMD_ERASE: + { + uint32_t flash_addr; + uint32_t flash_size; + + if(s_ota_ctx.ota_state != OTA_ST_WAIT_PARTITION_INFO) + { + //case invalid state + handle_error_state(); + break; + } + + if(!s_ota_ctx.ota_resource) + { + //case invalid state + handle_error_state(); + break; + } + + Bytes2U32(flash_addr,cmd.p.erase.flash_addr); + Bytes2U32(flash_size,cmd.p.erase.size); + //erase + ret = ota_flash_erase_area(flash_addr, flash_size); + + if(ret != PPlus_SUCCESS) + { + handle_error(ret); + break; + } + + response(OTA_RSP_ERASE, PPlus_SUCCESS); + break; + } + + default: + s_ota_ctx.ota_state = OTA_ST_ERROR; + response(OTA_RSP_ERROR, PPlus_ERR_NOT_SUPPORTED); + break; + } +} + +/* + boot sector, total 256 bytes, 64 words: + count by words: + (0) : number of(N) + (1~3) : reserved + (4~7) : partition 1 information: flash address, run address, partition size, checksum + ... + (N*4 ~ (N*4+3) : partition N information: flash address, run address, partition size, checksum + + (20 ~63) : reserved +*/ + + + +#ifdef CFG_OTA_MESH +static int write_app_boot_sector(void) +{ + //write application boot sector data + int idx; + int ret; + uint32_t bs[4]; + osal_memset(bs, 0, 16); + bs[0] = 0x4641544f; //"OTAF" + bs[1] = s_ota_ctx.part_num; + bs[2] = 0xffffffff; + bs[3] = 0xffffffff; + ret = otafm_write_boot_sector(bs, 16, 0); + + if(ret) + return ret; + + for(idx = 0; idx < s_ota_ctx.part_num; idx ++) + { + bs[0] = s_ota_ctx.part[idx].flash_addr; + bs[1] = s_ota_ctx.part[idx].run_addr; + bs[2] = s_ota_ctx.part[idx].size; + + if(is_encrypt) + { + bs[3] = s_ota_ctx.part[idx].mic; + } + else + { + bs[3] = (uint32_t)s_ota_ctx.part[idx].checksum; + } + + return ret; + } + + return ret; +} + +static void partition_program(void) +{ + int ret; + ota_part_t* ppart = NULL; + uint32_t flash_addr = 0; + ppart = &s_ota_ctx.part[s_ota_ctx.current_part]; + flash_addr = ppart->flash_addr; + ret = otafm_write_partition(flash_addr, (uint32_t*)s_ota_ctx.partition_buf, ppart->size); + + if(ret != PPlus_SUCCESS) + { + handle_error(ret); + return; + } + + //case all partition data finished + if(s_ota_ctx.current_part+1 == s_ota_ctx.part_num) + { + if(!s_ota_ctx.ota_resource) + ret = write_app_boot_sector(); + + s_ota_ctx.ota_state = OTA_ST_COMPLETE; + response(OTA_RSP_OTA_COMPLETE,PPlus_SUCCESS); + } + else + { + s_ota_ctx.ota_state = OTA_ST_WAIT_PARTITION_INFO; + response(OTA_RSP_PARTITION_COMPLETE, PPlus_SUCCESS); + } +} +#else //normal OTA +static int write_app_boot_sector(void) +{ + //write application boot sector data + int idx; + int ret; + uint32_t bs[4]; + osal_memset(bs, 0, 16); + hal_flash_erase_sector(OTAF_2nd_BOOTINFO_ADDR); + bs[0] = s_ota_ctx.part_num; + + if(CFG_OTA_BANK_MODE==OTA_SINGLE_BANK) + bs[1] = OTAF_SINGLE_BANK; + else + bs[1] = (s_ota_ctx.bank_addr == OTAF_APP_BANK_0_ADDR) ? OTAF_DUAL_BANK_0 : OTAF_DUAL_BANK_1; + + bs[2] = 0; + bs[3] = 0xffffffff; + LOG("[WT_APP_BOOT]\n"); + ret = ota_flash_write_boot_sector(bs, 16, 0); + LOG("%08x %08x %08x %08x [%03d]\n",bs[0],bs[1],bs[2],bs[3],ret); + + if(ret) + return ret; + + for(idx = 0; idx < s_ota_ctx.part_num; idx ++) + { + bs[0] = s_ota_ctx.part[idx].flash_addr; + bs[1] = s_ota_ctx.part[idx].run_addr; + bs[2] = s_ota_ctx.part[idx].size; + + //bs[3] = (uint32_t)s_ota_ctx.part[idx].checksum; + if(is_encrypt) + { + bs[3] = s_ota_ctx.part[idx].mic; + } + else + { + bs[3] = (uint32_t)s_ota_ctx.part[idx].checksum; + } + + ret = ota_flash_write_boot_sector(bs, 16, 16*(idx+1)); + LOG("%08x %08x %08x %08x [%03d]\n",bs[0],bs[1],bs[2],bs[3],ret); + + if(ret) + return ret; + } + + return PPlus_SUCCESS; +} + +static void partition_program(void) +{ + int ret; + ota_part_t* ppart = NULL; + uint32_t flash_addr = 0; + ppart = &s_ota_ctx.part[s_ota_ctx.current_part]; + uint32_t er_addr, er_size; + + //write partition data + if(s_ota_ctx.ota_resource) + { + flash_addr = ppart->run_addr; + } + else if(ppart->flash_addr == ppart->run_addr) + { + flash_addr = ppart->run_addr; + er_addr = flash_addr & 0xfffff000;//make address 4k align + er_size = flash_addr + ppart->size + 0xfff - er_addr ; + er_size = er_size & 0xfffff000; + ret = ota_flash_erase_area(er_addr, er_size); + + if(ret != PPlus_SUCCESS) + { + handle_error(ret); + return; + } + } + else + { + flash_addr = ppart->flash_addr + s_ota_ctx.bank_addr; + + if((flash_addr%0x1000)==0) + { +// hal_flash_erase_sector(OTAF_2nd_BOOTINFO_ADDR); + er_addr = flash_addr & 0xfffff000;//make address 4k align + } + else + { + er_addr = (flash_addr & 0xfffff000) +0x1000;//make address 4k align + } + + er_size = flash_addr + ppart->size + 0xfff - er_addr ; + er_size = er_size & 0xfffff000; + ret = ota_flash_erase_area(er_addr, er_size); + + if(ret != PPlus_SUCCESS) + { + handle_error(ret); + return; + } + } + + ret = ota_flash_write_partition(flash_addr, (uint32_t*)s_ota_ctx.partition_buf, ppart->size); + + if(ret != PPlus_SUCCESS) + { + handle_error(ret); + return; + } + + //case all partition data finished + if(s_ota_ctx.current_part+1 == s_ota_ctx.part_num) + { + if(!s_ota_ctx.ota_resource) + ret = write_app_boot_sector(); + + s_ota_ctx.ota_state = OTA_ST_COMPLETE; + response(OTA_RSP_OTA_COMPLETE,PPlus_SUCCESS); + } + else + { + s_ota_ctx.ota_state = OTA_ST_WAIT_PARTITION_INFO; + response(OTA_RSP_PARTITION_COMPLETE, PPlus_SUCCESS); + } +} +#endif +static void process_ota_partition_data(uint8_t* data, uint8_t size) +{ + uint32_t block_offset = s_ota_ctx.block_offset; + ota_part_t* ppart = NULL; + ppart = &s_ota_ctx.part[s_ota_ctx.current_part]; + osal_memcpy(s_ota_ctx.partition_buf + block_offset, data, size); + block_offset += size; + AT_LOG("boff[%d], rty[%d]\n", block_offset,s_ota_ctx.block_offset_retry); + + if(block_offset > ppart->size) + { + handle_error(PPlus_ERR_OTA_DATA_SIZE); + return; + } + + s_ota_ctx.block_offset = block_offset; + + if(s_ota_ctx.block_offset - s_ota_ctx.block_offset_retry == OTA_DATA_BURST_SIZE) + { + response(OTA_RSP_BLOCK_BURST, PPlus_SUCCESS); + s_ota_ctx.block_offset_retry = s_ota_ctx.block_offset; + start_timer(OTA_BLOCK_REQ_TIMEOUT); + } + else + { + start_timer(OTA_BLOCK_BURST_TIMEOUT); + } + + if(block_offset == ppart->size) + { + stop_timer(); + + //cec check + if(is_encrypt==0) + { + if(sector_crc() != PPlus_SUCCESS) + { + handle_error(PPlus_ERR_OTA_CRC); + return; + } + } + + if(sector_crypto()!=PPlus_SUCCESS) + { + handle_error(PPlus_ERR_OTA_CRYPTO); + //hal_system_soft_reset(); + return; + } + + partition_program(); + return; + } +} + +/* + static void process_ota_param_data(uint8_t* data, uint8_t size) + { + uint8_t offset = s_ota_ctx.param_offset; + uint8_t* param_buf = (uint8_t*)(s_ota_ctx.param_buf); + + osal_memcpy(param_buf + offset, data, size); + offset += size; + + if(offset > s_ota_ctx.param_size){ + handle_error(PPlus_ERR_OTA_DATA_SIZE); + return; + } + + if(offset == s_ota_ctx.param_size){ + //case param data finished + s_ota_ctx.ota_state = OTA_ST_WAIT_PARTITION_INFO; + response(OTA_RSP_PARAM, PPlus_SUCCESS); + } + return; + } +*/ + + +void process_ota_data(uint8_t* data, uint8_t size) +{ + switch(s_ota_ctx.ota_state) + { + case OTA_ST_DATA: + process_ota_partition_data(data, size); + break; + + //case OTA_ST_PARAM: + // process_ota_param_data(data, size); + // break; + default: + handle_error_state(); + break; + } +} + + + +void process_service_evt(ota_Evt_t* pev) +{ + AT_LOG("PSE: ev[%d], st[%d ]\n",pev->ev, s_ota_ctx.ota_state); + + switch(pev->ev) + { + case OTA_EVT_CONTROL: + process_ctrl_cmd(pev->data, pev->size); + break; + + case OTA_EVT_DATA: + process_ota_data(pev->data, pev->size); + break; + + case OTA_EVT_CONNECTED: + break; + + case OTA_EVT_DISCONNECTED: + LOG("[OTA_EVT_DISCONNECTED]Disconnected!\n"); + + if(s_ota_ctx.reboot_flag) + { + LOG("Reboot!\n"); + hal_system_soft_reset(); + } + + reset_ctx(); + break; + + case OTA_EVT_NOTIF_ENABLE: + s_ota_ctx.ota_state = OTA_ST_CONNECTED; + s_ota_ctx.notif_en = TRUE; + break; + + case OTA_EVT_NOTIF_DISABLE: + s_ota_ctx.ota_state = OTA_ST_UNCONNECTED; + s_ota_ctx.notif_en = FALSE; + break; + + default: + break; + } +} +#define __APP_RUN_ADDR__ (0x1FFF1838) +__asm void __attribute__((section("ota_app_loader_area"))) otaProtocol_RunApp(void) +{ + LDR R0, = __APP_RUN_ADDR__ + LDR R1, [R0, #4] + BX R1 + ALIGN +} + +int __attribute__((section("ota_app_loader_area"))) run_application(void) +{ + int ret; + HAL_ENTER_CRITICAL_SECTION(); + ret = ota_flash_load_app(); + + if(ret == PPlus_SUCCESS) + { + otaProtocol_RunApp(); + } + + HAL_EXIT_CRITICAL_SECTION(); + return PPlus_SUCCESS; +} + +int run_fct(void) +{ + HAL_ENTER_CRITICAL_SECTION(); + { + #if(CFG_FLASH >= 512) + int ret = ota_flash_load_fct(); + + if(ret != PPlus_SUCCESS) + #endif + otaProtocol_RunApp(); + } + HAL_EXIT_CRITICAL_SECTION(); + return PPlus_SUCCESS; +} + +void otaProtocol_mtu(uint16_t mtu) +{ + s_ota_ctx.mtu_a = mtu - 3; + //response(OTA_RSP_BLOCK_BURST, PPlus_ERR_OTA_BAD_DATA); +} + +void otaProtocol_TimerEvt(void) +{ + s_ota_ctx.block_offset = s_ota_ctx.block_offset_retry; + response(OTA_RSP_BLOCK_BURST, PPlus_ERR_OTA_BAD_DATA); + LOG("ll_to_hci_pkt_cnt = %d\r\n", conn_param[0].pmCounter.ll_to_hci_pkt_cnt); + LOG("ll_hci_to_ll_pkt_cnt = %d\r\n", conn_param[0].pmCounter.ll_hci_to_ll_pkt_cnt); + LOG("ll_hci_buffer_alloc_err_cnt = %d\r\n", conn_param[0].pmCounter.ll_hci_buffer_alloc_err_cnt); +} + +void otaProtocol_BootMode(void) +{ + uint32_t ota_mode = read_reg(OTA_MODE_SELECT_REG) & 0xf; + uint32_t reg = ((SDK_VER_MAJOR &0xf) << 4) | ((SDK_VER_MINOR &0xf)<< 8) | ((SDK_VER_REVISION &0xff)<<12); + #ifdef SDK_VER_TEST_BUILD + reg |= (((SDK_VER_TEST_BUILD - 'a' + 1)&0xf) << 20); + #endif + write_reg(OTA_MODE_SELECT_REG,reg); + + switch(ota_mode) + { + case OTA_MODE_OTA_APPLICATION: + run_application(); + break; + + case OTA_MODE_OTA_FCT: + run_fct(); + break; + + case OTA_MODE_RESOURCE: + s_ota_resource = TRUE; + break; + + case OTA_MODE_OTA_NADDR: + s_ota_address_plus = FALSE; + + default: + break; + } +} + +bool otaProtocol_address_plus(void) +{ + return s_ota_address_plus; +} + + +int otaProtocol_init(uint8_t task_id, uint16_t tm_evt) +{ + s_ota_ctx.task_id = task_id; + s_ota_ctx.tm_evt = tm_evt; + reset_ctx(); + ota_flash_read_bootsector(&s_ota_ctx.bank_addr); + ota_AddService(process_service_evt); + return PPlus_SUCCESS; +} + diff --git a/src/components/profiles/ota/ota_protocol.h b/src/components/profiles/ota/ota_protocol.h new file mode 100644 index 0000000..6b5afd8 --- /dev/null +++ b/src/components/profiles/ota/ota_protocol.h @@ -0,0 +1,105 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +#ifndef _OTA_PROTOCOL_H +#define _OTA_PROTOCOL_H + +#define MAX_OTA_PARAM_SIZE 256 +//#define OTA_BLOCK_SIZE 1024 + +#define OTA_DATA_BURST_SIZE (((uint32_t)s_ota_ctx.mtu_a) * ((uint32_t)s_ota_burst_size)) + +enum +{ + + OTA_CMD_START_OTA = 1, + OTA_CMD_PARTITION_INFO, + OTA_CMD_BLOCK_INFO, + OTA_CMD_REBOOT, + OTA_CMD_ERASE, + OTA_CMD_SEC_CONFIRM, + OTA_CMD_RND_CHANGE, + OTA_CMD_VERIFY_KEY, + //OTA_CMD_VERIFY_INFO, + + + OTA_RSP_START_OTA = 0x81, //81 + OTA_RSP_PARAM, //82 + OTA_RSP_OTA_COMPLETE, //83 + OTA_RSP_PARTITION_INFO, //84 + OTA_RSP_PARTITION_COMPLETE, //85 + OTA_RSP_BLOCK_INFO, //86 + OTA_RSP_BLOCK_BURST, //87 + OTA_RSP_BLOCK_COMPLETE, //88 + OTA_RSP_ERASE, //89 + OTA_RSP_REBOOT, //8a + OTA_RSP_SEC_CONFIRM, //8b + OTA_RSP_RND_CHANGE, //8c + OTA_RSP_VERIFY_KEY, //8d + //OTA_RSP_VERIFY_INFO, //8e + OTA_RSP_ERROR = 0xff, + +}; + +typedef struct +{ + uint8_t cmd; + + union + { + + uint8_t random[16]; + + uint8_t ver_key[16]; + uint8_t confirm[16]; + struct + { + uint8_t sector_num; + uint8_t burst_size; + } start; + struct + { + uint8_t index; + uint8_t flash_addr[4]; + uint8_t run_addr[4]; + uint8_t size[4]; + uint8_t checksum[4]; + //uint8_t mic[4]; + } part; +// struct +// { +// uint8_t index; +// uint8_t flash_addr[4]; +// uint8_t run_addr[4]; +// uint8_t size[4]; +// uint8_t checksum[4]; +// } part_sec; + struct + { + uint8_t size[2]; //max 1024 + uint8_t index; + } block; + + struct + { + uint8_t flash_addr[4]; + uint8_t size[4]; + } erase; + + uint8_t reboot_flag; + + } p; //parameter +} ota_cmd_t; + +extern const char* OTA_CRYPTO_IV; +extern bool aes_ccm_phyplus_dec(const unsigned char* iv, unsigned char* din, int dLen, unsigned char* micIn, unsigned char* dout); + +void otaProtocol_mtu(uint16_t mtu); +void otaProtocol_TimerEvt(void); +bool otaProtocol_address_plus(void); +void otaProtocol_BootMode(void); +void otaProtocol_RunApp(void); +int otaProtocol_init(uint8_t task_id, uint16_t tm_evt); + +#endif diff --git a/src/components/profiles/ota/ota_service.c b/src/components/profiles/ota/ota_service.c new file mode 100644 index 0000000..aa88215 --- /dev/null +++ b/src/components/profiles/ota/ota_service.c @@ -0,0 +1,302 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +#include "bcomdef.h" +#include "OSAL.h" +#include "linkdb.h" +#include "att.h" +#include "gatt.h" +#include "gatt_uuid.h" +#include "gatt_profile_uuid.h" +#include "peripheral.h" +#include "gattservapp.h" + +#include "ota_service.h" +#include "log.h" + +#ifndef CFG_OTA_MESH +static const uint8 ota_ServiceUUID[ATT_UUID_SIZE] = +{0x23, 0xf1, 0x6e, 0x53, 0xa4, 0x22, 0x42, 0x61, 0x91, 0x51, 0x8b, 0x9b, 0x01, 0xff, 0x33, 0x58}; + +//command characteristic +static const uint8 ota_CommandUUID[ATT_UUID_SIZE] = +{0x23, 0xf1, 0x6e, 0x53, 0xa4, 0x22, 0x42, 0x61, 0x91, 0x51, 0x8b, 0x9b, 0x02, 0xff, 0x33, 0x58}; + +// Sensor location characteristic +static const uint8 ota_ResponseUUID[ATT_UUID_SIZE] = +{0x23, 0xf1, 0x6e, 0x53, 0xa4, 0x22, 0x42, 0x61, 0x91, 0x51, 0x8b, 0x9b, 0x03, 0xff, 0x33, 0x58}; + +// Command characteristic +static const uint8 ota_DataUUID[ATT_UUID_SIZE] = +{0x23, 0xf1, 0x6e, 0x53, 0xa4, 0x22, 0x42, 0x61, 0x91, 0x51, 0x8b, 0x9b, 0x04, 0xff, 0x33, 0x58}; + +#else +static const uint8 ota_ServiceUUID[ATT_UUID_SIZE] = +{0xde, 0x61, 0x49, 0x67, 0xea, 0x50, 0x57, 0x2c, 0xbb, 0xba, 0x52, 0x9b, 0x01, 0xff, 0x33, 0x58}; + +//command characteristic +static const uint8 ota_CommandUUID[ATT_UUID_SIZE] = +{0xde, 0x61, 0x49, 0x67, 0xea, 0x50, 0x57, 0x2c, 0xbb, 0xba, 0x52, 0x9b, 0x02, 0xff, 0x33, 0x58}; + +// Sensor location characteristic +static const uint8 ota_ResponseUUID[ATT_UUID_SIZE] = +{0xde, 0x61, 0x49, 0x67, 0xea, 0x50, 0x57, 0x2c, 0xbb, 0xba, 0x52, 0x9b, 0x03, 0xff, 0x33, 0x58}; + +// Command characteristic +static const uint8 ota_DataUUID[ATT_UUID_SIZE] = +{0xde, 0x61, 0x49, 0x67, 0xea, 0x50, 0x57, 0x2c, 0xbb, 0xba, 0x52, 0x9b, 0x04, 0xff, 0x33, 0x58}; +#endif + +static const gattAttrType_t ota_Service = {ATT_UUID_SIZE, ota_ServiceUUID}; + +static uint8 ota_CommandProps = GATT_PROP_WRITE; +static uint8 ota_CommandValue = 0; + +// OTA response Characteristic +static uint8 ota_ResponseProps = GATT_PROP_NOTIFY; +static uint8 ota_ResponseValue = 0; +static gattCharCfg_t ota_ResponseCCCD[GATT_MAX_NUM_CONN]; + +// OTA Data Characteristic +static uint8 ota_DataProps = GATT_PROP_WRITE_NO_RSP; +static uint8 ota_DataValue = 0; + +#define OTA_COMMAND_HANDLE 2 +#define OTA_RSP_HANDLE 4 +#define OTA_DATA_HANDLE 7 +static gattAttribute_t ota_AttrTbl[] = +{ + //OTA Service + { + {ATT_BT_UUID_SIZE, primaryServiceUUID}, /* type */ + GATT_PERMIT_READ, /* permissions */ + 0, /* handle */ + (uint8*)& ota_Service /* pValue */ + }, + + //OTA Command Declaration + { + {ATT_BT_UUID_SIZE, characterUUID}, + GATT_PERMIT_READ, + 0, + &ota_CommandProps + }, + + //OTA Command Value + { + {ATT_UUID_SIZE, ota_CommandUUID}, + GATT_PERMIT_WRITE, + 0, + &ota_CommandValue + }, + + // OTA response Declaration + { + {ATT_BT_UUID_SIZE, characterUUID}, + GATT_PERMIT_READ, + 0, + &ota_ResponseProps + }, + + //response Value + { + {ATT_UUID_SIZE, ota_ResponseUUID}, + GATT_PERMIT_READ, + 0, + &ota_ResponseValue + }, + + // OTA response Client Characteristic Configuration + { + {ATT_BT_UUID_SIZE, clientCharCfgUUID}, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8*)ota_ResponseCCCD + }, + + //Data Declaration + { + {ATT_BT_UUID_SIZE, characterUUID}, + GATT_PERMIT_READ, + 0, + &ota_DataProps + }, + + // Command Value + { + {ATT_UUID_SIZE, ota_DataUUID}, + GATT_PERMIT_WRITE, + 0, + &ota_DataValue + } +}; + +static ota_ProfileChangeCB_t ota_AppCBs = NULL; + +static void handleConnStatusCB(uint16 connHandle, uint8 changeType); + +static uint8 ota_ReadAttrCB(uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen); +static bStatus_t ota_WriteAttrCB(uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset); + +CONST gattServiceCBs_t ota_ProfileCBs = +{ + ota_ReadAttrCB, // Read callback function pointer + ota_WriteAttrCB, // Write callback function pointer + NULL // Authorization callback function pointer +}; + +static uint8 ota_ReadAttrCB(uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen) +{ + bStatus_t status = ATT_ERR_READ_NOT_PERMITTED; + LOG("ReadAttrCB\n"); + + // If attribute permissions require authorization to read, return error + if (gattPermitAuthorRead(pAttr->permissions)) + { + // Insufficient authorization + return (ATT_ERR_INSUFFICIENT_AUTHOR); + } + + return (status); +} + +static bStatus_t ota_WriteAttrCB(uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset) +{ + bStatus_t status = SUCCESS; + + //uint8 notifyApp = 0xFF; + // If attribute permissions require authorization to write, return error + if (gattPermitAuthorWrite(pAttr->permissions)) + { + // Insufficient authorization + return (ATT_ERR_INSUFFICIENT_AUTHOR); + } + + if (pAttr->type.len == ATT_BT_UUID_SIZE) + { + // 16-bit UUID + uint16 uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]); + + if (uuid == GATT_CLIENT_CHAR_CFG_UUID) + { + status = GATTServApp_ProcessCCCWriteReq(connHandle, pAttr, pValue, len, + offset, GATT_CLIENT_CFG_NOTIFY); + + if (status == SUCCESS && ota_AppCBs) + { + uint16 charCfg = BUILD_UINT16(pValue[0], pValue[1]); + LOG("CCCD set: [%d]\n", charCfg); + + if (ota_AppCBs) + { + ota_Evt_t evt; + evt.ev = charCfg == 1 ? OTA_EVT_NOTIF_ENABLE : OTA_EVT_NOTIF_DISABLE; + evt.size = 0; + evt.data = NULL; + ota_AppCBs(&evt); + } + } + } + } + else + { + //LOG("WR:%d\n", pAttr->handle); + // 128-bit UUID Command + if (pAttr->handle == ota_AttrTbl[OTA_COMMAND_HANDLE].handle) + { + if (ota_AppCBs) + { + ota_Evt_t evt; + evt.ev = OTA_EVT_CONTROL; + evt.size = len; + evt.data = pValue; + ota_AppCBs(&evt); + } + } + + // 128-bit UUID Data + if (pAttr->handle == ota_AttrTbl[OTA_DATA_HANDLE].handle) + { + if (ota_AppCBs) + { + ota_Evt_t evt; + evt.ev = OTA_EVT_DATA; + evt.size = len; + evt.data = pValue; + ota_AppCBs(&evt); + } + } + } + + return (status); +} + +bStatus_t ota_AddService(ota_ProfileChangeCB_t cb) +{ + uint8 status = SUCCESS; + // Register with Link DB to receive link status change callback + VOID linkDB_Register(handleConnStatusCB); + GATTServApp_InitCharCfg(INVALID_CONNHANDLE, ota_ResponseCCCD); + // Register GATT attribute list and CBs with GATT Server App + status = GATTServApp_RegisterService(ota_AttrTbl, + GATT_NUM_ATTRS(ota_AttrTbl), + &ota_ProfileCBs); + + if (status != SUCCESS) + LOG("Add OTA service failed!\n"); + + ota_AppCBs = cb; + return (status); +} + +static void handleConnStatusCB(uint16 connHandle, uint8 changeType) +{ + // Make sure this is not loopback connection + if (connHandle != LOOPBACK_CONNHANDLE) + { + // Reset Client Char Config if connection has dropped + if ((changeType == LINKDB_STATUS_UPDATE_REMOVED) || + ((changeType == LINKDB_STATUS_UPDATE_STATEFLAGS) && + (!linkDB_Up(connHandle)))) + { + GATTServApp_InitCharCfg(connHandle, ota_ResponseCCCD); + + if (ota_AppCBs) + { + ota_Evt_t evt; + evt.ev = OTA_EVT_DISCONNECTED; + evt.size = 0; + evt.data = NULL; + ota_AppCBs(&evt); + } + } + } +} + +bStatus_t ota_Notify(attHandleValueNoti_t* pNoti) +{ + uint16 connHandle; + uint16 value; + GAPRole_GetParameter(GAPROLE_CONNHANDLE, &connHandle); + value = GATTServApp_ReadCharCfg(connHandle, ota_ResponseCCCD); + + if (connHandle == INVALID_CONNHANDLE) + return bleIncorrectMode; + + // If notifications enabled + if (value & GATT_CLIENT_CFG_NOTIFY) + { + AT_LOG("Notif %x,%x\n", pNoti->value[0], pNoti->value[1]); + // Set the handle + pNoti->handle = ota_AttrTbl[OTA_RSP_HANDLE].handle; + // Send the Indication + return GATT_Notification(connHandle, pNoti, FALSE); + } + + return bleIncorrectMode; +} diff --git a/src/components/profiles/ota/ota_service.h b/src/components/profiles/ota/ota_service.h new file mode 100644 index 0000000..596224a --- /dev/null +++ b/src/components/profiles/ota/ota_service.h @@ -0,0 +1,37 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#ifndef _OTA_SERVICE_H +#define _OTA_SERVICE_H +#include "att.h" + +enum +{ + OTA_EVT_CONTROL = 1, + OTA_EVT_DATA, + OTA_EVT_CONNECTED, + OTA_EVT_DISCONNECTED, + OTA_EVT_NOTIF_ENABLE, + OTA_EVT_NOTIF_DISABLE, +}; + + +typedef struct +{ + uint8 ev; + uint8_t size; + uint8_t* data; +} ota_Evt_t; + +typedef void (*ota_ProfileChangeCB_t)(ota_Evt_t* pev); + + +bStatus_t ota_AddService( ota_ProfileChangeCB_t cb); +bStatus_t ota_Notify(attHandleValueNoti_t* pNoti); + + + +#endif + diff --git a/src/components/profiles/ota/otam_protocol.c b/src/components/profiles/ota/otam_protocol.c new file mode 100644 index 0000000..68f2377 --- /dev/null +++ b/src/components/profiles/ota/otam_protocol.c @@ -0,0 +1,621 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + + +#include "bcomdef.h" +#include "OSAL.h" +#include "OSAL_PwrMgr.h" +#include "OSAL_bufmgr.h" +#include "gatt.h" +#include "ll.h" +#include "ll_common.h" +#include "hci.h" +#include "gapgattserver.h" +#include "gattservapp.h" +#include "central.h" +#include "gapbondmgr.h" +#include "simpleGATTprofile_ota.h" +#include "ota_mesh_master.h" +#include "timer.h" +#include "log.h" +#include "ll_def.h" +#include "global_config.h" +#include "flash.h" +#include "rflib.h" +#include "otam_cmd.h" +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "otam_protocol.h" +#include "ota_mesh.h" +#include "ota_app_service.h" +#include "ota_protocol.h" +#include "ota_flash.h" +#include "ota_flash_mesh.h" +//#include "otam_1clk_ota.h" +#include "crc16.h" +#include "error.h" + +#define OTAF_BASE_ADDR 0x11000000 +#define OTAF_END_ADDR 0x1107ffff + +enum +{ + OTAM_ST_DISCONNECT = 0, + OTAM_ST_CONNECTED, //connected, idle + OTAM_ST_WAIT_STARTED, + OTAM_ST_PARAM, + OTAM_ST_WAIT_PARTITION_INFO, + OTAM_ST_DATA, + OTAM_ST_COMPLETE, + OTAM_ST_ERROR, + OTAM_ST_CANCELING, //wait stop +}; + + + + + +typedef struct +{ + ota_fw_t fw; + + //data cache for a block transmit + uint32_t cache_size; + uint32_t cache_offset; + uint8_t cache_retry; + uint8_t* cache; +} otam_fw_t; + + +typedef struct +{ + uint8_t state; + uint8_t run_mode; + bool reset_mode; + uint16_t mtu_a; + uint16_t burst_size; + uint8_t opcode; + otam_fw_t fw; + otam_proto_meth_t method; +} otam_proto_ctx_t; + + +static otam_proto_ctx_t s_otap_ctx_t; + +static void print_hex (const uint8* data, uint16 len) +{ + //return; + #if(DEBUG_INFO > 1) + uint16 i; + char strdata[5]; + + for (i = 0; i < len - 1; i++) + { + //if(i %16 == 0 && i >0) + // LOG("\n"); + sprintf(strdata, "%.2x", data[i]); + AT_LOG("%s ",strdata); + } + + sprintf(strdata, "%.2x", data[i]); + AT_LOG("%s\n",strdata); + #endif +} + + + + +static int otam_proto_ctx_reset(uint8_t st) +{ + otam_proto_ctx_t* pctx = &s_otap_ctx_t; + otam_proto_meth_t* method = &(pctx->method); + pctx->state = st; + pctx->opcode = 0; + memset(&(pctx->fw), 0, sizeof(otam_fw_t)); + method->clear(); + return PPlus_SUCCESS; +} + +static void otam_proto_disconnect(void* param) +{ + otam_proto_ctx_reset(OTAM_ST_DISCONNECT); +} +static void otam_proto_connect(void* param) +{ + otam_proto_ctx_t* pctx = &s_otap_ctx_t; + otam_proto_conn_param_t* pconn = (otam_proto_conn_param_t*)param; + pctx->state = OTAM_ST_CONNECTED; + pctx->mtu_a = pconn->mtu -3; + pctx->opcode = 0xff; + + if(pconn->run_mode == OTAC_RUNMODE_APP) + { + pctx->run_mode = OTAC_RUNMODE_APP; + pctx->reset_mode = 0; + } + else if(pconn->run_mode == OTAC_RUNMODE_OTA) + { + pctx->run_mode = OTAC_RUNMODE_OTA; + + if(pctx->reset_mode == OTAC_RUNMODE_OTARES) + pctx->run_mode = OTAC_RUNMODE_OTARES; + + pctx->reset_mode = 0; + } + else + { + pctx->run_mode = 0; + pctx->reset_mode = 0; + } +} + +static int send_patition_info(void) +{ + otam_proto_ctx_t* pctx = &s_otap_ctx_t; + otam_fw_t* pfw = &(pctx->fw); + otam_proto_meth_t* method = &(pctx->method); + uint8_t data[20]; + + if(pctx->state != OTAM_ST_WAIT_STARTED && pctx->state != OTAM_ST_DATA) + { + return PPlus_ERR_INVALID_STATE; + } + + //partition cmd: 02 ID FA FA FA FA RA RA RA RA SZ SZ SZ SZ CS CS + // ID: index + // FA: flash address + // RA: run address + // SZ: partition size + // CS: checksum + uint32_t val; + uint16_t offset = 0; + uint32_t flash_addr = 0; + uint32_t run_addr = pfw->fw.part[pfw->fw.part_current].run_addr; + + if(run_addr > OTAF_BASE_ADDR && run_addr < OTAF_END_ADDR ) + { + flash_addr = run_addr; + } + else + { + //calculate store address in flash + for(int i = 0; ifw.part_current; i++ ) + { + if(pfw->fw.part[i].run_addr > OTAF_BASE_ADDR && pfw->fw.part[i].run_addr < OTAF_END_ADDR) + continue; + + val = pfw->fw.part[i].size +3; + val = val - (val%4); + flash_addr += val; + } + } + + data[offset ++] = OTA_CMD_PARTITION_INFO; + data[offset ++] = pfw->fw.part_current; + val = flash_addr; + data[offset ++] = (uint8_t)(val&0xff); + data[offset ++] = (uint8_t)((val>>8)&0xff); + data[offset ++] = (uint8_t)((val>>16)&0xff); + data[offset ++] = (uint8_t)((val>>24)&0xff); + val = run_addr; + data[offset ++] = (uint8_t)(val&0xff); + data[offset ++] = (uint8_t)((val>>8)&0xff); + data[offset ++] = (uint8_t)((val>>16)&0xff); + data[offset ++] = (uint8_t)((val>>24)&0xff); + val = pfw->fw.part[pfw->fw.part_current].size; + data[offset ++] = (uint8_t)(val&0xff); + data[offset ++] = (uint8_t)((val>>8)&0xff); + data[offset ++] = (uint8_t)((val>>16)&0xff); + data[offset ++] = (uint8_t)((val>>24)&0xff); + val = (uint32_t)(pfw->fw.part[pfw->fw.part_current].checksum); + data[offset ++] = (uint8_t)(val&0xff); + data[offset ++] = (uint8_t)((val>>8)&0xff); + pctx->state = OTAM_ST_WAIT_PARTITION_INFO; + pfw->cache_offset = 0; + pfw->cache_size = 0; + pfw->cache_retry = 0; + pfw->fw.offset = 0; + return method->write_cmd(data, offset, 1000); +} + + +static int load_data_cache(void) +{ + otam_proto_ctx_t* pctx = &s_otap_ctx_t; + otam_fw_t* pfw = &(pctx->fw); + ota_fw_part_t* ppart = &(pfw->fw.part[pfw->fw.part_current]); + uint16_t mtu_a = pctx->mtu_a; + uint32_t size = mtu_a * pctx->burst_size; + + if(pfw->fw.offset + size > ppart->size) + { + size = ppart->size - pfw->fw.offset; + } + + //memset(pfw->cache, 0, (ATT_MTU_SIZE-3)); + pfw->cache = (uint8_t*)(ppart->flash_addr + pfw->fw.offset+OTAFM_FW_OTA_DATA_ADDR); + pfw->cache_size = size; + pfw->cache_offset = 0; + pfw->cache_retry = 0; + pfw->fw.offset += size; + return PPlus_SUCCESS; +} + +static int send_data(void) +{ + otam_proto_ctx_t* pctx = &s_otap_ctx_t; + otam_fw_t* pfw = &(pctx->fw); + otam_proto_meth_t* method = &(pctx->method); + + if(!(method->write_data)) + return PPlus_ERR_NOT_REGISTED; + + if(pctx->state != OTAM_ST_DATA) + return PPlus_ERR_INVALID_STATE; + + int ret = PPlus_SUCCESS; + uint16_t size = 0; + uint16_t mtu_a = pctx->mtu_a; + + while(pfw->cache_size - pfw->cache_offset) + { + size = mtu_a; + + if((pfw->cache_size - pfw->cache_offset) < mtu_a) + size = pfw->cache_size - pfw->cache_offset; + + ret = method->write_data(pfw->cache + pfw->cache_offset, size); + + if(ret != PPlus_SUCCESS) + { + method->write_data_delay(2); + return PPlus_SUCCESS; + } + + pfw->cache_offset += size; + } + + return PPlus_SUCCESS; +} + +void print_version(uint8_t* vinfo) +{ +} + +static void handle_app_notify_event(void* param, uint8_t len) +{ + otam_proto_ctx_t* pctx = &s_otap_ctx_t; + + switch(pctx->opcode) + { + case OTAAPP_CMD_START_OTA: + break; + + case OTAAPP_CMD_VER: + print_version(param); + break; + + default: + break; + } +} + +static void handle_ota_notify_event(void* param, uint8_t len) +{ + otam_proto_ctx_t* pctx = &s_otap_ctx_t; + otam_fw_t* pfw = &(pctx->fw); + uint8_t* pnotify = (uint8_t*)param; + otam_proto_meth_t* method = &(pctx->method); + int retval = pnotify[0]; + + if(len == 1) //fatal error + { + otam_proto_ctx_reset(OTAM_ST_CONNECTED); + return; + } + + LOG("OTA Notif %x, %x\n",pnotify[0],pnotify[1]); + print_hex(pnotify, len); + + switch(pnotify[1]) //response type + { + case OTA_RSP_START_OTA: + { + if(retval == PPlus_SUCCESS && pctx->state == OTAM_ST_WAIT_STARTED) + { + send_patition_info(); + } + else + { + pctx->state = OTAM_ST_ERROR; + } + + break; + } + + case OTA_RSP_PARAM: + case OTA_RSP_BLOCK_INFO: + case OTA_RSP_BLOCK_COMPLETE: + { + pctx->state = OTAM_ST_ERROR; + break; + } + + case OTA_RSP_OTA_COMPLETE: + { + uint8_t data[20]; + + if(method->write_cmd) + { + data[0] = OTA_CMD_REBOOT; + data[1] = 1; + pctx->state = OTAM_ST_COMPLETE; + LOG("OTA completed!!\n"); + method->write_cmd(data, 2, 1000); + } + + break; + } + + case OTA_RSP_PARTITION_INFO: + { + pctx->state = OTAM_ST_DATA; + + if(pfw->fw.part_current) + { + LOG(" "); + } + + load_data_cache(); + send_data(); + break; + } + + case OTA_RSP_PARTITION_COMPLETE: + { + pfw->fw.total_offset += pfw->cache_size; + pfw->fw.part_current ++; + send_patition_info(); + break; + } + + case OTA_RSP_BLOCK_BURST: + { + if(pctx->state != OTAM_ST_DATA) + { + pctx->state = OTAM_ST_ERROR; + break; + } + + if(retval == PPlus_SUCCESS) + { + load_data_cache(); + send_data(); + } + else if(retval == PPlus_ERR_OTA_BAD_DATA) + { + //case block data is not completed, retry block data + pfw->cache_retry++; + pfw->cache_offset = 0; + + if(pfw->cache_retry > 3) + { + pctx->state = OTAM_ST_ERROR; + break; + } + + send_data(); + } + else + { + pctx->state = OTAM_ST_ERROR; + } + + break; + } + + case OTA_RSP_REBOOT: + { + LOG("[OTA_RSP_REBOOT]GAPCentralRole_TerminateLink\n"); + GAPCentralRole_TerminateLink(0); + } + + case OTA_RSP_ERASE: + case OTA_RSP_ERROR: + default: + { + pctx->state = OTAM_ST_ERROR; + break; + } + } +} + + +void otamProtocol_event(otap_evt_t* pev) +{ + otam_proto_ctx_t* pctx = &s_otap_ctx_t; + + switch(pev->ev) + { + case OTAP_EVT_DISCONNECTED: + otam_proto_disconnect(pev->data); + break; + + case OTAP_EVT_CONNECTED: + otam_proto_connect(pev->data); + break; + + case OTAP_EVT_NOTIFY: + { + if(pctx->run_mode == OTAC_RUNMODE_APP) + handle_app_notify_event(pev->data, pev->len); + else + handle_ota_notify_event(pev->data, pev->len); + + break; + } + + case OTAP_EVT_DATA_WR_DELAY: + { + send_data(); + break; + } + + case OTAP_EVT_BLE_TIMEOUT: + default: + { + //pctx->state = OTAM_ST_ERROR; + break; + } + } +} +#define OTAM_FW_DATA_ADDR 0x11040000 +#define OTAM_FW_DATA_ADDR1 0x11060000 + +/* + word | desc: + 0 | flag: "OTAF" + 1 | partition number + i*2 + 2 | run address + i*2 + 3 | size + N*2 +2 | data area + +*/ + +int load_fw(uint8_t fw_id) +{ + otam_proto_ctx_t* pctx = &s_otap_ctx_t; + otam_fw_t* pfw = &(pctx->fw); + uint32_t faddr = fw_id == 0 ? OTAM_FW_DATA_ADDR : OTAM_FW_DATA_ADDR1; + uint8_t* pdata = (uint8_t*) (faddr); + uint32_t* pdata32 = (uint32_t*) pdata; + uint32_t offset = 0; + LOG("load fw %x\n", faddr); + memset((void*)pfw, 0,sizeof(otam_fw_t)); + + if(!((char)(pdata[0]) == 'O' && (char)(pdata[1]) == 'T' &&(char)(pdata[2]) == 'A'&&(char)(pdata[3]) == 'F')) + { + return PPlus_ERR_INVALID_DATA; + } + + pfw->fw.part_num = (uint8_t)(pdata32[1]); + offset = 2 * 4 + 2 * 4 * pfw->fw.part_num; + pfw->fw.total_size = 0; + + for (uint8_t i = 0; i < pfw->fw.part_num; i++) + { + pfw->fw.part[i].run_addr = pdata32[i*2+2]; + pfw->fw.part[i].size = pdata32[i*2+3]; + pfw->fw.part[i].flash_addr = faddr + offset; + pfw->fw.part[i].checksum = crc16(0, (const volatile void* )(pfw->fw.part[i].flash_addr), pfw->fw.part[i].size); + offset += pfw->fw.part[i].size; + pfw->fw.total_size += pfw->fw.part[i].size; + } + + pfw->fw.total_size += 0; + return PPlus_SUCCESS; +} + +int load_res(void) +{ + return PPlus_ERR_NOT_IMPLEMENTED; +} + + +int otamProtocol_start_ota(ota_fw_t* pffw) +{ + otam_proto_ctx_t* pctx = &s_otap_ctx_t; + otam_fw_t* pfw = &(pctx->fw); + otam_proto_meth_t* method = &(pctx->method); + uint8_t data[20]; + memcpy(&(pfw->fw), pffw, sizeof(ota_fw_t)); + pfw->fw.offset = 0; + pfw->fw.part_current = 0; + pfw->fw.total_offset = 0; + + if(pctx->state < OTAM_ST_CONNECTED) + return PPlus_ERR_BLE_NOT_READY; + + if(pctx->run_mode != OTAC_RUNMODE_OTA) + { + return PPlus_ERR_INVALID_STATE; + } + + if(method->write_cmd) + { + pctx->state = OTAM_ST_WAIT_STARTED; + pfw->fw.part_current = 0; + + if(pctx->mtu_a == 20) + { + pctx->burst_size = OTA_BURST_SIZE_DEFAULT; + data[0] = OTA_CMD_START_OTA; + data[1] = pfw->fw.part_num; + data[2] = 0; + } + else + { + pctx->burst_size = 0xffff; + data[0] = OTA_CMD_START_OTA; + data[1] = pfw->fw.part_num; + data[2] = OTA_BURST_SIZE_HISPEED; + } + + return method->write_cmd(data, 3, 1000); + } + + return PPlus_ERR_NOT_REGISTED; +} + + +int otamProtocol_stop_ota(void) +{ + otam_proto_ctx_t* pctx = &s_otap_ctx_t; + otam_proto_meth_t* method = &(pctx->method); + uint8_t data[20]; + + if(method->write_cmd) + { + data[0] = OTA_CMD_START_OTA; + data[1] = 0xff; + data[2] = 0; + pctx->state = OTAM_ST_CANCELING; + return method->write_cmd(data, 3, 1000); + } + + return PPlus_ERR_NOT_REGISTED; +} + +int otamProtocol_app_start_ota(uint8_t mode) +{ + otam_proto_ctx_t* pctx = &s_otap_ctx_t; + otam_proto_meth_t* method = &(pctx->method); + uint8_t data[20]; + + if(pctx->run_mode != OTAC_RUNMODE_APP) + return PPlus_ERR_INVALID_STATE; + + if(mode > OTA_MODE_RESOURCE) + return PPlus_ERR_INVALID_PARAM; + + if(method->write_cmd) + { + data[0] = OTAAPP_CMD_START_OTA; + data[1] = mode; + data[2] = 1; + return method->write_cmd(data, 3, 0); + } + + return PPlus_ERR_NOT_REGISTED; +} + +int otamProtocol_init(otam_proto_meth_t* method) +{ + memset(&s_otap_ctx_t, 0, sizeof(s_otap_ctx_t)); + s_otap_ctx_t.method = *method; + return PPlus_SUCCESS; +} + diff --git a/src/components/profiles/ota/otam_protocol.h b/src/components/profiles/ota/otam_protocol.h new file mode 100644 index 0000000..edff75b --- /dev/null +++ b/src/components/profiles/ota/otam_protocol.h @@ -0,0 +1,61 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#ifndef __OTA_MAST_PROTO_ +#define __OTA_MAST_PROTO_ + +#include "ota_flash.h" + + +#define OTA_BURST_SIZE_DEFAULT 16 +#define OTA_BURST_SIZE_HISPEED 0xff + + +enum +{ + OTAP_EVT_DISCONNECTED =1, + OTAP_EVT_CONNECTED, + OTAP_EVT_NOTIFY, + OTAP_EVT_DATA_WR_DELAY, + OTAP_EVT_BLE_TIMEOUT, +}; + + +typedef struct +{ + uint8_t run_mode; + uint16_t mtu; +} otam_proto_conn_param_t; + +typedef struct +{ + uint8_t ev; + uint16_t len; + void* data; +} otap_evt_t; + +typedef int (*otam_clear_t)(void); +typedef int (*otam_wcmd_op_t)(uint8_t* data, uint16_t len, uint32_t timeout); +typedef int (*otam_wdata_op_t)(uint8_t* data, uint16_t len); +typedef int (*otam_wdata_delay_t)(uint32_t msec_delay); + +typedef struct +{ + otam_clear_t clear; + otam_wcmd_op_t write_cmd; + otam_wdata_op_t write_data; + otam_wdata_delay_t write_data_delay; +} otam_proto_meth_t; + + + +void otamProtocol_event(otap_evt_t* pev); +int otamProtocol_start_ota(ota_fw_t* pffw); +int otamProtocol_stop_ota(void); +int otamProtocol_app_start_ota(uint8_t mode); +int otamProtocol_init(otam_proto_meth_t* method); + +#endif + diff --git a/src/components/profiles/ota_app/ota_app_service.c b/src/components/profiles/ota_app/ota_app_service.c new file mode 100644 index 0000000..2b0c82d --- /dev/null +++ b/src/components/profiles/ota_app/ota_app_service.c @@ -0,0 +1,581 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +#include "bcomdef.h" +#include +#include +#include "OSAL.h" +#include "linkdb.h" +#include "att.h" +#include "gatt.h" +#include "gatt_uuid.h" +#include "gatt_profile_uuid.h" +#include "peripheral.h" +#include "gattservapp.h" +#include "clock.h" +#include "ota_app_service.h" +#include "log.h" +#include "error.h" +#include "ll.h" + + +CONST uint8 ota_ServiceUUID[ATT_UUID_SIZE] = +{0x23, 0xf1, 0x6e, 0x53, 0xa4, 0x22, 0x42, 0x61, 0x91, 0x51, 0x8b, 0x9b, 0x01, 0xff, 0x33, 0x58}; + +//command characteristic +CONST uint8 ota_CommandUUID[ATT_UUID_SIZE] = +{0x23, 0xf1, 0x6e, 0x53, 0xa4, 0x22, 0x42, 0x61, 0x91, 0x51, 0x8b, 0x9b, 0x02, 0xff, 0x33, 0x58}; + +// Response characteristic +CONST uint8 ota_ResponseUUID[ATT_UUID_SIZE] = +{0x23, 0xf1, 0x6e, 0x53, 0xa4, 0x22, 0x42, 0x61, 0x91, 0x51, 0x8b, 0x9b, 0x03, 0xff, 0x33, 0x58}; + +static uint8 ota_passcode[11]={0}; +//static uint8 ota_key_register_flag=0; +static uint8 ota_key_check_flag=1; +static CONST gattAttrType_t ota_Service = {ATT_UUID_SIZE, ota_ServiceUUID}; + +static uint8 ota_CommandProps = GATT_PROP_WRITE; +static uint8 ota_CommandValue = 0; + +// OTA response Characteristic +static uint8 ota_ResponseProps = GATT_PROP_NOTIFY; +static uint8 ota_ResponseValue = 0; +static gattCharCfg_t ota_ResponseCCCD[GATT_MAX_NUM_CONN]; + +extern void LL_ENC_AES128_Encrypt( uint8* key,uint8* plaintext,uint8* ciphertext ); +extern uint32_t g_ota_sec_key[4]; + +#define OTA_COMMAND_HANDLE 2 +#define OTA_RSP_HANDLE 4 +#define OTA_DATA_HANDLE 7 +static gattAttribute_t ota_AttrTbl[] = +{ + //OTA Service + { + {ATT_BT_UUID_SIZE, primaryServiceUUID}, /* type */ + GATT_PERMIT_READ, /* permissions */ + 0, /* handle */ + (uint8*)& ota_Service /* pValue */ + }, + + //OTA Command Declaration + { + {ATT_BT_UUID_SIZE, characterUUID}, + GATT_PERMIT_READ, + 0, + &ota_CommandProps + }, + + //OTA Command Value + { + {ATT_UUID_SIZE, ota_CommandUUID}, + GATT_PERMIT_WRITE, + 0, + &ota_CommandValue + }, + + // OTA response Declaration + { + {ATT_BT_UUID_SIZE, characterUUID}, + GATT_PERMIT_READ, + 0, + &ota_ResponseProps + }, + + //response Value + { + {ATT_UUID_SIZE, ota_ResponseUUID}, + GATT_PERMIT_READ, + 0, + &ota_ResponseValue + }, + + // OTA response Client Characteristic Configuration + { + {ATT_BT_UUID_SIZE, clientCharCfgUUID}, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8*)ota_ResponseCCCD + }, + +}; + +typedef struct +{ + bool notify_en; + uint8_t s_random[16]; + uint8_t m_random[16]; + uint8_t s_key[16]; + uint8_t m_key[16]; + uint8_t m_confirm[16]; + uint8_t s_confirm[16]; + + uint8_t ver_major; + uint8_t ver_minor; + uint8_t ver_revision; + uint8_t ver_test_build; + uint8_t ota_mode; + uint8_t bank_info; +} ota_app_ctx; + +ota_app_ctx s_ota_app; + +bool s_reboot_flg = false; + +static uint8 ota_ReadAttrCB(uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen); +static bStatus_t ota_WriteAttrCB(uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset); + +static bStatus_t sendNotify(attHandleValueNoti_t* pNoti); +CONST gattServiceCBs_t ota_ProfileCBs = +{ + ota_ReadAttrCB, // Read callback function pointer + ota_WriteAttrCB, // Write callback function pointer + NULL // Authorization callback function pointer +}; + +/*response format:*/ +/*Byte value*/ +/*0 error code*/ +/*1~19 response data payload*/ +static void response(uint8_t* rsp_data, uint8_t size) +{ + attHandleValueNoti_t notif; + osal_memset(¬if, 0, sizeof(notif)); + + if (size > 20) + return; + + notif.len = size; + osal_memcpy(notif.value, rsp_data, size); + sendNotify(¬if); +} + +static void response_rsp(int state_cmd, uint8_t* rsp_data, uint8_t size) +{ + attHandleValueNoti_t notif; + osal_memset(¬if, 0, sizeof(notif)); + + if (size > 20) + return; + + notif.len = size+1; + notif.value[0] = (uint8_t)state_cmd; + osal_memcpy(notif.value+1, rsp_data, size); + sendNotify(¬if); +} + +static int set_ota_mode(uint8_t mode) +{ + if (mode > OTA_MODE_RESOURCE && mode != OTA_MODE_OTA_NADDR) + return PPlus_ERR_INVALID_PARAM; + + write_reg(OTA_MODE_SELECT_REG, mode); + return PPlus_SUCCESS; +} + +static void load_ota_version(void) +{ + uint32_t reg = read_reg(OTA_MODE_SELECT_REG); + s_ota_app.ver_major = (uint8_t)((reg >> 4) & 0xf); + s_ota_app.ver_minor = (uint8_t)((reg >> 8) & 0xf); + s_ota_app.ver_revision = (uint8_t)((reg >> 12) & 0xff); + s_ota_app.ver_test_build = (uint8_t)((reg >> 20) & 0xf); + + if (s_ota_app.ver_test_build) + LOG("OTA Boot Version: %d.%d.%d%c\n", + s_ota_app.ver_major, s_ota_app.ver_minor, s_ota_app.ver_revision, s_ota_app.ver_test_build + 'a' - 1); + else + LOG("OTA Boot Version: %d.%d.%d\n", + s_ota_app.ver_major, s_ota_app.ver_minor, s_ota_app.ver_revision); +} + +void __attribute__((weak)) ui_firmware_upgrade(void); +static void ota_disconnect_link(void) +{ + LL_Disconnect(0, LL_DISCONNECT_REMOTE_DEV_POWER_OFF); + WaitMs(500); +} + +static void process_cmd(uint8_t* cmdbuf, uint8_t size) +{ + uint8_t rsp = PPlus_SUCCESS; + ota_app_cmd_t cmd; + + if(size > sizeof(cmd)) + { + return; + } + + osal_memcpy(&cmd, cmdbuf, size); + + switch (cmd.cmd) // switch (cmdbuf[0]) + { + case OTAAPP_CMD_START_OTA: + { + if(ota_key_check_flag == 0){ + break; + } + uint8_t ota_mode = cmdbuf[1]; + s_reboot_flg = false; + //set AON register then reboot + rsp = set_ota_mode(ota_mode); + + if (rsp == PPlus_SUCCESS) + { + //GAPRole_TerminateConnection(); + if (size != 3) + { + ota_disconnect_link(); + hal_system_soft_reset(); + } + + if (cmdbuf[2] != 1) + { + ota_disconnect_link(); + hal_system_soft_reset(); + } + + //if cmdbuf[2] is 1 + //case host will initiate termination request + //when device terminated, device reboot to ota mode + response(&rsp, 1); + s_reboot_flg = true; + } + else + { + response(&rsp, 1); + } + } + break; + + case OTAAPP_CMD_FORMAT: + { + rsp = PPlus_ERR_NOT_SUPPORTED; + //format fs and application + response(&rsp, 1); + } + break; + + case OTAAPP_CMD_INFO: + { + //take mac address and version info + uint8_t info_rsp[20]; + osal_memset(info_rsp, 0, 20); + info_rsp[0] = PPlus_SUCCESS; + GAPRole_GetParameter(GAPROLE_BD_ADDR, info_rsp + 1); + + if (s_ota_app.ver_test_build) + { + sprintf((char*)(info_rsp + 7), "V%d.%d.%d%c", + s_ota_app.ver_major, + s_ota_app.ver_minor, + s_ota_app.ver_revision, + 'a' + s_ota_app.ver_test_build - 1); + } + else + { + sprintf((char*)(info_rsp + 7), "V%d.%d.%d", s_ota_app.ver_major, s_ota_app.ver_minor, s_ota_app.ver_revision); + } + + response(info_rsp, 8 + strlen((const char*)info_rsp + 7)); + } + break; + case OTAAPP_CMD_CHECKKEY: + { + + if((size-1)==ota_passcode[0]&&ota_passcode[0]>0) + { + if(osal_memcmp(&ota_passcode[1],&cmdbuf[1],ota_passcode[0])==TRUE) + { + ota_key_check_flag=1; + rsp = PPlus_SUCCESS; + response(&rsp, 1); + break; + + } + else + { + LOG("pass key error\n\r"); + rsp = PPlus_ERR_NOT_SUPPORTED; + response(&rsp, 1); + + } + + + } + else + { + rsp = PPlus_ERR_NOT_SUPPORTED; + response(&rsp, 1); + + } + } + break; + + case OTAAPP_CMD_GETKEY: + { + if(cmdbuf[1]==0x0F&&ota_passcode[0]>0&&ota_passcode[0]<=10) + { + uint8 buf[20]={OTAAPP_CMD_GETKEY}; + osal_memcpy(&buf[1],&ota_passcode[0],ota_passcode[0]+1); + response(buf, ota_passcode[0]+2); + } + else + { + rsp = PPlus_ERR_NOT_SUPPORTED; + response(&rsp, 1); + } + } + break; + + case OTAAPP_CMD_SEC_CONFIRM: + { + osal_memset(s_ota_app.m_key,0,sizeof(s_ota_app.m_key)); + osal_memcpy(s_ota_app.m_key, cmd.p.ver_key, sizeof(s_ota_app.m_key)); + LL_Rand((uint8_t*)s_ota_app.s_random, sizeof(s_ota_app.s_random)); + osal_memset(s_ota_app.s_key,0,sizeof(s_ota_app.s_key)); + LL_ENC_AES128_Encrypt((uint8_t*)g_ota_sec_key, s_ota_app.s_random,s_ota_app.s_key); + response_rsp(OTAAPP_RSP_SEC_CONFIRM,s_ota_app.s_key,sizeof(s_ota_app.s_key)); + } + break; + + case OTAAPP_CMD_RND_CHANGE: + { + osal_memset(s_ota_app.m_random,0,sizeof(s_ota_app.m_random)); + osal_memcpy(s_ota_app.m_random,cmd.p.random,sizeof(s_ota_app.m_random)); + uint8_t key[16]; + LL_ENC_AES128_Encrypt((uint8_t*)g_ota_sec_key,s_ota_app.m_random,key); + + if(osal_memcmp(key,s_ota_app.m_key,sizeof(key))==0) + { + ota_disconnect_link(); + hal_system_soft_reset(); + } + else + { + response_rsp(OTAAPP_RSP_RND_CHANGE,s_ota_app.s_random,sizeof(s_ota_app.s_random)); + } + } + break; + + case OTAAPP_CMD_VERIFY_KEY: + { + osal_memset(s_ota_app.m_confirm,0,sizeof(s_ota_app.m_confirm)); + osal_memcpy(s_ota_app.m_confirm,cmd.p.confirm,sizeof(s_ota_app.m_confirm)); + uint8_t random_key[16]; + LL_ENC_AES128_Encrypt(s_ota_app.m_random,s_ota_app.s_random,random_key); + LL_ENC_AES128_Encrypt((uint8_t*)g_ota_sec_key,random_key,s_ota_app.s_confirm); + + if(osal_memcmp(s_ota_app.s_confirm,s_ota_app.m_confirm,sizeof(s_ota_app.s_confirm))==0) + { + ota_disconnect_link(); + hal_system_soft_reset(); + } + else + { + //s_ota_ctx.ota_state = OTA_ST_CONNECTED; + response_rsp(OTAAPP_RSP_VERIFY_KEY,s_ota_app.s_confirm,sizeof(s_ota_app.s_confirm)); + } + } + break; + + default: + rsp = PPlus_ERR_OTA_UNKNOW_CMD; + response(&rsp, 1); + } +} + +static void handleConnStatusCB(uint16 connHandle, uint8 changeType) +{ + // Make sure this is not loopback connection +// LOG("handleConnStatusCB %x, %d\n", connHandle, changeType); + if (connHandle != LOOPBACK_CONNHANDLE) + { + // Reset Client Char Config if connection has dropped + if ((changeType == LINKDB_STATUS_UPDATE_REMOVED) || + ((changeType == LINKDB_STATUS_UPDATE_STATEFLAGS) && + (!linkDB_Up(connHandle)))) + { + GATTServApp_InitCharCfg(connHandle, ota_ResponseCCCD); + + if (s_reboot_flg) + { + hal_system_soft_reset(); + } + } + else + { + s_reboot_flg = false; + } + } +} + +static bStatus_t sendNotify(attHandleValueNoti_t* pNoti) +{ + uint16 connHandle; + uint16 value; + GAPRole_GetParameter(GAPROLE_CONNHANDLE, &connHandle); + value = GATTServApp_ReadCharCfg(connHandle, ota_ResponseCCCD); + + if (connHandle == INVALID_CONNHANDLE) + return bleIncorrectMode; + + // If notifications enabled + if (value & GATT_CLIENT_CFG_NOTIFY) + { + // Set the handle + pNoti->handle = ota_AttrTbl[OTA_RSP_HANDLE].handle; + // Send the Indication + return GATT_Notification(connHandle, pNoti, FALSE); + } + + return bleIncorrectMode; +} + +static uint8 ota_ReadAttrCB(uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen) +{ + bStatus_t status = ATT_ERR_READ_NOT_PERMITTED; + LOG("ReadAttrCB\n"); + + // If attribute permissions require authorization to read, return error + if (gattPermitAuthorRead(pAttr->permissions)) + { + // Insufficient authorization + return (ATT_ERR_INSUFFICIENT_AUTHOR); + } + + return (status); +} + +static bStatus_t ota_WriteAttrCB(uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset) +{ + bStatus_t status = SUCCESS; + + //uint8 notifyApp = 0xFF; + // If attribute permissions require authorization to write, return error + if (gattPermitAuthorWrite(pAttr->permissions)) + { + // Insufficient authorization + return (ATT_ERR_INSUFFICIENT_AUTHOR); + } + + if (pAttr->type.len == ATT_BT_UUID_SIZE) + { + // 16-bit UUID + uint16 uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]); + + if (uuid == GATT_CLIENT_CHAR_CFG_UUID) + { + status = GATTServApp_ProcessCCCWriteReq(connHandle, pAttr, pValue, len, + offset, GATT_CLIENT_CFG_NOTIFY); + + if (status == SUCCESS) + { + uint16 charCfg = BUILD_UINT16(pValue[0], pValue[1]); + LOG("CCCD set: [%d]\n", charCfg); + s_ota_app.notify_en = (charCfg == 1); + } + } + } + else + { + LOG("WR:%d\n", pAttr->handle); + + // 128-bit UUID Command + if (pAttr->handle == ota_AttrTbl[OTA_COMMAND_HANDLE].handle) + { + process_cmd(pValue, len); + } + } + + return (status); +} + +bStatus_t ota_app_AddService(void) +{ + uint8 status = SUCCESS; + // Register with Link DB to receive link status change callback + VOID linkDB_Register(handleConnStatusCB); + load_ota_version(); + GATTServApp_InitCharCfg(INVALID_CONNHANDLE, ota_ResponseCCCD); + // Register GATT attribute list and CBs with GATT Server App + status = GATTServApp_RegisterService(ota_AttrTbl, + GATT_NUM_ATTRS(ota_AttrTbl), + &ota_ProfileCBs); + + if (status != SUCCESS) + LOG("Add OTA service failed!\n"); + + return (status); +} +bStatus_t ota_app_AddService_UseKey(uint8 ota_key_len,uint8 * ota_key) +{ + uint8 status = SUCCESS; + + // Register with Link DB to receive link status change callback + VOID linkDB_Register(handleConnStatusCB); + + load_ota_version(); + + GATTServApp_InitCharCfg(INVALID_CONNHANDLE, ota_ResponseCCCD); + + // Register GATT attribute list and CBs with GATT Server App + status = GATTServApp_RegisterService(ota_AttrTbl, + GATT_NUM_ATTRS(ota_AttrTbl), + &ota_ProfileCBs); + + if (status != SUCCESS) + LOG("Add OTA service failed!\n"); + + + if(ota_key_len<=10&&ota_key_len>0) + { + //ota_key_register_flag=1; + ota_key_check_flag = 0; + ota_passcode[0] = ota_key_len; + osal_memcpy(&ota_passcode[1],ota_key,ota_key_len); + LOG("Add OTA passcode!\n"); + + } + + return (status); +} + + +int ota_vendor_module_StartOTA(uint8_t mode) +{ + int ret = 0; + uint32_t reg = read_reg(OTA_MODE_SELECT_REG); + + if (reg == 0) + return PPlus_ERR_NOT_REGISTED; + + ret = set_ota_mode(mode); + + if (ret == PPlus_SUCCESS) + { + hal_system_soft_reset(); + } + + return ret; +} + +int ota_vendor_module_Version(uint8_t* major, uint8_t* minor, uint8_t* revision, uint8_t* test_build) +{ + uint32_t reg = read_reg(OTA_MODE_SELECT_REG); + + if (reg == 0) + return PPlus_ERR_NOT_REGISTED; + + *major = (uint8_t)((reg >> 4) & 0xf); + *minor = (uint8_t)((reg >> 8) & 0xf); + *revision = (uint8_t)((reg >> 12) & 0xff); + *test_build = (uint8_t)((reg >> 20) & 0xf); + return PPlus_SUCCESS; +} diff --git a/src/components/profiles/ota_app/ota_app_service.h b/src/components/profiles/ota_app/ota_app_service.h new file mode 100644 index 0000000..596b2be --- /dev/null +++ b/src/components/profiles/ota_app/ota_app_service.h @@ -0,0 +1,70 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#ifndef _OTA_APP_SERVICE_H +#define _OTA_APP_SERVICE_H +#include "bcomdef.h" +#include "version.h" + +enum +{ + OTA_MODE_OTA_APPLICATION= 0, + OTA_MODE_OTA_FCT,// 1 + OTA_MODE_OTA,// 2 + OTA_MODE_RESOURCE,// 3 + OTA_MODE_OTA_NADDR = 6// 6 ota no address plus +}; + +#define OTA_MODE_SELECT_REG 0x4000f034 + + +#define OTA_APP_SERVICE_VERSION "V2.0.1" + +enum +{ + OTAAPP_CMD_START_OTA = 1, + OTAAPP_CMD_INFO, + OTAAPP_CMD_FORMAT, + OTAAPP_CMD_VER, + OTAAPP_CMD_SEC_CONFIRM, + OTAAPP_CMD_RND_CHANGE, + OTAAPP_CMD_VERIFY_KEY, + + OTAAPP_RSP_SEC_CONFIRM = 0x71, + OTAAPP_RSP_RND_CHANGE, + OTAAPP_RSP_VERIFY_KEY, + OTAAPP_CMD_CHECKKEY, + OTAAPP_CMD_GETKEY, +}; + +typedef struct +{ + uint8_t cmd; + union + { + uint8_t random[16]; + + uint8_t ver_key[16]; + uint8_t confirm[16]; + struct + { + uint8_t reserv[20-1]; + } dummy; + struct + { + uint8_t mode; + } start; + } p; //parameter +} ota_app_cmd_t; + + +bStatus_t ota_app_AddService(void); +bStatus_t ota_app_AddService_UseKey(uint8 ota_key_len,uint8 * ota_key); +int ota_vendor_module_StartOTA(uint8_t mode); +int ota_vendor_module_Version( uint8_t* major, uint8_t* minor, uint8_t* revision, uint8_t* test_build); + + +#endif + diff --git a/src/components/profiles/ppsp/core_queu.c b/src/components/profiles/ppsp/core_queu.c new file mode 100644 index 0000000..b4bca79 --- /dev/null +++ b/src/components/profiles/ppsp/core_queu.c @@ -0,0 +1,339 @@ +/* + ****************************************************************************** + History: Date; Author; Description + 07 Dec. 2015; Chen, George; file creation + ****************************************************************************** +*/ + + +/* + ****************************************************************************** + explanation + ****************************************************************************** + Multiple Task Pending On Single Msg Queue. + + +============+ +===========+ +===========+ + | msgq | | pdat | | pdat | + +============+ +===========+ +===========+ + | ~ | | ~ | | ~ | + | pdat_head |-+ NULL/-+| pdat_list |/-~-/| pdat_list |->NULL + | ~ | +---------/+| ~ | | ~ | + +------------+ +-----------+ +-----------+ + +*/ + +/* + ****************************************************************************** + Includes + ****************************************************************************** +*/ +#include "core_queu.h" +// #include "core_imgr.h" + + +/* + ****************************************************************************** + Definition + ****************************************************************************** +*/ +// #define CORE_QUEU_CFGS_LOGS_TAG "QUEU" +#ifdef CORE_QUEU_CFGS_LOGS_TAG +/* ERROR */ +#define log_err(fmt, ...) \ + logs_logs_err(CORE_QUEU_CFGS_LOGS_TAG, fmt, ##__VA_ARGS__) + +/* WARNING */ +#define log_war(fmt, ...) \ + logs_logs_war(CORE_QUEU_CFGS_LOGS_TAG, fmt, ##__VA_ARGS__) + +/* INFORMATION */ +#define log_inf(fmt, ...) \ + logs_logs_inf(CORE_QUEU_CFGS_LOGS_TAG, fmt, ##__VA_ARGS__) + +/* VERB */ +#define log_ver(fmt, ...) \ + logs_logs_ver(CORE_QUEU_CFGS_LOGS_TAG, fmt, ##__VA_ARGS__) + +/* Function entry */ +#define log_ent(fmt, ...) \ + logs_logs_ent(fmt, ##__VA_ARGS__) + +/* function exit */ +#define log_exi(fmt, ...) \ + logs_logs_exi(fmt, ##__VA_ARGS__) + +#else +/* ERROR */ +#define log_err(fmt, ...) + +/* WARNING */ +#define log_war(fmt, ...) + +/* INFORMATION */ +#define log_inf(fmt, ...) + +/* VERB */ +#define log_ver(fmt, ...) + +/* Function entry */ +#define log_ent(fmt, ...) + +/* function exit */ +#define log_exi(fmt, ...) + +#endif /* CORE_QUEU_CFGS_LOGS_TAG */ + + +/* + ****************************************************************************** + Definition + ****************************************************************************** +*/ + + +/* + ****************************************************************************** + public function implementations + ****************************************************************************** +*/ +/* + # Name: core_msgq_ini + # Desc: initialize a msg queue + # Para: msgq: msg queue to be initialised. + name: name of new task, in c string. + # rslt: 0 success; others failure. +*/ +int32 +core_sque_ini(core_sque_t* sque) +{ + int32 rslt = FALSE; + uint32 size = 0; + uint32 coun = 0; + void* blck = NULL; + log_ent("PARA>>msgq:0x%08x", sque); + + /* message pool */ + // sque->sque_pool; // [set by usr] + // sque->pool_size; // [set by usr] + + /* message size */ + // sque->size_qdat; // [set by usr] + + if ( NULL == sque->sque_pool ) + { + goto ERR_POOL; + } + + /* ini queue */ + if ( TRUE != list_sque_ini(&sque->sque_dats) ) + { + goto ERR_SQUE; + } + + /* insert queue node */ + size = sizeof ( core_qdat_t ) + sque->size_qdat; + coun = (sque->size_pool / size); + blck = ((uint8*) sque->sque_pool) + coun * size; + + while ( coun -- ) + { + blck = ((uint8*) blck) - size; + + // if ( TRUE != list_snod_ini_cir((list_snod_t*) blck) ) { + if ( TRUE != list_snod_ini((list_snod_t*) blck, list_slst_enum_snod_cir) ) + { + goto ERR_SQUE; + } + + if ( TRUE != list_slst_add(&sque->sque_dats.list, (list_snod_t*) blck) ) + { + goto ERR_SQUE; + } + } + + /* get ready to use */ + if ( TRUE != list_sque_fsh(&sque->sque_dats) ) + { + goto ERR_SQUE; + } + + rslt = TRUE; + goto ERR_SUCC; +ERR_SQUE: +ERR_POOL: +ERR_SUCC: + log_exi("RSLT>>rslt: %d", rslt); + return ( rslt ); +} + +core_sque_t* +core_sque_new(uint32 size, uint32 coun) +{ + uint32 plsz = (size + sizeof ( core_qdat_t )) * coun; // pool size of all msg blk + msg dat + core_sque_t* sque = NULL; + log_ent("PARA>>size:%d, cunt:%d", size, coun); + + // allocate memory for task control block & task stack, shares one mem control block + if ( NULL == (sque = (core_sque_t*) osal_mem_alloc(sizeof ( core_sque_t ) + plsz)) ) + { + goto ERR_MMGR; + } + + // initialize sque control block + sque->sque_pool = ((uint8*) sque + sizeof ( core_sque_t )); + sque->size_pool = plsz; + sque->size_qdat = size; + + // sque->sque_msgs + if ( TRUE != core_sque_ini(sque) ) + { + goto ERR_SQUE; + } + + goto ERR_SUCC; +ERR_SQUE: + osal_mem_free(sque); + sque = NULL; +ERR_MMGR: +ERR_SUCC: + log_exi("RSLT>>sque:0x%08x", sque); + return ( sque ); +} + +int32 +core_sque_del(core_sque_t* sque) +{ + osal_mem_free(sque); + return ( TRUE ); +} + +int32 +core_sque_pop(core_sque_t* sque, void* data) +{ + int32 rslt = FALSE; + log_ent("PARA>>sque:0x%08x, data:0x%08x", sque, data); + + if ( NULL == sque ) + { + goto ERR_SQUE; + } + + if ( TRUE != list_sque_pop(&sque->sque_dats, data, sque->size_qdat) ) + { + goto ERR_SQUE; + } + + rslt = TRUE; + goto ERR_SUCC; +ERR_SQUE: +ERR_SUCC: + log_exi("RSLT>>rslt: %d", rslt); + return ( rslt ); +} + +int32 +core_sque_psh(core_sque_t* sque, const void* data) +{ + int32 rslt = FALSE; + log_ent("PARA>>sque:0x%08x, data:0x%08x", sque, data); + + if ( NULL == sque ) + { + goto ERR_SQUE; + } + + if ( TRUE != list_sque_psh(&sque->sque_dats, (void*)data, sque->size_qdat) ) + { + goto ERR_SQUE; + } + + rslt = TRUE; + goto ERR_SUCC; +ERR_SQUE: +ERR_SUCC: + log_exi("RSLT>>rslt: %d", rslt); + return ( rslt ); +} + + +/* + # Name: core_msgq_ini + # Desc: initialize a msg queue + # Para: msgq: msg queue to be initialised. + name: name of new task, in c string. + # rslt: 0 success; others failure. +*/ +// int32 +// core_msgq_ini(core_msgq_t* msgq) +// { +// int32 rslt = FALSE; + +// log_ent("PARA>>msgq:0x%08x", msgq); + +// /* pending task */ +// msgq->pend_task = NULL; + +// /* init' queue */ +// if ( TRUE != core_sque_ini(&msgq->msgq_msgs) ) { +// goto ERRN_SQUE; +// } + +// rslt = TRUE; +// goto ERRN_SUCC; + +// ERRN_SQUE: +// ERRN_SUCC: +// log_exi("RSLT>>rslt: %d", rslt); +// return ( rslt ); +// } + +// core_msgq_t* +// core_msgq_new(uint32 size, uint32 coun) +// { +// uint32 plsz = (size + sizeof ( core_qdat_t )) * coun; // pool size of all msg blk + msg dat +// core_msgq_t* msgq = NULL; + +// log_ent("PARA>>size:%d, cunt:%d", size, coun); + +// // allocate memory for task control block & task stack, shares one mem control block +// if ( NULL == (msgq = (core_msgq_t*) core_mmgr_new(sizeof ( core_msgq_t ) + plsz)) ) { +// goto ERR_MMGR; +// } + +// // initialize msgq control block +// msgq->msgq_msgs.sque_pool = ((uint8*) msgq + sizeof ( core_msgq_t )); +// msgq->msgq_msgs.size_pool = plsz; +// msgq->msgq_msgs.size_qdat = size; +// //msgq->sque_msgs +// if ( TRUE != core_msgq_ini(msgq) ) { +// goto ERR_MSGQ; +// } + +// goto ERR_SUCC; + +// ERR_MSGQ: +// core_mmgr_del(msgq); +// msgq = NULL; +// ERR_MMGR: +// ERR_SUCC: +// log_exi("RSLT>>msgq:0x%08x", msgq); +// return ( msgq ); +// } + +// int32 +// core_msgq_del(core_msgq_t* msgq) +// { +// return ( core_mmgr_del(msgq) ); +// } + +// int32 +// core_msgq_pop(core_msgq_t* msgq, void* data) +// { +// return ( core_sque_pop(&msgq->msgq_msgs, data) ); +// } + +// int32 +// core_msgq_psh(core_msgq_t* msgq, const void* data) +// { +// return ( core_sque_psh(&msgq->msgq_msgs, data) ); +// } \ No newline at end of file diff --git a/src/components/profiles/ppsp/core_queu.h b/src/components/profiles/ppsp/core_queu.h new file mode 100644 index 0000000..3f2bb10 --- /dev/null +++ b/src/components/profiles/ppsp/core_queu.h @@ -0,0 +1,95 @@ +/* + ****************************************************************************** + History: Date; Author; Description + 07 Dec. 2015; Chen, George; file creation + ****************************************************************************** +*/ + +#ifndef __CORE_QUEU_H__ +#define __CORE_QUEU_H__ + + +/* + ****************************************************************************** + Includes + ****************************************************************************** +*/ +// #include "tbox_cfgs.h" +// #include "comn_cfgs.h" +// #include "core_task.h" +#include "OSAL.h" +#include "list_slst.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* ########################### msg queue Types ########################### */ + +/* msg types definitions */ +typedef struct core_msgq_stru_qdat_def +{ + list_snod_t qdat_node; +} core_qdat_t; + +/* msgq types definitions */ +typedef struct core_msgq_stru_sque_def +{ + // message pool + void* sque_pool; // [set by usr] data pool, ptr from malloc + uint32 size_pool; // [set by usr] pool size in bytes + + // message ctrlq + uint32 size_qdat; // [set by usr] a data size in bytes (excl. core_msg_t) + list_sque_t sque_dats; // [set by sys] circle singled linked list +} core_sque_t; + +/* msgq types definitions */ +// typedef struct core_msgq_stru_msgq_def { +// // +// // void* pend_task; + +// core_sque_t msgq_msgs; +// } core_msgq_t, *core_msgq_h; +/* + ****************************************************************************** + function prototypes + ****************************************************************************** +*/ +int32 +core_sque_ini(core_sque_t* sque); + +core_sque_t* +core_sque_new(uint32 size, uint32 coun); + +int32 +core_sque_del(core_sque_t* sque); + +int32 +core_sque_pop(core_sque_t* sque, void* data); + +int32 +core_sque_psh(core_sque_t* sque, const void* data); + + +// int +// core_msgq_ini(core_msgq_t* msgq); + +// core_msgq_t* +// core_msgq_new(uint32 size, uint32 coun); + +// int +// core_msgq_del(core_msgq_t* msgq); + +// int +// core_msgq_pop(core_msgq_t* msgq, void* data); + +// int +// core_msgq_psh(core_msgq_t* msgq, const void* data); + +#ifdef __cplusplus +} +#endif + +#endif // __CORE_CMN_H__ diff --git a/src/components/profiles/ppsp/list_slst.c b/src/components/profiles/ppsp/list_slst.c new file mode 100644 index 0000000..df75c69 --- /dev/null +++ b/src/components/profiles/ppsp/list_slst.c @@ -0,0 +1,613 @@ +/* + ****************************************************************************** + # Hist: + Date; Author; Description + 30 Oct. 2017; Chen, George; file creation, transported from prtos + ****************************************************************************** +*/ + + +/* + ****************************************************************************** + Includes + ****************************************************************************** +*/ + +// #include +#include "OSAL.h" +#include "list_slst.h" +// #include "logs_logs.h" + + + +/* + ****************************************************************************** + defines + ****************************************************************************** +*/ +// #define LIST_SLST_DEFS_LOGS_TAG "SLST" +#ifdef LIST_SLST_DEFS_LOGS_TAG +/* ERROR */ +#define log_err(fmt, ...) \ + logs_logs_err(LIST_SLST_DEFS_LOGS_TAG, fmt, ##__VA_ARGS__) + +/* WARNING */ +#define log_war(fmt, ...) \ + logs_logs_war(LIST_SLST_DEFS_LOGS_TAG, fmt, ##__VA_ARGS__) + +/* INFORMATION */ +#define log_inf(fmt, ...) \ + logs_logs_inf(LIST_SLST_DEFS_LOGS_TAG, fmt, ##__VA_ARGS__) + +/* VERB */ +#define log_ver(fmt, ...) \ + logs_logs_ver(LIST_SLST_DEFS_LOGS_TAG, fmt, ##__VA_ARGS__) + +/* Function entry */ +#define log_ent(fmt, ...) \ + logs_logs_ent(fmt, ##__VA_ARGS__) + +/* function exit */ +#define log_exi(fmt, ...) \ + logs_logs_exi(fmt, ##__VA_ARGS__) + +#else +/* ERROR */ +#define log_err(fmt, ...) + +/* WARNING */ +#define log_war(fmt, ...) + +/* INFORMATION */ +#define log_inf(fmt, ...) + +/* VERB */ +#define log_ver(fmt, ...) + +/* Function entry */ +#define log_ent(fmt, ...) + +/* function exit */ +#define log_exi(fmt, ...) + +#endif /* LIST_SLST_DEFS_LOGS_TAG */ + + +/* + ****************************************************************************** + Private Functions + ****************************************************************************** +*/ + + +/* + # name: + # desc: + # para: + # rslt: +*/ +static signed int +list_snod_ini_lin(list_snod_t* snod) +{ + signed int rslt = 0; + + if ( 0 == snod ) /* validation check */ + { + // + rslt = 0; + } + else /* initialize to 0 */ + { + snod->next = 0; + rslt = 1; + } + + return ( rslt ); +} + +/* + # name: + # desc: + # para: + # rslt: +*/ +static signed int +list_snod_ini_cir(list_snod_t* snod) +{ + signed int rslt = 0; + + if ( 0 == snod ) /* validation check */ + { + // + rslt = 0; + } + else /* initial to self */ + { + snod->next = snod; + rslt = 1; + } + + return ( rslt ); +} + +/* + # name: + # desc: + # para: + # rslt: +*/ +static signed int +list_snod_ins_aft(list_snod_t* nod0, list_snod_t* nod1) +{ + signed int rslt = 0; + + /* validation checking */ + if ( 0 == nod0 || 0 == nod1 ) + { + rslt = 0; + goto ERR_INV; + } + + /* insert list node */ + nod1->next = nod0->next; + nod0->next = nod1; + /* result success */ + rslt = 1; + goto ERR_SUC; +ERR_INV: +ERR_SUC: + return ( rslt ); +} + +/* + # name: + # desc: + # para: + # rslt: +*/ +static signed int +list_snod_rmv_aft(list_snod_t* snod) +{ + signed int rslt = 0; + + /* validation checking */ + if ( 0 == snod ) + { + rslt = 0; + goto ERR_INV; + } + + if ( 0 != snod->next ) + { + snod->next = snod->next->next; + } + + /* result success */ + rslt = 1; + goto ERR_SUC; +ERR_INV: +ERR_SUC: + return ( rslt ); +} + +/* + ****************************************************************************** + Public Functions + ****************************************************************************** +*/ +signed int +list_snod_ini(list_snod_t* snod, list_snod_e type) +{ + signed int rslt = 0; + + if ( list_slst_enum_snod_lin == type ) + { + rslt = list_snod_ini_lin(snod); + } + else if ( list_slst_enum_snod_cir == type ) + { + rslt = list_snod_ini_cir(snod); + } + + return ( rslt ); +} + +/* + ****************************************************************************** + Public Functions : slst + ****************************************************************************** +*/ +/* + # name: + # desc: + # para: + # rslt: +*/ +signed int +list_slst_ini(list_slst_t* slst) +{ + signed int rslt = 0; + + /* validation checking */ + if ( 0 == slst ) + { + rslt = 0; + goto ERR_INV; + } + + slst->head = 0; // [set by sys] head node + slst->tail = 0; // [set by sys] tail node + slst->iter = 0; // [set by sys] iter node + slst->coun = 0; // [set by sys] list size of entity + /* result success */ + rslt = 1; + goto ERR_SUC; +ERR_INV: +ERR_SUC: + return ( rslt ); +} + +/* + # name: + # desc: insert at tail + # para: + # rslt: +*/ +signed int +list_slst_add(list_slst_t* slst, list_snod_t* snod) +{ + signed int rslt = 0; + list_snod_t* curr = 0; + + if ( 0 == snod ) + { + rslt = 0; + goto ERR_INV; + } + + list_slst_emu(slst); + + while ( 1 ) + { + curr = list_slst_nxt(slst); + + if ( 0 == curr ) // not found + { + if ( 0 >= slst->coun ) // empty list?, + { + slst->head = snod; // then, become the first node + slst->tail = snod; + } + else // otherwise, insert @ tail + { + // ignore result check, always true at this case + list_snod_ins_aft(slst->tail, snod); + slst->tail = snod; // update tail + } + + slst->coun ++; // update list capability + rslt = 1; + goto ERR_SUC; // SUCCESS + } + else if ( snod == curr ) // found + { + rslt = 0; + goto ERR_DOE; // DOEXIST + } + } + +ERR_DOE: +ERR_INV: +ERR_SUC: + return ( rslt ); +} + +/* TODO: MARK HERE */ +/* + # name: + # desc: remove at head + # para: + # rslt: +*/ +signed int +list_slst_rmv(list_slst_t* slst, list_snod_t* snod) +{ + signed int rslt = 0; + list_snod_t* prev = 0; + list_snod_t* curr = 0; + + /* validation checking */ + if ( 0 == snod ) + { + rslt = 0; + goto ERR_INV; + } + + list_slst_emu(slst); + + while ( 1 ) + { + curr = list_slst_nxt(slst); + + if ( 0 == curr ) // not found + { + rslt = 0; + goto ERR_NOF; + } + else if ( snod == curr ) // found + { + slst->coun --; // [set by sys] list size of entity + + if ( 0 >= slst->coun ) + { + slst->tail = slst->head = 0; + } + else if ( snod == slst->head ) + { + slst->head = snod->next; + } + else if ( snod == slst->tail ) + { + slst->tail = prev; + } + + // remove given snod + if ( 0 != prev ) + { + list_snod_rmv_aft(prev); + } + + rslt = 1; + goto ERR_SUC; + } + + prev = curr; + } + +ERR_NOF: +ERR_INV: +ERR_SUC: + return ( rslt ); +} + +/* + # name: + # desc: + # para: + # rslt: +*/ +signed int +list_slst_has(list_slst_t* slst, const list_snod_t* snod) +{ + signed int rslt = 0; + list_snod_t* curr = 0; + + /* validation checking */ + if ( 0 == snod ) + { + rslt = 0; + goto ERR_INV; + } + + list_slst_emu(slst); + + while ( 1 ) + { + curr = list_slst_nxt(slst); + + if ( 0 == curr ) // not found + { + rslt = 0; + break; + } + else if ( snod == curr ) // found + { + rslt = 1; + break; + } + } + +ERR_INV: + return ( rslt ); +} + +/* + # name: + # desc: + # para: + # rslt: +*/ +signed int +list_slst_emu(list_slst_t* slst) +{ + return ( 0 != (slst->iter = slst->head) ? 1 : 0 ); +} + +/* + # name: + # desc: + # para: + # rslt: +*/ +list_snod_t* +list_slst_nxt(list_slst_t* slst) +{ + list_snod_t* rslt = 0; + + if ( 0 != slst ) + { + rslt = slst->iter; + } + + if ( 0 != rslt ) + { + slst->iter = rslt->next; + } + + if ( slst->iter == slst->head ) + { + rslt = 0; + } + + return ( rslt ); +} + +/* + ****************************************************************************** + Public Functions : sque + ****************************************************************************** +*/ +/* + # name: + # desc: + # para: + # rslt: +*/ +signed int +list_sque_ini(list_sque_t* sque) +{ + signed int rslt = 0; + + if ( 0 == sque ) + { + rslt = 0; + goto ERR_INV; + } + + // ignore validation check, always result true in this case + list_slst_ini(&sque->list); + /* + initialize post & pend ptrs to 0. + sque->list now is a empty list. + util_sque_fsh should called after the sque->list is filled + before using the sque. + */ + sque->post = 0; // [set by sys] head node to pop out/out box + sque->pend = 0; // [set by sys] tail node to push in/in box + sque->coun = 0; // [set by sys] counts of records + /* result success */ + rslt = 1; + goto ERR_SUC; +ERR_INV: +ERR_SUC: + return ( rslt ); +} + +/* + # name: + # desc: + # para: + # rslt: +*/ +signed int +list_sque_fsh(list_sque_t* sque) +{ + signed int rslt = 0; + + /* validation checking */ + if ( 0 == sque ) + { + rslt = 0; + goto ERR_INV; + } + + sque->post = sque->list.head; + sque->pend = sque->list.head; + sque->coun = 0; + /* result success */ + rslt = 1; + goto ERR_SUC; +ERR_INV: +ERR_SUC: + return ( rslt ); +} + +/* + # name: + # desc: + # para: + # rslt: +*/ +signed int +list_sque_pop(list_sque_t* sque, void* data, unsigned int size) +{ + signed int rslt = 0; + + /* validation checking */ + /* NOTE: dst and scpy validation should be checked by user or in scpy */ + if ( 0 == sque ) + { + rslt = 0; + goto ERR_INV; + } + + /* NOTE: do nothing on empty queue */ + if ( 0 >= sque->coun ) + { + rslt = 0; + goto ERR_INV; + } + + /* NOTE: push & pops only works on circular queue */ + if ( sque->list.head != sque->list.tail->next ) + { + rslt = 0; + goto ERR_INV; + } + + osal_memcpy(data, sque->post+1, size); + /* maintainence */ + sque->post = sque->post->next; + sque->coun --; + /* result success */ + rslt = 1; + goto ERR_SUC; +ERR_INV: +ERR_SUC: + return ( rslt ); +} + +/* + # name: + # desc: + # para: + # rslt: +*/ +signed int +list_sque_psh(list_sque_t* sque, void* data, unsigned int size) +{ + signed int rslt = 0; + + /* validation checking */ + /* NOTE: src and scpy validation should be checked by user or in scpy */ + if ( 0 == sque ) + { + rslt = 0; + goto ERR_INV; + } + + /* NOTE: do nothing on full list */ + if ( sque->coun >= sque->list.coun ) + { + rslt = 0; + goto ERR_INV; + } + + /* NOTE: push & pops only works on circular queue */ + if ( sque->list.head != sque->list.tail->next ) + { + rslt = 0; + goto ERR_INV; + } + + osal_memcpy(sque->pend+1, data, size); + sque->pend = sque->pend->next; + sque->coun ++; + /* result success */ + rslt = 1; + goto ERR_SUC; +ERR_INV: +ERR_SUC: + return ( rslt ); +} + diff --git a/src/components/profiles/ppsp/list_slst.h b/src/components/profiles/ppsp/list_slst.h new file mode 100644 index 0000000..fbd688c --- /dev/null +++ b/src/components/profiles/ppsp/list_slst.h @@ -0,0 +1,178 @@ +/* + ****************************************************************************** + File: util_slst.h + + # Hist: + Date; Author; Description + 30 Oct. 2017; Chen, George; file creation, transported from prtos + ****************************************************************************** +*/ +#ifndef __LIST_SLST_H__ +#define __LIST_SLST_H__ + +/* + ****************************************************************************** + Includes + ****************************************************************************** +*/ +//#include "../comn/comn_cfgs.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/* ####################### Single Linked List Types ####################### */ +/* + USAGE + refer to util_dlst.h +*/ +typedef enum list_slst_enum_snod_def +{ + list_slst_enum_snod_lin = 0, + list_slst_enum_snod_cir, +} list_snod_e; + +typedef struct list_slst_stru_snod_def +{ + struct list_slst_stru_snod_def* next; // next node +} list_snod_t; + +/* slist types definitions */ +typedef struct list_slst_stru_slst_def +{ + list_snod_t* head; // [set by sys] head node + list_snod_t* tail; // [set by sys] tail node + list_snod_t* iter; // [set by sys] node iterator + unsigned int coun; // [set by sys] counts of entity +} list_slst_t; + +typedef struct list_slst_stru_sque_def +{ + list_slst_t list; + list_snod_t* post; // [set by sys] head node to pop out + list_snod_t* pend; // [set by sys] tail node to push in + unsigned int coun; // [set by sys] counts of records +} list_sque_t; + +/* ########################## function prototypes ########################## */ +/* + # Name: util_slst_ini + # Desc: initialize single linked list + # Para: node: list being initialized + # return:node +*/ +signed int +list_snod_ini(list_snod_t* snod, list_snod_e type); + +// signed int +// list_snod_ini_lin(list_snod_t* snod); + +// signed int +// list_snod_ini_cir(list_snod_t* snod); + +// /* +// * # Name: util_slst_ins_aft +// * # Desc: insert node after a list, link member pointers each other +// * # Para: slist1: list to which new list being put after +// * slist2: list which being put after a list +// * # return:slist1 +// */ +// signed int +// list_snod_ins_aft(list_snod_t* nod0, list_snod_t* nod1); + +// /* +// * # Name: util_slst_rmv_aft +// * # Desc: remove a node after a list. +// * # Para: slist: list after which a node being removed. +// * # return:slist +// */ +// signed int +// list_snod_rmv_aft(list_snod_t* snod); + +/* + # Name: list_slst_ini + # Desc: initialize a single linked list. + # Para: slst: . + # rslt: 0 failure otherwise success. +*/ +signed int +list_slst_ini(list_slst_t* slst); + +/* + # Name: list_slst_add + # Desc: add node to list tail. + # Para: slst: . + snod: + # rslt: 0 failure otherwise success. +*/ +signed int +list_slst_add(list_slst_t* slst, list_snod_t* snod); + +/* + # Name: list_slst_rmv + # Desc: search & remove node in list. + # Para: slst: . + node: + # rslt: 0 failure otherwise success. +*/ +signed int +list_slst_rmv(list_slst_t* slst, list_snod_t* snod); + +/* + # Name: list_slst_has + # Desc: check if the list contains the node. + # Para: list: list . + node: node . + # return:TRUE sucess, otherwise FALSE. +*/ +signed int +list_slst_has(list_slst_t* slst, const list_snod_t* snod); + +/* + # Name: list_dlst_emu + # Desc: iterates each node. + # Para: list: + # return:num of nodes +*/ +signed int +list_slst_emu(list_slst_t* slst); + +/* + # Name: list_dlst_nxt + # Desc: get iterated node. + # Para: list: + # return:num of nodes +*/ +list_snod_t* +list_slst_nxt(list_slst_t* slst); + +/* + # Name: list_sque_ini + # Desc: initialize single linked list queue. + # Para: list: + # return:num of nodes +*/ +signed int +list_sque_ini(list_sque_t* sque); + +/* + # Name: util_slst_fsh + # Desc: reset queue. + # Para: list: list should be operated on. + # return:TRUE sucess, otherwise FALSE. +*/ +signed int +list_sque_fsh(list_sque_t* sque); + +signed int +list_sque_pop(list_sque_t* sque, void* data, unsigned int size); + +signed int +list_sque_psh(list_sque_t* sque, void* data, unsigned int size); + +#ifdef __cplusplus +} +#endif + +#endif // __UTIL_SLST_H__ diff --git a/src/components/profiles/ppsp/ppsp_impl.c b/src/components/profiles/ppsp/ppsp_impl.c new file mode 100644 index 0000000..82c493a --- /dev/null +++ b/src/components/profiles/ppsp/ppsp_impl.c @@ -0,0 +1,1592 @@ + +/********************************************************************* + INCLUDES +*/ +#include "ppsp_impl.h" +#include "ppsp_serv.h" +#include "error.h" +#include "OSAL.h" +#include "core_queu.h" +#include "log.h" +#include "flash.h" + + +#define PPSP_IMPL_CFGS_BUSY_STAT_BITS 0x00000001 +#define PPSP_IMPL_CFGS_AUTH_STAT_BITS 0x00000002 +#define PPSP_IMPL_CFGS_OTAS_STAT_BITS 0x00000004 // ota bgns +#define PPSP_IMPL_CFGS_OTAE_STAT_BITS 0x00000008 // ota ends + +#define PPSP_IMPL_CFGS_ALIS_PIDS_COUN 4 +#define PPSP_IMPL_CFGS_ALIS_MACS_COUN 6 +#define PPSP_IMPL_CFGS_ALIS_SCRT_COUN 16 + +#define PPSP_IMPL_CFGS_MSGS_CRYP_ENAB 0 +#if (1 == PPSP_IMPL_CFGS_MSGS_CRYP_ENAB) + #include "sha256.h" + #include "tinycrypt/aes.h" +#endif + +#define PPSP_IMPL_CFGS_MSGS_HDER_SIZE 4 + +#define PPSP_IMPL_CFGS_OPCO_MISN_ISSU 0x02 // issu by master, resp by slave +#define PPSP_IMPL_CFGS_OPCO_MISR_RESP 0x03 // resp by slave, issu by master +#define PPSP_IMPL_CFGS_OPCO_MNSI_ISSU 0x04 // issu by slave, resp by master +#define PPSP_IMPL_CFGS_OPCO_MRSI_RESP 0x05 // resp by master, issu by slave +#define PPSP_IMPL_CFGS_OPCO_NRSP_ISSU 0x06 // issu W/O resp + +#define PPSP_IMPL_CFGS_OPCO_RAND_ISSU 0x10 // issu RAND by master, resp by slave +#define PPSP_IMPL_CFGS_OPCO_CIPR_RESP 0x11 // resp RAND by slave, issu by master. CIPR = ENCR(RAND, BKEY(RAND,MACS,SCRT)) +#define PPSP_IMPL_CFGS_OPCO_VERF_ISSU 0x12 // issu VERF by master, resp by slave. verify result of encryption +#define PPSP_IMPL_CFGS_OPCO_BKEY_RESP 0x13 // resp VERF by slave, issu by master +#define PPSP_IMPL_CFGS_OPCO_NWRK_ISSU 0x14 // issu NWRK by master, resp by slave. networking rsult, unprov/proved +#define PPSP_IMPL_CFGS_OPCO_NWRK_RESP 0x15 // resp NWRK by slave, issu by master. confirm of networking rsult + +#define PPSP_IMPL_CFGS_OPCO_VERS_ISSU 0x20 // issu VERS by master, resp by slave +#define PPSP_IMPL_CFGS_OPCO_VERS_RESP 0x21 // resp VERS by slave, issu by master +#define PPSP_IMPL_CFGS_OPCO_UPDA_ISSU 0x22 // issu UPDA by master, resp by slave +#define PPSP_IMPL_CFGS_OPCO_UPDA_RESP 0x23 // resp UPDA by slave, issu by master. confirm, rcvd size, fast mode +#define PPSP_IMPL_CFGS_OPCO_PACK_ISSU 0x2F // issu PACK by master, issu W/O resp. +#define PPSP_IMPL_CFGS_OPCO_PACK_RESP 0x24 // issu PACK by slave, issu W/O resp. confirm of total frame +#define PPSP_IMPL_CFGS_OPCO_COMP_ISSU 0x25 // issu COMP by master, resp by slave. complete of transfer +#define PPSP_IMPL_CFGS_OPCO_COMP_RESP 0x26 // resp COMP by slave, issu by master. reply with crc + +#define PPSP_IMPL_CFGS_OPCO_USER_ISSU 0xFE // issu USER, resp by slave +#define PPSP_IMPL_CFGS_OPCO_USER_RESP 0xFF // issu USER, resp by slave + +#define PPSP_IMPL_CFGS_PROG_ADDR_BASE (0x11000000) +#define PPSP_IMPL_CFGS_PROG_SCTR_SIZE (0x1000) // program sector size in byte +#define PPSP_IMPL_CFGS_PROG_ADDR_BGNS (0x55000) // program data bgn address of flash +#define PPSP_IMPL_CFGS_PROG_FLSH_SIZE (0x2B000) // program total size in byte +#define PPSP_IMPL_CFGS_PROG_ADDR_ENDS (PPSP_IMPL_CFGS_PROG_ADDR_BGNS+PPSP_IMPL_CFGS_PROG_FLSH_SIZE) // program data end address of flash + +#define PPSP_IMPL_CFGS_PROG_VERS_REVI (0) +#define PPSP_IMPL_CFGS_PROG_VERS_MINR (0) +#define PPSP_IMPL_CFGS_PROG_VERS_MAJR (1) + + +extern void +ppsp_impl_serv_rcvd_hdlr(uint8 para, uint16 coun); +static ppsp_serv_appl_CBs_t +__ppsp_impl_hdlr_serv = +{ + ppsp_impl_serv_rcvd_hdlr, +}; + +static uint32 +__ppsp_impl_stat_bits_flag = 0x00; +static uint32 +__ppsp_impl_proc_tout_coun = 0x00; + + +static core_sque_t* +__ppsp_impl_msgs_queu_rcvd = NULL; // received msgs queue +static core_sque_t* +__ppsp_impl_msgs_queu_xfer = NULL; // transfer msgs queue + + +static const uint8 +__ppsp_impl_opco_prim_list[] = +{ + PPSP_IMPL_CFGS_OPCO_MISN_ISSU, + PPSP_IMPL_CFGS_OPCO_MNSI_ISSU, + PPSP_IMPL_CFGS_OPCO_MISR_RESP, + PPSP_IMPL_CFGS_OPCO_MRSI_RESP, + PPSP_IMPL_CFGS_OPCO_NRSP_ISSU, + + PPSP_IMPL_CFGS_OPCO_RAND_ISSU, + PPSP_IMPL_CFGS_OPCO_CIPR_RESP, + PPSP_IMPL_CFGS_OPCO_VERF_ISSU, + PPSP_IMPL_CFGS_OPCO_BKEY_RESP, + PPSP_IMPL_CFGS_OPCO_NWRK_ISSU, + PPSP_IMPL_CFGS_OPCO_NWRK_RESP, + + PPSP_IMPL_CFGS_OPCO_VERS_ISSU, + PPSP_IMPL_CFGS_OPCO_VERS_RESP, + PPSP_IMPL_CFGS_OPCO_UPDA_ISSU, + PPSP_IMPL_CFGS_OPCO_UPDA_RESP, + PPSP_IMPL_CFGS_OPCO_PACK_ISSU, + PPSP_IMPL_CFGS_OPCO_PACK_RESP, + PPSP_IMPL_CFGS_OPCO_COMP_ISSU, + PPSP_IMPL_CFGS_OPCO_COMP_RESP, + + PPSP_IMPL_CFGS_OPCO_USER_ISSU, + PPSP_IMPL_CFGS_OPCO_USER_RESP, +}; +static uint8 +__ppsp_impl_opco_prim_coun = sizeof(__ppsp_impl_opco_prim_list); + +static uint8 +__ppsp_impl_opco_user_coun = 0; +static uint8* +__ppsp_impl_opco_user_list = 0; + +#if (1 == PPSP_IMPL_CFGS_MSGS_CRYP_ENAB) + static uint8 + __ppsp_impl_auth_keys_data[16]; +#endif + +/* + private function prototype +*/ +// static uint8 +// ppsp_impl_psh_msgs_xfer(const uint8* data, uint16 leng); + + + + +/* + private function implimentation +*/ +#define ppsp_impl_get_auth_rslt(rslt) \ + { \ + (rslt) = ((__ppsp_impl_stat_bits_flag & PPSP_IMPL_CFGS_AUTH_STAT_BITS)?1:0); \ + } + +#define ppsp_impl_set_auth_rslt(flag) \ + { \ + if ( 0 == (flag) ) \ + __ppsp_impl_stat_bits_flag &= ~PPSP_IMPL_CFGS_AUTH_STAT_BITS; \ + else \ + __ppsp_impl_stat_bits_flag |= PPSP_IMPL_CFGS_AUTH_STAT_BITS; \ + } + +#define ppsp_impl_get_msgs_numb(msgs, numb) \ + { \ + if ( 0 != msgs ) \ + (numb) = msgs[0]&0x0F; \ + } + +#define ppsp_impl_set_msgs_numb(msgs, numb) \ + { \ + if ( 0 != msgs ) \ + msgs[0] |= (numb)&0x0F; \ + } + +#define ppsp_impl_get_msgs_encr(msgs, numb) \ + { \ + if ( 0 != msgs ) \ + (numb) = ((msgs[0]&0x10)>>4); \ + } + +#define ppsp_impl_set_msgs_encr(msgs, flag) \ + { \ + if ( 0 != msgs ) \ + msgs[0] |= (((flag)&0x01)<<4); \ + } + +#define ppsp_impl_get_msgs_opco(msgs, opco) \ + { \ + if ( 0 != msgs ) \ + (opco) = msgs[1]&0xFF; \ + } + +#define ppsp_impl_set_msgs_opco(msgs, opco) \ + { \ + if ( 0 != msgs ) \ + msgs[1] = (opco)&0xFF; \ + } + +#define ppsp_impl_get_msgs_seqn(msgs, alln, seqn) \ + { \ + if ( 0 != msgs ) { \ + alln = (msgs[2]&0xF0)>>4; \ + seqn = (msgs[2]&0x0F)>>0; \ + } \ + } + +#define ppsp_impl_set_msgs_seqn(msgs, alln, seqn) \ + { \ + if ( 0 != msgs ) \ + msgs[2] = ((alln&0x0F))<<4 | ((seqn&0x0F)<<0); \ + } + +/* + desc: get msg payload length, byte 3 of header +*/ +#define ppsp_impl_get_msgs_frsz(msgs, frsz) \ + { \ + if ( 0 != msgs ) \ + (frsz) = msgs[3]&0xFF; \ + } + +#define ppsp_impl_set_msgs_frsz(msgs, frsz) \ + { \ + if ( 0 != msgs ) \ + msgs[3] = (frsz)&0xFF; \ + } + +/* + desc: get msg payload +*/ +#define ppsp_impl_get_msgs_plds(msgs, data) \ + { \ + if ( 0 != msgs ) \ + (/* (uint8*) */(data)) = (((uint8*)(msgs))+PPSP_IMPL_CFGS_MSGS_HDER_SIZE); \ + } + +/* + desc: set msg payload +*/ +#define ppsp_impl_set_msgs_plds(msgs, data, coun) \ + { \ + if ( 0 != (uint8*)(msgs) ) \ + osal_memcpy(((uint8*)(msgs))+PPSP_IMPL_CFGS_MSGS_HDER_SIZE, (uint8*)(data), coun); \ + } + +/* + desc: PKCS#7 padding +*/ +#define ppsp_impl_get_pkcs_7pad(bksz, dasz, pval) \ + { \ + pval = bksz - (dasz % bksz); \ + } + +/* + desc: chk mesg package size +*/ +static uint8 +ppsp_impl_chk_msgs_leng(const uint8* mesg, uint16 coun) +{ + return ( NULL != mesg && PPSP_IMPL_CFGS_MSGS_HDER_SIZE <= coun ); +} + +/* + desc: chk mesg id +*/ +static uint8 +ppsp_impl_chk_msgs_numb(const uint8* mesg, uint16 coun) +{ + uint8 rslt = 0; + + if ( 0 != mesg ) + { + uint8 numb; + ppsp_impl_get_msgs_numb(mesg, numb); + rslt = (/* (0 <= numb) && */(15 >= numb)); // comment for compuler warning + } + else + { + rslt = 0; + } + + return ( rslt ); +} + +/* + desc: chk mesg opcode +*/ +static uint8 +ppsp_impl_chk_msgs_opco(const uint8* mesg, uint16 coun) +{ + uint8 rslt = 0; + + if ( NULL != mesg ) + { + uint8 opco; + opco = mesg[1] & 0xFF; + + for ( int itr0 = 0; itr0 < __ppsp_impl_opco_prim_coun; itr0 += 1 ) + { + if ( opco == __ppsp_impl_opco_prim_list[itr0] ) + { + rslt = 1; + break; + } + } + + if ( !rslt ) + for ( int itr0 = 0; itr0 < __ppsp_impl_opco_user_coun; itr0 += 1 ) + { + if ( opco == __ppsp_impl_opco_user_list[itr0] ) + { + rslt = 1; + break; + } + } + } + + return ( rslt ); +} + +/* + desc: chk mesg segment number + total segment number +*/ +static uint8 +ppsp_impl_chk_msgs_seqn(const uint8* mesg, uint16 coun) +{ + uint8 rslt = 1; + + if ( NULL != mesg ) + { + uint8 numb; + /* numb of segment sequence */ + numb = (mesg[2] & 0x0F) >> 0; + rslt = (/* 0 <= numb && */(15 >= numb)); // comment for compuler warning + } + + if ( 1 == rslt ) + { + uint8 numb; + /* numb of total segments */ + numb = (mesg[2] & 0xF0) >> 4; + rslt = (/* 0 <= numb && */(15 >= numb)); // comment for compuler warning + } + + return ( rslt ); +} + +/* + desc: create response message +*/ +static void* +ppsp_impl_new_msgs_resp(uint8 numb, uint8 opco, uint8* data, uint16 leng) +{ + uint8* msgs = 0; + /* only consider unsegmented case */ + msgs = osal_mem_alloc(PPSP_IMPL_CFGS_MSGS_HDER_SIZE+leng); + + if ( 0 != msgs ) + { + osal_memset(msgs, 0, PPSP_IMPL_CFGS_MSGS_HDER_SIZE+leng); + ppsp_impl_set_msgs_numb(msgs, numb); + // ppsp_impl_set_msgs_encr(msgs, numb); + // ppsp_impl_set_msgs_vers(msgs, numb); + ppsp_impl_set_msgs_opco(msgs, opco); + ppsp_impl_set_msgs_seqn(msgs, 0, 0); // frame numb, frame sequ + ppsp_impl_set_msgs_frsz(msgs, leng); // frame size + ppsp_impl_set_msgs_plds(msgs, data, leng); // payload + } + + return ( msgs ); +} + + +static uint8 +ppsp_impl_psh_msgs_rcvd(const uint8* mesg, uint16 coun) +{ + uint8 rslt = 1; + + if ( 0 == mesg ) + { + LOG("[PANDA][ERR] NULL POINTER !!!"); + rslt = 0; + } + + // for (uint8 itr0 = 0; itr0 < coun; itr0 += 1) + // LOG("[PANDA][INF] rcvd msg: data[%d]=%02x", itr0, mesg[itr0]); + + /* */ + if ( 1 == rslt ) + { + rslt = ppsp_impl_chk_msgs_leng(mesg, coun); + // LOG("[PANDA][INF] ppsp_impl_chk_msgs_leng: %s\n\r", rslt ? "OK" :"NG"); + // printf("[PANDA][INF] ppsp_impl_chk_msgs_leng: %s\n\r", rslt ? "OK" :"NG"); + } + + /* */ + if ( 1 == rslt ) + { + rslt = ppsp_impl_chk_msgs_numb(mesg, coun); + // LOG("[PANDA][ERR] ppsp_impl_chk_msgs_numb: %s\n\r", rslt ? "OK" :"NG"); + // printf("[PANDA][ERR] ppsp_impl_chk_msgs_numb: %s\n\r", rslt ? "OK" :"NG"); + } + + /* */ + if ( 1 == rslt ) + { + rslt = ppsp_impl_chk_msgs_opco(mesg, coun); + // LOG("[PANDA][ERR] ppsp_impl_chk_msgs_opco: %s\n\r", rslt ? "OK" :"NG"); + // printf("[PANDA][ERR] ppsp_impl_chk_msgs_opco: %s\n\r", rslt ? "OK" :"NG"); + } + + /* */ + if ( 1 == rslt ) + { + rslt = ppsp_impl_chk_msgs_seqn(mesg, coun); + // LOG("[PANDA][ERR] ppsp_impl_chk_msgs_seqn: %s\n\r", rslt ? "OK" :"NG"); + // printf("[PANDA][ERR] ppsp_impl_chk_msgs_seqn: %s\n\r", rslt ? "OK" :"NG"); + } + + /* */ + if ( 1 == rslt ) + { + uint8* vmsg = osal_mem_alloc(coun); + osal_memcpy(vmsg, mesg, coun); + rslt = core_sque_psh(__ppsp_impl_msgs_queu_rcvd, &vmsg); + // if segment msg, enqueue(); + // else notify upper layer new msgs + // __ppsp_impl_msgs_rcvd = (uint8*)data; + } + + // LOG("[EXI] %s(), rslt:%x \r\n", __func__, rslt); + return ( rslt ); +} + + +static uint8 +ppsp_impl_psh_msgs_xfer(const uint8* data, uint16 leng) +{ + return ( core_sque_psh(__ppsp_impl_msgs_queu_xfer, &data) ); +} + + +static void +ppsp_impl_cvt_hex2Str(const unsigned char* const srcs, unsigned char* dest, int coun, int revs) +{ +} + +#if (1 == PPSP_IMPL_CFGS_MSGS_CRYP_ENAB) +static void +ppsp_impl_prc_msgs_rand(uint8* msgs_rcvd) +{ + uint8 itr0; + uint8 msgn; + uint8 rsiz; + uint8* rand; + ppsp_impl_get_msgs_numb(msgs_rcvd, msgn); // mesg id + ppsp_impl_get_msgs_frsz(msgs_rcvd, rsiz); // rand size + ppsp_impl_get_msgs_plds(msgs_rcvd, rand); // rand pointer + uint8 pids[PPSP_IMPL_CFGS_ALIS_PIDS_COUN]; + uint8 macs[PPSP_IMPL_CFGS_ALIS_MACS_COUN]; + uint8 scrt[PPSP_IMPL_CFGS_ALIS_SCRT_COUN]; + //load PID + ppsp_impl_get_pids(pids); + //load MAC + ppsp_impl_get_macs(macs); + //load SEC + ppsp_impl_get_scrt(scrt); + + if ( 1 == ppsp_impl_cal_keys(rand, rsiz, pids, sizeof(pids), macs, sizeof(macs), scrt, sizeof(scrt)) ) + { + LOG("\n\rKEY:>>> "); + + for ( itr0 = 0; itr0 < sizeof(__ppsp_impl_auth_keys_data); itr0 ++ ) LOG("%02x,", __ppsp_impl_auth_keys_data[itr0]); + + LOG("KEY:<<< \n\r"); + uint8* msgs_xfer = 0; + uint8 cipr[16] = { 0x00, }; // ciper + ppsp_impl_enc_text(rand, cipr); + LOG("\n\rCIP:>>> "); + + for ( itr0 = 0; itr0 < sizeof(cipr); itr0 ++ ) LOG("%02x,", cipr[itr0]); + + LOG("KEY:<<< \n\r"); + msgs_xfer = ppsp_impl_new_msgs_resp(msgn, PPSP_IMPL_CFGS_OPCO_CIPR_RESP, cipr, sizeof(cipr)); + + if ( 0 != msgs_xfer ) ppsp_impl_psh_msgs_xfer(msgs_xfer, 20); + } + else + { + LOG("[PANDA][ERR] gen_aligenie_auth_key FAIL !!!"); + } +} +#endif + +static void +ppsp_impl_prc_msgs_verf(uint8* msgs_rcvd) +{ + uint8 msgn; + uint8 frsz; + uint8* plds; + ppsp_impl_get_msgs_numb(msgs_rcvd, msgn); + ppsp_impl_get_msgs_frsz(msgs_rcvd, frsz); + ppsp_impl_get_msgs_plds(msgs_rcvd, plds); + + if ( NULL != plds && 0 == plds[0] ) + { + uint8* msgs_xfer = 0; + /* Auth Success */ + ppsp_impl_set_auth_rslt(1); + msgs_xfer = ppsp_impl_new_msgs_resp(msgn, PPSP_IMPL_CFGS_OPCO_BKEY_RESP, plds, frsz); + + if ( 0 != msgs_xfer ) ppsp_impl_psh_msgs_xfer(msgs_xfer, 20); + } +} + +static void +ppsp_impl_prc_msgs_nwrk(uint8* msgs_rcvd) +{ + uint8 msgn; + uint8 encr; + uint8 frsz; + uint8* plds; + ppsp_impl_get_msgs_numb(msgs_rcvd, msgn); + ppsp_impl_get_msgs_encr(msgs_rcvd, encr); + ppsp_impl_get_msgs_frsz(msgs_rcvd, frsz); + ppsp_impl_get_msgs_plds(msgs_rcvd, plds); + uint8 cipr_text[16], text_offs; + #if (1 == PPSP_IMPL_CFGS_MSGS_CRYP_ENAB) + + if ( 0x01 == encr ) + { + ppsp_impl_dec_cipr(cipr_text, plds); + } + else + #endif + { + osal_memcpy(cipr_text, plds, frsz); + } + + if ( 0 == cipr_text[0] ) + { + LOG("NETW EXIT DONE"); + } + else if ( 1 == cipr_text[0] ) + { + LOG("NETW CFGS DONE"); + } + + // rply text + cipr_text[0] = 0x01; + text_offs = 1; + #if (1 == PPSP_IMPL_CFGS_MSGS_CRYP_ENAB) + uint8 text_size, padd_valu; + uint8 cipr_data[16]; + + if ( 0x01 == encr ) + { + text_size = sizeof(cipr_text); + ppsp_impl_get_pkcs_7pad(text_size, text_offs, padd_valu); + osal_memset(cipr_text+text_offs, padd_valu, text_size-text_offs); + ppsp_impl_enc_text(cipr_text, cipr_data); + } + + #endif + uint8* xfer = 0; + #if (1 == PPSP_IMPL_CFGS_MSGS_CRYP_ENAB) + + if ( 0x01 == encr ) + { + xfer = ppsp_impl_new_msgs_resp(msgn, PPSP_IMPL_CFGS_OPCO_NWRK_RESP, cipr_data, sizeof(cipr_data)); + } + else + #endif + { + xfer = ppsp_impl_new_msgs_resp(msgn, PPSP_IMPL_CFGS_OPCO_NWRK_RESP, cipr_text, text_offs); + } + + if ( 0 != xfer ) + { + ppsp_impl_set_msgs_encr(xfer, encr); + ppsp_impl_psh_msgs_xfer(xfer, 20); + } +} + +/*****************************************************************************/ +// ota relative +uint8 __ppsp_impl_upda_type; +uint32 __ppsp_impl_upda_vers; +uint32 __ppsp_impl_upda_fwsz; +uint16 __ppsp_impl_upda_crcs; // crc from upstream +uint8 __ppsp_impl_upda_flag; + +uint8 __ppsp_impl_upda_buff[255]; +uint16 __ppsp_impl_upda_offs; // offset of filled posi +uint16 __ppsp_impl_upda_crcd; // crc calc on local +uint32 __ppsp_impl_upda_wrsz; +uint32 __ppsp_impl_upda_dnsz; +uint32 __ppsp_impl_upda_seqn; // expect sequ numb of next + + +static uint8 +ppsp_impl_era_prog_data(uint32 addr) +{ + uint8 rslt = PPlus_ERR_FATAL; + + // flash address range check + if ( PPSP_IMPL_CFGS_PROG_ADDR_BGNS > addr || PPSP_IMPL_CFGS_PROG_ADDR_ENDS <= addr ) + { + rslt = PPlus_ERR_INVALID_ADDR; + goto RSLT_FAIL_ADDR; + } + + hal_flash_erase_sector(PPSP_IMPL_CFGS_PROG_ADDR_BASE + (addr&0xFFF000)); + rslt = PPlus_SUCCESS; +RSLT_FAIL_ADDR: + return ( rslt ); +} + +static uint8 +ppsp_impl_pul_prog_data(uint32 addr, uint32* valu) +{ + uint8 rslt = PPlus_ERR_FATAL; + + // flash address range check + if ( PPSP_IMPL_CFGS_PROG_ADDR_BGNS > addr || PPSP_IMPL_CFGS_PROG_ADDR_ENDS <= addr ) + { + rslt = PPlus_ERR_INVALID_ADDR; + goto RSLT_FAIL_ADDR; + } + + // 4 bytes aligned + if ( addr & 0x000003 ) + { + rslt = PPlus_ERR_DATA_ALIGN; + goto RSLT_FAIL_ADDR; + } + + *valu = read_reg(PPSP_IMPL_CFGS_PROG_ADDR_BASE + addr); + rslt = PPlus_SUCCESS; +RSLT_FAIL_ADDR: + return ( rslt ); +} + +static uint8 +ppsp_impl_psh_prog_data(uint32 addr, uint32 valu) +{ + uint8 rslt = PPlus_ERR_FATAL; + + // flash address range check + if ( PPSP_IMPL_CFGS_PROG_ADDR_BGNS > addr || PPSP_IMPL_CFGS_PROG_ADDR_ENDS <= addr ) + { + rslt = PPlus_ERR_INVALID_ADDR; + goto RSLT_FAIL_ADDR; + } + + // 4 bytes aligned + if ( addr & 0x000003 ) + { + rslt = PPlus_ERR_DATA_ALIGN; + goto RSLT_FAIL_ADDR; + } + + if ( 0 == hal_flash_write(PPSP_IMPL_CFGS_PROG_ADDR_BASE + addr, (uint8*)&valu, sizeof(valu)) ) + { + rslt = PPlus_ERR_FATAL; + goto RSLT_FAIL_PROG; + } + + rslt = PPlus_SUCCESS; +RSLT_FAIL_PROG: +RSLT_FAIL_ADDR: + return ( rslt ); +} + +static uint16 +ppsp_impl_cal_crc16_CCITT_FALSE(uint16 crci, uint8* data, uint32 coun) +{ + uint16 wCRCin = crci; + uint16 wCPoly = 0x1021; + + while (coun--) + { + wCRCin ^= (*(data++) << 8); + + for (int i = 0; i < 8; i++) + { + if (wCRCin & 0x8000) + wCRCin = (wCRCin << 1) ^ wCPoly; + else + wCRCin = wCRCin << 1; + } + } + + return (wCRCin); +} + +static void +ppsp_impl_prc_msgs_vers(uint8* msgs) +{ + uint8 msgn; + uint8 encr; + uint8 frsz; + uint8* plds; + ppsp_impl_get_msgs_numb(msgs, msgn); + ppsp_impl_get_msgs_encr(msgs, encr); + ppsp_impl_get_msgs_frsz(msgs, frsz); + ppsp_impl_get_msgs_plds(msgs, plds); + + if ( (0x01 == encr && 0x10 != frsz) || (0x00 == encr && 0x01 != frsz) ) + { + LOG("%s, !! INVALID MESG CONTENT !!"); + return; + } + + uint8 cipr_text[16], text_offs; // plain text, text size, offset, padding byte; + #if (1 == PPSP_IMPL_CFGS_MSGS_CRYP_ENAB) + + if ( 0x01 == encr ) + { + ppsp_impl_dec_cipr(cipr_text, plds); + } + else + #endif + { + osal_memcpy(cipr_text, plds, frsz); + } + + // rply text + cipr_text[0] = ((0x00==cipr_text[0]) ? 0x00 : 0xFF); // type + cipr_text[1] = PPSP_IMPL_CFGS_PROG_VERS_REVI; // revision + cipr_text[2] = PPSP_IMPL_CFGS_PROG_VERS_MINR; // minor + cipr_text[3] = PPSP_IMPL_CFGS_PROG_VERS_MAJR; // major + cipr_text[4] = 0x00; // reserved + text_offs = 5; + #if (1 == PPSP_IMPL_CFGS_MSGS_CRYP_ENAB) + uint8 text_size, padd_valu; // plain text, text size, offset, padding byte; + uint8 cipr_data[16]; // ciper + + if ( 0x01 == encr ) + { + text_size = sizeof(cipr_text); + ppsp_impl_get_pkcs_7pad(text_size, text_offs, padd_valu); + osal_memset(cipr_text+text_offs, padd_valu, text_size-text_offs); + ppsp_impl_enc_text(cipr_text, cipr_data); + } + + #endif + uint8* xfer = 0; + #if (1 == PPSP_IMPL_CFGS_MSGS_CRYP_ENAB) + + if ( 0x01 == encr ) + { + xfer = ppsp_impl_new_msgs_resp(msgn, PPSP_IMPL_CFGS_OPCO_VERS_RESP, cipr_data, sizeof(cipr_data)); + } + else + #endif + { + xfer = ppsp_impl_new_msgs_resp(msgn, PPSP_IMPL_CFGS_OPCO_VERS_RESP, cipr_text, text_offs); + } + + if ( 0 != xfer ) + { + ppsp_impl_set_msgs_encr(xfer, encr); + ppsp_impl_psh_msgs_xfer(xfer, 20); + } + + // if ( __ppsp_impl_stat_bits_flag & PPSP_IMPL_CFGS_OTAE_STAT_BITS ) { + // __ppsp_impl_stat_bits_flag &= ~PPSP_IMPL_CFGS_OTAE_STAT_BITS; + // write_reg(0x4000f034, 0); // flag as an OTAs auto reset + // } +} + +static void +ppsp_impl_prc_msgs_upda(uint8* msgs) +{ + uint8 msgn; + uint8 encr; + uint8 frsz; + uint8* plds; + ppsp_impl_get_msgs_numb(msgs, msgn); + ppsp_impl_get_msgs_encr(msgs, encr); + ppsp_impl_get_msgs_frsz(msgs, frsz); + ppsp_impl_get_msgs_plds(msgs, plds); + + // LOG("msgn = %x\r\n",msgn); + // LOG("encr = %x\r\n",encr); + // LOG("frsz = %x\r\n",frsz); + if ( (0x01 == encr && 0x10 != frsz) || (0x00 == encr && 0x0C != frsz) ) + { + LOG("%s, !! INVALID MESG CONTENT !! \r\n"); + return; + } + + // plain text, text size, offset, padding byte + uint8 cipr_text[16], padd_offs; + #if (1 == PPSP_IMPL_CFGS_MSGS_CRYP_ENAB) + + if ( 0x01 == encr ) + { + ppsp_impl_dec_cipr(cipr_text, plds); + } + else + #endif + { + osal_memcpy(cipr_text, plds, frsz); + } + + uint8 copy_offs = 0; + osal_memcpy(&__ppsp_impl_upda_type, cipr_text+copy_offs, sizeof(__ppsp_impl_upda_type)); // fw type + copy_offs += sizeof(__ppsp_impl_upda_type); + osal_memcpy(&__ppsp_impl_upda_vers, cipr_text+copy_offs, sizeof(__ppsp_impl_upda_vers)); // fw version + copy_offs += sizeof(__ppsp_impl_upda_vers); + osal_memcpy(&__ppsp_impl_upda_fwsz, cipr_text+copy_offs, sizeof(__ppsp_impl_upda_fwsz)); // fw size in byte + copy_offs += sizeof(__ppsp_impl_upda_fwsz); + osal_memcpy(&__ppsp_impl_upda_crcs, cipr_text+copy_offs, sizeof(__ppsp_impl_upda_crcs)); // crc16 + copy_offs += sizeof(__ppsp_impl_upda_crcs); + osal_memcpy(&__ppsp_impl_upda_flag, cipr_text+copy_offs, sizeof(__ppsp_impl_upda_flag)); // flag: 0:full update, 1:incr update + LOG("%s, type:%x,vers:%x,size:%x,crcs:%x,flag:%x \r\n", + __func__, __ppsp_impl_upda_type, __ppsp_impl_upda_vers, __ppsp_impl_upda_fwsz, __ppsp_impl_upda_crcs, __ppsp_impl_upda_flag); + + if ( PPSP_IMPL_CFGS_PROG_FLSH_SIZE < __ppsp_impl_upda_fwsz ) + { + LOG("%s, !! FIRMWARE SIZE EXCEED LIMIT OF %d BYTES !! \r\n", __func__, PPSP_IMPL_CFGS_PROG_FLSH_SIZE); + return; + } + + uint32 sctr = (__ppsp_impl_upda_fwsz/PPSP_IMPL_CFGS_PROG_SCTR_SIZE) + (__ppsp_impl_upda_fwsz%PPSP_IMPL_CFGS_PROG_SCTR_SIZE?1:0); + +// LOG("__ppsp_impl_upda_fwsz = %x\r\n",__ppsp_impl_upda_fwsz); +// LOG("sctr = %x\r\n",sctr); + for ( uint8 itr0 = 0; itr0 < sctr; itr0 += 1 ) + { + // PPSP_IMPL_CFGS_PROG_ADDR_BGNS + sctr * 0x1000 +// LOG("itr0 = %x\r\n",itr0); + ppsp_impl_era_prog_data(PPSP_IMPL_CFGS_PROG_ADDR_BGNS + (itr0<<12)); + } + + LOG("%s, total sctr:%x@size:%x erased!! \r\n", __func__, sctr, __ppsp_impl_upda_fwsz); + /* resume of last trans point is not supported */ + // reset to initial + __ppsp_impl_upda_offs = 0; + __ppsp_impl_upda_crcd = 0xFFFF; + __ppsp_impl_upda_wrsz = 0; + __ppsp_impl_upda_dnsz = 0; + __ppsp_impl_upda_seqn = 0; + // LOG("%s, pkcs#7=%x\n", __func__, padd); + cipr_text[0] = 0x01; // 1: upda allow, 0: upda deny + osal_memcpy(cipr_text+1, &__ppsp_impl_upda_dnsz, sizeof(__ppsp_impl_upda_dnsz)); + // text[1] = 0x00; // last upda posi + // text[2] = 0x00; // last upda posi + // text[3] = 0x00; // last upda posi + // text[4] = 0x00; // last upda posi + cipr_text[5] = 0x0F; // maxi frame in pack(0x00~0x0f:1~16) + padd_offs = 6; + #if (1 == PPSP_IMPL_CFGS_MSGS_CRYP_ENAB) + uint8 text_size, padd_valu; + uint8 cipr_data[16]; + + if ( 0x01 == encr ) + { + text_size = sizeof(cipr_text); + ppsp_impl_get_pkcs_7pad(text_size, padd_offs, padd_valu); + osal_memset(cipr_text+padd_offs, padd_valu, text_size-padd_offs); + ppsp_impl_enc_text(cipr_text, cipr_data); + } + + #endif + uint8* xfer = 0; + #if (1 == PPSP_IMPL_CFGS_MSGS_CRYP_ENAB) + + if ( 0x01 == encr ) + { + xfer = ppsp_impl_new_msgs_resp(msgn, PPSP_IMPL_CFGS_OPCO_UPDA_RESP, cipr_data, sizeof(cipr_data)); + } + else + #endif + { + xfer = ppsp_impl_new_msgs_resp(msgn, PPSP_IMPL_CFGS_OPCO_UPDA_RESP, cipr_text, padd_offs); + } + + if ( 0 != xfer ) + { + ppsp_impl_set_msgs_encr(xfer, encr); + ppsp_impl_psh_msgs_xfer(xfer, 20); + } +} + +static void +ppsp_impl_prc_msgs_pack(uint8* msgs) +{ + uint8 msgn; + // uint8 encr; + uint8 alln; + uint8 seqn; + uint8 frsz; // payload size in byte + uint8* plds; // payloads + ppsp_impl_get_msgs_numb(msgs, msgn); + // ppsp_impl_get_msgs_encr(msgs, encr); + ppsp_impl_get_msgs_seqn(msgs, alln, seqn); + ppsp_impl_get_msgs_frsz(msgs, frsz); + ppsp_impl_get_msgs_plds(msgs, plds); +// LOG("__ppsp_impl_update_cnt_1 = %d\r\n",__ppsp_impl_update_cnt); +// LOG("alln = %x\r\n",alln); +// LOG("seqn = %x\r\n",seqn); +// LOG("frsz = %x\r\n",frsz); + // if ( 0x01 == encr || 0x10 != frsz ) { + // LOG("%s, !! INVALID MESG CONTENT !!"); + // goto RSLT_FAIL_MESG; + // } + // TODO: HANDLE EXCEPTION OF FRAME LOSS, IN THAT CASE, LAST FRAME NUMB SHOULD RESP FOR RETRANSMITION + /* + copy offset of this received frame, data copy upto the offset would be copied to a buffer. + when the buffer is full, data in this buffer should write into flash right a way. + above procedure could repeat untill all data of the frame, being write into flash. + */ + + if ( seqn != __ppsp_impl_upda_seqn ) + { + LOG("[PPSP][WARN] !! FRAME LOSS !! \r\n"); + LOG("[PPSP][WARN] !! DNSZ=#X%x !! \r\n", __ppsp_impl_upda_dnsz); + // THIS FRAME AND ALL FOLLOWS WILL BE DROP + // AND RSPN LAST SUCC UPDA SIZE + goto RSLT_RESP_MESG; + } + else + { + __ppsp_impl_upda_seqn += 1; + } + + { + // DEPRESSION OF COMPILER WARNING + uint16 offs = 0; + + while ( offs < frsz ) + { + uint16 size = MIN(sizeof(__ppsp_impl_upda_buff)-__ppsp_impl_upda_offs, frsz-offs); + // LOG("base(dest:%x,srcs:%x) \n", __ppsp_impl_upda_buff, plds); + // LOG("copy(dest:%x,srcs:%x,size:%d) \n", __ppsp_impl_upda_buff+__ppsp_impl_upda_offs, plds+offs, size); + osal_memcpy(__ppsp_impl_upda_buff+__ppsp_impl_upda_offs, plds+offs, size); + __ppsp_impl_upda_offs += size; + offs += size; + +// LOG("size = %x\r\n",size); +// LOG("offs = %x\r\n",offs); +// LOG("frsz = %x\r\n",frsz); +// LOG("__ppsp_impl_upda_offs = %x\r\n",__ppsp_impl_upda_offs); +// LOG("sizeof(__ppsp_impl_upda_buff) = %x\r\n",sizeof(__ppsp_impl_upda_buff)); + if ( sizeof(__ppsp_impl_upda_buff) <= __ppsp_impl_upda_offs ) + { + // flsh pack + // LOG("push for write\r\n"); + #if 0 + uint32 dwrd = (__ppsp_impl_upda_offs/sizeof(uint32)) + (__ppsp_impl_upda_offs%sizeof(uint32)?1:0); + uint32 valw, valr; + + for ( int itr0 = 0; itr0 < dwrd; itr0 += 1 ) + { + // push for write + ppsp_impl_psh_prog_data( + PPSP_IMPL_CFGS_PROG_ADDR_BGNS + __ppsp_impl_upda_wrsz + (itr0 * sizeof(uint32)), + valw = *((uint32*)__ppsp_impl_upda_buff + itr0)); + } + + #else + hal_flash_write(PPSP_IMPL_CFGS_PROG_ADDR_BGNS + __ppsp_impl_upda_wrsz, __ppsp_impl_upda_buff, sizeof(__ppsp_impl_upda_buff)); + #endif + __ppsp_impl_upda_crcd = ppsp_impl_cal_crc16_CCITT_FALSE(__ppsp_impl_upda_crcd, __ppsp_impl_upda_buff, __ppsp_impl_upda_offs); + __ppsp_impl_upda_wrsz += __ppsp_impl_upda_offs; + // LOG("__ppsp_impl_upda_wrsz = %x\r\n",__ppsp_impl_upda_wrsz); + __ppsp_impl_upda_offs = 0; + } + } + + __ppsp_impl_upda_dnsz += frsz; + LOG("%s, crci:%04x, dnsz:%08x \r\n", __func__, __ppsp_impl_upda_crcd, __ppsp_impl_upda_dnsz); + } + + if ( alln != seqn ) + { + goto RSLT_SKIP_RESP; + } + else + { + __ppsp_impl_upda_seqn = 0; + } + +RSLT_RESP_MESG: + { + // DEPRESSION OF COMPILER WARNING + /* complete of a package, should resp rcvd seqn, rcvd size */ + uint8 cipr_text[16], padd_offs; + cipr_text[0] = ((alln&0x0F)<<4)|((seqn&0x0F)<<0); // + osal_memcpy(cipr_text+1, &__ppsp_impl_upda_dnsz, sizeof(__ppsp_impl_upda_dnsz)); + // text[1] = 0x00; // last upda posi + // text[2] = 0x20; // last upda posi + // text[3] = 0x00; // last upda posi + // text[4] = 0x00; // last upda posi + padd_offs = 5; + uint8 auth; + ppsp_impl_get_auth_rslt(auth); + //LOG("auth = %x\r\n",auth); + #if (1 == PPSP_IMPL_CFGS_MSGS_CRYP_ENAB) + uint8 cipr_data[16]; + uint8 text_size, padd_valu; // plain text, text size, offset, padding byte; + + if ( auth ) + { + text_size = sizeof(cipr_text); + ppsp_impl_get_pkcs_7pad(text_size, padd_offs, padd_valu); + osal_memset(cipr_text+padd_offs, padd_valu, text_size-padd_offs); + ppsp_impl_enc_text(cipr_text, cipr_data); + } + + #endif + uint8* xfer = 0; + #if (1 == PPSP_IMPL_CFGS_MSGS_CRYP_ENAB) + + if ( auth ) + { + xfer = ppsp_impl_new_msgs_resp(msgn, PPSP_IMPL_CFGS_OPCO_PACK_RESP, cipr_data, sizeof(cipr_data)); + } + else + #endif + { + xfer = ppsp_impl_new_msgs_resp(msgn, PPSP_IMPL_CFGS_OPCO_PACK_RESP, cipr_text, padd_offs); + } + + if ( 0 != xfer ) + { + ppsp_impl_set_msgs_encr(xfer, auth); + ppsp_impl_psh_msgs_xfer(xfer, 20); + } + } +RSLT_SKIP_RESP: +// RSLT_FAIL_MESG: + return; +} + +static void +ppsp_impl_prc_msgs_comp(uint8* msgs) +{ + uint8 msgn; + uint8 encr; + uint8 frsz; + uint8* plds; + ppsp_impl_get_msgs_numb(msgs, msgn); + ppsp_impl_get_msgs_encr(msgs, encr); + ppsp_impl_get_msgs_frsz(msgs, frsz); + ppsp_impl_get_msgs_plds(msgs, plds); + + if ( (0x01 == encr && 0x10 != frsz) || (0x00 == encr && 0x01 != frsz) ) + { + LOG("[PPSP][ERRN] %s, !! INVALID MESG CONTENT !! \r\n", __func__); + goto RSLT_FAIL_MESG; + } + + uint8 cipr_text[16], padd_offs; // plain text, text size, offset, padding byte; + #if (1 == PPSP_IMPL_CFGS_MSGS_CRYP_ENAB) + + if ( 0x01 == encr ) + { + ppsp_impl_dec_cipr(cipr_text, plds); + } + else + #endif + { + osal_memcpy(cipr_text, plds, frsz); + } + + if ( 0x01 != cipr_text[0] ) + { + LOG("%s, !! INVALID MESG CONTENT !! \r\n", __func__); + goto RSLT_FAIL_MESG; + } + +// LOG("__ppsp_impl_upda_offs = %x\r\n",__ppsp_impl_upda_offs); + // flsh remains in buffer + if ( 0 < __ppsp_impl_upda_offs ) + { + // LOG("push tail pack\r\n"); + #if 0 + //LOG("__ppsp_impl_upda_fwsz_1= %x\r\n",__ppsp_impl_upda_fwsz); + // flsh pack + uint32 dwrd = (__ppsp_impl_upda_offs/sizeof(uint32)) + (__ppsp_impl_upda_offs%sizeof(uint32)?1:0); + + for ( int itr0 = 0; itr0 < dwrd; itr0 += 1 ) + { + uint32 valw, valr; + // push for write + ppsp_impl_psh_prog_data( + PPSP_IMPL_CFGS_PROG_ADDR_BGNS + __ppsp_impl_upda_wrsz + (itr0 * sizeof(uint32)), + valw = *((uint32*)__ppsp_impl_upda_buff + itr0)); + } + + #else + osal_memset(__ppsp_impl_upda_buff + __ppsp_impl_upda_offs, 0x00, sizeof(__ppsp_impl_upda_buff) - __ppsp_impl_upda_offs); + hal_flash_write(PPSP_IMPL_CFGS_PROG_ADDR_BGNS + __ppsp_impl_upda_wrsz, __ppsp_impl_upda_buff, __ppsp_impl_upda_offs); + #endif + // __ppsp_impl_upda_crcd = ppsp_impl_cal_crc16_CCITT_FALSE(__ppsp_impl_upda_crcd, __ppsp_impl_upda_buff, __ppsp_impl_upda_offs); + __ppsp_impl_upda_wrsz += __ppsp_impl_upda_offs; + __ppsp_impl_upda_offs = 0; + } + +// LOG("__ppsp_impl_upda_fwsz = %x\r\n",__ppsp_impl_upda_fwsz); + /* complete of bins, should calc crc16 */ + __ppsp_impl_upda_crcd = 0xffff; + + for ( int itr0 = 0; itr0 < __ppsp_impl_upda_fwsz; itr0++ ) + { + uint8 valu; + osal_memcpy(&valu, (uint8_t*)(PPSP_IMPL_CFGS_PROG_ADDR_BASE+PPSP_IMPL_CFGS_PROG_ADDR_BGNS+itr0), 1); + __ppsp_impl_upda_crcd = ppsp_impl_cal_crc16_CCITT_FALSE(__ppsp_impl_upda_crcd, &valu, 1); + } + + LOG("%s, crci:%04x, dnsz:%08x, fwsz:%08x \r\n", __func__, __ppsp_impl_upda_crcd, __ppsp_impl_upda_dnsz, __ppsp_impl_upda_fwsz); + //printf("%s, crci:%04x, dnsz:%08x, fwsz:%08x \n", __func__, __ppsp_impl_upda_crcd, __ppsp_impl_upda_dnsz, __ppsp_impl_upda_fwsz); + /* complete of bins, should write tags for bldr */ + // uint32 tags; + // osal_memcpy(&tags, "OTAF", 4); + ppsp_impl_psh_prog_data(PPSP_IMPL_CFGS_PROG_ADDR_BGNS, 0x4641544f); // tag:"OTAF" + // printf("%s, tags:%x \r\n", __func__, tags); +// uint32 val; +// ppsp_impl_pul_prog_data(PPSP_IMPL_CFGS_PROG_ADDR_BGNS,(uint32 *) &val); +// LOG("val=%x\n",val); + // osal_memset(&tags, 0xFF, 4); + // ppsp_impl_pul_prog_data(PPSP_IMPL_CFGS_PROG_ADDR_BGNS,&tags); + // printf("%s, tags:%x \r\n", __func__, tags); + /* complete of bins, should resp crcs chck */ + cipr_text[0] = ((__ppsp_impl_upda_crcd == __ppsp_impl_upda_crcs) ? 0x01 : 0x00); //1:succ, 0:fail + LOG("%s, complete of bins: crcs comp:%s \r\n", __func__, cipr_text[0]?"SUCC": "FAIL"); +// for(int i=0;i<16;i++){ +// uint32 value; +// ppsp_impl_pul_prog_data(PPSP_IMPL_CFGS_PROG_ADDR_BGNS+0x10+i*4,(uint32 *) &value); +// LOG("value_comp=%x\n",value); +// } + //printf("%s, complete of bins: crcs comp:%s \n", __func__, cipr_text[0]?"SUCC": "FAIL"); + padd_offs = 1; + #if (1 == PPSP_IMPL_CFGS_MSGS_CRYP_ENAB) + uint8 text_size, padd_valu; + uint8 cipr_data[16]; + + if ( 0x01 == encr ) + { + text_size = sizeof(cipr_text); + ppsp_impl_get_pkcs_7pad(text_size, padd_offs, padd_valu); + osal_memset(cipr_text+padd_offs, padd_valu, text_size-padd_offs); + ppsp_impl_enc_text(cipr_text, cipr_data); + } + + #endif + uint8* xfer; + #if (1 == PPSP_IMPL_CFGS_MSGS_CRYP_ENAB) + + if ( 0x01 == encr ) + { + xfer = ppsp_impl_new_msgs_resp(msgn, PPSP_IMPL_CFGS_OPCO_COMP_RESP, cipr_data, sizeof(cipr_data)); + } + else + #endif + { + xfer = ppsp_impl_new_msgs_resp(msgn, PPSP_IMPL_CFGS_OPCO_COMP_RESP, cipr_text, padd_offs); + } + + ppsp_impl_set_msgs_encr(xfer, encr); + + if ( 0 != xfer ) ppsp_impl_psh_msgs_xfer(xfer, 20); + + __ppsp_impl_stat_bits_flag |= PPSP_IMPL_CFGS_OTAS_STAT_BITS; +// LOG("__ppsp_impl_stat_bits_flag=%x\n",__ppsp_impl_stat_bits_flag); + __ppsp_impl_proc_tout_coun = 10; // 1secs +RSLT_FAIL_MESG: + return; +} + +static void +ppsp_impl_prc_msgs_user(uint8* msgs_rcvd) +{ + uint8 msgn; + uint8 frsz; + uint8* plds; + ppsp_impl_get_msgs_numb(msgs_rcvd, msgn); + ppsp_impl_get_msgs_frsz(msgs_rcvd, frsz); + ppsp_impl_get_msgs_plds(msgs_rcvd, plds); + + if ( NULL == plds || 0 >= frsz ) + { + return; + } + + /* do whatever user wants */ + //tbrsh_leds_gpio_set_mode(TBRSH_LEDS_ENUM_LED1, plds[0]); + //tbrsh_leds_gpio_set_mode(TBRSH_LEDS_ENUM_LED2, plds[0]); + //tbrsh_leds_gpio_set_mode(TBRSH_LEDS_ENUM_LED3, plds[0]); + //tbrsh_motr_pwms_set_valu(30); + //tbrsh_motr_pwms_set_mode(plds[0]); + /* do whatever user wants */ + plds[0] = 0x01; // set resp of true + uint8* xfer = 0; + xfer = ppsp_impl_new_msgs_resp(msgn, PPSP_IMPL_CFGS_OPCO_BKEY_RESP, plds, frsz); + + if ( 0 != xfer ) + { + ppsp_impl_psh_msgs_xfer(xfer, 20); + } +} + +static uint8 +ppsp_impl_queu_msgs_hdlr(void) +{ + uint8 rslt = 0; + uint8* mesg = NULL; + rslt = core_sque_pop(__ppsp_impl_msgs_queu_rcvd, &mesg); + + /* */ + if ( 1 == rslt ) + { + uint8 opco; + ppsp_impl_get_msgs_opco(mesg, opco); + // LOG("[INF] ppsp_impl_get_msgs_opco: %02x\n\r", opco); + + if ( PPSP_IMPL_CFGS_OPCO_RAND_ISSU == opco ) + { + #if (1 == PPSP_IMPL_CFGS_MSGS_CRYP_ENAB) + //printf("[PANDA][ERR] ppsp_impl_get_msgs_opco: %02x\n\r", opco); + ppsp_impl_prc_msgs_rand(mesg); + #endif + } + else if ( PPSP_IMPL_CFGS_OPCO_VERF_ISSU == opco ) + { + //printf("[PANDA][ERR] ppsp_impl_get_msgs_opco: %02x\n\r", opco); + ppsp_impl_prc_msgs_verf(mesg); + } + else if ( PPSP_IMPL_CFGS_OPCO_NWRK_ISSU == opco ) + { + //printf("[PANDA][ERR] ppsp_impl_get_msgs_opco: %02x\n\r", opco); + ppsp_impl_prc_msgs_nwrk(mesg); + } + else if ( PPSP_IMPL_CFGS_OPCO_VERS_ISSU == opco ) + { + //printf("[PANDA][ERR] ppsp_impl_get_msgs_opco: %02x\n\r", opco); + ppsp_impl_prc_msgs_vers(mesg); + } + else if ( PPSP_IMPL_CFGS_OPCO_UPDA_ISSU == opco ) + { + //printf("[PANDA][ERR] ppsp_impl_get_msgs_opco: %02x\n\r", opco); + ppsp_impl_prc_msgs_upda(mesg); + } + else if ( PPSP_IMPL_CFGS_OPCO_PACK_ISSU == opco ) + { + ppsp_impl_prc_msgs_pack(mesg); + } + else if ( PPSP_IMPL_CFGS_OPCO_COMP_ISSU == opco ) + { + //printf("[PANDA][ERR] ppsp_impl_get_msgs_opco: %02x\n\r", opco); + ppsp_impl_prc_msgs_comp(mesg); + } + else if ( PPSP_IMPL_CFGS_OPCO_USER_ISSU == opco ) + { + ppsp_impl_prc_msgs_user(mesg); + } + + osal_mem_free(mesg); + } + + return ( rslt ); +} + +static void +ppsp_impl_serv_rcvd_hdlr(uint8 para, uint16 coun) +{ + // LOG("[ENT] %s para:%d, coun:%d \r\n", __func__, para, coun); + if ( PPSP_SERV_CFGS_CHAR_FFD5_INDX == para || + PPSP_SERV_CFGS_CHAR_FFD7_INDX == para ) + { + void* data = NULL; + + if ( NULL == (data = osal_mem_alloc(coun)) ) return; + + ppsp_serv_get_para(para, data, coun); + ppsp_impl_psh_msgs_rcvd(data, coun); + ppsp_impl_queu_msgs_hdlr(); + /* if ( NULL != data ) */ + osal_mem_free(data); + } + + // LOG("[EXI] %s \r\n", __func__); +} + +/* alia: ppsp_impl_pop_msgs_xfer */ +static void +ppsp_impl_serv_xfer_hdlr(void) +{ + // LOG("[PANDA][ENT] %s \r\n", __func__); + uint8 rslt = 1; + uint8* mesg = NULL; + uint8 opco = 0; + uint8 frsz = 0; + rslt = core_sque_pop(__ppsp_impl_msgs_queu_xfer, &mesg); + + if ( 1 == rslt ) + { + ppsp_impl_get_msgs_opco(mesg, opco); + ppsp_impl_get_msgs_frsz(mesg, frsz); + + if ( PPSP_IMPL_CFGS_OPCO_VERS_ISSU <= opco && PPSP_IMPL_CFGS_OPCO_COMP_RESP >= opco ) + ppsp_serv_set_para(PPSP_SERV_CFGS_CHAR_FFD8_INDX, frsz + PPSP_IMPL_CFGS_MSGS_HDER_SIZE, (void*)mesg); + else + ppsp_serv_set_para(PPSP_SERV_CFGS_CHAR_FFD6_INDX, frsz + PPSP_IMPL_CFGS_MSGS_HDER_SIZE, (void*)mesg); + + osal_mem_free(mesg); + } +} + +void +ppsp_impl_appl_timr_hdlr(void) +{ + // ppsp_impl_queu_msgs_hdlr(); + ppsp_impl_serv_xfer_hdlr(); + + //LOG("timer_hdlr\n"); + if ( __ppsp_impl_stat_bits_flag & PPSP_IMPL_CFGS_OTAS_STAT_BITS ) + { + //LOG("__ppsp_impl_stat_bits_flag\n"); + if ( 0 < __ppsp_impl_proc_tout_coun ) + { + __ppsp_impl_proc_tout_coun --; + + if ( 0 == __ppsp_impl_proc_tout_coun ) + { + LOG("hal_system_soft_reset for bgns of otas \r\n"); + write_reg(0x4000f034, 'O'); // flag as an OTAs auto reset + hal_system_soft_reset(); + } + } + }/* else + + if ( __ppsp_impl_stat_bits_flag & PPSP_IMPL_CFGS_OTAE_STAT_BITS ) { + if ( 0 < __ppsp_impl_proc_tout_coun ) { + __ppsp_impl_proc_tout_coun --; + if ( 0 == __ppsp_impl_proc_tout_coun ) { + printf("%s, hal_system_soft_reset for ends of otas \r\n"); + // write_reg(0x4000f034, 'O'); // flag as an OTAs auto reset + hal_system_soft_reset(); + } + } + } */ +} + +uint8 +ppsp_impl_ini(void) +{ + __ppsp_impl_stat_bits_flag = 0x00; + uint32 regs = read_reg(0x4000f034); + + if ( 'O' == regs ) + { + write_reg(0x4000f034, 0); // flag as an OTAs auto reset + __ppsp_impl_stat_bits_flag |= PPSP_IMPL_CFGS_OTAE_STAT_BITS; + // __ppsp_impl_proc_tout_coun = 300; // 30secs + } + + __ppsp_impl_msgs_queu_rcvd = core_sque_new(sizeof(uint8*), 32); + __ppsp_impl_msgs_queu_xfer = core_sque_new(sizeof(uint8*), 32); + ppsp_serv_add_serv(PPSP_SERV_CFGS_SERV_FEB3_MASK); + ppsp_serv_reg_appl(&__ppsp_impl_hdlr_serv); + LOG("\r\n ################################## \r\n"); + LOG("%s, ALIS VERS NUMB: %02d.%02d.%02d \r\n", + __func__, PPSP_IMPL_CFGS_PROG_VERS_MAJR, PPSP_IMPL_CFGS_PROG_VERS_MINR, PPSP_IMPL_CFGS_PROG_VERS_REVI); + return ( PPlus_SUCCESS ); +} + + +uint32 +ppsp_impl_get_stat(void) +{ + return ( __ppsp_impl_stat_bits_flag ); +} + +uint8 +ppsp_impl_get_pids(uint8* pids) +{ + uint8 rslt = 1; + + if ( NULL != pids ) + { + // load PID + for ( uint8 itr0 = 0; itr0 < PPSP_IMPL_CFGS_ALIS_PIDS_COUN; itr0 += 1 ) + { + hal_flash_read(0x4030+itr0,&pids[PPSP_IMPL_CFGS_ALIS_PIDS_COUN-itr0-1],1); + } + } + + return ( rslt ); +} + +uint8 +ppsp_impl_get_macs(uint8* macs) +{ + uint8 rslt = 1; + uint32 addr = 0x4000; + + if ( NULL != macs ) + { + // load MAC + hal_flash_read(addr ++,&macs [3],1); + hal_flash_read(addr ++,&macs [2],1); + hal_flash_read(addr ++,&macs [1],1); + hal_flash_read(addr ++,&macs [0],1); + hal_flash_read(addr ++,&macs [5],1); + hal_flash_read(addr ++,&macs [4],1); +// macs [3] = (uint8)ReadFlash(addr ++); +// macs [2] = (uint8)ReadFlash(addr ++); +// macs [1] = (uint8)ReadFlash(addr ++); +// macs [0] = (uint8)ReadFlash(addr ++); +// macs [5] = (uint8)ReadFlash(addr ++); +// macs [4] = (uint8)ReadFlash(addr); + } + + return ( rslt ); +} + +uint8 +ppsp_impl_get_scrt(uint8* scrt) +{ + uint8 rslt = 1; + + if ( NULL != scrt ) + { + for ( uint8 itr0 = 0; itr0 < PPSP_IMPL_CFGS_ALIS_SCRT_COUN; itr0 ++ ) + { + hal_flash_read(0x4010+itr0,&scrt[itr0],1); + //scrt[itr0] = (uint8_t)ReadFlash(0x4010+itr0); + } + } + + return ( rslt ); +} + +/* calc auth keys */ +#if (1 == PPSP_IMPL_CFGS_MSGS_CRYP_ENAB) + +uint8 +ppsp_impl_cal_keys(const uint8* rand, uint8 rsiz, const uint8* pids, uint8 psiz, const uint8* macs, uint8 msiz, const uint8* scrt, uint8 ssiz) +{ + LOG("[ENT]: %s(rand:#X08%x,rsiz:#D%d,pids#X08%x,psiz:#D%d,macs#X08%x,msiz:#D%d,scrt#X08%x,ssiz:#D%d) \r\n", + __func__, rand, rsiz, pids, psiz, macs, msiz, scrt, ssiz); + uint8 rslt = 1; + uint8 temp[128]; + uint8 posi = 0; + /* rand numb + ',' */ + LOG("\r\n[INF]: RAND DUMP:>>> "); + my_dump_byte((uint8_t*)rand, rsiz); + osal_memcpy(temp+posi, rand, rsiz); + posi += rsiz; + temp[posi] = ','; + posi += 1; + /* pids in hex str + ',' */ + LOG("\r\n[INF]: PIDS DUMP:>>> "); + my_dump_byte((uint8_t*)pids, rsiz); + hex2Str(pids, temp+posi, psiz, 1); + posi += psiz * 2; + temp[posi] = ','; + posi += 1; + /* mac in hex str + ',' */ + LOG("\r\n[INF]: MACS DUMP:>>> "); + my_dump_byte((uint8_t*)macs, msiz); + hex2Str(macs, temp+posi, msiz, 1); + posi += msiz * 2; + temp[posi] = ','; + posi += 1; + /* secret */ + LOG("\r\n[INF]: SCRT DUMP:>>> "); + my_dump_byte((uint8_t*)scrt, ssiz); + hex2Str(scrt, temp+posi, ssiz, 0); + posi += ssiz * 2; + mbedtls_sha256_context ctxt; + uint8 sha256sum[32]; + mbedtls_sha256_init(&ctxt); + rslt = mbedtls_sha256_starts_ret(&ctxt, 0); + + if ( rslt == 0 ) + { + rslt = mbedtls_sha256_update_ret(&ctxt, temp, posi); + } + + if ( rslt == 0 ) + { + rslt = mbedtls_sha256_finish_ret(&ctxt, sha256sum); + } + + if ( rslt == 0 ) // sucess + { + osal_memcpy(__ppsp_impl_auth_keys_data, sha256sum, sizeof(__ppsp_impl_auth_keys_data)); + rslt = 1; + } + + LOG("\r\n[INF]: KEYS DUMP:>>> "); + my_dump_byte((uint8_t*)__ppsp_impl_auth_keys_data, sizeof(__ppsp_impl_auth_keys_data)); + #if 0 + gen_aligenie_auth_key((uint8*)rand, rsiz, (uint8*)pids, psiz, (uint8*)macs, msiz, (uint8*)scrt, ssiz); + cpy_aligenie_auth_key(__ppsp_impl_auth_keys_data); + #endif + return ( rslt ); +} + +uint8* +ppsp_impl_get_keys(void) +{ + return ( __ppsp_impl_auth_keys_data ); +} + +uint8 +ppsp_impl_enc_text(uint8* text, uint8* cipr) +{ + uint8 rslt = 1; + uint8 iv[16] = { 0x31, 0x32, 0x33, 0x61, 0x71, 0x77, 0x65, 0x64, + 0x23, 0x2a, 0x24, 0x21, 0x28, 0x34, 0x6a, 0x75, + }; + uint8 data[16]; + uint8 itr0 = 0; + osal_memcpy(data, text, 16); + + while ( itr0 < 16 ) + { + data[itr0] ^= iv[itr0]; + itr0 += 1; + } + + struct tc_aes_key_sched_struct s; + + if ( 0 == tc_aes128_set_encrypt_key(&s, __ppsp_impl_auth_keys_data) ) + { + LOG("AES128 %s (NIST encr test) failed.\n", __func__); + rslt = 0; + goto RSLT_FAIL_ENCR; + } + + if (tc_aes_encrypt(cipr, data, &s) == 0) + { + LOG("AES128 %s (NIST encr test) failed.\n", __func__); + rslt = 0; + goto RSLT_FAIL_ENCR; + } + + rslt = 1; +RSLT_FAIL_ENCR: + return ( rslt ); +} + +uint8 +ppsp_impl_dec_cipr(uint8* text, uint8* cipr) +{ + uint8 rslt = 1; + struct tc_aes_key_sched_struct s; + + if (0 == tc_aes128_set_decrypt_key(&s, __ppsp_impl_auth_keys_data) ) + { + LOG("AES128 %s (NIST decr test) failed.\n", __func__); + rslt = 0; + goto RSLT_FAIL_ENCR; + } + + if (tc_aes_decrypt(text, cipr, &s) == 0) + { + LOG("AES128 %s (NIST decr test) failed.\n", __func__); + rslt = 0; + goto RSLT_FAIL_ENCR; + } + + uint8 aesiv[16] = { 0x31, 0x32, 0x33, 0x61, 0x71, 0x77, 0x65, 0x64, + 0x23, 0x2a, 0x24, 0x21, 0x28, 0x34, 0x6a, 0x75, + }; + uint8 itr0 = 0; + + while ( itr0 < 16 ) + { + text[itr0] ^= aesiv[itr0]; + itr0 += 1; + } + + rslt = 1; +RSLT_FAIL_ENCR: + return ( rslt ); +} +#endif + + +/* + callback of connection stat changes +*/ +void +ppsp_impl_ack_conn(uint8 flag) +{ +// /* this likely a disconnection after OTAs, reset is required for complete */ +// if ( __ppsp_impl_stat_bits_flag & PPSP_IMPL_CFGS_OTAS_STAT_BITS ) { +// write_reg(0x4000f034, 'O'); // flag as an OTAs auto reset +// hal_system_soft_reset(); +// } +// // connection loss, shold reset all status +// __ppsp_impl_stat_bits_flag = 0x00; +} + diff --git a/src/components/profiles/ppsp/ppsp_impl.h b/src/components/profiles/ppsp/ppsp_impl.h new file mode 100644 index 0000000..39487ea --- /dev/null +++ b/src/components/profiles/ppsp/ppsp_impl.h @@ -0,0 +1,63 @@ +#ifndef PPSP_IMPL_H +#define PPSP_IMPL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/********************************************************************* + INCLUDES +*/ +#include "comdef.h" + +/********************************************************************* + CONSTANTS +*/ +#define PPSP_IMPL_CFGS_TIMR_TOUT (100) + +/* + callback of tick, on which used as watch guard and ticker for xfer +*/ +void +ppsp_impl_appl_timr_hdlr(void); + +uint8 +ppsp_impl_ini(void); + +uint32 +ppsp_impl_get_stat(void); + +uint8 +ppsp_impl_get_pids(uint8* pids); + +uint8 +ppsp_impl_get_macs(uint8* macs); + +uint8 +ppsp_impl_get_scrt(uint8* scrt); + +uint8 +ppsp_impl_cal_keys(const uint8* rand, uint8 rsiz, const uint8* pids, uint8 psiz, const uint8* macs, uint8 msiz, const uint8* scrt, uint8 ssiz); + +uint8 +ppsp_impl_enc_text(uint8* text, uint8* cipr); + +uint8 +ppsp_impl_dec_cipr(uint8* text, uint8* cipr); + +/* + callback of connection stat changes +*/ +void +ppsp_impl_ack_conn(uint8 flag); + +// uint8 +// ppsp_impl_set_msgs(); + +#ifdef __cplusplus +} +#endif + +#endif /* */ diff --git a/src/components/profiles/ppsp/ppsp_serv.c b/src/components/profiles/ppsp/ppsp_serv.c new file mode 100644 index 0000000..09ef009 --- /dev/null +++ b/src/components/profiles/ppsp/ppsp_serv.c @@ -0,0 +1,957 @@ + +/************************************************************************************************** + Filename: ppsp_serv.c + Revised: + Revision: + + Description: This file contains the Simple GATT profile sample GATT service + profile for use with the BLE sample application. + + +**************************************************************************************************/ + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "linkdb.h" +#include "att.h" +#include "gatt.h" +#include "gatt_uuid.h" +#include "gattservapp.h" +#include "gapbondmgr.h" + +#include "ppsp_serv.h" +#include "ppsp_impl.h" +#include "log.h" + + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + + +// Simple GATT Profile Service UUID: 0xFFF0 +CONST uint8 __ppsp_serv_serv_uuid[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(PPSP_SERV_CFGS_SERV_FEB3_UUID), HI_UINT16(PPSP_SERV_CFGS_SERV_FEB3_UUID) +}; + +// Characteristic 1 UUID: 0xFFF1 +CONST uint8 __ppsp_serv_char_ffd4_uuid[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(PPSP_SERV_CFGS_CHAR_FED4_UUID), HI_UINT16(PPSP_SERV_CFGS_CHAR_FED4_UUID) +}; + +// Characteristic 2 UUID: 0xFFF2 +CONST uint8 __ppsp_serv_char_ffd5_uuid[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(PPSP_SERV_CFGS_CHAR_FED5_UUID), HI_UINT16(PPSP_SERV_CFGS_CHAR_FED5_UUID) +}; + +// Characteristic 3 UUID: 0xFFF3 +CONST uint8 __ppsp_serv_char_ffd6_uuid[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(PPSP_SERV_CFGS_CHAR_FED6_UUID), HI_UINT16(PPSP_SERV_CFGS_CHAR_FED6_UUID) +}; + +// Characteristic 4 UUID: 0xFFF4 +CONST uint8 __ppsp_serv_char_ffd7_uuid[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(PPSP_SERV_CFGS_CHAR_FED7_UUID), HI_UINT16(PPSP_SERV_CFGS_CHAR_FED7_UUID) +}; + +// Characteristic 5 UUID: 0xFFF5 +CONST uint8 __ppsp_serv_char_ffd8_uuid[ATT_BT_UUID_SIZE] = +{ + LO_UINT16(PPSP_SERV_CFGS_CHAR_FED8_UUID), HI_UINT16(PPSP_SERV_CFGS_CHAR_FED8_UUID) +}; + + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +static ppsp_serv_appl_CBs_t* simpleProfile_AppCBs = NULL; + +/********************************************************************* + Profile Attributes - variables +*/ + +// Simple Profile Service attribute +static CONST gattAttrType_t +__ppsp_serv_serv = { ATT_BT_UUID_SIZE, __ppsp_serv_serv_uuid }; + + +// Simple Profile Characteristic 1 Properties +static uint8 +__ppsp_serv_char_ffd4_prop = GATT_PROP_READ; + +// Characteristic 1 Value +static uint8 +__ppsp_serv_char_ffd4_para[PPSP_SERV_CFGS_CHAR_FED4_DLEN]; +static uint16 +__ppsp_serv_char_ffd4_para_size = 0; +// Simple Profile Characteristic 1 User Description +// static uint8 +// __ppsp_serv_char_ffd4_desc[] = "READ\0"; + + +// Simple Profile Characteristic 2 Properties +static uint8 +__ppsp_serv_char_ffd5_prop = GATT_PROP_WRITE; + +// Characteristic 2 Value +static uint8 +__ppsp_serv_char_ffd5_para[PPSP_SERV_CFGS_CHAR_FED5_DLEN]; + +// Simple Profile Characteristic 2 User Description +// static uint8 +// __ppsp_serv_char_ffd5_desc[] = "WRITE\0"; + + +// Simple Profile Characteristic 3 Properties +static uint8 +__ppsp_serv_char_ffd6_prop = GATT_PROP_READ | GATT_PROP_INDICATE; + +// Characteristic 3 Value +static uint8 +__ppsp_serv_char_ffd6_para[PPSP_SERV_CFGS_CHAR_FED6_DLEN]; +static uint16 +__ppsp_serv_char_ffd6_para_size = 0; +// Simple Profile Characteristic 4 Configuration Each client has its own +// instantiation of the Client Characteristic Configuration. Reads of the +// Client Characteristic Configuration only shows the configuration for +// that client and writes only affect the configuration of that client. +static gattCharCfg_t +__ppsp_serv_char_ffd6_cfgs[GATT_MAX_NUM_CONN]; + +// Simple Profile Characteristic 3 User Description +// static uint8 +// __ppsp_serv_char_ffd6_desc[] = "INDICATE\0"; + + +// Simple Profile Characteristic 4 Properties +static uint8 +__ppsp_serv_char_ffd7_prop = GATT_PROP_WRITE_NO_RSP; + +// Characteristic 4 Value +static uint8 +__ppsp_serv_char_ffd7_para[PPSP_SERV_CFGS_CHAR_FED7_DLEN]; + +// Simple Profile Characteristic 4 User Description +// static uint8 +// __ppsp_serv_char_ffd7_desc[] = "WRITE_WITH_NO_RESP\0"; + + +// Simple Profile Characteristic 5 Properties +static uint8 +__ppsp_serv_char_ffd8_prop = GATT_PROP_READ | GATT_PROP_NOTIFY; // to change to write only, HZF + +// Characteristic 5 Value +static uint8 +__ppsp_serv_char_ffd8_para[PPSP_SERV_CFGS_CHAR_FED8_DLEN]; +static uint16 +__ppsp_serv_char_ffd8_para_size = 0; +// Simple Profile Characteristic 1 Configuration Each client has its own +// instantiation of the Client Characteristic Configuration. Reads of the +// Client Characteristic Configuration only shows the configuration for +// that client and writes only affect the configuration of that client. +static gattCharCfg_t __ppsp_serv_char_ffd8_cfgs[GATT_MAX_NUM_CONN]; + +// Simple Profile Characteristic 5 User Description +// static uint8 +// __ppsp_serv_char_ffd8_desc[] = "NOTIFY\0"; + + + +/********************************************************************* + Profile Attributes - Table +*/ + +static gattAttribute_t simpleProfileAttrTbl[] = +{ + // Simple Profile Service + { + { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */ + GATT_PERMIT_READ, /* permissions */ + 0, /* handle */ + (uint8*)& __ppsp_serv_serv /* pValue */ + }, + + // Characteristic 1 Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &__ppsp_serv_char_ffd4_prop + }, + // Characteristic Value 1 + { + { ATT_BT_UUID_SIZE, __ppsp_serv_char_ffd4_uuid }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + __ppsp_serv_char_ffd4_para + }, + // Characteristic 1 User Description + /* { + { ATT_BT_UUID_SIZE, charUserDescUUID }, + GATT_PERMIT_READ, + 0, + __ppsp_serv_char_FFD4_desc + }, */ + + // Characteristic 2 Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &__ppsp_serv_char_ffd5_prop + }, + // Characteristic Value 2 + { + { ATT_BT_UUID_SIZE, __ppsp_serv_char_ffd5_uuid }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + __ppsp_serv_char_ffd5_para + }, + // Characteristic 2 User Description + /* { + { ATT_BT_UUID_SIZE, charUserDescUUID }, + GATT_PERMIT_READ, + 0, + __ppsp_serv_char_FFD5_desc + }, */ + + // Characteristic 3 Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &__ppsp_serv_char_ffd6_prop + }, + // Characteristic Value 3 + { + { ATT_BT_UUID_SIZE, __ppsp_serv_char_ffd6_uuid }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + __ppsp_serv_char_ffd6_para + }, + // Characteristic 3 configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8*)__ppsp_serv_char_ffd6_cfgs + }, + // Characteristic 3 User Description + /* { + { ATT_BT_UUID_SIZE, charUserDescUUID }, + GATT_PERMIT_READ, + 0, + __ppsp_serv_char_FFD6_desc + }, */ + + // Characteristic 4 Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &__ppsp_serv_char_ffd7_prop + }, + // Characteristic Value 4 + { + { ATT_BT_UUID_SIZE, __ppsp_serv_char_ffd7_uuid }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + __ppsp_serv_char_ffd7_para + }, + // Characteristic 4 User Description + /* { + { ATT_BT_UUID_SIZE, charUserDescUUID }, + GATT_PERMIT_READ, + 0, + __ppsp_serv_char_FFD7_desc + }, */ + + // Characteristic 5 Declaration + { + { ATT_BT_UUID_SIZE, characterUUID }, + GATT_PERMIT_READ, + 0, + &__ppsp_serv_char_ffd8_prop + }, + // Characteristic Value 5 + { + { ATT_BT_UUID_SIZE, __ppsp_serv_char_ffd8_uuid }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + __ppsp_serv_char_ffd8_para + }, + // Characteristic 5 configuration + { + { ATT_BT_UUID_SIZE, clientCharCfgUUID }, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8*)__ppsp_serv_char_ffd8_cfgs + }, + // Characteristic 5 User Description + /* { + { ATT_BT_UUID_SIZE, charUserDescUUID }, + GATT_PERMIT_READ, + 0, + __ppsp_serv_char_FFD8_desc + }, */ +}; + + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static uint8 +ppsp_serv_get_attr( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ); +static bStatus_t +ppsp_serv_set_attr( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ); +static void +ppsp_serv_hdlr_conn_stat( uint16 connHandle, uint8 changeType ); + +// static bStatus_t send_notity_indication( gattCharCfg_t *charCfgTbl, uint8 *pValue, +// uint8 authenticated, gattAttribute_t *attrTbl, +// uint16 numAttrs, uint8 taskId,uint8 dlen); + + +/********************************************************************* + @fn simpleProfile_ReadAttrCB + + @brief Read an attribute. + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be read + @param pLen - length of data to be read + @param offset - offset of the first octet to be read + @param maxLen - maximum length of data to be read + + @return Success or Failure +*/ +static uint8 ppsp_serv_get_attr( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16* pLen, uint16 offset, uint8 maxLen ) +{ + bStatus_t status = SUCCESS; + + // LOG("[PANDA][ENT] %s len:%d, offs:%d, max:%d \r\n", __func__, *pLen, offset, maxLen); + // printf("[PANDA][INF] mtu:%d", ATT_GetCurrentMTUSize()); + + // If attribute permissions require authorization to read, return error + if ( gattPermitAuthorRead( pAttr->permissions ) ) + { + // Insufficient authorization + return ( ATT_ERR_INSUFFICIENT_AUTHOR ); + } + + // Make sure it's not a blob operation (no attributes in the profile are long) + // if ( 0 < offset ) { + // return ( ATT_ERR_ATTR_NOT_LONG ); + // } + + if ( pAttr->type.len == ATT_BT_UUID_SIZE ) + { + // 16-bit UUID + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + // LOG("[PANDA][INF] uuid:%x \r\n", uuid); + uint16 gsiz = offset + 1; // size of read + uint16 ssiz = 0; // size of left + + switch ( uuid ) + { + // No need for "GATT_SERVICE_UUID" or "GATT_CLIENT_CHAR_CFG_UUID" cases; + // gattserverapp handles those reads + case PPSP_SERV_CFGS_CHAR_FED4_UUID: + { + ssiz = PPSP_SERV_CFGS_CHAR_FED4_DLEN - gsiz; + *pLen = ssiz > maxLen ? maxLen : ssiz; + VOID osal_memcpy( pValue, pAttr->pValue + offset, *pLen ); + } + break; + + case PPSP_SERV_CFGS_CHAR_FED5_UUID: + { + ssiz = PPSP_SERV_CFGS_CHAR_FED5_DLEN - gsiz; + *pLen = ssiz > maxLen ? maxLen : ssiz; + VOID osal_memcpy( pValue, pAttr->pValue + offset, *pLen ); + } + break; + + case PPSP_SERV_CFGS_CHAR_FED6_UUID: + { + ssiz = PPSP_SERV_CFGS_CHAR_FED6_DLEN - gsiz; + *pLen = ssiz > maxLen ? maxLen : ssiz; + //osal_memcpy( pValue, pAttr->pValue + offset, *pLen ); + osal_memcpy( pValue, pAttr->pValue, *pLen = __ppsp_serv_char_ffd6_para_size ); + } + break; + + case PPSP_SERV_CFGS_CHAR_FED7_UUID: + { + ssiz = PPSP_SERV_CFGS_CHAR_FED7_DLEN - gsiz; + *pLen = ssiz > maxLen ? maxLen : ssiz; + VOID osal_memcpy( pValue, pAttr->pValue + offset, *pLen ); + } + break; + + case PPSP_SERV_CFGS_CHAR_FED8_UUID: + { + ssiz = PPSP_SERV_CFGS_CHAR_FED8_DLEN - gsiz; + *pLen = ssiz > maxLen ? maxLen : ssiz; + // VOID osal_memcpy( pValue, pAttr->pValue + offset, *pLen ); + osal_memcpy( pValue, pAttr->pValue, *pLen = __ppsp_serv_char_ffd8_para_size ); + } + break; + + default: + // Should never get here! (characteristics 3 and 4 do not have read permissions) + *pLen = 0; + status = ATT_ERR_ATTR_NOT_FOUND; + break; + } + } + else + { + // 128-bit UUID + *pLen = 0; + status = ATT_ERR_INVALID_HANDLE; + } + + return ( status ); +} + +/********************************************************************* + @fn simpleProfile_WriteAttrCB + + @brief Validate attribute data prior to a write operation + + @param connHandle - connection message was received on + @param pAttr - pointer to attribute + @param pValue - pointer to data to be written + @param len - length of data + @param offset - offset of the first octet to be written + + @return Success or Failure +*/ +// TODO: test this function +static bStatus_t ppsp_serv_set_attr( uint16 connHandle, gattAttribute_t* pAttr, + uint8* pValue, uint16 len, uint16 offset ) +{ + bStatus_t status = SUCCESS; + uint8 upda_para = 0xFF; + + // LOG("[PANDA][ENT] %s: len:%d, offs:%d \n\r", __func__, len, offset); + // printf("[PANDA][ENT] %s: len:%d, offs:%d \n\r", __func__, len, offset); + // LOG("[PANDA][INF] mtu:%d", ATT_GetCurrentMTUSize()); + // LOG("\r\n[DUMP] >> "); for ( int itr0 = 0; itr0 < 4; itr0 += 1 ) LOG("%02x,", pValue[itr0]); LOG("[DUMP] << \r\n"); + + // If attribute permissions require authorization to write, return error + if ( gattPermitAuthorWrite( pAttr->permissions ) ) + { + // Insufficient authorization + return ( ATT_ERR_INSUFFICIENT_AUTHOR ); + } + + // Make sure it's not a blob operation (no attributes in the profile are long) + // if ( 0 < offset ) { + // return ( ATT_ERR_ATTR_NOT_LONG ); + // } + + if ( pAttr->type.len == ATT_BT_UUID_SIZE ) + { + // 16-bit UUID + uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); + + switch ( uuid ) + { + case PPSP_SERV_CFGS_CHAR_FED4_UUID: + { + if ( PPSP_SERV_CFGS_CHAR_FED4_DLEN <= offset ) + { + status = ATT_ERR_INVALID_VALUE_SIZE; + } + else + { + // Write the value + VOID osal_memcpy( pAttr->pValue + offset, pValue, len ); + upda_para = PPSP_SERV_CFGS_CHAR_FFD4_INDX; + } + } + break; + + case PPSP_SERV_CFGS_CHAR_FED5_UUID: + { + if ( PPSP_SERV_CFGS_CHAR_FED5_DLEN <= offset ) + { + status = ATT_ERR_INVALID_VALUE_SIZE; + } + else + { + // Write the value + VOID osal_memcpy( pAttr->pValue + offset, pValue, PPSP_SERV_CFGS_CHAR_FED5_DLEN ); + upda_para = PPSP_SERV_CFGS_CHAR_FFD5_INDX; + } + } + break; + + case PPSP_SERV_CFGS_CHAR_FED6_UUID: + { + if ( PPSP_SERV_CFGS_CHAR_FED6_DLEN <= offset ) + { + status = ATT_ERR_INVALID_VALUE_SIZE; + } + else + { + // Write the value + VOID osal_memcpy( pAttr->pValue + offset, pValue, PPSP_SERV_CFGS_CHAR_FED6_DLEN ); + upda_para = PPSP_SERV_CFGS_CHAR_FFD6_INDX; + } + } + break; + + case PPSP_SERV_CFGS_CHAR_FED7_UUID: + { + if ( PPSP_SERV_CFGS_CHAR_FED7_DLEN <= offset ) + { + status = ATT_ERR_INVALID_VALUE_SIZE; + } + else + { + // Write the value + VOID osal_memcpy( pAttr->pValue + offset, pValue, PPSP_SERV_CFGS_CHAR_FED7_DLEN ); + upda_para = PPSP_SERV_CFGS_CHAR_FFD7_INDX; + } + } + break; + + case PPSP_SERV_CFGS_CHAR_FED8_UUID: + { + if ( PPSP_SERV_CFGS_CHAR_FED8_DLEN <= offset ) + { + status = ATT_ERR_INVALID_VALUE_SIZE; + } + else + { + // Write the value + VOID osal_memcpy( pAttr->pValue + offset, pValue, PPSP_SERV_CFGS_CHAR_FED8_DLEN ); + upda_para = PPSP_SERV_CFGS_CHAR_FFD8_INDX; + } + } + break; + + case GATT_CLIENT_CHAR_CFG_UUID: + { + // Validate/Write Temperature measurement setting + if ( pAttr->handle == simpleProfileAttrTbl[7].handle ) + { + // LOG("[PANDA][INF] CHAR FED6 CFGS: %d \n\r", *pValue); + uint16 valu; + + if ( 0 != *pValue ) valu = 0x02; + else valu = 0x00; + + status = GATTServApp_ProcessCCCWriteReq(connHandle, pAttr, (uint8*)&valu, sizeof(valu), + offset, GATT_CLIENT_CFG_INDICATE ); + } + else if ( pAttr->handle == simpleProfileAttrTbl[12].handle ) + { + // LOG("[PANDA][INF] CHAR FED8 CFGS: %d \n\r", *pValue); + status = GATTServApp_ProcessCCCWriteReq(connHandle, pAttr, pValue, 2, + offset, GATT_CLIENT_CFG_NOTIFY ); + } + } + break; + + default: + // Should never get here! (characteristics 2 and 4 do not have write permissions) + status = ATT_ERR_ATTR_NOT_FOUND; + break; + } + } + else + { + // 128-bit UUID + status = ATT_ERR_INVALID_HANDLE; + } + + // If a charactersitic value changed then callback function to notify application of change + if ( upda_para != 0xFF && + NULL != simpleProfile_AppCBs && + NULL != simpleProfile_AppCBs->char_upda ) + { + simpleProfile_AppCBs->char_upda( upda_para, len ); + } + + return ( status ); +} + +/********************************************************************* + @fn simpleProfile_HandleConnStatusCB + + @brief Simple Profile link status change handler function. + + @param conn_hdle - connection handle + @param changeType - type of change + + @return none +*/ +static void ppsp_serv_hdlr_conn_stat( uint16 conn_hdle, uint8 chng_type ) +{ + // Make sure this is not loopback connection + if ( conn_hdle != LOOPBACK_CONNHANDLE ) + { + // Reset Client Char Config if connection has dropped + if ( ( chng_type == LINKDB_STATUS_UPDATE_REMOVED ) || + ( ( chng_type == LINKDB_STATUS_UPDATE_STATEFLAGS ) && + ( !linkDB_Up( conn_hdle ) ) ) ) + { + // __ppsp_impl_update_cnt = 0; + GATTServApp_InitCharCfg( conn_hdle, __ppsp_serv_char_ffd6_cfgs ); + GATTServApp_InitCharCfg( conn_hdle, __ppsp_serv_char_ffd8_cfgs ); + ppsp_impl_ack_conn(0); // ack upper impl loss of connection + } + } +} + +/********************************************************************* + PROFILE CALLBACKS +*/ +// Simple Profile Service Callbacks +CONST gattServiceCBs_t ppspCBs = +{ + ppsp_serv_get_attr, // Read callback function pointer + ppsp_serv_set_attr, // Write callback function pointer + NULL, // Authorization callback function pointer +}; + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/********************************************************************* + @fn SimpleProfile_AddService + + @brief Initializes the Simple Profile service by registering + GATT attributes with the GATT server. + + @param services - services to add. This is a bit map and can + contain more than one service. + + @return Success or Failure +*/ +bStatus_t ppsp_serv_add_serv(uint32 serv) +{ + uint8 status = SUCCESS; + // Initialize Client Characteristic Configuration attributes + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, __ppsp_serv_char_ffd6_cfgs ); + GATTServApp_InitCharCfg( INVALID_CONNHANDLE, __ppsp_serv_char_ffd8_cfgs ); + // Register with Link DB to receive link status change callback + VOID linkDB_Register( ppsp_serv_hdlr_conn_stat ); + + if ( serv & PPSP_SERV_CFGS_SERV_FEB3_MASK ) + { + // Register GATT attribute list and CBs with GATT Server App + status = GATTServApp_RegisterService( simpleProfileAttrTbl, + GATT_NUM_ATTRS( simpleProfileAttrTbl ), + &ppspCBs ); + } + + // for (int i = 0; i < PPSP_SERV_CFGS_CHAR_FED4_DLEN; i++) + // { + // __ppsp_serv_char_FFD4_para[i] =i; + // } + return ( status ); +} + + +/********************************************************************* + @fn SimpleProfile_RegisterAppCBs + + @brief Registers the application callback function. Only call + this function once. + + @param callbacks - pointer to application callbacks. + + @return SUCCESS or bleAlreadyInRequestedMode +*/ +bStatus_t ppsp_serv_reg_appl( ppsp_serv_appl_CBs_t* appCallbacks ) +{ + if ( appCallbacks ) + { + simpleProfile_AppCBs = appCallbacks; + return ( SUCCESS ); + } + else + { + return ( bleAlreadyInRequestedMode ); + } +} + + +/********************************************************************* + @fn SimpleProfile_SetParameter + + @brief Set a Simple Profile parameter. + + @param param - Profile parameter ID + @param len - length of data to right + @param value - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t ppsp_serv_set_para( uint8 para, uint16 leng, void* valu ) +{ + // LOG("[PANDA][ENT] %s: para:%d, leng:%d, valu:%x \n\r", __func__, para, leng, valu); + // LOG("\r\n[DUMP] >> "); for ( int itr0 = 0; itr0 < leng; itr0 += 1 ) LOG("%02x,", ((uint8*)valu)[itr0]); LOG("[DUMP] << \r\n"); + bStatus_t ret = SUCCESS; + + switch ( para ) + { + case PPSP_SERV_CFGS_CHAR_FFD4_INDX: + { + if ( leng <= PPSP_SERV_CFGS_CHAR_FED4_DLEN ) + { + osal_memcpy(__ppsp_serv_char_ffd4_para, valu, __ppsp_serv_char_ffd4_para_size = leng); + } + else + { + ret = bleInvalidRange; + } + } + break; + + // case PPSP_SERV_CFGS_CHAR_2_INDX: + // if ( len <= PPSP_SERV_CFGS_CHAR_2_DLEN ) + // { + // osal_memcpy(__ppsp_serv_char_2_para, value, len); + // } + // else + // { + // ret = bleInvalidRange; + // } + // break; + + // case PPSP_SERV_CFGS_CHAR_3_INDX: + // if ( len == sizeof ( uint16 ) ) + // { + // // simpleProfileChar3 = (*(uint8 *)value) << 8 | *((uint8 *)value + 1); + // } + // else + // { + // ret = bleInvalidRange; + // } + // break; + + case PPSP_SERV_CFGS_CHAR_FFD6_INDX: + { + uint16 cfgs = GATTServApp_ReadCharCfg( 0, __ppsp_serv_char_ffd6_cfgs ); + + if ( GATT_CLIENT_CFG_INDICATE == cfgs ) + { + if ( leng <= PPSP_SERV_CFGS_CHAR_FED6_DLEN ) + { + osal_memcpy( __ppsp_serv_char_ffd6_para, valu, __ppsp_serv_char_ffd6_para_size = leng ); + // send Noti/Indi if enabled + GATTServApp_ProcessCharCfg( __ppsp_serv_char_ffd6_cfgs, + __ppsp_serv_char_ffd6_para, + FALSE, + simpleProfileAttrTbl, + GATT_NUM_ATTRS( simpleProfileAttrTbl ), + INVALID_TASK_ID ); + /* send_notity_indication( __ppsp_serv_char_ffd6_cfgs, + __ppsp_serv_char_ffd6_para, + FALSE, + simpleProfileAttrTbl, + GATT_NUM_ATTRS( simpleProfileAttrTbl ), + INVALID_TASK_ID,__ppsp_serv_char_ffd6_para_size ); */ + } + else + { + ret = bleInvalidRange; + } + } + } + break; + + // case PPSP_SERV_CFGS_CHAR_5_INDX: + // if ( leng == sizeof ( uint8 ) ) + // { + // // simpleProfileChar5 = *((uint8*)value); + // } + // else + // { + // ret = bleInvalidRange; + // } + // break; + + case PPSP_SERV_CFGS_CHAR_FFD8_INDX: + { + uint16 cfgs = GATTServApp_ReadCharCfg( 0, __ppsp_serv_char_ffd8_cfgs ); + + if ( GATT_CLIENT_CFG_NOTIFY == cfgs ) + { + if ( leng <= PPSP_SERV_CFGS_CHAR_FED8_DLEN ) + { + osal_memcpy( __ppsp_serv_char_ffd8_para, valu, __ppsp_serv_char_ffd8_para_size = leng ); + // send Noti/Indi if enabled + GATTServApp_ProcessCharCfg( __ppsp_serv_char_ffd8_cfgs, + __ppsp_serv_char_ffd8_para, + FALSE, + simpleProfileAttrTbl, + GATT_NUM_ATTRS( simpleProfileAttrTbl ), + INVALID_TASK_ID ); + /* send_notity_indication( __ppsp_serv_char_ffd8_cfgs, + __ppsp_serv_char_ffd8_para, + FALSE, + simpleProfileAttrTbl, + GATT_NUM_ATTRS( simpleProfileAttrTbl ), + INVALID_TASK_ID,__ppsp_serv_char_ffd8_para_size ); */ + } + else + { + ret = bleInvalidRange; + } + } + } + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + +/********************************************************************* + @fn SimpleProfile_GetParameter + + @brief Get a Simple Profile parameter. + + @param param - Profile parameter ID + @param value - pointer to data to put. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). + + @return bStatus_t +*/ +bStatus_t ppsp_serv_get_para( uint8 para, void* valu, uint16 leng ) +{ + bStatus_t ret = SUCCESS; + + switch ( para ) + { + case PPSP_SERV_CFGS_CHAR_FFD4_INDX: + VOID osal_memcpy( valu, __ppsp_serv_char_ffd4_para, leng ); + break; + + case PPSP_SERV_CFGS_CHAR_FFD5_INDX: + VOID osal_memcpy( valu, __ppsp_serv_char_ffd5_para, leng ); + break; + + case PPSP_SERV_CFGS_CHAR_FFD6_INDX: + // *((uint16*)value) = simpleProfileChar3; + break; + + case PPSP_SERV_CFGS_CHAR_FFD7_INDX: + VOID osal_memcpy( valu, __ppsp_serv_char_ffd7_para, leng ); + break; + + case PPSP_SERV_CFGS_CHAR_FFD8_INDX: + // *((uint8*)value) = simpleProfileChar5; + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ( ret ); +} + + +/* static bStatus_t send_notity_indication( gattCharCfg_t *charCfgTbl, uint8 *pValue, + uint8 authenticated, gattAttribute_t *attrTbl, + uint16 numAttrs, uint8 taskId,uint8 dlen) + { + bStatus_t status = SUCCESS; + + for ( uint8 i = 0; i < GATT_MAX_NUM_CONN; i++ ) + { + gattCharCfg_t *pItem = &(charCfgTbl[i]); + + if ( ( pItem->connHandle != INVALID_CONNHANDLE ) && + ( pItem->value != GATT_CFG_NO_OPERATION ) ) + { + gattAttribute_t *pAttr; + + // Find the characteristic value attribute + pAttr = GATTServApp_FindAttr( attrTbl, numAttrs, pValue ); + if ( pAttr != NULL ) + { + attHandleValueNoti_t noti; + + // If the attribute value is longer than (ATT_MTU - 3) octets, then + // only the first (ATT_MTU - 3) octets of this attributes value can + // be sent in a notification. + if ( GATTServApp_ReadAttr( pItem->connHandle, pAttr, + GATT_SERVICE_HANDLE( attrTbl ), noti.value, + ¬i.len, 0, (g_ATT_MTU_SIZE-3) ) == SUCCESS ) + { + noti.handle = pAttr->handle; + + if(dlen) + noti.len=dlen; + + if ( pItem->value & GATT_CLIENT_CFG_NOTIFY ) + { + status |= GATT_Notification( pItem->connHandle, ¬i, authenticated ); + } + + if ( pItem->value & GATT_CLIENT_CFG_INDICATE ) + { + status |= GATT_Indication( pItem->connHandle, (attHandleValueInd_t *)¬i, + authenticated, taskId ); + } + } + } + } + } // for + + return ( status ); + } */ + +/********************************************************************* +*********************************************************************/ diff --git a/src/components/profiles/ppsp/ppsp_serv.h b/src/components/profiles/ppsp/ppsp_serv.h new file mode 100644 index 0000000..8e273a4 --- /dev/null +++ b/src/components/profiles/ppsp/ppsp_serv.h @@ -0,0 +1,132 @@ + +/************************************************************************************************** + Filename: ppsp_serv.h + Revised: + Revision: + + Description: This file contains the Simple GATT profile definitions and + prototypes. + + **************************************************************************************************/ + +#ifndef PPSP_SERV_H +#define PPSP_SERV_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + INCLUDES +*/ + +/********************************************************************* + CONSTANTS +*/ + +// Profile Parameters +#define PPSP_SERV_CFGS_CHAR_FFD4_INDX 0 // RW uint8 - Profile Characteristic 1 value +#define PPSP_SERV_CFGS_CHAR_FFD5_INDX 1 // RW uint8 - Profile Characteristic 2 value +#define PPSP_SERV_CFGS_CHAR_FFD6_INDX 2 // RW uint8 - Profile Characteristic 3 value +#define PPSP_SERV_CFGS_CHAR_FFD7_INDX 3 // RW uint8 - Profile Characteristic 4 value +#define PPSP_SERV_CFGS_CHAR_FFD8_INDX 4 // RW uint8 - Profile Characteristic 5 value + +// Simple Profile Service UUID +#define PPSP_SERV_CFGS_SERV_FEB3_UUID 0xFEB3 + +// Key Pressed UUID +#define PPSP_SERV_CFGS_CHAR_FED4_UUID 0xFED4 +#define PPSP_SERV_CFGS_CHAR_FED5_UUID 0xFED5 +#define PPSP_SERV_CFGS_CHAR_FED6_UUID 0xFED6 +#define PPSP_SERV_CFGS_CHAR_FED7_UUID 0xFED7 +#define PPSP_SERV_CFGS_CHAR_FED8_UUID 0xFED8 + +// Simple Keys Profile Services bit fields +#define PPSP_SERV_CFGS_SERV_FEB3_MASK 0x00000001 + +// Data Length of Characteristic 5 in bytes +#define PPSP_SERV_CFGS_CHAR_FED4_DLEN 255//256 +#define PPSP_SERV_CFGS_CHAR_FED5_DLEN 255//256 +#define PPSP_SERV_CFGS_CHAR_FED6_DLEN 255//256 +#define PPSP_SERV_CFGS_CHAR_FED7_DLEN 255//256 +#define PPSP_SERV_CFGS_CHAR_FED8_DLEN 255//256 + +/********************************************************************* + TYPEDEFS +*/ +#include "bcomdef.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + Profile Callbacks +*/ + +// Callback when a characteristic value has changed +typedef void (*ppsp_serv_hdlr_char_upda_t)( uint8 para, uint16 coun ); + +typedef struct +{ + ppsp_serv_hdlr_char_upda_t char_upda; // Called when characteristic value changes +} ppsp_serv_appl_CBs_t; + + + +/********************************************************************* + API FUNCTIONS +*/ + + +/* + SimpleProfile_AddService- Initializes the Simple GATT Profile service by registering + GATT attributes with the GATT server. + + @param services - services to add. This is a bit map and can + contain more than one service. +*/ + +extern bStatus_t ppsp_serv_add_serv(uint32 serv); + +/* + SimpleProfile_RegisterAppCBs - Registers the application callback function. + Only call this function once. + + appCallbacks - pointer to application callbacks. +*/ +extern bStatus_t ppsp_serv_reg_appl( ppsp_serv_appl_CBs_t* appl_hdlr ); + +/* + SimpleProfile_SetParameter - Set a Simple GATT Profile parameter. + + param - Profile parameter ID + len - length of data to right + value - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). +*/ +extern bStatus_t ppsp_serv_set_para( uint8 para, uint16 leng, void* valu ); + +/* + SimpleProfile_GetParameter - Get a Simple GATT Profile parameter. + + param - Profile parameter ID + value - pointer to data to write. This is dependent on + the parameter ID and WILL be cast to the appropriate + data type (example: data type of uint16 will be cast to + uint16 pointer). +*/ +extern bStatus_t ppsp_serv_get_para( uint8 para, void* valu, uint16 leng ); + +// extern bStatus_t simpleProfile_Notify( uint8 param, uint8 len, void *value ); +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* SIMPLEGATTPROFILE_H */ diff --git a/src/components/profiles/slb/slb.c b/src/components/profiles/slb/slb.c new file mode 100644 index 0000000..fb0562f --- /dev/null +++ b/src/components/profiles/slb/slb.c @@ -0,0 +1,600 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#include +#include +#include "bus_dev.h" +//#include "ap_cp.h" +//#include "hal_mcu.h" +#include "flash.h" +//#include "common.h" +#include "crc16.h" +#include "slb.h" +#include "log.h" + +#ifdef CFG_FLASH + #undef CFG_FLASH +#endif +#ifdef USE_FCT + #undef USE_FCT +#endif +#ifdef CFG_OTA_BANK_MODE + #undef CFG_OTA_BANK_MODE +#endif +#define CFG_FLASH 512 +#define USE_FCT 0 +#define CFG_OTA_BANK_MODE 1 + +#include "ota_flash.h" +#include "error.h" + +#ifdef ON_SLB_BOOTLOADER +//boot loader mode +#define SLB_ASSERT(r) {if(r) return r;} +uint8_t s_partition_buf[16*1024+16] __attribute__((section("ota_partition_buffer_area"))); +#else +//application mode + +#define SLB_ASSERT(r) {if(r){m_slb_ctx.state |= 0x80000000; return r;}} +enum +{ + SLB_PROG_ST_UNINIT = 0, + SLB_PROG_ST_IDLE = 1, + SLB_PROG_ST_PART_INFO, + SLB_PROG_ST_PART_DATA, + SLB_PROG_ST_COMPLETED, + SLB_PROG_ST_OOO_PIECE //for out of order pieces +}; +typedef struct +{ + uint32_t state; + uint8_t part_num; + ota_fw_part_t part; + uint32_t offset; + uint32_t flash_offset; + uint32_t ooo_total_numbers; + uint32_t ooo_recv_numbers; + uint32_t ooo_piece_len; + slb_chksum_cb_t ccb; +} slb_ctx_t; + +slb_ctx_t m_slb_ctx = +{ + .state = 0, + .part_num = 0, + .offset = 0, +}; +#endif +const char* tag_ota_fw= "OTAF"; +const char* tag_ota_fw_used= "@TAF"; +const char* tag_selfload_ota_info= "SOIF"; + +int slb_spif_write(uint32_t faddr, uint8_t* pdata, uint32_t size) +{ + if(faddr & 3) + { + return PPlus_ERR_DATA_ALIGN; + } + + //#if(SLB_FLASH == SLB_FLASH_INTERNAL_512) + #if 0 + uint32_t data,datatmp,tmp,i,j; + + for(i = 0; i<(size+3)/4; i++) + { + data = 0; + tmp = 4; + + if((i+1)*4 > size) + tmp = size & 3; + + for(j = 0; j < tmp; j++) + { + datatmp = (*pdata)&0xff; + datatmp = datatmp<<(j*8); + data |= datatmp; + pdata ++; + } + + if(!flash_write_word(faddr, data)) + return PPlus_ERR_SPI_FLASH; + + faddr += 4; + } + + return PPlus_SUCCESS; + #endif + return(hal_flash_write_by_dma(faddr, (uint8_t*) pdata, size)); +} + +int slb_spif_read(uint32_t faddr, uint8_t* pdata, uint32_t size) +{ + #if(SLB_FLASH == SLB_FLASH_INTERNAL_512) + SLB_FLASH_CACHE_ENTER_BYPASS_SECTION(); + memcpy(pdata, (uint8_t*)faddr, size); + SLB_FLASH_CACHE_EXIT_BYPASS_SECTION(); + return PPlus_SUCCESS; + #endif +} +int slb_spif_erase(uint32_t faddr, uint32_t size) +{ + #if(SLB_FLASH == SLB_FLASH_INTERNAL_512) + uint32_t endaddr = faddr + size; + faddr = faddr & 0xfffff000; + + while(faddr < endaddr) + { + hal_flash_erase_sector(faddr); + faddr += 0x1000;//unit is 4K + } + + return PPlus_SUCCESS; + #endif +} + + +int slb_check_currfw_exchfw(void) +{ + return PPlus_SUCCESS; +} + +uint16_t slb_flash_calc_checksum(uint32_t addr, uint32_t size) +{ + return crc16(0, (const volatile void*) addr, size); +} + +//mark the exchange zone as garbage data +#define SLB_DELETE_EXCHANGE_ZONE() {uint32_t tmpdata = 0;slb_spif_write(SLB_FLASH_FW_BASE, (uint8_t*)(&tmpdata), 4);} + +#ifdef ON_SLB_BOOTLOADER + +static int slb_erase_fw(void) +{ + return ota_flash_erase(OTAF_APP_BANK_0_ADDR); +} +static int slb_apply_exch_zone_to_fw(uint32_t part_num) +{ + int i; + uint32_t part_info[4]; + uint32_t flash_offset = 0; + uint32_t ram_part_idx = 0; + + //validate partition + for(i = 1; i< part_num; i++) + { + uint32_t crc = 0; + slb_spif_read(SLB_FLASH_FW_PART_FADDR(i), (uint8_t*) part_info, 0x10); + slb_spif_read(SLB_FLASH_PART_DATA_BASE + part_info[0], (uint8_t*)s_partition_buf, part_info[2]); + crc = (uint32_t)crc16(0, (const volatile void*)s_partition_buf, part_info[2]); + + if(crc != part_info[3]) + { + SLB_DELETE_EXCHANGE_ZONE(); + return PPlus_ERR_INVALID_DATA; + } + } + + //make exchange zone effect(load data to boot zone) + slb_erase_fw(); + + for(i = 0; i< part_num; i++) + { + slb_spif_read(SLB_FLASH_FW_PART_FADDR(i), (uint8_t*) part_info, 0x10); + slb_spif_read(SLB_FLASH_PART_DATA_BASE + part_info[0], (uint8_t*)s_partition_buf, part_info[2]); + //LOG("part_num:%d,fladdr:%x,size:%x,crc:%x \n",i,part_info[1],part_info[2],part_info[3]); + + if((part_info[1] & 0xff000000) == OTAF_BASE_ADDR)//case runaddr is in XIP + { + //erase + slb_spif_erase(part_info[1], part_info[2]); + slb_spif_write(part_info[1], (uint8_t*)s_partition_buf, part_info[2]); + } + else + { + slb_spif_write(OTAF_APP_BANK_0_ADDR + flash_offset, (uint8_t*)s_partition_buf, part_info[2]); + + if(i > 0) //prepare boot sector + { + part_info[0] = flash_offset; + slb_spif_write(OTAF_2nd_BOOTINFO_ADDR + 0x10 + 0x10*ram_part_idx, (uint8_t*) part_info, 16); + ram_part_idx ++; + } + + flash_offset += part_info[2] +4; + flash_offset &= 0xfffffffc;//word align + } + } + + //prepare boot + part_info[0] = ram_part_idx; + part_info[1] = 0;//single bank + part_info[2] = 0; + part_info[3] = 0xffffffff; + slb_spif_write(OTAF_2nd_BOOTINFO_ADDR, (uint8_t*) part_info, 16); + SLB_DELETE_EXCHANGE_ZONE(); + return PPlus_SUCCESS; +} + + +int slb_boot_load_exch_zone(void) +{ + int ret = PPlus_SUCCESS; + uint32_t part_num = 0; + uint8_t read_tmp_data[32]; + uint32_t part_info[4]; + //check tag "OTAF" + read_tmp_data[4] = 0; + slb_spif_read(SLB_FLASH_FW_BASE, read_tmp_data, 4); + + if(strcmp((const char*)read_tmp_data, tag_ota_fw) != 0) + { + return PPlus_ERR_NOT_FOUND; + } + + slb_spif_read(SLB_FLASH_FW_PART_NUM, (uint8_t*)(&part_num), 4); + + if(part_num < 2 || part_num> OTAF_PARTITION_NUM_MAX) + { + SLB_DELETE_EXCHANGE_ZONE(); + return PPlus_ERR_INVALID_DATA; + } + + //check partition 0, if run address is 0xffffxxxx, it is special partition, need not load + slb_spif_read(SLB_FLASH_FW_PART_FADDR(0), (uint8_t*) part_info, 0x10); + + if((part_info[1] & 0xffff0000) != 0xffff0000) + { + SLB_DELETE_EXCHANGE_ZONE(); + return PPlus_ERR_INVALID_DATA; + } + + //check partition 0, + //if the fw information of exhcange zone(version, device type,hw version, boot address) match to current fw + ret = slb_check_currfw_exchfw(); + + if(ret != PPlus_SUCCESS) + { + SLB_DELETE_EXCHANGE_ZONE(); + return PPlus_ERR_INVALID_DATA; + } + + slb_apply_exch_zone_to_fw(part_num); + return PPlus_SUCCESS; +} + + + +int slb_boot_recover_exch_zone(void) +{ + uint32_t part_num; + uint8_t read_tmp_data[32]; + uint32_t part_info[4]; + //check tag "@TAF" + read_tmp_data[4] = 0; + slb_spif_read(SLB_EXCH_AREA_BASE, read_tmp_data, 4); + read_tmp_data[0] &= 0xf0; + + if(strcmp((const char*)read_tmp_data, tag_ota_fw_used) != 0) + { + return PPlus_ERR_NOT_FOUND; + } + + slb_spif_read(SLB_FLASH_FW_PART_NUM, (uint8_t*)(&part_num), 4); + + if(part_num < 2 || part_num) + { + SLB_DELETE_EXCHANGE_ZONE(); + return PPlus_ERR_INVALID_DATA; + } + + //check partition 0, if run address is 0xffffxxxx, it is special partition, need not load + slb_spif_read(SLB_FLASH_FW_PART_FADDR(0), (uint8_t*) part_info, 0x10); + + if((part_info[1] & 0xffff0000) != 0xffff0000) + { + SLB_DELETE_EXCHANGE_ZONE(); + return PPlus_ERR_INVALID_DATA; + } + + slb_apply_exch_zone_to_fw(part_num); + return PPlus_SUCCESS; +} +#else + +//buf[0] is piece data length +static uint32_t slb_ooo_buffer[SLB_OOB_PIECE_SIZE_MAX/4+1]; + +static int slb_ooo_pieces_upgrade_start(void) +{ + //erase exchange zone + slb_spif_erase(SLB_EXCH_AREA_BASE, SLB_EXCH_AREA_SIZE); + m_slb_ctx.state = SLB_PROG_ST_OOO_PIECE; + return PPlus_SUCCESS; +} +static int slb_oob_piece_write(uint32_t index) +{ + int ret; + uint32_t unit_size = m_slb_ctx.ooo_piece_len; + ret = slb_spif_write(SLB_EXCH_AREA_BASE + unit_size * index, (uint8_t*)(slb_ooo_buffer+1), slb_ooo_buffer[0]); + slb_ooo_buffer[0] = 0; + return ret; +} + +//build_datetime; ascii string: YYMMDDHHMMSS\n,this field can be NULL +int slb_upgrade_start(slb_fwinfo_t* pfwinfo, char* build_datetime) +{ + int ret; + uint32_t value = 0; + //reset data structure of contex + memset(&m_slb_ctx, 0, sizeof(m_slb_ctx)); + m_slb_ctx.state = SLB_PROG_ST_IDLE; + + if(pfwinfo == NULL && build_datetime == NULL) + { + return slb_ooo_pieces_upgrade_start(); + } + + //check parameter + if(pfwinfo->boot_addr != 0xffffffff) + { + if(pfwinfo->boot_addr < 0x1fff1838 || pfwinfo->boot_addr >SRAM2_BASE_ADDRESS) + SLB_ASSERT( PPlus_ERR_INVALID_ADDR); + } + + if(pfwinfo->partition_num > OTAF_PARTITION_NUM_MAX) + SLB_ASSERT( PPlus_ERR_INVALID_PARAM); + + //erase exchange zone + slb_spif_erase(SLB_EXCH_AREA_BASE, SLB_EXCH_AREA_SIZE); + //save fw information + value = (uint32_t)(pfwinfo->partition_num + 1); + ret = slb_spif_write(SLB_FLASH_FW_PART_NUM, (uint8_t*) (&value), 4); + SLB_ASSERT(ret); + //write special partition + ret = slb_spif_write(SLB_FLASH_PART_DATA_BASE, (uint8_t*)tag_selfload_ota_info, 4); + SLB_ASSERT(ret); + value = pfwinfo->manufactory_id &0xffff; + value = (value << 16) | (pfwinfo->dev_type&0xffff); + ret = slb_spif_write(SLB_FLASH_PART_DATA_BASE+4, (uint8_t*) (&value), 4); + SLB_ASSERT(ret); + value = (uint32_t)pfwinfo->fwver_major; + value = (value<<8)|(uint32_t)pfwinfo->fwver_minor; + value = (value<<8)|(uint32_t)pfwinfo->fwver_revision; + value = (value<<8)|(uint32_t)pfwinfo->fwver_test; + ret = slb_spif_write(SLB_FLASH_PART_DATA_BASE+8, (uint8_t*) (&value), 4); + SLB_ASSERT(ret); + value = pfwinfo->hwver; + ret = slb_spif_write(SLB_FLASH_PART_DATA_BASE+0xc, (uint8_t*) (&value), 4); + SLB_ASSERT(ret); + + if(build_datetime && strlen(build_datetime) < 0x10) + { + ret = slb_spif_write(SLB_FLASH_PART_DATA_BASE+0x10, (uint8_t*) (&build_datetime), strlen(build_datetime)+1); + SLB_ASSERT(ret); + } + + value = pfwinfo->boot_addr; + ret = slb_spif_write(SLB_FLASH_PART_DATA_BASE+0x20, (uint8_t*) (&value), 4); + SLB_ASSERT(ret); + //write partition info + value = 0; + ret = slb_spif_write(SLB_FLASH_FW_PART_FADDR(0), (uint8_t*) (&value), 4); + SLB_ASSERT(ret); + value = 0xffff00f0; + ret = slb_spif_write(SLB_FLASH_FW_PART_RADDR(0), (uint8_t*) (&value), 4); + SLB_ASSERT(ret); + value = 256; + ret = slb_spif_write(SLB_FLASH_FW_PART_SIZE(0), (uint8_t*) (&value), 4); + SLB_ASSERT(ret); + value = slb_flash_calc_checksum(SLB_FLASH_PART_DATA_BASE, 256); + ret = slb_spif_write(SLB_FLASH_FW_PART_CHKSUM(0), (uint8_t*) (&value), 4); + SLB_ASSERT(ret); + m_slb_ctx.state = SLB_PROG_ST_PART_INFO; + m_slb_ctx.part_num = pfwinfo->partition_num + 1; + m_slb_ctx.flash_offset = 256;//first 256 bytes is for special partition + return PPlus_SUCCESS; +} + +int slb_upgrade_partition_info(uint32_t runaddr, uint32_t len, uint16_t crc, bool* last_partition) +{ + int ret; + uint32_t value = 0; + ota_fw_part_t* ppart = &(m_slb_ctx.part); + *last_partition = FALSE; + + if( m_slb_ctx.state != SLB_PROG_ST_PART_INFO) + SLB_ASSERT(PPlus_ERR_INVALID_STATE); + + //save part info + ppart->flash_addr = m_slb_ctx.flash_offset; + ppart->run_addr = runaddr; + ppart->size = len; + ppart->checksum = crc; + + if(m_slb_ctx.part_num == 2 && last_partition) + *last_partition = TRUE; + + m_slb_ctx.offset = 0; + //write part info + value = ppart->flash_addr; + ret = slb_spif_write(SLB_FLASH_FW_PART_FADDR(m_slb_ctx.part_num-1), (uint8_t*) (&value), 4); + SLB_ASSERT(ret); + value = ppart->run_addr; + ret = slb_spif_write(SLB_FLASH_FW_PART_RADDR(m_slb_ctx.part_num-1), (uint8_t*) (&value), 4); + SLB_ASSERT(ret); + value = ppart->size; + ret = slb_spif_write(SLB_FLASH_FW_PART_SIZE(m_slb_ctx.part_num-1), (uint8_t*) (&value), 4); + SLB_ASSERT(ret); + value = (uint32_t)ppart->checksum; + ret = slb_spif_write(SLB_FLASH_FW_PART_CHKSUM(m_slb_ctx.part_num-1), (uint8_t*) (&value), 4); + SLB_ASSERT(ret); + m_slb_ctx.state = SLB_PROG_ST_PART_DATA; + return PPlus_SUCCESS; +} + +// partition data storing should be as stream, auto seek +stream_st_t slb_upgrade_partition_data(uint8_t* data, uint32_t len) +{ + int ret; + ota_fw_part_t* ppart = &(m_slb_ctx.part); + + if( m_slb_ctx.state != SLB_PROG_ST_PART_DATA) + SLB_ASSERT(SLB_SST_ERROR); + + if(m_slb_ctx.offset + len > ppart->size) + SLB_ASSERT(SLB_SST_ERROR); + + ret = slb_spif_write(SLB_FLASH_PART_DATA_BASE + m_slb_ctx.flash_offset + m_slb_ctx.offset, data, len); + + if(ret) + SLB_ASSERT(SLB_SST_ERROR); + + m_slb_ctx.offset += len; + + if(m_slb_ctx.offset == ppart->size) + { + uint16_t crc = slb_flash_calc_checksum(SLB_FLASH_PART_DATA_BASE + m_slb_ctx.flash_offset, ppart->size); + + if(crc != ppart->checksum) + { + SLB_ASSERT(SLB_SST_ERROR); + } + + m_slb_ctx.flash_offset += (ppart->size + 4) & 0xfffffffc; + m_slb_ctx.part_num --; + m_slb_ctx.state = SLB_PROG_ST_PART_INFO; + + if(m_slb_ctx.part_num == 1) + { + m_slb_ctx.state = SLB_PROG_ST_COMPLETED; + } + + return SLB_SST_SUCCESS; + } + + return SLB_SST_MOREDATA; +} + +//upgrade out of order pieces +int slb_upgrade_ooo_pieces(uint32_t numbers, uint32_t index, uint8_t* data, uint32_t len) +{ + int ret; + + if( m_slb_ctx.state != SLB_PROG_ST_OOO_PIECE) + SLB_ASSERT(PPlus_ERR_INVALID_STATE); + + if(m_slb_ctx.ooo_total_numbers == 0) + { + m_slb_ctx.ooo_total_numbers = numbers; + m_slb_ctx.ooo_recv_numbers = 0; + } + else + { + if(m_slb_ctx.ooo_total_numbers != numbers) + return PPlus_ERR_INVALID_PARAM; + } + + if(m_slb_ctx.ooo_piece_len == 0) + { + if(numbers != (index+1))//not last packet + { + if(len & 3) return PPlus_ERR_INVALID_LENGTH; + + m_slb_ctx.ooo_piece_len = len; + + if(slb_ooo_buffer[0]) //case last piece data stored temporarily + { + ret = slb_oob_piece_write(index); + SLB_ASSERT(ret); + } + + slb_ooo_buffer[0] = len; + memcpy((void*)(slb_ooo_buffer+1), data, len); + ret = slb_oob_piece_write(index); + SLB_ASSERT(ret); + } + else + { + slb_ooo_buffer[0] = len; + memcpy((void*)(slb_ooo_buffer+1), data, len); + } + } + else + { + if(numbers != (index+1) && m_slb_ctx.ooo_piece_len != len) + return PPlus_ERR_INVALID_LENGTH; + + slb_ooo_buffer[0] = len; + memcpy((void*)(slb_ooo_buffer+1), data, len); + ret = slb_oob_piece_write(index); + SLB_ASSERT(ret); + } + + return PPlus_SUCCESS; +} + + +int slb_upgrade_apply_new_fw(void) +{ + int ret,i; + + if( m_slb_ctx.state == SLB_PROG_ST_COMPLETED) + { + //write tag + ret = slb_spif_write(SLB_FLASH_FW_BASE, (uint8_t*)tag_ota_fw, 4); + SLB_ASSERT(ret); + WaitMs(100); + NVIC_SystemReset(); + } + else if(m_slb_ctx.state == SLB_PROG_ST_OOO_PIECE) + { + //data integrity check + uint32_t part_num; + uint32_t part_info[4]; + slb_spif_read(SLB_FLASH_FW_PART_NUM, (uint8_t*)(&part_num), 4); + + if(part_num < 2 || part_num> OTAF_PARTITION_NUM_MAX) + { + SLB_DELETE_EXCHANGE_ZONE(); + return PPlus_ERR_INVALID_DATA; + } + + //check partition 0, if run address is 0xffffxxxx, it is special partition, need not load + slb_spif_read(SLB_FLASH_FW_PART_FADDR(0), (uint8_t*) part_info, 0x10); + + if((part_info[1] & 0xffff0000) != 0xffff0000) + { + SLB_DELETE_EXCHANGE_ZONE(); + return PPlus_ERR_INVALID_DATA; + } + + //validate partition + for(i = 1; i< part_num; i++) + { + uint32_t crc = 0; + slb_spif_read(SLB_FLASH_FW_PART_FADDR(i), (uint8_t*) part_info, 0x10); + crc = slb_flash_calc_checksum(SLB_FLASH_PART_DATA_BASE + part_info[0], part_info[2]); + + if(crc != part_info[3]) + { + SLB_DELETE_EXCHANGE_ZONE(); + return PPlus_ERR_INVALID_DATA; + } + } + + ret = slb_spif_write(SLB_FLASH_FW_BASE, (uint8_t*)tag_ota_fw, 4); + SLB_ASSERT(ret); + WaitMs(100); + NVIC_SystemReset(); + } + + return PPlus_ERR_INVALID_STATE; +} + + + + +#endif + diff --git a/src/components/profiles/slb/slb.h b/src/components/profiles/slb/slb.h new file mode 100644 index 0000000..fe96e3d --- /dev/null +++ b/src/components/profiles/slb/slb.h @@ -0,0 +1,91 @@ +#ifndef __SLB_H +#define __SLB_H + + +#ifndef SLB_EXCH_AREA_BASE + #define SLB_EXCH_AREA_BASE 0x11055000 +#endif +#ifndef SLB_EXCH_AREA_SIZE + #define SLB_EXCH_AREA_SIZE (172*1024) //172K +#endif + +#define SLB_OOB_PIECE_SIZE_MAX 256 + +enum +{ + SLB_FLASH_INTERNAL_512 = 1, + SLB_FLASH_INTERNAL_1M, + SLB_FLASH_INTERNAL_4M, + SLB_FLASH_EXTERNAL_SPI = 0xf0 +}; + +#define SLB_DATA_OUT_OF_ORDER 1 //case data out-of-order, each data record should have certain run address + +#if(SLB_DATA_OUT_OF_ORDER == 1) + #define SLB_PART_INFO_SAVED OTAF_PARTITION_NUM_MAX +#else + #define SLB_PART_INFO_SAVED 1 +#endif + +#define SLB_FLASH SLB_FLASH_INTERNAL_512 + + +#define SLB_FLASH_FW_BASE (SLB_EXCH_AREA_BASE) +#define SLB_FLASH_FW_PART_NUM (SLB_EXCH_AREA_BASE+4) + +#define SLB_FLASH_FW_PART_FADDR(n) (SLB_EXCH_AREA_BASE + 0x10 + 0x10*(n)) +#define SLB_FLASH_FW_PART_RADDR(n) (SLB_EXCH_AREA_BASE + 0x14 + 0x10*(n)) +#define SLB_FLASH_FW_PART_SIZE(n) (SLB_EXCH_AREA_BASE + 0x18 + 0x10*(n)) +#define SLB_FLASH_FW_PART_CHKSUM(n) (SLB_EXCH_AREA_BASE + 0x1c + 0x10*(n)) + +#define SLB_FLASH_PART_DATA_BASE (SLB_EXCH_AREA_BASE + 0x1000) + +#define SLB_FLASH_CACHE_ENTER_BYPASS_SECTION() do{ \ + AP_CACHE->CTRL0 = 0x02; \ + AP_PCR->CACHE_RST = 0x02;\ + AP_PCR->CACHE_BYPASS = 1; \ + }while(0); + + +#define SLB_FLASH_CACHE_EXIT_BYPASS_SECTION() do{ \ + AP_CACHE->CTRL0 = 0x00;\ + AP_PCR->CACHE_RST = 0x03;\ + AP_PCR->CACHE_BYPASS = 0;\ + }while(0); + +typedef enum +{ + SLB_SST_SUCCESS = 0, + SLB_SST_MOREDATA = 1, + SLB_SST_ERROR = 0xff +} stream_st_t; + +typedef struct +{ + uint32_t boot_addr; + uint8_t partition_num; + uint32_t dev_type; + uint32_t manufactory_id; + uint8_t fwver_major; + uint8_t fwver_minor; + uint8_t fwver_revision; + uint8_t fwver_test; + uint32_t hwver; +} slb_fwinfo_t; + +typedef int (*slb_chksum_cb_t)(uint8_t* data, uint32_t len); + + +#ifdef ON_SLB_BOOTLOADER + + int slb_boot_load_exch_zone(void); + int slb_boot_recover_exch_zone(void); +#else + int slb_upgrade_start(slb_fwinfo_t* pfwinfo, char* build_datetime); + int slb_upgrade_partition_info(uint32_t runaddr, uint32_t len, uint16_t crc, bool* last_partition); + stream_st_t slb_upgrade_partition_data(uint8_t* data, uint32_t len); + int slb_upgrade_apply_new_fw(void); +#endif + + +#endif diff --git a/src/lib/aoxEst.lib b/src/lib/aoxEst.lib new file mode 100644 index 0000000000000000000000000000000000000000..ac3e5a102572e6a70de9566829588fc80f2551d4 GIT binary patch literal 33830 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 Kj|!3pX#oHhe9=Sz literal 0 HcmV?d00001 diff --git a/src/lib/ble_controller/ll.c b/src/lib/ble_controller/ll.c new file mode 100644 index 0000000..80f00ba --- /dev/null +++ b/src/lib/ble_controller/ll.c @@ -0,0 +1,8838 @@ + +/******************************************************************************* + Filename: ll.c, updated base on ll.h + Revised: + Revision: + + Description: This file contains the Link Layer (LL) API for the Bluetooth + Low Energy (BLE) Controller. It provides the defines, types, + and functions for all supported Bluetooth Low Energy (BLE) + commands. + + This API is based on the Bluetooth Core Specification, + V4.0.0, Vol. 6. + + +*******************************************************************************/ +//#define DEBUG_LL + +/******************************************************************************* + INCLUDES +*/ +#include +#include +#include +#include "ll_buf.h" +#include "ll.h" +#include "ll_def.h" +#include "ll_common.h" +#include "ll_hw_drv.h" +#include "OSAL.h" +#include "OSAL_PwrMgr.h" +#include "osal_bufmgr.h" +#include "bus_dev.h" +#include "jump_function.h" +#include "global_config.h" +#include "ll_debug.h" +#include "ll_enc.h" +#include "rf_phy_driver.h" +#include "time.h" + +#define OWN_PUBLIC_ADDR_POS 0x11004000 + +extern uint32_t get_timer_count(AP_TIM_TypeDef* TIMx); +/******************************************************************************* + MACROS +*/ +#define LL_COPY_DEV_ADDR_LE( dstPtr, srcPtr ) { \ + (dstPtr)[0] = (srcPtr)[0]; \ + (dstPtr)[1] = (srcPtr)[1]; \ + (dstPtr)[2] = (srcPtr)[2]; \ + (dstPtr)[3] = (srcPtr)[3]; \ + (dstPtr)[4] = (srcPtr)[4]; \ + (dstPtr)[5] = (srcPtr)[5];} +// ALT: COULD USE OSAL COPY. +// osal_memcpy( (dstPtr), (srcPtr), LL_DEVICE_ADDR_LEN ); + +#define LL_COPY_DEV_ADDR_BE( dstPtr, srcPtr ) { \ + (dstPtr)[0] = (srcPtr)[5]; \ + (dstPtr)[1] = (srcPtr)[4]; \ + (dstPtr)[2] = (srcPtr)[3]; \ + (dstPtr)[3] = (srcPtr)[2]; \ + (dstPtr)[4] = (srcPtr)[1]; \ + (dstPtr)[5] = (srcPtr)[0];} +// ALT: COULD USE OSAL COPY. +// osal_memcpy( (dstPtr), (srcPtr), LL_DEVICE_ADDR_LEN ); + +#define BDADDR_VALID( bdAddr ) \ + ( !( \ + ((bdAddr)[0] == 0xFF) && \ + ((bdAddr)[1] == 0xFF) && \ + ((bdAddr)[2] == 0xFF) && \ + ((bdAddr)[3] == 0xFF) && \ + ((bdAddr)[4] == 0xFF) && \ + ((bdAddr)[5] == 0xFF) \ + ) \ + ) + +// See "Supported States Related" below. +#define LL_SET_SUPPORTED_STATES( state ) \ + states[ (state)>>4 ] |= (1<<((state) & 0x0F)); + +/******************************************************************************* + CONSTANTS +*/ +// Bluetooth Version Information +#define LL_VERSION_NUM 0x09 // BT Core Specification V5.0.0, refer to https://www.bluetooth.com/specifications/assigned-numbers/host-controller-interface +#define LL_COMPANY_ID 0x0504 // Phyplus + +// Major Version (8 bits) . Minor Version (4 bits) . SubMinor Version (4 bits) +#define LL_SUBVERSION_NUM 0x0208 // Controller v1.0.0. Definition not found in BLE spec + +// Connection Window Information +#define LL_WINDOW_SIZE 2 // 2.5ms in 1.25ms ticks +#define LL_WINDOW_OFFSET 0 // 1.25ms + 0 + +/******************************************************************************* + TYPEDEFS +*/ + +/******************************************************************************* + LOCAL VARIABLES +*/ + +/* +** Own Device Address +** +** Note that the device may have a permanently assigned BLE address located in +** the Information Page. However, this address could be overridden with either +** the build flag BDADDR_FROM_FLASH, or by the vendor specific command +** LL_EXT_SET_BDADDR. +*/ +// Own Device Public Address +uint8 ownPublicAddr[ LL_DEVICE_ADDR_LEN ]; // index 0..5 is LSO..MSB + +// Own Device Random Address +uint8 ownRandomAddr[ LL_DEVICE_ADDR_LEN ]; // index 0..5 is LSO..MSB + +// Delay Sleep +static uint16 sleepDelay; // delay sleep for XOSC stabilization upon reset + +syncInfo_t syncInfo; + +scannerSyncInfo_t scanSyncInfo; + +extern uint32 llWaitingIrq; +extern struct buf_rx_desc g_rx_adv_buf; + +extern uint8 g_currentLocalRpa[LL_DEVICE_ADDR_LEN]; +extern uint8 g_currentPeerRpa[LL_DEVICE_ADDR_LEN]; +extern uint8 g_currentPeerAddrType; +extern uint8 g_currentLocalAddrType; + + +/******************************************************************************* + GLOBAL VARIABLES +*/ + +advInfo_t adv_param; // Advertiser info +// add for scanner +scanInfo_t scanInfo; // Scanner info +// add for initiator 2018-05-09 +initInfo_t initInfo; // Initiator info + +extScanInfo_t extScanInfo; // extended Scanner info +extInitInfo_t extInitInfo; // extended initiator info + +// BBB new: the memory of LL connect context is allocated by APP +llConnState_t* conn_param = NULL; +uint8 g_maxConnNum = 0; +uint8 g_maxPktPerEventTx = TYP_CONN_BUF_LEN; +uint8 g_maxPktPerEventRx = TYP_CONN_BUF_LEN; +uint8 g_blePktVersion = BLE_PKT_VERSION_4_0; + +//move to llConnStat_t +//preChanMapUpdate_t preChanMapUpdate[MAX_NUM_LL_CONN]; + +llPeriodicScannerInfo_t g_llPeriodAdvSyncInfo[MAX_NUM_LL_PRD_ADV_SYNC]; + +// A2 multi-connection +llConns_t g_ll_conn_ctx; + + +uint8 LL_TaskID; // OSAL LL task ID +uint8_t llState; // state of LL ==> to move to per connection context ??? +peerInfo_t peerInfo; // peer device's address and address type ==> to move to per connection context??? +chanMap_t chanMapUpdate; // channel map for updates +featureSet_t deviceFeatureSet; // feature set for this device +verInfo_t verInfo; // own version information +//llConns_t llConns; // LL connections table +uint8 numComplPkts; // number of completed Tx buffers, use global beacuse we report HCI event when numComplPkts >= numComplPktsLimit +uint8 numComplPktsLimit; // minimum number of completed Tx buffers before event +rfCounters_t rfCounters; // counters for LL RX/TX atomic operation in one connection event + +uint8 fastTxRespTime; // flag indicates if fast TX response time feature is enabled/disabled + +// ======= add by HZF, for whitelist +peerInfo_t g_llWhitelist[LL_WHITELIST_ENTRY_NUM]; // whitelist table +uint8 g_llWlDeviceNum; // current device number in whitelist list, should not exceed LL_WHITELIST_ENTRY_NUM + +// ======= add by HZF, for resolving list +resolvingListInfo_t g_llResolvinglist[LL_RESOLVINGLIST_ENTRY_NUM]; // resolving list table, size to be consider +uint8 g_llRlDeviceNum; // current device number in resolving list, should not exceed LL_RESOLVINGLIST_ENTRY_NUM +uint8 g_llRlEnable = FALSE; +uint16 g_llRlTimeout = 900; // Unit: second + + +// ============== A1 ROM metal change add +uint32_t g_llHdcDirAdvTime; // for HDC direct adv +//== + +//uint8 numComplPktsLimit; // minimum number of completed Tx buffers before event +//uint8 numComplPktsFlush; // flag to indicate send number of completed buffers at end of event +//uint8 fastTxRespTime; // flag indicates if fast TX response time feature is enabled/disabled +//== + +// RX Flow Control +uint8 rxFifoFlowCtrl; + +//llLinkBuf_t ll_buf; + +llGlobalStatistics_t g_pmCounters; // TODO: to divide into per connection counters & global counters + +// ===== A2 metal change add +llPduLenManagment_t g_llPduLen; //for dle feature ==> to move to per connection context +//llPhyModeManagment_t g_llPhyModeCtrl;// for phy update ==> to move to per connection context +uint8_t llSecondaryState; // secondary state of LL +// ===== A2 add End +extern l2capSARDbugCnt_t g_sarDbgCnt; + +extern struct buf_tx_desc g_tx_adv_buf; +extern struct buf_tx_desc g_tx_ext_adv_buf; + +extern struct buf_tx_desc tx_scanRsp_desc; + +extern uint32 g_interAuxPduDuration; + +// ============ extended advertisement variables +extAdvInfo_t* g_pExtendedAdvInfo = NULL; // extended adv information, note that periodic adv also need it +periodicAdvInfo_t* g_pPeriodicAdvInfo = NULL; + +// TODO: add periodic adv set array +uint8 g_extAdvNumber; // number of ext adv set +uint8 g_perioAdvNumber; // number of periodic adv set + +uint16 g_advSetMaximumLen; // maximum length of adv data + +// extended adv scheduler context, move to a structure? +llAdvScheduleInfo_t* g_pAdvSchInfo; +uint8 g_schExtAdvNum; // current schedule extended adv number +uint8 g_currentExtAdv; // current schedule extended adv index +uint32 g_advPerSlotTick; // us +uint32 g_advSlotPeriodic; // us +uint32 g_currentAdvTimer; // us + +// ==== periodic adv scheduler context +llPeriodicAdvScheduleInfo_t* g_pAdvSchInfo_periodic; // periodic adv scheduler info +uint8 g_schExtAdvNum_periodic; // current scheduler periodic adv number +uint8 g_currentExtAdv_periodic; // current scheduler periodic adv index + + +// +uint8 g_currentTimerTask; // scan or adv +uint32 g_timerExpiryTick; // us + +// 2020-02-15 add for connectionless IQ Sample buffer +uint16* g_pLLcteISample=NULL; +uint16* g_pLLcteQSample=NULL; + +// according to BQB test case HCI/GEV/BV-02-C & HCI/GEV/BV-03-C, +// mixed legacy advertisement and extended advertisement is disallowed +// mixed legacy scan and extended scan is disallowed +#define LL_MODE_INVALID 0xFF +#define LL_MODE_LEGACY 0x00 +#define LL_MODE_EXTENDED 0x01 +uint8 g_llScanMode = LL_MODE_INVALID; +uint8 g_llAdvMode = LL_MODE_INVALID; + + +// RF path compensation +extern int16 g_rfTxPathCompensation, g_rfRxPathCompensation; + +// periodic advertiser device list +periodicAdvertiserListInfo_t g_llPeriodicAdvlist[LL_PRD_ADV_ENTRY_NUM]; +uint8 g_llPrdAdvDeviceNum; // current periodic advertiser device number + +// LOCAL FUNCTIONS +void llPrdAdvDecideNextChn(extAdvInfo_t* pAdvInfo, periodicAdvInfo_t* pPrdAdv); +void llSetupSyncInfo(extAdvInfo_t* pAdvInfo, periodicAdvInfo_t* pPrdAdv); + + + +/******************************************************************************* + @fn LL_Init0 + + @brief This is the Link Layer task initialization called by OSAL. It + must be called once when the software system is started and + before any other function in the LL API is called. + + input parameters + + @param taskId - Task identifier assigned by OSAL. + + output parameters + + @param None. + + @return None. +*/ +void LL_Init0( uint8 taskId ) +{ + #ifndef HOST + uint8* p; + #endif + LL_TaskID = taskId; + // set BLE version information + verInfo.verNum = LL_VERSION_NUM; + verInfo.comId = LL_COMPANY_ID; + verInfo.subverNum = LL_SUBVERSION_NUM; + // =========== calculate whiten seed + calculate_whiten_seed(); // must set!!! + #ifdef HOST + // hardcoded address + ownPublicAddr[0] = 0xF3; + ownPublicAddr[1] = 0xE4; + ownPublicAddr[2] = 0xa2; + ownPublicAddr[3] = 0x98; + ownPublicAddr[4] = 0x58; + ownPublicAddr[5] = 0xdf; + #else + // read flash driectly becasue HW has do the address mapping for read Flash operation + p = (uint8*)pGlobal_config[MAC_ADDRESS_LOC]; + ownPublicAddr[3] = *(p++); + ownPublicAddr[2] = *(p++); + ownPublicAddr[1] = *(p++); + ownPublicAddr[0] = *(p++); + ownPublicAddr[5] = *(p++); + ownPublicAddr[4] = *(p); +// ownPublicAddr[3] = ReadFlash(address ++); +// ownPublicAddr[2] = ReadFlash(address ++); +// ownPublicAddr[1] = ReadFlash(address ++); +// ownPublicAddr[0] = ReadFlash(address ++); +// +// ownPublicAddr[5] = ReadFlash(address ++); +// ownPublicAddr[4] = ReadFlash(address); + #endif + // set own random address as invalid until one is provided + ownRandomAddr[0] = 0xFF; + ownRandomAddr[1] = 0xFF; + ownRandomAddr[2] = 0xFF; + ownRandomAddr[3] = 0xFF; + ownRandomAddr[4] = 0xFF; + ownRandomAddr[5] = 0xFF; + adv_param.ownAddr[0] = 0xFF; + adv_param.ownAddr[1] = 0xFF; + adv_param.ownAddr[2] = 0xFF; + adv_param.ownAddr[3] = 0xFF; + adv_param.ownAddr[4] = 0xFF; + adv_param.ownAddr[5] = 0xFF; + adv_param.ownAddrType = LL_DEV_ADDR_TYPE_PUBLIC; + adv_param.advMode = LL_ADV_MODE_OFF; + adv_param.advInterval = LL_ADV_INTERVAL_DEFAULT; + adv_param.advEvtType = LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT; + adv_param.advChanMap = LL_ADV_CHAN_MAP_DEFAULT; // correct by HZF, 2-23 + adv_param.wlPolicy = LL_ADV_WL_POLICY_ANY_REQ; + adv_param.scaValue = LL_SCA_SLAVE_DEFAULT; + adv_param.advDataLen = 0; + adv_param.scanRspLen = 0; + + for (int i = 0; i < g_maxConnNum; i++) + { + conn_param[i].connId = i; + conn_param[i].active = FALSE; + conn_param[i].allocConn = FALSE; + memset((uint8_t*)&conn_param[i].pmCounter, 0, sizeof(llLinkStatistics_t) ); + } + + // set default Scan values + scanInfo.ownAddr[0] = 0xFF; + scanInfo.ownAddr[1] = 0xFF; + scanInfo.ownAddr[2] = 0xFF; + scanInfo.ownAddr[3] = 0xFF; + scanInfo.ownAddr[4] = 0xFF; + scanInfo.ownAddr[5] = 0xFF; + scanInfo.ownAddrType = LL_DEV_ADDR_TYPE_PUBLIC; + scanInfo.initPending = TRUE; + scanInfo.scanMode = LL_SCAN_STOP; + scanInfo.scanType = LL_SCAN_PASSIVE; + scanInfo.scanInterval = LL_SCAN_INTERVAL_DEFAULT; + scanInfo.scanWindow = LL_SCAN_INTERVAL_DEFAULT; + scanInfo.wlPolicy = LL_SCAN_WL_POLICY_ANY_ADV_PKTS; + scanInfo.filterReports = TRUE; + scanInfo.scanBackoffUL = 1; + scanInfo.nextScanChan = LL_SCAN_ADV_CHAN_37; + scanInfo.numSuccess = 0; + scanInfo.numFailure = 0; + // set default Init values + initInfo.ownAddr[0] = 0xFF; + initInfo.ownAddr[1] = 0xFF; + initInfo.ownAddr[2] = 0xFF; + initInfo.ownAddr[3] = 0xFF; + initInfo.ownAddr[4] = 0xFF; + initInfo.ownAddr[5] = 0xFF; + initInfo.ownAddrType = LL_DEV_ADDR_TYPE_PUBLIC; + initInfo.initPending = TRUE; + initInfo.scanMode = LL_SCAN_STOP; + initInfo.scanInterval = LL_SCAN_INTERVAL_DEFAULT; + initInfo.scanWindow = LL_SCAN_INTERVAL_DEFAULT; + initInfo.nextScanChan = LL_SCAN_ADV_CHAN_37; + initInfo.wlPolicy = LL_INIT_WL_POLICY_USE_PEER_ADDR; + initInfo.connId = 0; + initInfo.scaValue = LL_SCA_MASTER_DEFAULT; + // set default extended Init values + extInitInfo.ownAddr[0] = 0xFF; + extInitInfo.ownAddr[1] = 0xFF; + extInitInfo.ownAddr[2] = 0xFF; + extInitInfo.ownAddr[3] = 0xFF; + extInitInfo.ownAddr[4] = 0xFF; + extInitInfo.ownAddr[5] = 0xFF; + extInitInfo.ownAddrType = LL_DEV_ADDR_TYPE_PUBLIC; +// extInitInfo.initPending = TRUE; + extInitInfo.scanMode = LL_SCAN_STOP; + + for (int i = 0; i < LL_MAX_EXTENDED_SCAN_PHYS; i ++) // bug correct 2020-03-09 + { + extInitInfo.scanInterval[i] = LL_SCAN_INTERVAL_DEFAULT; + extInitInfo.scanWindow[i] = LL_SCAN_INTERVAL_DEFAULT; + } + + extInitInfo.wlPolicy = LL_INIT_WL_POLICY_USE_PEER_ADDR; + extInitInfo.connId = 0; + extInitInfo.scaValue = LL_SCA_MASTER_DEFAULT; + extInitInfo.current_chn = LL_SCAN_ADV_CHAN_37; + scanSyncInfo.valid = FALSE; + // reset the Link Layer + (void)LL_Reset(); + // generate true random number for AES-CCM + (void)LL_ENC_GenerateTrueRandNum( cachedTRNGdata, LL_ENC_TRUE_RAND_BUF_SIZE ); + numComplPkts = 0; + numComplPktsLimit = 1; + // add by HZF, init globals + fastTxRespTime = LL_EXT_DISABLE_FAST_TX_RESP_TIME; // what is fast TX feature??? + llState = LL_STATE_IDLE; + // add in A2 + llSecondaryState = LL_SEC_STATE_IDLE; + // initialize this devices Feature Set + // has been called in LL_Reset() , so comended by ZQ + //llInitFeatureSet(); + (void)osal_pwrmgr_task_state( LL_TaskID, PWRMGR_CONSERVE ); + // default sleep delay + sleepDelay = pGlobal_config[MIN_TIME_TO_STABLE_32KHZ_XOSC]; + // delay sleep to allow the 32kHz crystal to stablize + osal_set_event( LL_TaskID, LL_EVT_START_32KHZ_XOSC_DELAY ); +} + + +/******************************************************************************* + @fn LL_ProcessEvent0 + + @brief This is the Link Layer process event handler called by OSAL. + + input parameters + + @param taskId - Task identifier assigned by OSAL. + events - Event flags to be processed by this task. + + output parameters + + @param None. + + @return Unprocessed event flags. +*/ + +uint16 LL_ProcessEvent0( uint8 task_id, uint16 events ) +{ + if ( events & LL_EVT_NEXT_INTERVAL ) + { + ll_debug_output(DEBUG_LL_TIMER_EXPIRY_ENTRY); + LL_evt_schedule(); + ll_debug_output(DEBUG_LL_TIMER_EXPIRY_EXIT); + return (events ^ LL_EVT_NEXT_INTERVAL ); + } + + /* + ** Directed Advertising results in a Master Connection + */ + if ( events & LL_EVT_MASTER_CONN_CREATED ) + { + llConnState_t* connPtr; + connPtr = &conn_param[initInfo.connId]; + + // if own addr or peer addr using RPA, report enhance connection complete event + // otherwise report legacy connection complete event. + // note that it may not align to below words int the spec + // "If this event is unmasked and the HCI_LE_Connection_Complete event is + // unmasked, only the HCI_LE_Enhanced_Connection_Complete event is sent + // when a new connection has been created" + /*if (g_currentPeerAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC || + g_currentPeerAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM || + g_currentLocalAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC || + g_currentLocalAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM) + { + uint8* local, *peer; + uint8 nil_addr[] = {0, 0, 0, 0, 0, 0}; + + if (g_currentPeerAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC || + g_currentPeerAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM ) + peer = g_currentPeerRpa; + else + peer = nil_addr; + + if (g_currentLocalAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC || + g_currentLocalAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM ) + local = g_currentLocalRpa; + else + local = nil_addr; + + LL_EnhConnectionCompleteCback( LL_STATUS_SUCCESS, + (uint16)connPtr->connId, // connection handle + LL_LINK_CONNECT_COMPLETE_MASTER, // role + g_currentPeerAddrType, // peer's address type + peerInfo.peerAddr, // peer's address + local, + peer, + connPtr->curParam.connInterval >> 1, // connection interval, back to 1.25ms units + connPtr->curParam.slaveLatency, // slave latency + connPtr->curParam.connTimeout >> 4, // connection timeout, back to 10ms units + 0 ); // sleep clock accurracy not valid for master + } + else */ + { + LL_ConnectionCompleteCback( LL_STATUS_SUCCESS, // reasonCode + (uint16)connPtr->connId, // connection handle + LL_LINK_CONNECT_COMPLETE_MASTER, // role + peerInfo.peerAddrType, // peer's address type + peerInfo.peerAddr, // peer's address + connPtr->curParam.connInterval >> 1, // connection interval, back to 1.25ms units + connPtr->curParam.slaveLatency, // slave latency + connPtr->curParam.connTimeout >> 4, // connection timeout, back to 10ms units + 0 ); // sleep clock accurracy + } + + //if (connPtr->channel_selection == LL_CHN_SEL_ALGORITHM_2) + // LL_ChannelSelectionAlgorithmCback((uint16)connPtr->connId, LL_CHN_SEL_ALGORITHM_2); + + return (events ^ LL_EVT_MASTER_CONN_CREATED ); + } + + /* + ** Create Connection Cancel + */ + if ( events & LL_EVT_MASTER_CONN_CANCELLED ) + { + // notify Host + LL_ConnectionCompleteCback( LL_STATUS_ERROR_UNKNOWN_CONN_HANDLE, // reasonCode + (uint16)0, // connection handle + LL_LINK_CONNECT_COMPLETE_MASTER, // role + peerInfo.peerAddrType, // peer's address type + peerInfo.peerAddr, // peer's address + 0, // connection interval, back to 1.25ms units + 0, // slave latency + 0, // connection timeout, back to 10ms units + 0 ); // sleep clock accurracy not valid for master + return (events ^ LL_EVT_MASTER_CONN_CANCELLED ); + } + + /* + ** Directed Advertising failed to connect + */ + if ( events & LL_EVT_DIRECTED_ADV_FAILED ) + { + // notify Host + LL_ConnectionCompleteCback( LL_STATUS_ERROR_DIRECTED_ADV_TIMEOUT, // reasonCode + (uint16)0, // connection handle + LL_LINK_CONNECT_COMPLETE_SLAVE, // role + peerInfo.peerAddrType, // peer's address type + peerInfo.peerAddr, // peer's address + 0, // connection interval, back to 1.25ms units + 0, // slave latency + 0, // connection timeout, back to 10ms units + 0 ); // sleep clock accurracy + return (events ^ LL_EVT_DIRECTED_ADV_FAILED ); + } + + /* + ** Directed Advertising results in a Slave Connection + */ + if ( events & LL_EVT_SLAVE_CONN_CREATED ) + { + llConnState_t* connPtr; + connPtr = &conn_param[adv_param.connId]; + + // if own addr or peer addr using RPA, report enhance connection complete event + // otherwise report legacy connection complete event. + // note that it may not align to below words int the spec + // "If this event is unmasked and the HCI_LE_Connection_Complete event is + // unmasked, only the HCI_LE_Enhanced_Connection_Complete event is sent + // when a new connection has been created" + /*if (g_currentPeerAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC || + g_currentPeerAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM || + g_currentLocalAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC || + g_currentLocalAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM) + { + uint8* local, *peer; + uint8 nil_addr[] = {0, 0, 0, 0, 0, 0}; + + if (g_currentPeerAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC || + g_currentPeerAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM ) + peer = g_currentPeerRpa; + else + peer = nil_addr; + + if (g_currentLocalAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC || + g_currentLocalAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM ) + local = g_currentLocalRpa; + else + local = nil_addr; + + LL_EnhConnectionCompleteCback( LL_STATUS_SUCCESS, + (uint16)connPtr->connId, // connection handle + LL_LINK_CONNECT_COMPLETE_SLAVE, // role + g_currentPeerAddrType, // peer's address type + peerInfo.peerAddr, // peer's address + local, + peer, + connPtr->curParam.connInterval >> 1, // connection interval, back to 1.25ms units + connPtr->curParam.slaveLatency, // slave latency + connPtr->curParam.connTimeout >> 4, // connection timeout, back to 10ms units + connPtr->sleepClkAccuracy ); // sleep clock accurracy + } + else*/ + { + LL_ConnectionCompleteCback( LL_STATUS_SUCCESS, // reasonCode + (uint16)connPtr->connId, // connection handle + LL_LINK_CONNECT_COMPLETE_SLAVE, // role + peerInfo.peerAddrType, // peer's address type + peerInfo.peerAddr, // peer's address + connPtr->curParam.connInterval >> 1, // connection interval, back to 1.25ms units + connPtr->curParam.slaveLatency, // slave latency + connPtr->curParam.connTimeout >> 4, // connection timeout, back to 10ms units + connPtr->sleepClkAccuracy ); // sleep clock accurracy + } + + //if (connPtr->channel_selection == LL_CHN_SEL_ALGORITHM_2) + // LL_ChannelSelectionAlgorithmCback((uint16)connPtr->connId, LL_CHN_SEL_ALGORITHM_2); + + return (events ^ LL_EVT_SLAVE_CONN_CREATED ); + } + + /* + ** Advertising results in a Slave Connection with an Unacceptable + ** Connection Interval + */ + if ( events & LL_EVT_SLAVE_CONN_CREATED_BAD_PARAM ) + { + // notify Host + LL_ConnectionCompleteCback( LL_STATUS_ERROR_UNACCEPTABLE_CONN_INTERVAL, // reasonCode + (uint16)0, // connection handle + LL_LINK_CONNECT_COMPLETE_SLAVE, // role + peerInfo.peerAddrType, // peer's address type + peerInfo.peerAddr, // peer's address + 0, // connection interval, back to 1.25ms units + 0, // slave latency + 0, // connection timeout, back to 10ms units + 0 ); // sleep clock accurracy + return (events ^ LL_EVT_SLAVE_CONN_CREATED_BAD_PARAM ); + } + + /* + ** Ensure the 32kHz crystal is stable after POR/External Reset/PM3 + ** before allowing sleep. + ** Note: There is nothing in hardware to indicate this to software. + */ + if ( events & LL_EVT_START_32KHZ_XOSC_DELAY ) + { + // check if the delay hasn't been disabled + if ( sleepDelay ) + { + //osal_pwrmgr_device( PWRMGR_ALWAYS_ON ); + (void)osal_pwrmgr_task_state( LL_TaskID, PWRMGR_HOLD ); + osal_start_timerEx( LL_TaskID, LL_EVT_32KHZ_XOSC_DELAY, sleepDelay ); + } + + return (events ^ LL_EVT_START_32KHZ_XOSC_DELAY ); + } + + /* + ** The minimum stabilization delay for the 32kHz crystal has expired. + */ + if ( events & LL_EVT_32KHZ_XOSC_DELAY ) + { + // delay over, so allow sleep + //osal_pwrmgr_device( PWRMGR_BATTERY ); + (void)osal_pwrmgr_task_state( LL_TaskID, PWRMGR_CONSERVE ); + return (events ^ LL_EVT_32KHZ_XOSC_DELAY ); + } + + /* + ** Issue Hard System Reset + */ + if ( events & LL_EVT_RESET_SYSTEM_HARD ) + { + // Note: This will break communication with USB dongle. + // Note: No return here after reset. + //SystemReset(); + // Note: Unreachable statement generates compiler warning! + //return (events ^ LL_EVT_RESET_SYSTEM_HARD ); + } + + /* + ** Issue Soft System Reset + */ + if ( events & LL_EVT_RESET_SYSTEM_SOFT ) + { + // Note: This will not break communication with USB dongle. + // Note: No return here after reset. + //SystemResetSoft(); + return (events ^ LL_EVT_RESET_SYSTEM_SOFT ); + } + + //====== add in A2, for simultaneous connect & adv/scan + if (events & LL_EVT_SECONDARY_ADV) + { + #ifdef DEBUG_LL + LOG("--->\n"); + #endif + + if (llSecondaryState == LL_SEC_STATE_IDLE + || llSecondaryState == LL_SEC_STATE_IDLE_PENDING) // adv may be cancel during waiting period, do nothing in this case + ; + else + { + // advertise allow decision + if (llSecAdvAllow()) + { + llSetupSecAdvEvt(); +// if (llSetupSecAdvEvt()) +// llSecondaryState = LL_SEC_STATE_ADV; +// else +// llSecondaryState = LL_SEC_STATE_ADV_PENDING;; +//#ifdef DEBUG_LL +// LOG("setup secondary adv event\r\n"); +//#endif + } + else + { + llSecondaryState = LL_SEC_STATE_ADV_PENDING; + } + } + + return (events ^ LL_EVT_SECONDARY_ADV ); + } + + // ===== scan + if (events & LL_EVT_SECONDARY_SCAN) + { + if (llSecondaryState == LL_SEC_STATE_IDLE || scanInfo.scanMode == LL_SCAN_STOP) // scan may be cancel during waiting period, do nothing in this case + llSecondaryState = LL_SEC_STATE_IDLE; + else + { + llSetupSecScan(scanInfo.nextScanChan); + } + + return (events ^ LL_EVT_SECONDARY_SCAN ); + } + + // ======= add for A2 multi-conn, init + if (events & LL_EVT_SECONDARY_INIT) + { + if (llSecondaryState == LL_SEC_STATE_IDLE || initInfo.scanMode == LL_SCAN_STOP) // scan may be cancel during waiting period, do nothing in this case + llSecondaryState = LL_SEC_STATE_IDLE; + else + { + llSetupSecInit(initInfo.nextScanChan); + // TODO + } + + return (events ^ LL_EVT_SECONDARY_INIT ); + } + + // ======= RPA re-calculate + if (events & LL_EVT_RPA_TIMEOUT) + { + uint8 resolve_address[6]; + uint8* localIrk; + + // calculate RPA & update adv_param + if (peerInfo.peerAddrType == LL_DEV_ADDR_TYPE_PUBLIC || peerInfo.peerAddrType == LL_DEV_ADDR_TYPE_RANDOM) +// if (g_currentLocalAddrType == LL_DEV_ADDR_TYPE_PUBLIC || g_currentLocalAddrType == LL_DEV_ADDR_TYPE_RANDOM) + { + // search the resolving list to get local IRK + if ((adv_param.ownAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC || adv_param.ownAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM) + && (ll_readLocalIRK(&localIrk, peerInfo.peerAddr, peerInfo.peerAddrType) == TRUE)) + { + if (!ll_isIrkAllZero(localIrk) && + ll_CalcRandomAddr(localIrk, resolve_address) == SUCCESS) + { + LL_COPY_DEV_ADDR_LE( adv_param.ownAddr, resolve_address ); + SET_BITS(g_tx_adv_buf.txheader, LL_DEV_ADDR_TYPE_RANDOM, TX_ADD_SHIFT, TX_ADD_MASK); + osal_memcpy( &g_tx_adv_buf.data[0], adv_param.ownAddr, 6); + SET_BITS(tx_scanRsp_desc.txheader, LL_DEV_ADDR_TYPE_RANDOM, TX_ADD_SHIFT, TX_ADD_MASK); + osal_memcpy( &tx_scanRsp_desc.data[0], adv_param.ownAddr, 6); + osal_memcpy( &g_currentLocalRpa[0], resolve_address, 6); +// for (int i = 0; i < 6; i ++) +// LOG("%x ", resolve_address[i]); +// LOG("\n"); + } + } + + // update initA(targetA) for direct ADV + if (adv_param.advEvtType == LL_ADV_CONNECTABLE_LDC_DIRECTED_EVT || + adv_param.advEvtType == LL_ADV_CONNECTABLE_HDC_DIRECTED_EVT) + { + uint8* peerIrk; + + // search the resolving list to get local IRK + if (ll_readPeerIRK(&peerIrk, peerInfo.peerAddr, peerInfo.peerAddrType) == TRUE) + { + if (!ll_isIrkAllZero(peerIrk)) // for all-zero local IRK, not RPA used + { + if (ll_CalcRandomAddr(peerIrk, resolve_address) == SUCCESS) + { + osal_memcpy((uint8_t*) &(g_tx_adv_buf.data[6]), resolve_address, 6); + osal_memcpy( &g_currentPeerRpa[0], resolve_address, 6); + } + } + } + } + } + else // if generate RPA failed, do nothing. + { + } + + if (g_llRlDeviceNum > 0) + osal_start_timerEx( LL_TaskID, LL_EVT_RPA_TIMEOUT, g_llRlTimeout * 1000 ); + + return (events ^ LL_EVT_RPA_TIMEOUT ); + } + + return 0; +} + + +/******************************************************************************* + LL API for HCI +*/ + +/******************************************************************************* + @fn LL_TX_bm_alloc API + + @brief This API is used to allocate memory using buffer management. + + Note: This function should never be called by the application. + It is only used by HCI and L2CAP_bm_alloc. + + input parameters + + @param size - Number of bytes to allocate from the heap. + + output parameters + + @param None. + + @return Pointer to buffer, or NULL. +*/ +void* LL_TX_bm_alloc( uint16 size ) +{ + uint8* pBuf; + #if 0 + // Note: This is the lowest call for TX buffer management allocation. + + // provide padding for encryption + // Note: Potentially wastes up to 15 bytes per packet, but speeds up + // execution. + if ( size <= LL_ENC_BLOCK_LEN ) + { + size = LL_ENC_BLOCK_LEN; + } + else + { + size = 2*LL_ENC_BLOCK_LEN; + } + + #else + //size = (size+LL_ENC_BLOCK_LEN-1)&0xfff0;//align to 16Byte + #endif + size = (size+LL_ENC_BLOCK_LEN-1)&0xfff0;//align to 16Byte + pBuf = osal_bm_alloc( size + + sizeof(txData_t) + + LL_PKT_HDR_LEN + + LL_PKT_MIC_LEN ); + + if ( pBuf != NULL ) + { + // return pointer to user payload + return( pBuf + ((uint16)sizeof(txData_t)+LL_PKT_HDR_LEN) ); + } + + return( (void*)NULL ); +} + + +/******************************************************************************* + This API is used to allocate memory using buffer management. + + Public function defined in ll.h. +*/ +void* LL_RX_bm_alloc( uint16 size ) +{ + uint8* pBuf; + // Note: This is the lowest call for RX buffer management allocation. + pBuf = osal_bm_alloc( size + HCI_RX_PKT_HDR_SIZE ); + + if ( pBuf != NULL ) + { + // return pointer to user payload + return( pBuf + HCI_RX_PKT_HDR_SIZE ); + } + + return( (void*)NULL ); +} + +/******************************************************************************* + This function is used by the HCI to reset and initialize the LL Controller. + + Public function defined in ll.h. +*/ +llStatus_t LL_Reset0( void ) +{ + // enter critical section + HAL_ENTER_CRITICAL_SECTION(); + // clear the white list table + g_llWlDeviceNum = 0; + + for (int i = 0; i < LL_WHITELIST_ENTRY_NUM; i++) + g_llWhitelist[i].peerAddrType = 0xff; + + // clear resolving list + g_llRlDeviceNum = 0; + + for (int i = 0; i < LL_RESOLVINGLIST_ENTRY_NUM; i++) + { + g_llResolvinglist[i].peerAddrType = 0xff; + g_llResolvinglist[i].privacyMode = NETWORK_PRIVACY_MODE; + } + + g_llRlEnable = FALSE; + g_llRlTimeout = 900; + g_llPrdAdvDeviceNum = 0; + + for (int i = 0; i < LL_PRD_ADV_ENTRY_NUM; i++) + g_llPeriodicAdvlist[i].addrType = 0xff; + + // set the peer's device address type, as allowed for connections by Host + peerInfo.peerAddrType = LL_DEV_ADDR_TYPE_PUBLIC; + // clear the peer's address + peerInfo.peerAddr[0] = 0x00; + peerInfo.peerAddr[1] = 0x00; + peerInfo.peerAddr[2] = 0x00; + peerInfo.peerAddr[3] = 0x00; + peerInfo.peerAddr[4] = 0x00; + peerInfo.peerAddr[5] = 0x00; + // init the Adv parameters to their default values + adv_param.advMode = LL_ADV_MODE_OFF; + // clear the advertising interval + adv_param.advInterval = LL_ADV_INTERVAL_DEFAULT;// Ti set this parameter = 0; + // Note that only the first three bits are used, and note that despite the + // fact that the Host HCI call passes 5 bytes to specify which advertising + // channels are to be used, only the first three bits of the first byte are + // actually used. We'll save four bytes then, and default to all used. + adv_param.advChanMap = LL_ADV_CHAN_ALL; + // set a default type of advertising + adv_param.advEvtType = LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT; + // payload length, including AdvA + adv_param.advDataLen = 0; + #ifdef DEBUG + // clear memory + (void)osal_memset( advInfo.advData, 0, LL_MAX_ADV_DATA_LEN ); + // clear memory + (void)osal_memset( advInfo.scanRspData, 0, LL_MAX_SCAN_DATA_LEN ); + #endif // DEBUG + // default to no scan response data + adv_param.scanRspLen = 0; + // ===================== for scan/init parameters + // disable scanning + scanInfo.scanMode = LL_SCAN_STOP; + // disable init scanning + initInfo.scanMode = LL_SCAN_STOP; + // initialize this devices Feature Set + llInitFeatureSet(); + // initialize default channel map + chanMapUpdate.chanMap[0] = 0xFF; + chanMapUpdate.chanMap[1] = 0xFF; + chanMapUpdate.chanMap[2] = 0xFF; + chanMapUpdate.chanMap[3] = 0xFF; + chanMapUpdate.chanMap[4] = 0x1F; + // set state/role + llState = LL_STATE_IDLE; + ll_debug_output(DEBUG_LL_STATE_IDLE); + // add in A2 + llSecondaryState = LL_SEC_STATE_IDLE; + numComplPkts = 0; + numComplPktsLimit = 1; + fastTxRespTime = LL_EXT_DISABLE_FAST_TX_RESP_TIME; // TI default enable it, hzf + rxFifoFlowCtrl = LL_RX_FLOW_CONTROL_DISABLED; + #if 0 // TODO: normally LL should not invoke upper layer function. And gap also invoke these operation??? + //add by ZQ 20181030 for DLE feature + L2CAP_SegmentPkt_Reset(); + L2CAP_ReassemblePkt_Reset(); + osal_memset(&g_sarDbgCnt, 0, sizeof(g_sarDbgCnt)); + #endif + llPduLengthManagmentReset(); + llPhyModeCtrlReset(); + + for (int i = 0; i < g_maxConnNum; i ++) + { + conn_param[i].llPhyModeCtrl.def.txPhy = LE_1M_PHY | LE_2M_PHY; + conn_param[i].llPhyModeCtrl.def.rxPhy = LE_1M_PHY | LE_2M_PHY; + conn_param[i].llPhyModeCtrl.def.allPhy=0; + llResetConnId(i); + reset_conn_buf(i); + } + + // HZF: add for multi-connection + g_ll_conn_ctx.currentConn = LL_INVALID_CONNECTION_ID; + g_ll_conn_ctx.numLLConns = 0; + g_ll_conn_ctx.numLLMasterConns = 0; + // =========== extended adv/extended scan relate reset + g_llScanMode = LL_MODE_INVALID; + g_llAdvMode = LL_MODE_INVALID; + + // clear adv set (extended adv part) + for (int i = 0; i < g_extAdvNumber; i ++) + { + uint8* scanRspData = g_pExtendedAdvInfo[i].scanRspData; + uint8* advData = g_pExtendedAdvInfo[i].data.advertisingData; + memset(&g_pExtendedAdvInfo[i], 0, sizeof(extAdvInfo_t)); + g_pExtendedAdvInfo[i].scanRspData = scanRspData; + g_pExtendedAdvInfo[i].data.advertisingData = advData; + g_pExtendedAdvInfo[i].advHandle = LL_INVALID_ADV_SET_HANDLE; + } + + // clear adv set (periodic adv part) + for (int i = 0; i < g_perioAdvNumber; i ++) + { + uint8* advData = g_pPeriodicAdvInfo[i].data.advertisingData; + memset(&g_pPeriodicAdvInfo[i], 0, sizeof(periodicAdvInfo_t)); + g_pPeriodicAdvInfo[i].data.advertisingData = advData; + g_pPeriodicAdvInfo[i].advHandle = LL_INVALID_ADV_SET_HANDLE; + } + + // exit critical section + HAL_EXIT_CRITICAL_SECTION(); + // reset all statistics counters + osal_memset(&g_pmCounters, 0, sizeof(g_pmCounters)); + return( LL_STATUS_SUCCESS ); +} + + + +/******************************************************************************* + @fn LL_Disconnect0 API + + @brief This API is called by the HCI to terminate a LL connection. + + input parameters + + @param connId - The LL connection ID on which to send this data. + @param reason - The reason for the Host connection termination. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + LL_STATUS_ERROR_INACTIVE_CONNECTION + LL_STATUS_ERROR_CTRL_PROC_ALREADY_ACTIVE +*/ +llStatus_t LL_Disconnect0( uint16 connId, + uint8 reason ) +{ + llStatus_t status; + llConnState_t* connPtr; + + // check if the reason code is valid + if ( (reason != LL_DISCONNECT_AUTH_FAILURE) && + (reason != LL_DISCONNECT_REMOTE_USER_TERM) && + (reason != LL_DISCONNECT_REMOTE_DEV_LOW_RESOURCES) && + (reason != LL_DISCONNECT_REMOTE_DEV_POWER_OFF) && + (reason != LL_DISCONNECT_UNSUPPORTED_REMOTE_FEATURE) && + (reason != LL_DISCONNECT_KEY_PAIRING_NOT_SUPPORTED) && + (reason != LL_DISCONNECT_UNACCEPTABLE_CONN_INTERVAL) ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // make sure connection ID is valid + if ( (status = LL_ConnActive(connId)) != LL_STATUS_SUCCESS ) + { + return( status ); + } + + // get connection info + connPtr = &conn_param[connId]; + + // check if any control procedure is already pending + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // check if a terminate control procedure is already what's pending + if ( connPtr->ctrlPktInfo.ctrlPkts[0] == LL_CTRL_TERMINATE_IND ) + { + return( LL_STATUS_ERROR_CTRL_PROC_ALREADY_ACTIVE ); + } + else // spec now says a terminate can happen any time + { + // indicate the peer requested this termination + connPtr->termInfo.reason = reason; + // de-activate slave latency to expedite termination + connPtr->slaveLatency = 0; + // override any control procedure that may be in progress + llReplaceCtrlPkt( connPtr, LL_CTRL_TERMINATE_IND ); + } + } + else // no control procedure currently active, so set this one up + { + // indicate the peer requested this termination + connPtr->termInfo.reason = reason; + // de-activate slave latency to expedite termination + connPtr->slaveLatency = 0; + // queue control packet for processing + llEnqueueCtrlPkt( connPtr, LL_CTRL_TERMINATE_IND ); + } + + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + @fn LL_TxData0 API + + @brief This API is called by the HCI to transmit a buffer of data on a + given LL connection. If fragmentation is supported, the HCI must + also indicate whether this is the first Host packet, or a + continuation Host packet. When fragmentation is not supported, + then a start packet should always specified. If the device is in + a connection as a Master and the current connection ID is the + connection for this data, or is in a connection as a Slave, then + the data is written to the TX FIFO (even if the radio is + curerntly active). If this is a Slave connection, and Fast TX is + enabled and Slave Latency is being used, then the amount of time + to the next event is checked. If there's at least a connection + interval plus some overhead, then the next event is re-aligned + to the next event boundary. Otherwise, in all cases, the buffer + pointer will be retained for transmission, and the callback + event LL_TxDataCompleteCback will be generated to the HCI when + the buffer pointer is no longer needed by the LL. + + Note: If the return status is LL_STATUS_ERROR_OUT_OF_TX_MEM, + then the HCI must not release the buffer until it receives + the LL_TxDataCompleteCback callback, which indicates the + LL has copied the transmit buffer. + + Note: The HCI should not call this routine if a buffer is still + pending from a previous call. This is fatal! + + Note: If the connection should be terminated within the LL + before the Host knows, attempts by the HCI to send more + data (after receiving a LL_TxDataCompleteCback) will + fail (LL_STATUS_ERROR_INACTIVE_CONNECTION). + + input parameters + + @param connId - The LL connection ID on which to send this data. + @param *pBuf - A pointer to the data buffer to transmit. + @param pktLen - The number of bytes to transmit on this connection. + @param fragFlag - LL_DATA_FIRST_PKT_HOST_TO_CTRL: + Indicates buffer is the start of a + Host-to-Controller packet. + LL_DATA_CONTINUATION_PKT: + Indicates buffer is a continuation of a + Host-to-Controller packet. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + LL_STATUS_ERROR_INACTIVE_CONNECTION, + LL_STATUS_ERROR_OUT_OF_TX_MEM, + LL_STATUS_ERROR_UNEXPECTED_PARAMETER +*/ +llStatus_t LL_TxData0( uint16 connId, + uint8* pBuf, + uint8 pktLen, + uint8 fragFlag ) +{ + llConnState_t* connPtr; + txData_t* pTxData; + // get the connection info based on the connection ID + connPtr = &conn_param[connId]; + + // sanity check input parameters + if ( (pBuf == NULL) || (pktLen > connPtr->llPduLen.local.MaxTxOctets/*LL_MAX_LINK_DATA_LEN*/) || + ((fragFlag != LL_DATA_FIRST_PKT_HOST_TO_CTRL) && + (fragFlag != LL_DATA_CONTINUATION_PKT)) ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // make sure connection ID is valid + if ( !conn_param [connId].active ) + { + //return( status ); + return( LL_STATUS_ERROR_INACTIVE_CONNECTION ); + } + + // check if the number of available data buffers has been exceeded + if ( getTxBufferFree(connPtr) == 0) + { + return( LL_STATUS_ERROR_OUT_OF_TX_MEM ); + } + + // adjust pointer to start of packet (i.e. at the header) + pBuf -= LL_PKT_HDR_LEN; + // set the packet length field + // Note: The LLID and Length fields are swapped for the nR (for DMA). + pBuf[0] = pktLen; + // set LLID fragmentation flag in header + // Note: NESN=SN=MD=0 and is handled by RF. + pBuf[1] = (fragFlag==LL_DATA_FIRST_PKT_HOST_TO_CTRL) ? + LL_DATA_PDU_HDR_LLID_DATA_PKT_FIRST : // first pkt + LL_DATA_PDU_HDR_LLID_DATA_PKT_NEXT; // continuation pkt + // ALT: Place check if packet needs to be encrypted and encryption here, + // but be careful about control packets and getting them out of order! + // point to Tx data entry + pTxData = (txData_t*)(pBuf - sizeof(txData_t)); + // it does, so queue up this data + llEnqueueDataQ( &connPtr->txDataQ, pTxData ); + + // check that we are either the master or slave, and if so, that the current + // connection is connId + if ( !(((llState == LL_STATE_CONN_MASTER) || (llState == LL_STATE_CONN_SLAVE)))) + //(connId == g_ll_conn_ctx.currentConn)) ) + { + // either we are not the master or the slave, or the we are but the connId + // is not the current connection, so just return success as the data is + // queued on the connection + return( LL_STATUS_SUCCESS ); + } + + // copy any pending data to the TX FIFO + llProcessTxData( connPtr, LL_TX_DATA_CONTEXT_SEND_DATA ); + + // check if TX FIFO has anything in it + if (getTxBufferSize(connPtr) > 0 ) + { + // check if we are a master or slave (i.e. in a connection), and the current + // current connection is connId; check if fast TX is enabled; check if + // slave latency is in use + if ( (fastTxRespTime == LL_EXT_ENABLE_FAST_TX_RESP_TIME) && connPtr->slaveLatency ) + { + // ÎÒÃÇĿǰ²»Ö§³Öfast Tx resp timeÕâ¸öfeature£¬Èç¹ûÒªÖ§³ÖÒÔϵĴúÂëÐèÒªÐÞ¸Ä + #if 0 + HAL_ENTER_CRITICAL_SECTION(cs); + + // taskInfo_t *curTask = llGetCurrentTask(); + // uint32 curTime = llGetCurrentTime(); + + // check if there's enough time before the next event to readjust the + // event timing + // Note: If T2E1 > CT+1, then there is at least two ticks before T2E1. + // Note: TRUE means first parameter T2E1 is not <= second parameter CT, + // thus T2E1 > CT. + if ( llTimeCompare( conn_param [0].next_event_base_time, conn_param [0].next_event_fine_time ) == TRUE ) + { + // There is, and at this point, there could be events between now + // and the next connection event. In order to wake on the next + // event boundary, the number of elapsed events is found. + + // update current time, and adjust for one event plus some pad + // Note: If we are just before the next event, then there's no + // point to an event re-alignment. + // curTime += connPtr->curParam.connInterval + + // LL_FAST_TX_TICKS_TO_EVT_PAD; + + // check if there's enough time before the next event + // Note: If T2E1 > CT+CI+6, then there is at least six ticks + // before the N-1 event. + // Note: TRUE means first parameter T2E1 is not <= second + // parameter CT, thus T2E1 > CT. + if (llTimeCompare( conn_param [0].next_event_base_time, conn_param [0].next_event_fine_time )) + { + // yes, so it is necessary to re-align on an earlier event + // then the next event + uint16 numEventsPast; + uint32 time; + // get the time delta between current time (CT) and last T2E1 + // Note: The assumption here is that CT is always ahead of the + // lastT2e1 because T2E1 is always ahead of lastT2e1 and + // CT is at this point behind T2E1. If the call to this + // function happens during a radio event (assuming the + // MCU is not halted) or between the end of a radio + // event and the start of LL processing, then CT will + // still be greater than T2E1 (because T2E1 has not yet + // been updated). If the call is made after LL + // processing, then T2E1 will be updated to the next + // radio event (i.e. ahead of CT), and lastT2e1 will be + // the previous radio event (i.e. behind CT). So if CT + // is behind T2E1, then it is always ahead of lastT2e1. + // Note: The only time CT could be equal to lastT2e1 is + // if radio event ended in less than one software tick + // and this routine is called before the rollover. This + // should never happen given the current radio time and + // post-processing time, but even if it does, this code + // should still be fine as the delta would be zero. + time = calculateTimeDelta(conn_param[0].next_event_base_time, conn_param [0].next_event_fine_time ); + // determine the number of events past the last T2E1 + // Note: Only quotient in upper halfword needed. + // time = llDivide31By16To16( time, connPtr->curParam.connInterval ); + numEventsPast = time / (conn_param [0].curParam.connInterval * 625)+1; + // update next event counter + connPtr->currentEvent = connPtr->lastCurrentEvent; + connPtr->nextEvent = connPtr->currentEvent + numEventsPast; + // update time to next event based on last adjusted AP + // Note: No need to re-calculate the receive window; can + // re-use rxTimeout value previously set by Slave + // post-processing. + // curTask->t2e1.coarse = + // (curTask->lastT2e1.coarse + + // ((uint32)numEventsPast * + // (uint32)connPtr->curParam.connInterval)) & 0x00FFFFFF; + // adjust data channel + connPtr->nextChan = connPtr->currentChan; + llSetNextDataChan( connPtr ); + // enable RF event + // llScheduleTask( curTask ); + } // else amount of time to next event is less than CI+6 + } // else not enough time before next event to make realignment worthwhile + + HAL_EXIT_CRITICAL_SECTION(); + #endif + } // else delta correction active so queue packet + + // M/S, curConn==connID, fast Tx enabled, and SL in use + } // TX FIFO empty + + // indicate the packet is sent of buffered + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + @fn LL_SetAdvParam0 API + + @brief This API is called by the HCI to set the Advertiser's + parameters. + + input parameters + @param advIntervalMin - The minimum Adv interval. + @param advIntervalMax - The maximum Adv interval. + @param advEvtType - The type of advertisment event. + @param ownAddrType - The Adv's address type of public or random. + @param peerAddrType - BLE4.0: Only used for directed advertising. BLE4.2: Peer address type + @param *peerAddr - BLE4.0: Only used for directed advertising (NULL otherwise). BLE4.2: Peer address + @param advChanMap - A byte containing 1 bit per advertising + channel. A bit set to 1 means the channel is + used. The bit positions define the advertising + channels as follows: + Bit 0: 37, Bit 1: 38, Bit 2: 39. + @param advWlPolicy - The Adv white list filter policy. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + LL_STATUS_ERROR_NO_ADV_CHAN_FOUND +*/ +llStatus_t LL_SetAdvParam0( uint16 advIntervalMin, + uint16 advIntervalMax, + uint8 advEvtType, + uint8 ownAddrType, + uint8 peerAddrType, + uint8* peerAddr, + uint8 advChanMap, + uint8 advWlPolicy ) +{ + uint8 pduType; + uint8 resolve_address[6]; + uint8* localIrk, *peerIrk; + + if (g_llAdvMode == LL_MODE_EXTENDED ) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llAdvMode = LL_MODE_LEGACY; + + // sanity check of parameters + if ( ( (advEvtType != LL_ADV_CONNECTABLE_UNDIRECTED_EVT) && + (advEvtType != LL_ADV_CONNECTABLE_HDC_DIRECTED_EVT) && + (advEvtType != LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT) && + (advEvtType != LL_ADV_SCANNABLE_UNDIRECTED_EVT) && + (advEvtType != LL_ADV_CONNECTABLE_LDC_DIRECTED_EVT) ) || + ( ((advEvtType == LL_ADV_CONNECTABLE_HDC_DIRECTED_EVT) || + (advEvtType == LL_ADV_CONNECTABLE_LDC_DIRECTED_EVT)) && + ((peerAddr == NULL) || + ((peerAddrType != LL_DEV_ADDR_TYPE_PUBLIC) && + (peerAddrType != LL_DEV_ADDR_TYPE_RANDOM))) ) || + ( ((advEvtType == LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT) || + (advEvtType == LL_ADV_SCANNABLE_UNDIRECTED_EVT)) && + // the minimum interval for nonconnectable Adv is 100ms + ((advIntervalMin < LL_ADV_CONN_INTERVAL_MIN) || // should use LL_ADV_NONCONN_INTERVAL_MIN after update it to 20ms + (advIntervalMin > LL_ADV_NONCONN_INTERVAL_MAX) || + (advIntervalMax < LL_ADV_CONN_INTERVAL_MIN) || // should use LL_ADV_NONCONN_INTERVAL_MIN after update it to 20ms + (advIntervalMax > LL_ADV_NONCONN_INTERVAL_MAX)) ) || + ( (advEvtType == LL_ADV_CONNECTABLE_UNDIRECTED_EVT) && + // the minimum interval for connectable undirected Adv is 20ms + ((advIntervalMin < LL_ADV_CONN_INTERVAL_MIN) || + (advIntervalMin > LL_ADV_CONN_INTERVAL_MAX) || + (advIntervalMax < LL_ADV_CONN_INTERVAL_MIN) || + (advIntervalMax > LL_ADV_CONN_INTERVAL_MAX)) ) || + ( advIntervalMax < advIntervalMin ) || + ( (ownAddrType != LL_DEV_ADDR_TYPE_PUBLIC) && + (ownAddrType != LL_DEV_ADDR_TYPE_RANDOM) && + (ownAddrType != LL_DEV_ADDR_TYPE_RPA_PUBLIC) && // BLE 4.2 + (ownAddrType != LL_DEV_ADDR_TYPE_RPA_RANDOM)) || // BLE 4.2 + ( ((ownAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC) || + (ownAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM)) && + (peerAddr == NULL)) || + ( (advWlPolicy != LL_ADV_WL_POLICY_ANY_REQ) && + (advWlPolicy != LL_ADV_WL_POLICY_WL_SCAN_REQ) && + (advWlPolicy != LL_ADV_WL_POLICY_WL_CONNECT_REQ) && + (advWlPolicy != LL_ADV_WL_POLICY_WL_ALL_REQ) ) || + ( ((advChanMap & LL_ADV_CHAN_ALL) == 0) ) ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // check if advertising is active + if ( adv_param.advMode == LL_ADV_MODE_ON ) + { + // yes, so not allowed per the spec + return( LL_STATUS_ERROR_COMMAND_DISALLOWED ); + } + + adv_param.advEvtType = advEvtType; + adv_param.ownAddrType = ownAddrType; + // save off the advertiser channel map + adv_param.advChanMap = advChanMap & 0x07; + + // make sure there's at least one advertising channel that can be used + if ( !adv_param.advChanMap ) + { + // force all to be usable in case the error message is ignored + adv_param.advChanMap = LL_ADV_CHAN_ALL; + return( LL_STATUS_ERROR_NO_ADV_CHAN_FOUND ); + } + + // save the white list policy + adv_param.wlPolicy = advWlPolicy; + + // set the advertiser address based on the HCI's address type preference + if ( ownAddrType == LL_DEV_ADDR_TYPE_PUBLIC ) + { + // get our address and address type + g_currentLocalAddrType = LL_DEV_ADDR_TYPE_PUBLIC; + LL_COPY_DEV_ADDR_LE( adv_param.ownAddr, ownPublicAddr ); + } + else if ( ownAddrType == LL_DEV_ADDR_TYPE_RANDOM ) + { + // get our address and address type + g_currentLocalAddrType = LL_DEV_ADDR_TYPE_RANDOM; + LL_COPY_DEV_ADDR_LE( adv_param.ownAddr, ownRandomAddr ); + } + // BBB ROM code add + else if ( ownAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC || + ownAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM) + { + uint8 found = FALSE; + + // search the resolving list to get local IRK + if (ll_readLocalIRK(&localIrk, peerAddr, peerAddrType) == TRUE) + { + if (!ll_isIrkAllZero(localIrk)) // for all-zero local IRK, not RPA used + { + if (ll_CalcRandomAddr(localIrk, resolve_address) == SUCCESS) + { + LL_COPY_DEV_ADDR_LE( adv_param.ownAddr, resolve_address ); + osal_memcpy( &g_currentLocalRpa[0], resolve_address, 6); + found = TRUE; + g_currentLocalAddrType = LL_DEV_ADDR_TYPE_RANDOM; + } + } + } + + if (found == FALSE) + { + if (ownAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC) + { + LL_COPY_DEV_ADDR_LE( adv_param.ownAddr, ownPublicAddr ); + g_currentLocalAddrType = LL_DEV_ADDR_TYPE_PUBLIC; + } + else + { + LL_COPY_DEV_ADDR_LE( adv_param.ownAddr, ownRandomAddr ); + g_currentLocalAddrType = LL_DEV_ADDR_TYPE_RANDOM; + } + } + } + + // save peer address info, to consider whether we need it + if (peerAddr != NULL) + LL_COPY_DEV_ADDR_LE( peerInfo.peerAddr, peerAddr ); + + peerInfo.peerAddrType = peerAddrType; + + // a Connectable Directed Adv event requires Init address info + if ( advEvtType == LL_ADV_CONNECTABLE_HDC_DIRECTED_EVT ) + { + // get the Init's address and address type as well + LL_COPY_DEV_ADDR_LE( peerInfo.peerAddr, peerAddr ); + // the advertising interval and delay are not used + adv_param.advInterval = 2;//0; // set by HZF, 2 means 1.25ms, so 3 adv channel = 3.75ms, spec require < 3.75ms + } + else if ( advEvtType == LL_ADV_CONNECTABLE_LDC_DIRECTED_EVT ) + { + // get the Init's address and address type as well + LL_COPY_DEV_ADDR_LE( peerInfo.peerAddr, peerAddr ); + // calculate the advertising interface based on the max/min values + // ALT: COULD UPDATE WITH ALGO IF NEED BE. + adv_param.advInterval = advIntervalMin; + } + else // undirected, discoverable, or non-connectable + { + // calculate the advertising interface based on the max/min values + // ALT: COULD UPDATE WITH ALGO IF NEED BE. + adv_param.advInterval = advIntervalMin; + } + + // mapping from adv event type to packet header + switch (adv_param.advEvtType) + { + case LL_ADV_CONNECTABLE_UNDIRECTED_EVT: + pduType = ADV_IND; + break; + + case LL_ADV_CONNECTABLE_HDC_DIRECTED_EVT: + case LL_ADV_CONNECTABLE_LDC_DIRECTED_EVT: + pduType = ADV_DIRECT_IND; + break; + + case LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT: + pduType = ADV_NONCONN_IND; + break; + + case LL_ADV_SCANNABLE_UNDIRECTED_EVT: + pduType = ADV_SCAN_IND; + break; + + default: + // should not come here, sanity check in the function start. set default value to suppress warning + pduType = ADV_IND; + break; + } + + SET_BITS(g_tx_adv_buf.txheader, pduType, PDU_TYPE_SHIFT, PDU_TYPE_MASK); + SET_BITS(g_tx_adv_buf.txheader, g_currentLocalAddrType, TX_ADD_SHIFT, TX_ADD_MASK); + +// SET_BITS(g_tx_adv_buf.txheader, peerInfo.peerAddrType, RX_ADD_SHIFT, RX_ADD_MASK); // RxAdd need't set + if ((advEvtType == LL_ADV_CONNECTABLE_UNDIRECTED_EVT + || advEvtType == LL_ADV_CONNECTABLE_HDC_DIRECTED_EVT + || advEvtType == LL_ADV_CONNECTABLE_LDC_DIRECTED_EVT) + && pGlobal_config[LL_SWITCH] & CONN_CSA2_ALLOW) + SET_BITS(g_tx_adv_buf.txheader, 1, CHSEL_SHIFT, CHSEL_MASK); + + osal_memcpy( g_tx_adv_buf.data, adv_param.ownAddr, 6); + SET_BITS(tx_scanRsp_desc.txheader, ADV_SCAN_RSP, PDU_TYPE_SHIFT, PDU_TYPE_MASK); + SET_BITS(tx_scanRsp_desc.txheader, g_currentLocalAddrType, TX_ADD_SHIFT, TX_ADD_MASK); + osal_memcpy( tx_scanRsp_desc.data, adv_param.ownAddr, 6); + // adv length should be set for not direct adv type, 2018-04-05 + SET_BITS(g_tx_adv_buf.txheader, (adv_param.advDataLen + 6), LENGTH_SHIFT, LENGTH_MASK); + + // for direct adv, copy the peer address to PDU + if(pduType == ADV_DIRECT_IND ) + { + uint8 useRpa = FALSE; + SET_BITS(g_tx_adv_buf.txheader, 12, LENGTH_SHIFT, LENGTH_MASK); +// SET_BITS(tx_scanRsp_desc.txheader, peerInfo.peerAddrType, RX_ADD_SHIFT, RX_ADD_MASK); + + // search the resolving list to get local IRK + if (ll_readPeerIRK(&peerIrk, peerAddr, peerAddrType) == TRUE) + { + if (!ll_isIrkAllZero(peerIrk)) // for all-zero local IRK, not RPA used + { + if (ll_CalcRandomAddr(peerIrk, resolve_address) == SUCCESS) + { + useRpa = TRUE; + osal_memcpy((uint8_t*) &(g_tx_adv_buf.data[6]), resolve_address, 6); +// osal_memcpy( &g_currentPeerRpa[0], resolve_address, 6); + } + } + } + + if (useRpa == FALSE) + osal_memcpy((uint8_t*) &(g_tx_adv_buf.data[6]), peerInfo.peerAddr, 6); + } + + // ======================== add by HZF, init ll state so that adv PDU could be changed + if (llState != LL_STATE_CONN_MASTER && llState != LL_STATE_CONN_SLAVE) + { + switch(adv_param .advEvtType) + { + case LL_ADV_CONNECTABLE_UNDIRECTED_EVT: + llState=LL_STATE_ADV_UNDIRECTED; + ll_debug_output(DEBUG_LL_STATE_ADV_UNDIRECTED); + break; + + case LL_ADV_CONNECTABLE_HDC_DIRECTED_EVT: + case LL_ADV_CONNECTABLE_LDC_DIRECTED_EVT: + llState=LL_STATE_ADV_DIRECTED; + ll_debug_output(DEBUG_LL_STATE_ADV_DIRECTED); + break; + + case LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT: + llState=LL_STATE_ADV_NONCONN; + ll_debug_output(DEBUG_LL_STATE_ADV_NONCONN); + break; + + case LL_ADV_SCANNABLE_UNDIRECTED_EVT: + llState=LL_STATE_ADV_SCAN; + ll_debug_output(DEBUG_LL_STATE_ADV_SCAN); + break; + + default: + llState=LL_STATE_IDLE; + ll_debug_output(DEBUG_LL_STATE_IDLE); + break; + } + } + + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + @fn LL_SetAdvData0 API + + @brief This API is called by the HCI to set the Advertiser's data. + + Note: If the Advertiser is restarted without intervening calls + to this routine to make updates, then the previously + defined data will be reused. + + Note: If the data happens to be changed while advertising, then + the new data will be sent on the next advertising event. + + input parameters + + @param advDataLen - The number of scan response bytes: 0..31. + @param advData - Pointer to the advertiser data, or NULL. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER +*/ +llStatus_t LL_SetAdvData0( uint8 advDataLen, + uint8* advData ) +{ + if (g_llAdvMode == LL_MODE_EXTENDED ) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llAdvMode = LL_MODE_LEGACY; + + // check that data length isn't greater than the max allowed size + if ( advDataLen > LL_MAX_ADV_DATA_LEN ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // save advertiser data length + adv_param.advDataLen = advDataLen; + + // check if there's supposed to be data + if ( advDataLen > 0 ) + { + // yes, so make sure we have a valid pointer + if ( advData == NULL ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + else // okay to go + { + // save advertiser data + //osal_memcpy( (uint8_t *)adv_param.advData, advData, adv_param.advDataLen ); // save adv data + osal_memcpy( (uint8_t*) &(g_tx_adv_buf.data[6]), advData, adv_param.advDataLen ); // write adv to tx buffer, change it ?? ... HZF + } + } + +// set tx buffer, to be changed +// SET_BITS(g_tx_adv_buf.txheader, peerInfo .peerAddrType, RX_ADD_SHIFT, RX_ADD_MASK); + // osal_memcpy(g_tx_adv_buf.data, adv_param.ownAddr, 6); + SET_BITS(g_tx_adv_buf.txheader, (adv_param.advDataLen+6), LENGTH_SHIFT, LENGTH_MASK); + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + This API is called by the HCI to request the Controller to start or stop + advertising. + + Public function defined in ll.h. +*/ +llStatus_t LL_SetAdvControl0( uint8 advMode ) +{ + if (g_llAdvMode == LL_MODE_EXTENDED ) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llAdvMode = LL_MODE_LEGACY; + + // check if a direct test mode or modem test is in progress + if ( (llState == LL_STATE_DIRECT_TEST_MODE_TX) || + (llState == LL_STATE_DIRECT_TEST_MODE_RX) || + (llState == LL_STATE_MODEM_TEST_TX) || + (llState == LL_STATE_MODEM_TEST_RX) || + (llState == LL_STATE_MODEM_TEST_TX_FREQ_HOPPING) ) + { + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + } + + // sanity checks again to be sure we don't start with bad parameters + if ( ( (adv_param.advEvtType != LL_ADV_CONNECTABLE_UNDIRECTED_EVT) && + (adv_param.advEvtType != LL_ADV_CONNECTABLE_HDC_DIRECTED_EVT) && + (adv_param.advEvtType != LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT) && + (adv_param.advEvtType != LL_ADV_SCANNABLE_UNDIRECTED_EVT) && + (adv_param.advEvtType != LL_ADV_CONNECTABLE_LDC_DIRECTED_EVT) ) || + ( (adv_param.ownAddrType != LL_DEV_ADDR_TYPE_PUBLIC) && + (adv_param.ownAddrType != LL_DEV_ADDR_TYPE_RANDOM) && + (adv_param.ownAddrType != LL_DEV_ADDR_TYPE_RPA_PUBLIC) && + (adv_param.ownAddrType != LL_DEV_ADDR_TYPE_RPA_RANDOM)) || + ( ((adv_param.advEvtType == LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT) || + (adv_param.advEvtType == LL_ADV_SCANNABLE_UNDIRECTED_EVT)) && + (adv_param.advInterval < LL_ADV_CONN_INTERVAL_MIN) ) ) // should use LL_ADV_NONCONN_INTERVAL_MIN after update it to 20ms + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + #ifdef DEBUG_LL + LOG("llState = %d\n", llState); + #endif + + // check if we should begin advertising + switch( advMode ) + { + // Advertisment Mode is On + case LL_ADV_MODE_ON: + + // check if command makes sense + if ( adv_param.advMode == LL_ADV_MODE_ON ) + { + // this is unexpected; something is wrong + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + } + + // llState changed when configure adv parameters + if (llState == LL_STATE_ADV_UNDIRECTED + || llState == LL_STATE_ADV_DIRECTED + || llState == LL_STATE_ADV_NONCONN + || llState == LL_STATE_ADV_SCAN ) // TODO: check this setting + { + g_llHdcDirAdvTime = 0; // for HDC direct adv + adv_param.advNextChan = LL_ADV_CHAN_LAST + 1; // set adv channel invalid + + if ( llSetupAdv() != LL_STATUS_SUCCESS ) + { + // indicate advertising is no longer active + adv_param.advMode = LL_ADV_MODE_OFF; + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + } + } + // add in A2, simultaneous conn event & scan/adv event + else if((llState == LL_STATE_CONN_SLAVE + || llState == LL_STATE_CONN_MASTER) + && (pGlobal_config[LL_SWITCH] & SIMUL_CONN_ADV_ALLOW)) + { + #ifdef DEBUG_LL + LOG("LL_SetAdvControl: start sec adv\r\n"); + #endif + + if (llSecondaryState != LL_SEC_STATE_IDLE) + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + + // adv event check + if (adv_param.advEvtType != LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT + && adv_param.advEvtType != LL_ADV_SCANNABLE_UNDIRECTED_EVT + && adv_param.advEvtType != LL_ADV_CONNECTABLE_UNDIRECTED_EVT) + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + + // Note: we may need maximum slave number check here. If number of slave reach ceil, + // only no-connectable adv is allowed. The checking could be don't in host + llSecondaryState = LL_SEC_STATE_ADV; + adv_param.advNextChan = LL_ADV_CHAN_LAST + 1; // set adv channel invalid + osal_stop_timerEx( LL_TaskID, LL_EVT_SECONDARY_ADV ); + osal_set_event(LL_TaskID, LL_EVT_SECONDARY_ADV); // set adv event + } + else // other state + return (LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE); + + // indicate advertising is no longer active + adv_param.advMode = LL_ADV_MODE_ON; + + if (g_llRlDeviceNum > 0) + osal_start_timerEx( LL_TaskID, LL_EVT_RPA_TIMEOUT, g_llRlTimeout * 1000 ); + + break; + + case LL_ADV_MODE_OFF: + // check if command makes sense +// if ( adv_param.advMode == LL_ADV_MODE_OFF ) +// { +// // this is unexpected; something is wrong +// return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); +// } + HAL_ENTER_CRITICAL_SECTION(); + // free the associated task block + //llFreeTask( &advInfo.llTask ); + // indicate we are no longer actively advertising + adv_param.advMode = LL_ADV_MODE_OFF; + + if (llState != LL_STATE_CONN_SLAVE && + llState != LL_STATE_CONN_MASTER) // no conn + adv case + { + llState = LL_STATE_IDLE; // if not in connect state, set idle to disable advertise + //ZQ 20190912 + //stop ll timer when idle, considering the scan-adv interleve case + clear_timer(AP_TIM1); + ll_debug_output(DEBUG_LL_STATE_IDLE); + } + else // conn + adv case + { + uint8 i; + i = 0; + + while (!(adv_param.advChanMap & (1 << i))) i ++; // get the 1st adv channel in the adv channel map + + if ((llSecondaryState == LL_SEC_STATE_ADV) + && (adv_param.advNextChan != (LL_ADV_CHAN_FIRST + i))) // last adv event is not finished + llSecondaryState = LL_SEC_STATE_IDLE_PENDING; + else + { + llSecondaryState = LL_SEC_STATE_IDLE; + osal_stop_timerEx( LL_TaskID, LL_EVT_SECONDARY_ADV ); // stop timer + } + } + + HAL_EXIT_CRITICAL_SECTION(); + osal_stop_timerEx(LL_TaskID, LL_EVT_RPA_TIMEOUT); + break; + + default: + // we have an invalid value for advertisement mode + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + This API is called by the LL or HCI to check if a connection given by the + connection handle is active. + + Public function defined in ll.h. +*/ +llStatus_t LL_ConnActive( uint16 connId ) +{ + // check if the connection handle is valid + if (connId >= g_maxConnNum ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // check if the connection is active + if ( conn_param[connId].active == FALSE ) + { + return( LL_STATUS_ERROR_INACTIVE_CONNECTION ); + } + + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + This API is called by the HCI to read the peer controller's Version + Information. If the peer's Version Information has already been received by + its request for our Version Information, then this data is already cached and + can be directly returned to the Host. If the peer's Version Information is + not already cached, then it will be requested from the peer, and when + received, returned to the Host via the LL_ReadRemoteVersionInfoCback + callback. + + Note: Only one Version Indication is allowed for a connection. + + Public function defined in ll.h. +*/ +llStatus_t LL_ReadRemoteVersionInfo( uint16 connId ) +{ + llStatus_t status; + llConnState_t* connPtr; + + // make sure connection ID is valid + if ( (status=LL_ConnActive(connId)) != LL_STATUS_SUCCESS ) + { + return( status ); + } + + // get connection info + connPtr = &conn_param[connId]; + + // first, make sure the connection is still active + if ( !connPtr->active ) + { + return( LL_STATUS_ERROR_INACTIVE_CONNECTION ); + } + + // check if the peer's version information has already been obtained + if ( connPtr->verExchange.peerInfoValid == TRUE ) + { + // yes it has, so provide it to the host + LL_ReadRemoteVersionInfoCback( LL_STATUS_SUCCESS, + connId, + connPtr->verInfo.verNum, + connPtr->verInfo.comId, + connPtr->verInfo.subverNum ); + } + else // no it hasn't, so... + { + // ...check if the host has already requested this information + if ( connPtr->verExchange.hostRequest == FALSE ) + { + // no, so request it by queueing the control packet for processing + llEnqueueCtrlPkt( connPtr, LL_CTRL_VERSION_IND ); + // set the flag to indicate the host has requested this information + connPtr->verExchange.hostRequest = TRUE; + } + else // previously requested + { + return( LL_STATUS_ERROR_VER_INFO_REQ_ALREADY_PENDING ); + } + } + + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + @fn LL_ClearWhiteList0 API + + @brief This API is called by the HCI to clear the White List. + + Note: If Scanning is enabled using filtering, and the white + list policy is "Any", then this command will be + disallowed. + + input parameters + + @param None. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS +*/ +llStatus_t LL_ClearWhiteList0( void ) +{ + llStatus_t status; + int i, j; + + // check that it is okay to use the white list + if ( (status = llCheckWhiteListUsage()) != LL_STATUS_SUCCESS ) + { + return( status ); + } + + // clear number of entries, valid flags, address type flags, and entries + for (i = 0; i < LL_WHITELIST_ENTRY_NUM; i ++) + { + g_llWhitelist[i].peerAddrType = 0xff; + + for (j = 0; j < LL_DEVICE_ADDR_LEN; j ++) + g_llWhitelist[i].peerAddr[j] = 0; + } + + // set white list number 0 + g_llWlDeviceNum = 0; + return( LL_STATUS_SUCCESS ); +} + + +/******************************************************************************* + @fn LL_AddWhiteListDevice0 API + + @brief This API is called by the HCI to add a device address and its + type to the White List. + + input parameters + + @param devAddr - Pointer to a 6 byte device address. + @param addrType - Public or Random device address. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + LL_STATUS_ERROR_WL_TABLE_FULL +*/ +llStatus_t LL_AddWhiteListDevice0( uint8* devAddr, + uint8 addrType ) +{ + llStatus_t status; + int i, j; + + // check that it is okay to use the white list + if ( (status = llCheckWhiteListUsage()) != LL_STATUS_SUCCESS ) + { + return( status ); + } + + // check the WL device address type + if ( (addrType != LL_DEV_ADDR_TYPE_PUBLIC) && + (addrType != LL_DEV_ADDR_TYPE_RANDOM) ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // check if there was room for the entry + if (g_llWlDeviceNum >= LL_WHITELIST_ENTRY_NUM) + return( LL_STATUS_ERROR_WL_TABLE_FULL ); + + // add the device to a empty record + for (i = 0; i < LL_WHITELIST_ENTRY_NUM; i++) + { + if (g_llWhitelist[i].peerAddrType == 0xff) // empty record + { + g_llWhitelist[i].peerAddrType = addrType; + + for (j = 0; j < LL_DEVICE_ADDR_LEN; j++) + g_llWhitelist[i].peerAddr[j] = devAddr[j]; + + g_llWlDeviceNum ++; + break; + } + } + + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + @fn LL_RemoveWhiteListDevice0 API + + @brief This API is called by the HCI to remove a device address and + it's type from the White List. + + input parameters + + @param devAddr - Pointer to a 6 byte device address. + @param addrType - Public or Random device address. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + LL_STATUS_ERROR_WL_TABLE_EMPTY, + LL_STATUS_ERROR_WL_ENTRY_NOT_FOUND +*/ +llStatus_t LL_RemoveWhiteListDevice0( uint8* devAddr, + uint8 addrType ) +{ + llStatus_t status; + int i, j; + + // check that it is okay to use the white list + if ( (status = llCheckWhiteListUsage()) != LL_STATUS_SUCCESS ) + { + return( status ); + } + + // check the WL device address type + if ( (addrType != LL_DEV_ADDR_TYPE_PUBLIC) && + (addrType != LL_DEV_ADDR_TYPE_RANDOM) ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // check that there was at least one entry in the table + if ( g_llWlDeviceNum == 0 ) + { + return( LL_STATUS_ERROR_WL_TABLE_EMPTY ); + } + + for (i = 0; i < LL_WHITELIST_ENTRY_NUM; i++) + { + if (g_llWhitelist[i].peerAddrType == addrType) + { + for (j = 0; j < LL_DEVICE_ADDR_LEN; j++) // check whether the address is the same + { + if (g_llWhitelist[i].peerAddr[j] != devAddr[j]) + break; + } + + if (j == LL_DEVICE_ADDR_LEN) // found it + { + g_llWhitelist[i].peerAddrType = 0xff; + g_llWlDeviceNum --; + break; + } + } + } + + if (i == LL_WHITELIST_ENTRY_NUM) + return( LL_STATUS_ERROR_WL_ENTRY_NOT_FOUND ); + + return( LL_STATUS_SUCCESS ); +} + + +/******************************************************************************* + This API is called by the HCI to update the Host data channels initiating an + Update Data Channel control procedure. + + Note: While it isn't specified, it is assumed that the Host + expects an update channel map on all active connections. + + Note: This LL currently only supports one connection. + + Public function defined in ll.h. +*/ +llStatus_t LL_ChanMapUpdate( uint8* chanMap ) +{ + uint8 i; + + // make sure we're in Master role + if ( llState != LL_STATE_CONN_MASTER ) + { + return( LL_STATUS_ERROR_COMMAND_DISALLOWED ); + } + + // parameter check + if ( chanMap == NULL ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // ensure non-data channels 37..39 are not set and that the Core spec V4.0 + // requirement of a minimum of two data channels be used is met + if ( (chanMap[LL_NUM_BYTES_FOR_CHAN_MAP-1] & ~0x1F) || + (llAtLeastTwoChans( chanMap ) != TRUE) ) + { + return( LL_STATUS_ERROR_ILLEGAL_PARAM_COMBINATION ); + } + + // first need to check if any previous channel map update is still pending + for (i = 0; i < g_maxConnNum; i++) + { + if (conn_param [i].active ) + { + llConnState_t* connPtr = &conn_param[i]; + + // check if an update channel map control procedure is already pending + if ( ((connPtr->ctrlPktInfo.ctrlPktCount > 0) && + (connPtr->ctrlPktInfo.ctrlPkts[0] == LL_CTRL_CHANNEL_MAP_REQ)) || + (connPtr->pendingChanUpdate == TRUE) ) + { + return( LL_STATUS_ERROR_CTRL_PROC_ALREADY_ACTIVE ); + } + } + } + + // save the Host's channel map + for (i = 0; i < LL_NUM_BYTES_FOR_CHAN_MAP; i++) + { + chanMapUpdate.chanMap[i] = chanMap[i]; + } + + // need to issue an update on all active connections, if any + for (i = 0; i < g_maxConnNum; i++) + { + if (conn_param [i].active ) + { + llConnState_t* connPtr = &conn_param[i]; + // set the relative offset of the number of events for the channel update + // Note: The absolute event number will be determined at the time the + // packet is placed in the TX FIFO. + // Note: The master should allow a minimum of 6 connection events that the + // slave will be listening for before the instant occurs. + connPtr->chanMapUpdateEvent = (connPtr->curParam.slaveLatency+1) + + LL_INSTANT_NUMBER_MIN; + // queue control packet for processing + llEnqueueCtrlPkt( connPtr, LL_CTRL_CHANNEL_MAP_REQ ); + } + } + + return( LL_STATUS_SUCCESS ); +} + +llStatus_t LL_PhyUpdate0( uint16 connId ) +{ + llStatus_t status; + llConnState_t* connPtr; + uint8 phyMode; + + // make sure connection ID is valid + if ( (status=LL_ConnActive(connId)) != LL_STATUS_SUCCESS ) + { + return( status ); + } + + // get connection info + connPtr = &conn_param[connId ]; + + // check if an update control procedure is already pending + if ( ((connPtr->ctrlPktInfo.ctrlPktCount > 0) && + (connPtr->ctrlPktInfo.ctrlPkts[0] == LL_CTRL_PHY_UPDATE_IND)) || + (connPtr->pendingPhyModeUpdate == TRUE) ) + { + return( LL_STATUS_ERROR_CTRL_PROC_ALREADY_ACTIVE ); + } + + // we only support symmetric connection + // tx rx phy should be same + if(connPtr->llPhyModeCtrl.req.allPhy==0) + { + phyMode = connPtr->llPhyModeCtrl.req.txPhy & connPtr->llPhyModeCtrl.rsp.txPhy; + phyMode|= connPtr->llPhyModeCtrl.req.rxPhy & connPtr->llPhyModeCtrl.rsp.rxPhy; + } + else if(connPtr->llPhyModeCtrl.req.allPhy==1) + { + phyMode = connPtr->llPhyModeCtrl.req.rxPhy & connPtr->llPhyModeCtrl.rsp.rxPhy; + } + else if(connPtr->llPhyModeCtrl.req.allPhy==2) + { + phyMode = connPtr->llPhyModeCtrl.req.txPhy & connPtr->llPhyModeCtrl.rsp.txPhy; + } + else + { + phyMode=0; + } + + if(phyMode==0) + { + //no change case + connPtr->phyUpdateInfo.m2sPhy = 0; + connPtr->phyUpdateInfo.s2mPhy = 0; + } + else if(phyMode&LE_2M_PHY) + { + connPtr->phyUpdateInfo.m2sPhy = LE_2M_PHY; + connPtr->phyUpdateInfo.s2mPhy = LE_2M_PHY; + } + else if(phyMode&LE_CODED_PHY) + { + connPtr->phyUpdateInfo.m2sPhy = LE_CODED_PHY; + connPtr->phyUpdateInfo.s2mPhy = LE_CODED_PHY; + } + else + { + //no perferce can not support the tx/rx same time + connPtr->phyUpdateInfo.m2sPhy = LE_1M_PHY; + connPtr->phyUpdateInfo.s2mPhy = LE_1M_PHY; + } + + if(phyMode==0) + { + connPtr->phyModeUpdateEvent = 0; + connPtr->phyUpdateInfo.instant = connPtr->phyModeUpdateEvent; + } + else + { + connPtr->phyModeUpdateEvent = (connPtr->curParam.slaveLatency+1) + + LL_INSTANT_NUMBER_MIN; + connPtr->phyUpdateInfo.instant = connPtr->phyModeUpdateEvent; + } + + // queue control packet for processing + llEnqueueCtrlPkt( connPtr, LL_CTRL_PHY_UPDATE_IND ); + return( LL_STATUS_SUCCESS ); +} + + +/******************************************************************************* + @fn LL_ReadRemoteUsedFeatures API + + @brief This API is called by the Master HCI to initiate a feature + setup control process. + + input parameters + + @param connId - The LL connection ID on which to send this data. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS +*/ +llStatus_t LL_ReadRemoteUsedFeatures0( uint16 connId ) +{ + llStatus_t status; + llConnState_t* connPtr; + +// // make sure we're in Master role // in BLE4.2, it could be send in both master & slave +// if ( llState != LL_STATE_CONN_MASTER ) +// { +// return( LL_STATUS_ERROR_COMMAND_DISALLOWED ); +// } + + // make sure connection ID is valid + if ( (status=LL_ConnActive(connId)) != LL_STATUS_SUCCESS ) + { + return( status ); + } + + // get connection info + connPtr = &conn_param[connId ]; + // initiate a Feature Set control procedure + llEnqueueCtrlPkt( connPtr, LL_CTRL_FEATURE_REQ ); + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + @fn LL_ReadWlSize0 API + + @brief This API is called by the HCI to get the total number of white + list entries that can be stored in the Controller. + + input parameters + + @param None. + + output parameters + + @param *numEntries - Total number of available White List entries. + + @return LL_STATUS_SUCCESS +*/ +llStatus_t LL_ReadWlSize0( uint8* numEntries ) +{ + *numEntries = LL_WHITELIST_ENTRY_NUM; + return (LL_STATUS_SUCCESS); +} + + +/******************************************************************************* + @fn LL_NumEmptyWlEntries API + + @brief This API is called by the HCI to get the number of White List + entries that are empty. + + input parameters + + @param None. + + output parameters + + @param *numEmptyEntries - number of empty entries in the White List. + + @return LL_STATUS_SUCCESS +*/ +//extern llStatus_t LL_NumEmptyWlEntries( uint8 *numEmptyEntries ); // Not used by TI code + + +/******************************************************************************* + @fn LL_Encrypt API + + @brief This API is called by the HCI to request the LL to encrypt the + data in the command using the key given in the command. + + Note: The parameters are byte ordered MSO to LSO. + + input parameters + + @param *key - A 128 bit key to be used to calculate the + session key. + @param *plaintextData - A 128 bit block that is to be encrypted. + + output parameters + + @param *encryptedData - A 128 bit block that is encrypted. + + @param None. + + @return LL_STATUS_SUCCESS +*/ +llStatus_t LL_Encrypt0( uint8* key, + uint8* plaintextData, + uint8* encryptedData ) +{ + // check parameters + if ( (key == NULL ) || + (plaintextData == NULL) || + (encryptedData == NULL) ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // encrypt on behalf of the host + LL_ENC_AES128_Encrypt( key, plaintextData, encryptedData ); + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + This API is called by the HCI to request the LL Controller to provide a data + block with random content. + + Note: we use different scheme to TI. Below is from TI notes: + The HCI spec indicates that the random number + generation should adhere to one of those specified in FIPS + PUB 140-2. The Core spec refers specifically to the + algorithm specified in FIPS PUB 186-2, Appendix 3.1. + Note that this software only uses the RF hardware to + generate true random numbers. What's more, if the RF is + already in use (i.e. overlapped execution), then the use + of radio to generate true random numbers is prohibited. + In this case, a pseudo-random blocks of numbers will be + returned instead. + + Public function defined in ll.h. +*/ +llStatus_t LL_Rand( uint8* randData, + uint8 dataLen ) +{ + uint16 temp_rand; + uint8* pData = randData; + uint32 sysTick; + + // check if a DTM or Modem operation is in progress + if ( (llState == LL_STATE_DIRECT_TEST_MODE_TX) || + (llState == LL_STATE_DIRECT_TEST_MODE_RX) || + (llState == LL_STATE_MODEM_TEST_TX) || + (llState == LL_STATE_MODEM_TEST_RX) || + (llState == LL_STATE_MODEM_TEST_TX_FREQ_HOPPING) ) + { + // yes, so sorry, no true random number generation allowed as the radio + // is in continuous use + return( LL_STATUS_ERROR_COMMAND_DISALLOWED ); + } + + if (dataLen == 0) + { + return (LL_STATUS_ERROR_BAD_PARAMETER); + } + + // now use timer3 counter + sysTick = get_timer_count(AP_TIM3); + srand(sysTick); + + //srand((unsigned)time(&t)); + while (dataLen > 1) + { + temp_rand = (uint16)(rand() & 0xffff); + *(pData ++) = (uint8)((temp_rand & 0xff00) >> 8); + *(pData ++) = (uint8)(temp_rand & 0xff) ; + dataLen -= 2; + } + + if (dataLen == 1) + { + temp_rand = (uint16)(rand() & 0xffff); + *(pData) = (uint8)((temp_rand & 0xff00) >> 8); + } + + return( LL_STATUS_SUCCESS ); +} + + +/******************************************************************************* + This API is a generic interface to get a block of pseudo-random numbers. + + Public function defined in ll.h. +*/ +llStatus_t LL_PseudoRand( uint8* randData, + uint8 dataLen ) +{ + // ÎÒÃDz»ÓÃÕâ¸öº¯Êý + /* uint8 i; + + if ( (randData == NULL) || (dataLen == 0) ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // can't be sure the radio isn't in use, so provide pseudo random numbers + for (i=0; i0 + && txPowerMaping[txPowerIdx]>g_rfPhyTxPower) + { + txPowerIdx=txPowerIdx+2; + } + + // return the TX power level based on current setting + *txPower =txPowerMaping[txPowerIdx+1]; // assume when g_rfPhyTxPower = 0x1f, tx power = 10dBm, +// // check if Tx output power is valid +// if ( *txPower == LL_TX_POWER_INVALID ) +// { +// return( LL_STATUS_ERROR_PARAM_OUT_OF_RANGE ); +// } + break; + + case LL_READ_MAX_TX_POWER_LEVEL: + // return max data channel TX power level + *txPower = RF_PHY_TX_POWER_MAX; + break; + + default: + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + @fn LL_SetTxPowerLevel + + @brief This function is used to set transmit power level + + input parameters + + @param txPower - The transmit power level to be set + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + LL_STATUS_ERROR_INACTIVE_CONNECTION +*/ +llStatus_t LL_SetTxPowerLevel0( int8 txPower ) +{ + // TODO: add tx power range check + // TODO: add tx power mapping + g_rfPhyTxPower = txPower; + rf_phy_set_txPower(g_rfPhyTxPower); + return LL_STATUS_SUCCESS; +} + +/******************************************************************************* + @fn LL_ReadChanMap API + + @brief This API is called by the HCI to read the channel map that the + LL controller is using for the LL connection. + + input parameters + + @param connId - The LL connection handle. + + output parameters + + @param chanMap - A five byte array containing one bit per data channel + where a 1 means the channel is "used" and a 0 means + the channel is "unused". + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + LL_STATUS_ERROR_INACTIVE_CONNECTION +*/ +llStatus_t LL_ReadChanMap( uint8 connId, + uint8* chanMap ) +{ + llStatus_t status; + llConnState_t* connPtr; + + // make sure connection ID is valid + if ( (status=LL_ConnActive(connId)) != LL_STATUS_SUCCESS ) + { + return( status ); + } + + // get connection info + connPtr = &conn_param[ connId ]; + // copy current channel map + chanMap[0] = connPtr->chanMap[0]; + chanMap[1] = connPtr->chanMap[1]; + chanMap[2] = connPtr->chanMap[2]; + chanMap[3] = connPtr->chanMap[3]; + chanMap[4] = connPtr->chanMap[4]; + return( LL_STATUS_SUCCESS ); +} + + + +/******************************************************************************* + @fn LL_ReadRssi API + + @brief This API is called by the HCI to request RSSI. If there is an + active connection for the given connection ID, then the RSSI of + the last received data packet in the LL will be returned. If a + receiver Modem Test is running, then the RF RSSI for the last + received data will be returned. If no valid RSSI value is + available, then LL_RSSI_NOT_AVAILABLE will be returned. + + input parameters + + @param connId - The LL connection ID on which to read last RSSI. + + output parameters + + @param *lastRssi - The last data RSSI received. + Range: -127dBm..+20dBm, 127=Not Available. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + LL_STATUS_ERROR_INACTIVE_CONNECTION +*/ +llStatus_t LL_ReadRssi0( uint16 connId, + int8* lastRssi ) +{ + *lastRssi = conn_param[connId].lastRssi ; + return( LL_STATUS_SUCCESS ); +} + +llStatus_t LL_ReadFoff( uint16 connId, + uint16* foff ) +{ + *foff = conn_param[connId].foff ; + return( LL_STATUS_SUCCESS ); +} + +llStatus_t LL_ReadCarrSens( uint16 connId, + uint8* carrSens ) +{ + *carrSens = conn_param[connId].carrSens ; + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + This function is used to initiate a BLE PHY level Transmit Test in Direct + Test Mode where the DUT generates test reference packets at fixed intervals. + This test will make use of the nanoRisc Raw Data Transmit and Receive task. + + Note: The BLE device will transmit at maximum power. + + Public function defined in ll.h. +*/ +llStatus_t LL_DirectTestTxTest0( uint8 txFreq, + uint8 payloadLen, + uint8 payloadType ) +{ + return( LL_STATUS_SUCCESS ); +} + + +/******************************************************************************* + This function is used to initiate a BLE PHY level Receive Test in Direct Test + Mode where the DUT receives test reference packets at fixed intervals. This + test will make use of the nanoRisc Raw Data Transmit and Receive task. The + received packets are verified based on the CRC, and metrics are kept. + + Public function defined in ll.h. +*/ +llStatus_t LL_DirectTestRxTest0( uint8 rxFreq ) +{ + return( LL_STATUS_SUCCESS ); +} + + +/******************************************************************************* + This function is used to end the Direct Test Transmit or Direct Test Receive + tests executing in Direct Test mode. When the raw task is ended, the + LL_DirectTestEndDoneCback callback is called. If a Direct Test mode operation + is not currently active, an error is returned. + + Public function defined in ll.h. +*/ +llStatus_t LL_DirectTestEnd0( void ) +{ + return( LL_STATUS_SUCCESS ); +} + + + +/******************************************************************************* + @fn LL_EXT_ConnEventNotice Vendor Specific API + + @brief This API is called to enable or disable a notification to the + specified task using the specified task event whenever a + Connection event ends. A non-zero taskEvent value is taken to + be "enable", while a zero valued taskEvent is taken to be + "disable". + + Note: Currently, only a Slave connection is supported. + + input parameters + + @param taskID - User's task ID. + @param taskEvent - User's task event. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_INACTIVE_CONNECTION, + LL_STATUS_ERROR_BAD_PARAMETER +*/ +llStatus_t LL_EXT_ConnEventNotice( uint8 taskID, uint16 taskEvent ) +{ + return 0; +} + +/******************************************************************************* + @fn LL_EXT_DisconnectImmed Vendor Specific API + + @brief This function is used to disconnect the connection immediately. + + Note: The connection (if valid) is immediately terminated + without notifying the remote device. The Host is still + notified. + + input parameters + + @param connId - The LL connection ID on which to send this data. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_INACTIVE_CONNECTION +*/ +llStatus_t LL_EXT_DisconnectImmed( uint16 connId ) +{ + return 0; +} + +/******************************************************************************* + @fn LL_EXT_NumComplPktsLimit Vendor Specific API + + @brief This API is used to set the minimum number of + completed packets which must be met before a Number of + Completed Packets event is returned. If the limit is not + reach by the end of the connection event, then a Number of + Completed Packets event will be returned (if non-zero) based + on the flushOnEvt flag. + + input parameters + + @param limit - From 1 to LL_MAX_NUM_DATA_BUFFERS. + @param flushOnEvt - LL_EXT_DISABLE_NUM_COMPL_PKTS_ON_EVENT | + LL_EXT_ENABLE_NUM_COMPL_PKTS_ON_EVENT + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_ERROR_CODE_INVALID_HCI_CMD_PARAMS +*/ +llStatus_t LL_EXT_NumComplPktsLimit( uint8 limit, + uint8 flushOnEvt ) +{ + if ( (limit == 0) || (limit > g_maxPktPerEventTx) ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // save the limit + numComplPktsLimit = limit; + return LL_STATUS_SUCCESS; +} + +/******************************************************************************* + @fn LL_EXT_OnePacketPerEvent Vendor Specific API + + @brief This function is used to enable or disable allowing only one + packet per event. + + input parameters + + @param control - LL_EXT_ENABLE_ONE_PKT_PER_EVT, + LL_EXT_DISABLE_ONE_PKT_PER_EVT + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER +*/ +llStatus_t LL_EXT_OnePacketPerEvent( uint8 control ) +{ + return 0; +} + +/******************************************************************************* + @fn LL_EXT_OverlappedProcessing Vendor Specific API + + @brief This API is used to enable or disable overlapped processing. + + input parameters + + @param mode - LL_EXT_ENABLE_OVERLAPPED_PROCESSING | + LL_EXT_DISABLE_OVERLAPPED_PROCESSING + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_ERROR_CODE_INVALID_HCI_CMD_PARAMS +*/ +llStatus_t LL_EXT_OverlappedProcessing( uint8 mode ) +{ + return 0; +} + +/******************************************************************************* + @fn LL_EXT_PERbyChan Vendor Specific API + + @brief This API is called by the HCI to start or end Packet Error Rate + by Channel counter accumulation for a connection. If the + pointer is not NULL, it is assumed there is sufficient memory + for the PER data, per the type perByChan_t. If NULL, then + the operation is considered disabled. + + Note: It is the user's responsibility to make sure there is + sufficient memory for the data, and that the counters + are cleared prior to first use. + + Note: The counters are only 16 bits. At the shortest connection + interval, this provides a bit over 8 minutes of data. + + input parameters + + @param connId - The LL connection ID on which to send this data. + @param perByChan - Pointer to PER by Channel data, or NULL. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_INACTIVE_CONNECTION +*/ +llStatus_t LL_EXT_PERbyChan( uint16 connId, perByChan_t* perByChan ) +{ + return 0; +} + +/******************************************************************************* + @fn LL_ReadAdvChanTxPower + + @brief This function is used to read the transmit power level used + for BLE advertising channel packets. Currently, only two + settings are possible, a standard setting of 0 dBm, and a + maximum setting of 4 dBm. + + input parameters + + @param *txPower - A non-null pointer. + + output parameters + + @param *txPower - A signed value from -20..+10, in dBm. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_PARAM_OUT_OF_RANGE +*/ +llStatus_t LL_ReadAdvChanTxPower0( int8* txPower ) +{ + if (g_llAdvMode == LL_MODE_EXTENDED ) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llAdvMode = LL_MODE_LEGACY; + return 0; +} + +/******************************************************************************* + @fn LL_SetScanParam API + + @brief This API is called by the HCI to set the Scanner's parameters. + + input parameters + + @param scanType - Passive or Active scan type. + @param scanInterval - Time between scan events. + @param scanWindow - Duration of a scan. When the same as the scan + interval, then scan continuously. + @param ownAddrType - Address type (Public or Random) to use in the + SCAN_REQ packet. + @param advWlPolicy - Either allow all Adv packets, or only those that + are in the white list. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER +*/ +llStatus_t LL_SetScanParam0( uint8 scanType, + uint16 scanInterval, + uint16 scanWindow, + uint8 ownAddrType, + uint8 scanWlPolicy ) +{ + if (g_llScanMode == LL_MODE_EXTENDED ) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llScanMode = LL_MODE_LEGACY; + + // sanity check of parameters + if ( ( (scanType != LL_SCAN_PASSIVE) && + (scanType != LL_SCAN_ACTIVE) ) || + ( (ownAddrType != LL_DEV_ADDR_TYPE_PUBLIC) && + (ownAddrType != LL_DEV_ADDR_TYPE_RANDOM) && + (ownAddrType != LL_DEV_ADDR_TYPE_RPA_PUBLIC) && + (ownAddrType != LL_DEV_ADDR_TYPE_RPA_RANDOM) ) || + ( (scanInterval < LL_SCAN_WINDOW_MIN) || + (scanInterval > LL_SCAN_WINDOW_MAX) ) || + ( (scanWindow < LL_SCAN_WINDOW_MIN) || + (scanWindow > LL_SCAN_WINDOW_MAX) ) || + ( (scanWindow > scanInterval) ) || + ( (scanWlPolicy != LL_SCAN_WL_POLICY_ANY_ADV_PKTS) && + (scanWlPolicy != LL_SCAN_WL_POLICY_USE_WHITE_LIST) ) ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // check if scan is active + if ( scanInfo.scanMode == LL_SCAN_START ) + { + // yes, so not allowed per the spec + return( LL_STATUS_ERROR_COMMAND_DISALLOWED ); + } + + // set the scan type + scanInfo.scanType = scanType; + // save white list policy + scanInfo.wlPolicy = scanWlPolicy; + + // set the scanner's address based on the HCI's address type preference + if ( ownAddrType == LL_DEV_ADDR_TYPE_PUBLIC ) + { + // get our address and address type + scanInfo.ownAddrType = LL_DEV_ADDR_TYPE_PUBLIC; + LL_COPY_DEV_ADDR_LE( scanInfo.ownAddr, ownPublicAddr ); + } + else if ( ownAddrType == LL_DEV_ADDR_TYPE_RANDOM )// LL_DEV_ADDR_TYPE_RANDOM + { + // get our address and address type + scanInfo.ownAddrType = LL_DEV_ADDR_TYPE_RANDOM; + LL_COPY_DEV_ADDR_LE( scanInfo.ownAddr, ownRandomAddr ); + } + else + { + // for RPAs, scan control not indicate using which RPA list entry, no copy scanA here + scanInfo.ownAddrType = ownAddrType; + } + + // set the scan interval + scanInfo.scanInterval = scanInterval; + // set the scan window + scanInfo.scanWindow = scanWindow; + // set the scan filter policy +// if ( scanWlPolicy == LL_SCAN_WL_POLICY_ANY_ADV_PKTS ) +// { +//// PHY_SetScanWlPolicy( PHY_SCANNER_ALLOW_ALL_ADV_PKTS ); +// } +// else if ( scanWlPolicy == LL_SCAN_WL_POLICY_USE_WHITE_LIST ) +// { +//// PHY_SetScanWlPolicy( PHY_SCANNER_USE_WHITE_LIST ); +// } + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + @fn LL_SetScanControl API + + @brief This API is called by the HCI to start or stop the Scanner. It + also specifies whether the LL will filter duplicate advertising + reports to the Host, or generate a report for each packet + received. + + input parameters + + @param scanMode - LL_SCAN_START or LL_SCAN_STOP. + @param filterReports - LL_FILTER_REPORTS_DISABLE or + LL_FILTER_REPORTS_ENABLE + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + LL_STATUS_ERROR_UNEXPECTED_PARAMETER, + LL_STATUS_ERROR_OUT_OF_TX_MEM, + LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE +*/ +llStatus_t LL_SetScanControl0( uint8 scanMode, + uint8 filterReports ) +{ + if (g_llScanMode == LL_MODE_EXTENDED ) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llScanMode = LL_MODE_LEGACY; + + // check if a direct test mode or modem test is in progress + if ( (llState == LL_STATE_DIRECT_TEST_MODE_TX) || + (llState == LL_STATE_DIRECT_TEST_MODE_RX) || + (llState == LL_STATE_MODEM_TEST_TX) || + (llState == LL_STATE_MODEM_TEST_RX) || + (llState == LL_STATE_MODEM_TEST_TX_FREQ_HOPPING) ) + { + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + } + + // sanity checks again to be sure we don't start with bad parameters + if ( ( (scanInfo.scanType != LL_SCAN_PASSIVE) && + (scanInfo.scanType != LL_SCAN_ACTIVE)) || + ( (scanInfo.ownAddrType != LL_DEV_ADDR_TYPE_PUBLIC) && + (scanInfo.ownAddrType != LL_DEV_ADDR_TYPE_RANDOM)) || + ( (scanInfo.scanInterval < LL_SCAN_WINDOW_MIN) || + (scanInfo.scanInterval > LL_SCAN_WINDOW_MAX)) || + ( (scanInfo.scanWindow < LL_SCAN_WINDOW_MIN) || + (scanInfo.scanWindow > LL_SCAN_WINDOW_MAX)) || + ( (scanInfo.scanWindow > scanInfo.scanInterval) ) || + ( (filterReports != LL_FILTER_REPORTS_DISABLE) && + (filterReports != LL_FILTER_REPORTS_ENABLE)) ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // check if we should begin scanning + switch( scanMode ) + { + // Scanning Mode is On + case LL_SCAN_START: + + // check if command makes sense + if ( scanInfo.scanMode == LL_SCAN_START ) + { + // this is unexpected; something is wrong + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + } + + // get a task block for this BLE state/role + // Note: There will always be a valid pointer, so no NULL check required. +// scanInfo.llTask = llAllocTask( LL_TASK_ID_SCANNER ); + + // check if no other tasks are currently active + if ( llState == LL_STATE_IDLE ) + { + // indicate Scan has not already been initalized + scanInfo.initPending = TRUE; + // save the scan filtering flag + scanInfo.filterReports = filterReports; + // add by HZF + scanInfo.nextScanChan = LL_SCAN_ADV_CHAN_37; + // set LL state + llState = LL_STATE_SCAN; + // Note: llState has been changed. + LL_evt_schedule(); + } + else if ((llState == LL_STATE_CONN_SLAVE + || llState == LL_STATE_CONN_MASTER) // HZF: if we should support adv + scan, add more state here + && (pGlobal_config[LL_SWITCH] & SIMUL_CONN_SCAN_ALLOW)) + { + if (llSecondaryState != LL_SEC_STATE_IDLE) + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + + scanInfo.nextScanChan = LL_SCAN_ADV_CHAN_37; + llSecondaryState = LL_SEC_STATE_SCAN; + osal_set_event(LL_TaskID, LL_EVT_SECONDARY_SCAN); + } + else + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + + // indicate we are actively scanning + scanInfo.scanMode = LL_SCAN_START; + break; + + case LL_SCAN_STOP: + HAL_ENTER_CRITICAL_SECTION(); + + if (llState == LL_STATE_SCAN) // no conn + scan case + { + llState = LL_STATE_IDLE; // if not in connect state, set idle to disable scan + //ZQ 20190912 + //stop ll timer when idle, considering the scan-adv interleve case + clear_timer(AP_TIM1); + ll_debug_output(DEBUG_LL_STATE_IDLE); + } + else if (llState == LL_STATE_CONN_SLAVE + || llState == LL_STATE_CONN_MASTER) // conn + scan case + { + llSecondaryState = LL_SEC_STATE_IDLE; + } + + // indicate we are no longer actively scanning + scanInfo.scanMode = LL_SCAN_STOP; + // A2 multiconn, should we consider current LL state to avoid change master/slave configuration + // now LL slave/master event use same parameter 88 + ll_hw_set_rx_timeout(88); + // HZF: should we stop scan task immediately, or wait scan IRQ then stop? Now use option 2. + HAL_EXIT_CRITICAL_SECTION(); + break; + + default: + // we have an invalid value for advertisement mode + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + return( LL_STATUS_SUCCESS ); +} + + +/******************************************************************************* + This API is called by the HCI to set the Advertiser's Scan Response data. + + Public function defined in ll.h. +*/ +llStatus_t LL_SetScanRspData( uint8 scanRspLen, + uint8* scanRspData ) +{ + if (g_llAdvMode == LL_MODE_EXTENDED ) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llAdvMode = LL_MODE_LEGACY; + + // check that data length isn't greater than the max allowed size + if ( scanRspLen > LL_MAX_SCAN_DATA_LEN ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // save scan response data length + adv_param.scanRspLen = scanRspLen; + + // check if there is any scan response data + if ( scanRspLen > 0 ) + { + // yes, so make sure we have a valid pointer + if ( scanRspData == NULL ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + else // okay to go + { + // save scan response data + osal_memcpy( (uint8_t*) &(tx_scanRsp_desc.data[6]), scanRspData, adv_param.scanRspLen ); + } + } + + SET_BITS(tx_scanRsp_desc.txheader, (adv_param .scanRspLen+6), LENGTH_SHIFT, LENGTH_MASK); + //osal_memcpy( tx_scanRsp_desc.data, adv_param.ownAddr, 6); + return( LL_STATUS_SUCCESS ); +} + +#ifdef USE_UNPATCHED +/******************************************************************************* + @fn LL_EncLtkReply API + + @brief This API is called by the HCI to provide the controller with + the Long Term Key (LTK) for encryption. This command is + actually a reply to the link layer's LL_EncLtkReqCback, which + provided the random number and encryption diversifier received + from the Master during an encryption setup. + + Note: The key parameter is byte ordered LSO to MSO. + + input parameters + + @param connId - The LL connection ID on which to send this data. + @param *key - A 128 bit key to be used to calculate the session key. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS +*/ +llStatus_t LL_EncLtkReply( uint16 connId, + uint8* key ) +{ + uint8 i; + llStatus_t status; + llConnState_t* connPtr; + + // make sure we're in Master role + if ( llState != LL_STATE_CONN_SLAVE ) + { + return( LL_STATUS_ERROR_COMMAND_DISALLOWED ); + } + + // check parameters + if ( key == NULL ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // make sure connection ID is valid + if ( (status=LL_ConnActive(connId)) != LL_STATUS_SUCCESS ) + { + return( status ); + } + + // get connection info + connPtr = &conn_param[ connId ]; + + // ALT: COULD MAKE THIS PER CONNECTION. + + // save LTK + for (i=0; iencInfo.LTK[(LL_ENC_LTK_LEN-i)-1] = key[i]; + } + + // indicate the host has provided the key + connPtr->encInfo.LTKValid = TRUE; + // got the LTK, so schedule the start of encryption + // ALT: COULD MAKE THIS A REPLACE IF A DUMMY IS SITTING AT THE HEAD OF + // THE QUEUE. + llEnqueueCtrlPkt( connPtr, LL_CTRL_START_ENC_REQ ); + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + @fn LL_EncLtkNegReply API + + @brief This API is called by the HCI to indicate to the controller + that the Long Term Key (LTK) for encryption can not be provided. + This command is actually a reply to the link layer's + LL_EncLtkReqCback, which provided the random number and + encryption diversifier received from the Master during an + encryption setup. How the LL responds to the negative reply + depends on whether this is part of a start encryption or a + re-start encryption after a pause. For the former, an + encryption request rejection is sent to the peer device. For + the latter, the connection is terminated. + + input parameters + + @param connId - The LL connection ID on which to send this data. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS +*/ +llStatus_t LL_EncLtkNegReply( uint16 connId ) +{ + llStatus_t status; + llConnState_t* connPtr; + + // make sure we're in Master role + if ( llState != LL_STATE_CONN_SLAVE ) + { + return( LL_STATUS_ERROR_COMMAND_DISALLOWED ); + } + + // make sure connection ID is valid + if ( (status=LL_ConnActive(connId)) != LL_STATUS_SUCCESS ) + { + return( status ); + } + + // get connection info + connPtr = &conn_param[ connId ]; + + // check if this is during a start or a re-start encryption procedure + if ( connPtr->encInfo.encRestart == TRUE ) + { + // indicate the peer requested this termination + connPtr->termInfo.reason = LL_ENC_KEY_REQ_REJECTED; + // queue control packet for processing + // ALT: COULD MAKE THIS A REPLACE IF A DUMMY IS SITTING AT THE HEAD OF + // THE QUEUE. + //llReplaceCtrlPkt( connPtr, LL_CTRL_TERMINATE_IND ); + llEnqueueCtrlPkt( connPtr, LL_CTRL_TERMINATE_IND ); + } + else // during a start encryption + { + // set the encryption rejection error code + connPtr->encInfo.encRejectErrCode = LL_STATUS_ERROR_PIN_OR_KEY_MISSING; // same as LL_ENC_KEY_REQ_REJECTED + // and reject the encryption request + // ALT: COULD MAKE THIS A REPLACE IF A DUMMY IS SITTING AT THE HEAD OF + // THE QUEUE. + //llReplaceCtrlPkt( connPtr, LL_CTRL_REJECT_IND ); + llEnqueueCtrlPkt( connPtr, LL_CTRL_REJECT_IND ); + } + + return( LL_STATUS_SUCCESS ); +} +#endif // USE_UNPATCHED + +/******************************************************************************* + This API is called by the HCI to read the controller's own public device + address. + + Note: The device's address is stored in NV memory. + + Public function defined in ll.h. +*/ +llStatus_t LL_ReadBDADDR( uint8* bdAddr ) +{ + // return own public device address LSO..MSO + bdAddr[0] = ownPublicAddr[0]; + bdAddr[1] = ownPublicAddr[1]; + bdAddr[2] = ownPublicAddr[2]; + bdAddr[3] = ownPublicAddr[3]; + bdAddr[4] = ownPublicAddr[4]; + bdAddr[5] = ownPublicAddr[5]; + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + This API is called by the HCI to read the controller's Feature Set. The + Controller indicates which features it supports. + + Public function defined in ll.h. +*/ +llStatus_t LL_ReadLocalSupportedFeatures( uint8* featureSet ) +{ + uint8 i; + + // copy Feature Set + for (i=0; ictrlPktInfo.ctrlPktCount > 0) && + (connPtr->ctrlPktInfo.ctrlPkts[0] == LL_CTRL_CONNECTION_UPDATE_REQ)) || + (connPtr->pendingParamUpdate == TRUE) ) + { + return( LL_STATUS_ERROR_CTRL_PROC_ALREADY_ACTIVE ); + } + + // check if CI/SL/LSTO is valid (i.e. meets the requirements) + // Note: LSTO > (1 + Slave Latency) * (Connection Interval * 2) + // Note: The CI * 2 requirement based on ESR05 V1.0, Erratum 3904. + // Note: LSTO time is normalized to units of 1.25ms (i.e. 10ms = 8 * 1.25ms). + if ( LL_INVALID_CONN_TIME_PARAM_COMBO(connIntervalMax, connLatency, connTimeout) ) + { + return( LL_STATUS_ERROR_ILLEGAL_PARAM_COMBINATION ); + } + + // if there is at least one connection, make sure this connection interval + // is a multiple/divisor of all other active connection intervals; also make + // sure that this connection's interval is not less than the allowed maximum + // connection interval as determined by the maximum number of allowed + // connections times the number of slots per connection. + if ( g_ll_conn_ctx.numLLMasterConns > 0 ) // if ( g_ll_conn_ctx.numLLConns > 0 ) + { + uint16 connInterval = (connIntervalMax << 1); // convert to 625us ticks + uint16 minCI = g_ll_conn_ctx.connInterval; + + // // first check if this connection interval is even legal + // // Note: The number of active connections is limited by the minCI. + // if ( (minCI / NUM_SLOTS_PER_MASTER) < llConns.numActiveConns ) + // { + // return( LL_STATUS_ERROR_UNACCEPTABLE_CONN_INTERVAL ); + // } + + // // does the CI need to be checked as a multiple of the minCI? + if ( connInterval >= minCI ) + { + // check if this connection's CI is valid (i.e. a multiple of minCI) + if ( connInterval % minCI ) + { + return( LL_STATUS_ERROR_UNACCEPTABLE_CONN_INTERVAL ); + } + } + else + return( LL_STATUS_ERROR_UNACCEPTABLE_CONN_INTERVAL ); + } + + // no control procedure currently active, so set this one up + // set the window size (units of 1.25ms) + connPtr->paramUpdate.winSize = LL_WINDOW_SIZE; + // set the window offset (units of 1.25ms) +// connPtr->paramUpdate.winOffset = LL_WINDOW_OFFSET; + connPtr->paramUpdate.winOffset = 0; // multiconnection, this value could be 0 or x * old conn interval and should be less than new conn interval + // set the relative offset of the number of events for the parameter update + // Note: The absolute event number will be determined at the time the packet + // is placed in the TX FIFO. + // Note: The master should allow a minimum of 6 connection events that the + // slave will be listening for before the instant occurs. + connPtr->paramUpdateEvent = (connPtr->curParam.slaveLatency+1) + + LL_INSTANT_NUMBER_MIN; + // determine the connection interval based on min and max values + // Note: Range not used, so assume max value. + // Note: minLength and maxLength are informational. + connPtr->paramUpdate.connInterval = connIntervalMax; + // save the new connection slave latency to be used by the peer + connPtr->paramUpdate.slaveLatency = connLatency; + // save the new connection supervisor timeout + connPtr->paramUpdate.connTimeout = connTimeout; + // queue control packet for processing + llEnqueueCtrlPkt( connPtr, LL_CTRL_CONNECTION_UPDATE_REQ ); + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + This API is called by the HCI to create a connection. + + Public function defined in ll.h. +*/ +// TODO: check the usage of new enum value of ownAddrType/peerAddrType +llStatus_t LL_CreateConn0( uint16 scanInterval, + uint16 scanWindow, + uint8 initWlPolicy, + uint8 peerAddrType, + uint8* peerAddr, + uint8 ownAddrType, + uint16 connIntervalMin, + uint16 connIntervalMax, + uint16 connLatency, + uint16 connTimeout, + uint16 minLength, // minimum length of connection needed for this LE conn, no use now + uint16 maxLength ) // maximum length of connection needed for this LE conn, no use now +{ + uint8 i; + llConnState_t* connPtr; + uint16 txHeader = 0x2205; // header for CONNECT REQ message, length: 0x22, PDU type: 0x5, TxAdd & RxAdd to be set below + + if (g_llScanMode == LL_MODE_EXTENDED ) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llScanMode = LL_MODE_LEGACY; + + //--------------------------------------------------- + // protect for the LL_HW re-trigger + // 20190115 ZQ + // if(llWaitingIrq==TRUE) // HZF: temp comment out +// { +// return(LL_STATUS_WARNING_WAITING_LLIRQ); +// } + // ================== sanity check ================= + // check if a direct test mode or modem test is in progress + if ( (llState == LL_STATE_DIRECT_TEST_MODE_TX) || + (llState == LL_STATE_DIRECT_TEST_MODE_RX) || + (llState == LL_STATE_MODEM_TEST_TX) || + (llState == LL_STATE_MODEM_TEST_RX) || + (llState == LL_STATE_MODEM_TEST_TX_FREQ_HOPPING) ) + { + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + } + + // sanity checks again to be sure we don't start with bad parameters + if ( ( (scanInterval < LL_SCAN_INTERVAL_MIN) || + (scanInterval > LL_SCAN_INTERVAL_MAX) ) || + ( (scanWindow < LL_SCAN_INTERVAL_MIN) || + (scanWindow > LL_SCAN_INTERVAL_MAX) ) || + ( (scanWindow > scanInterval) ) || + ( (initWlPolicy != LL_INIT_WL_POLICY_USE_PEER_ADDR) && + (initWlPolicy != LL_INIT_WL_POLICY_USE_WHITE_LIST) ) || + ( (initWlPolicy == LL_INIT_WL_POLICY_USE_PEER_ADDR) && + (peerAddr == NULL) ) || + ( (peerAddrType != LL_DEV_ADDR_TYPE_PUBLIC) && + (peerAddrType != LL_DEV_ADDR_TYPE_RANDOM) && + (peerAddrType != LL_DEV_ADDR_TYPE_RPA_RANDOM) && + (peerAddrType != LL_DEV_ADDR_TYPE_RPA_PUBLIC)) || + ( (ownAddrType != LL_DEV_ADDR_TYPE_PUBLIC) && + (ownAddrType != LL_DEV_ADDR_TYPE_RANDOM) && + (ownAddrType != LL_DEV_ADDR_TYPE_RPA_RANDOM) && + (ownAddrType != LL_DEV_ADDR_TYPE_RPA_PUBLIC)) || + ( (maxLength < minLength) ) ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // The Host shall not set Peer_Address_Type to either 0x02 or 0x03 if both the Host and the Controller + // support the HCI_LE_Set_Privacy_Mode command. If a Controller that supports the HCI_LE_Set_Privacy_Mode + // command receives the HCI_LE_Create_Connection command with Peer_Address_Type set to either + // 0x02 or 0x03, it may use either device privacy mode or network privacy mode for that peer device. +// if(((peerAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM) || +// (peerAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC)) || +// ((ownAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM) || +// (ownAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC))) +// { // these values shall only be used by the Host if either the Host or the Controller does not support the HCI_LE_Set_Privacy_Mode command +// return( LL_STATUS_ERROR_BAD_PARAMETER ); +// } + + // sanity checks again to be sure we don't start with bad parameters + if ( LL_INVALID_CONN_TIME_PARAM( connIntervalMin, + connIntervalMax, + connLatency, + connTimeout ) ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // check if CI/SL/LSTO is valid (i.e. meets the requirements) + // Note: LSTO > (1 + Slave Latency) * (Connection Interval * 2) + // Note: The CI * 2 requirement based on ESR05 V1.0, Erratum 3904. + // Note: LSTO time is normalized to units of 1.25ms (i.e. 10ms = 8 * 1.25ms). + if ( LL_INVALID_CONN_TIME_PARAM_COMBO(connIntervalMax, connLatency, connTimeout) ) + { + return( LL_STATUS_ERROR_ILLEGAL_PARAM_COMBINATION ); + } + + // multi-connction limits check + if (g_ll_conn_ctx.numLLConns >= g_maxConnNum) + { + return( LL_STATUS_ERROR_OUT_OF_CONN_RESOURCES ); + } + + // if there is at least one connection, make sure this connection interval + // is a multiple/divisor of all other active connection intervals; also make + // sure that this connection's interval is not less than the allowed maximum + // connection interval as determined by the maximum number of allowed + // connections times the number of slots per connection. + if ( g_ll_conn_ctx.numLLMasterConns > 0 ) // if ( g_ll_conn_ctx.numLLConns > 0 ) + { + uint16 connInterval = (connIntervalMax << 1); // convert to 625us ticks + uint16 minCI = g_ll_conn_ctx.connInterval; + + // // first check if this connection interval is even legal + // // Note: The number of active connections is limited by the minCI. + // if ( (minCI / NUM_SLOTS_PER_MASTER) < llConns.numActiveConns ) + // { + // return( LL_STATUS_ERROR_UNACCEPTABLE_CONN_INTERVAL ); + // } + + // // does the CI need to be checked as a multiple of the minCI? + if ( connInterval >= minCI ) + { + // check if this connection's CI is valid (i.e. a multiple of minCI) + if ( connInterval % minCI ) + { + return( LL_STATUS_ERROR_UNACCEPTABLE_CONN_INTERVAL ); + } + } + else + return( LL_STATUS_ERROR_UNACCEPTABLE_CONN_INTERVAL ); + } + else + { + // TODO: should we consider if there is only slave connection, using the interval of slave as the standard interval of master? + // how could application know the slave interval? + } + +// // check if an update channel map control procedure is already pending +// // Note: This is the case where the control procedure is enqueued, but the +// // control packet has not yet been sent OTA. At this point, it is +// // easier to simply reject the new connection until that happens. Once +// // the packet is sent, and the pendingParamUpdate flag is set, the +// // update connection interval is checked by llGetMinCI. +// if ( llPendingUpdateParam() == TRUE ) +// { +// return( LL_STATUS_ERROR_UPDATE_CTRL_PROC_PENDING ); +// } + + // check if the white list policy uses the peer address, it is valid + if ( (initWlPolicy == LL_INIT_WL_POLICY_USE_PEER_ADDR) && (peerAddr == NULL) ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + if (llState == LL_STATE_CONN_MASTER || llState == LL_STATE_CONN_SLAVE) + { + if (llSecondaryState == LL_SEC_STATE_IDLE) + llSecondaryState = LL_SEC_STATE_INIT; + else + return LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE; + } + + // allocate a connection and assure it is valid + if ( (connPtr = llAllocConnId()) == NULL ) + { + llSecondaryState = LL_SEC_STATE_IDLE; // recover llSecondaryState + // exceeded the number of available connection structures + return( LL_STATUS_ERROR_CONNECTION_LIMIT_EXCEEDED ); + } + + g_ll_conn_ctx.numLLMasterConns ++; +// connId = 0; +// connPtr = &conn_param[connId]; + // reset connection parameters + LL_set_default_conn_params(connPtr); + // clear the connection buffer + reset_conn_buf(connPtr->connId); + // save the connection ID with Init + initInfo.connId = connPtr->connId; + // set the scan interval + initInfo.scanInterval = scanInterval; + // set the scan window + initInfo.scanWindow = scanWindow; + // set the Init white list policy + initInfo.wlPolicy = initWlPolicy; + + // set the connection channel map + for (i = 0; i < LL_NUM_BYTES_FOR_CHAN_MAP; i++) + { + connPtr->chanMap[i] = chanMapUpdate.chanMap[i]; + } + + // process connection channel map into the data channel table + llProcessChanMap( connPtr, connPtr->chanMap ); + + // Core spec V4.0 requires that a minimum of two data channels be used + if ( connPtr->numUsedChans < 2 ) + { + // it isn't, so release the resource + llReleaseConnId( connPtr ); + g_ll_conn_ctx.numLLMasterConns --; + return( LL_STATUS_ERROR_ILLEGAL_PARAM_COMBINATION ); + } + + // save the peer address + if (peerAddr != NULL) // bug fixed + LL_COPY_DEV_ADDR_LE( peerInfo.peerAddr, peerAddr ); + + // save our address type + initInfo.ownAddrType = ownAddrType; + + // check the type of own address + if ( ownAddrType == LL_DEV_ADDR_TYPE_PUBLIC ) + { + // save our address + LL_COPY_DEV_ADDR_LE( initInfo.ownAddr, ownPublicAddr ); + } + else // LL_DEV_ADDR_TYPE_RANDOM + { + // save our address + LL_COPY_DEV_ADDR_LE( initInfo.ownAddr, ownRandomAddr ); + } + + // save the peer address type + peerInfo.peerAddrType = peerAddrType; + txHeader |= (ownAddrType << TX_ADD_SHIFT & TX_ADD_MASK); + txHeader |= (peerAddrType << RX_ADD_SHIFT & RX_ADD_MASK); + // ramdomly generate a valid 24 bit CRC value + connPtr->initCRC = llGenerateCRC(); + // randomly generate a valid, previously unused, 32-bit access address + connPtr->accessAddr = llGenerateValidAccessAddr(); + +// g_ll_conn_ctx.scheduleInfo[connPtr->allocConn].linkRole = LL_ROLE_MASTER; // will change the role in move_to_master_function + + if (g_ll_conn_ctx.numLLMasterConns == 1) // A2 multi-connection, 1st connection, save the connection parameters + { + // determine the connection interval based on min and max values + // Note: Range not used, so assume max value. + // Note: minLength and maxLength are informational. + connPtr->curParam.connInterval = connIntervalMax; + // set the connection timeout + // Note: The spec says this begins at the end of the CONNECT_REQ, but the + // LSTO will be converted into events. + connPtr->curParam.connTimeout = connTimeout; + // set the slave latency + connPtr->curParam.slaveLatency = connLatency; + // save connection parameter as global + g_ll_conn_ctx.connInterval = connPtr->curParam.connInterval; // unit: 1.25ms + g_ll_conn_ctx.slaveLatency = connPtr->curParam.slaveLatency; + g_ll_conn_ctx.connTimeout = connPtr->curParam.connTimeout; + g_ll_conn_ctx.per_slot_time = connPtr->curParam.connInterval * 2 / g_maxConnNum; // unit: 625us + } + else + { + // determine the connection interval based on min and max values + // Note: Range not used, so assume max value. + // Note: minLength and maxLength are informational. + connPtr->curParam.connInterval = g_ll_conn_ctx.connInterval; + // set the connection timeout + // Note: The spec says this begins at the end of the CONNECT_REQ, but the + // LSTO will be converted into events. + connPtr->curParam.connTimeout = g_ll_conn_ctx.connTimeout; + // set the slave latency + connPtr->curParam.slaveLatency = g_ll_conn_ctx.slaveLatency; + } + + // set the master's SCA + connPtr->sleepClkAccuracy = initInfo.scaValue; + // set the window size (units of 1.25ms) + // Note: Must be the lesser of 10ms and the connection interval - 1.25ms. + connPtr->curParam.winSize = pGlobal_config[LL_CONN_REQ_WIN_SIZE];//5;//LL_WINDOW_SIZE; + // set the window offset (units of 1.25ms). TO change if we support multiple connections + // Note: Normally, the window offset is managed dynamically so that precise + // connection start times can be achieved (necessary for multiple + // connnections). However, sometimes it is useful to force the window + // offset to something specific for testing. This can be done by here + // when the project is built with the above define. + // Note: This define should only be used for testing one connection and will + // NOT work when multiple connections are attempted! + connPtr->curParam.winOffset = pGlobal_config[LL_CONN_REQ_WIN_OFFSET];//2;//LL_WINDOW_OFFSET; + // set the channel map hop length (5..16) + // Note: 0..255 % 12 = 0..11 + 5 = 5..16. + connPtr->hop = (uint8)( (LL_ENC_GeneratePseudoRandNum() % 12) + 5); + // track advertising channel for advancement at each scan window + initInfo.nextScanChan = LL_SCAN_ADV_CHAN_37; + // enable Init scan + initInfo.scanMode = LL_SCAN_START; + // check if this is the only task + // Note: If there are one or more master connections already running, then + // the Init task will be scheduled when the next connection ends. + { + // ============= construct CONN REQ message payload in g_tx_adv_buf buffer. Using byte copy to avoid + // hardfault cause by no word align reading + uint8 offset = 0; + g_tx_adv_buf.txheader = txHeader; + // setup CONN REQ in connPtr->ll_buf + LL_ReadBDADDR(&g_tx_adv_buf.data[offset]); // initA, Byte 0 ~ 5 + offset += 6; + + if (peerAddr != NULL) + LL_COPY_DEV_ADDR_LE(&g_tx_adv_buf.data[offset], peerAddr) // AdvA, Byte 6 ~ 11 + offset += 6; + + // Access Address, Byte 12 ~ 15 + memcpy((uint8*)&g_tx_adv_buf.data[offset], (uint8*)&connPtr->accessAddr, 4); + offset += 4; + // CRC init, Byte 16 ~ 18 + memcpy((uint8*)&g_tx_adv_buf.data[offset], (uint8*)&connPtr->initCRC, 3); + offset += 3; + // WinSize, Byte 19 + g_tx_adv_buf.data[offset] = connPtr->curParam.winSize; + offset += 1; + // WinOffset, Byte 20 ~ 21 + memcpy((uint8*)&g_tx_adv_buf.data[offset], (uint8*)&connPtr->curParam.winOffset, 2); + offset += 2; + // Interval, Byte 22 ~ 23 + memcpy((uint8*)&g_tx_adv_buf.data[offset], (uint8*)&connPtr->curParam.connInterval, 2); + offset += 2; + // Latency, Byte 24 ~ 25 + memcpy((uint8*)&g_tx_adv_buf.data[offset], (uint8*)&connPtr->curParam.slaveLatency, 2); + offset += 2; + // Timeout, Byte 26 ~ 27 + memcpy((uint8*)&g_tx_adv_buf.data[offset], (uint8*)&connPtr->curParam.connTimeout, 2); + offset += 2; + // Channel Map, Byte 28 ~ 32 + memcpy((uint8*)&g_tx_adv_buf.data[offset], (uint8*)&connPtr->chanMap[0], 5); + offset += 5; + // Hop(5bit) + SCA(3bit), Byte 33 + g_tx_adv_buf.data[offset] = (connPtr->hop & 0x1f) | ((connPtr->sleepClkAccuracy & 0x7) << 5); + // go ahead and start Init immediately +// llSetupInit( connPtr->connId ); + // TODO: calc new connection start time and set dynamic window offset + //llSetupConn(); + } + + if ( llState == LL_STATE_IDLE ) + // go ahead and start Init immediately + llSetupInit( connPtr->connId ); + else + osal_set_event(LL_TaskID, LL_EVT_SECONDARY_INIT); + + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + This API is called by the HCI to cancel a previously given LL connection + creation command that is still pending. This command should only be used + after the LL_CreateConn command as been issued, but before the + LL_ConnComplete callback. + + Public function defined in ll.h. +*/ +llStatus_t LL_CreateConnCancel0( void ) +{ + uint8 cancel_now = FALSE; + uint8 connId; + + // ensure Init is active + if ( initInfo.scanMode == LL_SCAN_STOP && extInitInfo.scanMode == LL_SCAN_STOP) + { + // no create connection in progress + return( LL_STATUS_ERROR_COMMAND_DISALLOWED ); + } + + // if scan has not trigger, release conn ID and report. Note: we assume only 1 type of scan could be enabled at the same time + if (initInfo.scanMode == LL_SCAN_START) + connId = initInfo.connId; + else if (extInitInfo.scanMode == LL_SCAN_START) + connId = extInitInfo.connId; + else + return LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE; + + if (llState == LL_STATE_INIT && !llWaitingIrq) // primary LL state is init case + { + cancel_now = TRUE; + llState = LL_STATE_IDLE; + } + else if( llSecondaryState == LL_SEC_STATE_INIT && !llWaitingIrq ) + { + cancel_now = TRUE; + llSecondaryState = LL_SEC_STATE_IDLE; + } + else if (llSecondaryState == LL_SEC_STATE_INIT_PENDING) // secondary LL state is init case + { + cancel_now = TRUE; + llSecondaryState = LL_SEC_STATE_IDLE; + } + + if (extInitInfo.scanMode == LL_SCAN_START && llTaskState != LL_TASK_EXTENDED_INIT) // extended init case + cancel_now = TRUE; + + // indicate we are no longer actively scanning + initInfo.scanMode = LL_SCAN_STOP; + extInitInfo.scanMode = LL_SCAN_STOP; + + // if the scan is not ongoing, release conn ID + if (cancel_now == TRUE) + { + llReleaseConnId(&conn_param[connId]); + g_ll_conn_ctx.numLLMasterConns --; + (void)osal_set_event( LL_TaskID, LL_EVT_MASTER_CONN_CANCELLED ); // inform high layer + } + + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + This API is called by the Master HCI to setup encryption and to update + encryption keys in the LL connection. If the connection is already in + encryption mode, then this command will first pause the encryption before + subsequently running the encryption setup. + + Public function defined in ll.h. +*/ +llStatus_t LL_StartEncrypt0( uint16 connId, + uint8* rand, + uint8* eDiv, + uint8* ltk ) +{ + uint8 i; + llStatus_t status; + llConnState_t* connPtr; + + // make sure we're in Master role + if ( llState != LL_STATE_CONN_MASTER ) + { + return( LL_STATUS_ERROR_COMMAND_DISALLOWED ); + } + + // check parameters + if ( (rand == NULL) || (eDiv == NULL) || (ltk == NULL) ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // make sure connection ID is valid + if ( (status=LL_ConnActive(connId)) != LL_STATUS_SUCCESS ) + { + return( status ); + } + + // get connection info + connPtr = &conn_param[connId]; + + // check if a feature response control procedure has taken place + if ( connPtr->featureSetInfo.featureRspRcved == FALSE ) + { + // it hasn't so re-load this device's local Feature Set to the + // connection as it may have been changed by the Host with HCI + // extenstion Set Local Feature Set command + for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + } + + // check if encryption is a supported feature set item + if ( (connPtr->featureSetInfo.featureSet[0] & LL_FEATURE_ENCRYPTION) != LL_FEATURE_ENCRYPTION ) + { + return( LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED ); + } + + // cache the master's random vector + // Note: The RAND will be left in LSO..MSO order as this is assumed to be the + // order of the bytes that will be returned to the Host. + for (i=0; iencInfo.RAND[i] = rand[i]; + } + + // cache the master's encryption diversifier + // Note: The EDIV will be left in LSO..MSO order as this is assumed to be the + // order of the bytes that will be returned to the Host. + connPtr->encInfo.EDIV[0] = eDiv[0]; + connPtr->encInfo.EDIV[1] = eDiv[1]; + + // cache the master's long term key + // Note: The order of the bytes will be maintained as MSO..LSO + // per FIPS 197 (AES). + for (i=0; iencInfo.LTK[(LL_ENC_LTK_LEN-i)-1] = ltk[i]; + } + + // generate SKDm + // Note: The SKDm LSO is the LSO of the SKD. + // Note: Placement of result forms concatenation of SKDm and SKDs. + // Note: The order of the bytes will be maintained as MSO..LSO + // per FIPS 197 (AES). + LL_ENC_GenDeviceSKD( &connPtr->encInfo.SKD[ LL_ENC_SKD_M_OFFSET ] ); + // generate IVm + // Note: The IVm LSO is the LSO of the IV. + // Note: Placement of result forms concatenation of IVm and IVs. + // Note: The order of the bytes will be maintained as MSO..LSO + // per FIPS 197 (AES). + LL_ENC_GenDeviceIV( &connPtr->encInfo.IV[ LL_ENC_IV_M_OFFSET ] ); + // schedule a cache update of FIPS TRNG values for next SKD/IV usage +// postRfOperations |= LL_POST_RADIO_CACHE_RANDOM_NUM; + // Ôö¼ÓÖØÐÂÉú³ÉcachedTRNGdata´¦Àí£¬ÊµÏÖmasterʱÐè²âÊÔ + (void)LL_ENC_GenerateTrueRandNum( cachedTRNGdata, LL_ENC_TRUE_RAND_BUF_SIZE ); + // set flag to stop all outgoing transmissions + connPtr->txDataEnabled = FALSE; + // invalidate the existing session key, if any + connPtr->encInfo.SKValid = FALSE; + // indicate the LTK is not valid + connPtr->encInfo.LTKValid = FALSE; + + // check if we are already in encryption mode + if ( connPtr->encEnabled == TRUE ) + { + // set a flag to indicate this is a restart (i.e. pause-then-start) + connPtr->encInfo.encRestart = TRUE; + // setup a pause encryption control procedure + llEnqueueCtrlPkt( connPtr, LL_CTRL_PAUSE_ENC_REQ ); + } + else // no, so... + { + // clear flag to indicate this is an encryption setup + connPtr->encInfo.encRestart = FALSE; + // setup an encryption control procedure + llEnqueueCtrlPkt( connPtr, LL_CTRL_ENC_REQ ); + } + + return( LL_STATUS_SUCCESS ); +} + + +llStatus_t LL_WriteSuggestedDefaultDataLength(uint16 TxOctets,uint16 TxTime) +{ + if(TxOctets > LL_PDU_LENGTH_SUPPORTED_MAX_TX_OCTECTS + || TxTime > LL_PDU_LENGTH_SUPPORTED_MAX_TX_TIME + || TxOctets < LL_PDU_LENGTH_INITIAL_MAX_TX_OCTECTS + || TxTime < LL_PDU_LENGTH_INITIAL_MAX_TX_TIME) + { + return(LL_STATUS_ERROR_PARAM_OUT_OF_RANGE); + } + else + { + g_llPduLen.suggested.MaxTxOctets= TxOctets; + g_llPduLen.suggested.MaxRxTime = TxTime; + return(LL_STATUS_SUCCESS); + } +} + +llStatus_t LL_SetDataLengh0( uint16 connId,uint16 TxOctets,uint16 TxTime ) +{ + uint8 i; + llStatus_t status; + llConnState_t* connPtr; + + if(TxOctets > LL_PDU_LENGTH_SUPPORTED_MAX_TX_OCTECTS + || TxTime > LL_PDU_LENGTH_SUPPORTED_MAX_TX_TIME + || TxOctets < LL_PDU_LENGTH_INITIAL_MAX_TX_OCTECTS + || TxTime < LL_PDU_LENGTH_INITIAL_MAX_TX_TIME) + { + return(LL_STATUS_ERROR_PARAM_OUT_OF_RANGE); + } + + // make sure connection ID is valid + if ( (status=LL_ConnActive(connId)) != LL_STATUS_SUCCESS ) + { + return( status ); + } + + // get connection info + connPtr = &conn_param[connId]; + + // check if a feature response control procedure has taken place + if ( connPtr->featureSetInfo.featureRspRcved == FALSE ) + { + // it hasn't so re-load this device's local Feature Set to the + // connection as it may have been changed by the Host with HCI + // extenstion Set Local Feature Set command + for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + } + + // check if dle is a supported feature set item + if ( (connPtr->featureSetInfo.featureSet[0] & LL_FEATURE_DATA_LENGTH_EXTENSION) != LL_FEATURE_DATA_LENGTH_EXTENSION ) + { + return( LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED ); + } + + // check if an updated parameters control procedure is already what's pending + if ( ((connPtr->ctrlPktInfo.ctrlPktCount > 0) && + (connPtr->ctrlPktInfo.ctrlPkts[0] == LL_CTRL_LENGTH_REQ)) || + (connPtr->llPduLen.isProcessingReq == TRUE) || (connPtr->llPduLen.isWatingRsp == TRUE) ) + { + return( LL_STATUS_ERROR_CTRL_PROC_ALREADY_ACTIVE ); + } + +// g_llPduLen.suggested.MaxTxOctets = TxOctets; // remove by HZF, suggested value is from host, should not change in controller +// g_llPduLen.suggested.MaxTxTime = TxTime; + // setup an LL_LENGTH_REQ + llEnqueueCtrlPkt( connPtr, LL_CTRL_LENGTH_REQ ); + return(LL_STATUS_SUCCESS); +} + + +llStatus_t LL_SetDefaultPhyMode( uint16 connId,uint8 allPhy,uint8 txPhy, uint8 rxPhy) +{ + conn_param[connId].llPhyModeCtrl.def.allPhy = allPhy; + conn_param[connId].llPhyModeCtrl.def.txPhy = txPhy; + conn_param[connId].llPhyModeCtrl.def.rxPhy = rxPhy; + return( LL_STATUS_SUCCESS ); +} + + +llStatus_t LL_SetPhyMode0( uint16 connId,uint8 allPhy,uint8 txPhy, uint8 rxPhy,uint16 phyOptions) +{ + uint8 i; + llStatus_t status; + llConnState_t* connPtr; + + // make sure connection ID is valid + if ( (status=LL_ConnActive(connId)) != LL_STATUS_SUCCESS ) + { + return( status ); + } + + // get connection info + connPtr = &conn_param[connId]; + + // check if a feature response control procedure has taken place + if ( connPtr->featureSetInfo.featureRspRcved == FALSE ) + { + // it hasn't so re-load this device's local Feature Set to the + // connection as it may have been changed by the Host with HCI + // extenstion Set Local Feature Set command + for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + } + + // check if dle is a supported feature set item + if( ( (connPtr->featureSetInfo.featureSet[1] & LL_FEATURE_2M_PHY) != LL_FEATURE_2M_PHY ) + && ( (connPtr->featureSetInfo.featureSet[1] & LL_FEATURE_CODED_PHY) != LL_FEATURE_CODED_PHY ) ) + { + return( LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED ); + } + + // check if an updated parameters control procedure is already what's pending + if ( ((connPtr->ctrlPktInfo.ctrlPktCount > 0) && + (connPtr->ctrlPktInfo.ctrlPkts[0] == LL_CTRL_PHY_REQ)) || + (connPtr->pendingPhyModeUpdate== TRUE) || + (connPtr->llPhyModeCtrl.isWatingRsp == TRUE) || (connPtr->llPhyModeCtrl.isProcessingReq == TRUE) ) + { + return( LL_STATUS_ERROR_CTRL_PROC_ALREADY_ACTIVE ); + } + + //support Symmetric Only + if(allPhy==0 &&(txPhy!=rxPhy)) + { + return( LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED ); + } + + // how to check the required param? + //LL_TS_5.0.3 Table 4.43: PDU payload contents for each case variation for LE 2M PHY + connPtr->llPhyModeCtrl.req.allPhy = allPhy; + + if(connPtr->llPhyModeCtrl.req.allPhy==0) + { + connPtr->llPhyModeCtrl.req.txPhy = txPhy; + connPtr->llPhyModeCtrl.req.rxPhy = txPhy; + } + else if(connPtr->llPhyModeCtrl.req.allPhy==1) + { + connPtr->llPhyModeCtrl.req.txPhy = 0; + connPtr->llPhyModeCtrl.req.rxPhy = txPhy; + } + else if(connPtr->llPhyModeCtrl.req.allPhy==2) + { + connPtr->llPhyModeCtrl.req.txPhy = txPhy; + connPtr->llPhyModeCtrl.req.rxPhy = 0; + } + else + { + //no prefer on both phy + connPtr->llPhyModeCtrl.req.txPhy = 0; + connPtr->llPhyModeCtrl.req.rxPhy = 0; + } + + connPtr->llPhyModeCtrl.phyOptions = phyOptions; + // setup an LL_LENGTH_REQ + llEnqueueCtrlPkt( connPtr, LL_CTRL_PHY_REQ ); + return(LL_STATUS_SUCCESS); +} + + +// add by HZF for resolving list +llStatus_t LL_AddResolvingListLDevice( uint8 addrType, + uint8* devAddr, + uint8* peerIrk, + uint8* localIrk) +{ + int i; + + if ( (llState == LL_STATE_ADV_UNDIRECTED) || + (llState == LL_STATE_ADV_DIRECTED) || + (llState == LL_STATE_ADV_SCAN) || + (llState == LL_STATE_ADV_NONCONN) || + (llState == LL_STATE_SCAN) || + (llState == LL_STATE_INIT) || + (llSecondaryState == LL_SEC_STATE_ADV) || + (llSecondaryState == LL_SEC_STATE_ADV_PENDING) || + (llSecondaryState == LL_SEC_STATE_SCAN) || + (llSecondaryState == LL_SEC_STATE_SCAN_PENDING) || + (llSecondaryState == LL_SEC_STATE_INIT) || + (llSecondaryState == LL_SEC_STATE_INIT_PENDING)) + { + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + } + + if (extInitInfo.scanMode == LL_SCAN_START) + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + + // check the RL device address type + if ( (addrType != LL_DEV_ADDR_TYPE_PUBLIC) && + (addrType != LL_DEV_ADDR_TYPE_RANDOM) ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // check if there was room for the entry + if (g_llRlDeviceNum >= LL_RESOLVINGLIST_ENTRY_NUM) + return( LL_STATUS_ERROR_RL_TABLE_FULL ); + + // add the device to a empty record + for (i = 0; i < LL_RESOLVINGLIST_ENTRY_NUM; i++) + { + if (g_llResolvinglist[i].peerAddrType == 0xff) // empty record + { + g_llResolvinglist[i].peerAddrType = addrType; + osal_memcpy(&g_llResolvinglist[i].peerAddr[0], &devAddr[0], LL_DEVICE_ADDR_LEN); + // TODO: should we revert the byte order??? + osal_memcpy(&g_llResolvinglist[i].localIrk[0], &localIrk[0], LL_ENC_IRK_LEN); + osal_memcpy(&g_llResolvinglist[i].peerIrk[0], &peerIrk[0], LL_ENC_IRK_LEN); + g_llRlDeviceNum ++; + break; + } + } + + return( LL_STATUS_SUCCESS ); +} + + +llStatus_t LL_RemoveResolvingListDevice( uint8* devAddr, + uint8 addrType ) +{ + int i, j; + + if ( (llState == LL_STATE_ADV_UNDIRECTED) || + (llState == LL_STATE_ADV_DIRECTED) || + (llState == LL_STATE_ADV_SCAN) || + (llState == LL_STATE_ADV_NONCONN) || + (llState == LL_STATE_SCAN) || + (llState == LL_STATE_INIT) || + (llSecondaryState == LL_SEC_STATE_ADV) || + (llSecondaryState == LL_SEC_STATE_ADV_PENDING) || + (llSecondaryState == LL_SEC_STATE_SCAN) || + (llSecondaryState == LL_SEC_STATE_SCAN_PENDING) || + (llSecondaryState == LL_SEC_STATE_INIT) || + (llSecondaryState == LL_SEC_STATE_INIT_PENDING)) + { + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + } + + if (extInitInfo.scanMode == LL_SCAN_START) + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + + // check the RL device address type + if ( (addrType != LL_DEV_ADDR_TYPE_PUBLIC) && + (addrType != LL_DEV_ADDR_TYPE_RANDOM) ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // check that there was at least one entry in the table + if ( g_llRlDeviceNum == 0 ) + { + return( LL_STATUS_ERROR_RL_TABLE_EMPTY ); + } + + for (i = 0; i < LL_RESOLVINGLIST_ENTRY_NUM; i++) + { + if (g_llResolvinglist[i].peerAddrType == addrType) + { + for (j = 0; j < LL_DEVICE_ADDR_LEN; j++) // check whether the address is the same + { + if (g_llResolvinglist[i].peerAddr[j] != devAddr[j]) + break; + } + + if (j == LL_DEVICE_ADDR_LEN) // found it + { + g_llResolvinglist[i].peerAddrType = 0xff; + g_llResolvinglist[i].privacyMode = NETWORK_PRIVACY_MODE; + g_llRlDeviceNum --; + break; + } + } + } + + if (i == LL_RESOLVINGLIST_ENTRY_NUM) + return( LL_STATUS_ERROR_RL_ENTRY_NOT_FOUND ); + + return( LL_STATUS_SUCCESS ); +} + +llStatus_t LL_ClearResolvingList( void ) +{ + int i; + + if ( (llState == LL_STATE_ADV_UNDIRECTED) || + (llState == LL_STATE_ADV_DIRECTED) || + (llState == LL_STATE_ADV_SCAN) || + (llState == LL_STATE_ADV_NONCONN) || + (llState == LL_STATE_SCAN) || + (llState == LL_STATE_INIT) || + (llSecondaryState == LL_SEC_STATE_ADV) || + (llSecondaryState == LL_SEC_STATE_ADV_PENDING) || + (llSecondaryState == LL_SEC_STATE_SCAN) || + (llSecondaryState == LL_SEC_STATE_SCAN_PENDING) || + (llSecondaryState == LL_SEC_STATE_INIT) || + (llSecondaryState == LL_SEC_STATE_INIT_PENDING)) + { + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + } + + if (extInitInfo.scanMode == LL_SCAN_START) + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + + // clear number of entries, valid flags, address type flags, and entries + for (i = 0; i < LL_RESOLVINGLIST_ENTRY_NUM; i ++) + { + g_llResolvinglist[i].peerAddrType = 0xff; + g_llResolvinglist[i].privacyMode = NETWORK_PRIVACY_MODE; + memset(&g_llResolvinglist[i].peerAddr[0], 0, LL_DEVICE_ADDR_LEN); + } + + // set white list number 0 + g_llRlDeviceNum = 0; + return( LL_STATUS_SUCCESS ); +} + + +llStatus_t LL_ReadResolvingListSize( uint8* numEntries ) +{ + *numEntries = LL_RESOLVINGLIST_ENTRY_NUM; + return (LL_STATUS_SUCCESS); +} + +llStatus_t LL_ReadPeerResolvableAddress( uint8* peerRpa ) +{ + peerRpa[0] = g_currentPeerRpa[0]; + peerRpa[1] = g_currentPeerRpa[1]; + peerRpa[2] = g_currentPeerRpa[2]; + peerRpa[3] = g_currentPeerRpa[3]; + peerRpa[4] = g_currentPeerRpa[4]; + peerRpa[5] = g_currentPeerRpa[5]; + return (LL_STATUS_SUCCESS); +} + +llStatus_t LL_ReadLocalResolvableAddress( uint8* localRpa ) +{ + localRpa[0] = g_currentPeerRpa[0]; + localRpa[1] = g_currentPeerRpa[1]; + localRpa[2] = g_currentPeerRpa[2]; + localRpa[3] = g_currentPeerRpa[3]; + localRpa[4] = g_currentPeerRpa[4]; + localRpa[5] = g_currentPeerRpa[5]; + return (LL_STATUS_SUCCESS); +} + +// enable : 1 - enable, 0 - disable +llStatus_t LL_SetAddressResolutionEnable( uint8 enable ) +{ + if ( (llState == LL_STATE_ADV_UNDIRECTED) || + (llState == LL_STATE_ADV_DIRECTED) || + (llState == LL_STATE_ADV_SCAN) || + (llState == LL_STATE_ADV_NONCONN) || + (llState == LL_STATE_SCAN) || + (llState == LL_STATE_INIT) || + (llSecondaryState == LL_SEC_STATE_ADV) || + (llSecondaryState == LL_SEC_STATE_ADV_PENDING) || + (llSecondaryState == LL_SEC_STATE_SCAN) || + (llSecondaryState == LL_SEC_STATE_SCAN_PENDING) || + (llSecondaryState == LL_SEC_STATE_INIT) || + (llSecondaryState == LL_SEC_STATE_INIT_PENDING)) + { + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + } + + if (extInitInfo.scanMode == LL_SCAN_START) + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + + g_llRlEnable = enable; +// if (g_llRlEnable == TRUE) +// osal_start_timerEx( LL_TaskID, LL_EVT_RPA_TIMEOUT, g_llRlTimeout * 1000 ); +// else // FALSE +// osal_stop_timerEx(LL_TaskID, LL_EVT_RPA_TIMEOUT); + return( LL_STATUS_SUCCESS ); +} + +llStatus_t LL_SetResolvablePrivateAddressTimeout( uint16 rpaTimeout ) +{ + g_llRlTimeout = rpaTimeout; +// if (g_llRlEnable == TRUE) +// osal_start_timerEx( LL_TaskID, LL_EVT_RPA_TIMEOUT, g_llRlTimeout * 1000 ); + return( LL_STATUS_SUCCESS ); +} + +llStatus_t LL_Set_Privacy_Mode(uint8 peerIdType, + uint8* peerIdAddr, + uint8 privacyMode) +{ + int i, j; + + // search the peer address in the resolving address list + if ( g_llRlDeviceNum == 0 ) + { + return( LL_STATUS_ERROR_RL_TABLE_EMPTY ); + } + + for (i = 0; i < LL_RESOLVINGLIST_ENTRY_NUM; i++) + { + if (g_llResolvinglist[i].peerAddrType == peerIdType) + { + for (j = 0; j < LL_DEVICE_ADDR_LEN; j++) // check whether the address is the same + { + if (g_llResolvinglist[i].peerAddr[j] != peerIdAddr[j]) + break; + } + + if (j == LL_DEVICE_ADDR_LEN) // found it + break; + } + } + + if (i == LL_RESOLVINGLIST_ENTRY_NUM) + return( LL_STATUS_ERROR_UNKNOWN_CONN_HANDLE ); + + g_llResolvinglist[i].privacyMode = privacyMode; + return LL_STATUS_SUCCESS; +} + +// extend advertisement function + +/******************************************************************************* + @fn LL_SetExtAdvSetRandomAddress + + @brief This function is used to set random address for a advertisement set + + input parameters + + @param adv_handle - advertisement set handler + random_address - random address + + output parameters + + @param none + + @return LL_STATUS_SUCCESS, error code(TBD) +*/ +llStatus_t LL_SetExtAdvSetRandomAddress( uint8 adv_handle, + uint8* random_address + ) +{ + int i; + + // extended advertiser memory is allocate by application, return fail if not + if (g_pExtendedAdvInfo == NULL) + return LL_STATUS_ERROR_OUT_OF_HEAP; + + // search advertisement handler list + for (i = 0; i < g_extAdvNumber; i ++) + { + if (g_pExtendedAdvInfo[i].advHandle == adv_handle) + break; + } + + // if not found, then adv parameter has not been set + if (i == g_extAdvNumber) + return LL_STATUS_ERROR_UNKNOWN_ADV_ID; + + g_pExtendedAdvInfo[i].parameter.isOwnRandomAddressSet = TRUE; + memcpy(&g_pExtendedAdvInfo[i].parameter.ownRandomAddress[0], random_address, LL_DEVICE_ADDR_LEN); + return( LL_STATUS_SUCCESS ); +} + + +/******************************************************************************* + @fn LL_SetExtAdvParam + + @brief This function is used to set extend advertiser parameters + + input parameters + + @param adv_handle - advertisement set handler + + + output parameters + + @param none + + @return LL_STATUS_SUCCESS, error code(TBD) +*/ +llStatus_t LL_SetExtAdvParam( uint8 adv_handle, + uint16 adv_event_properties, + uint32 primary_advertising_interval_Min, // 3 octets + uint32 primary_advertising_interval_Max, // 3 octets + uint8 primary_advertising_channel_map, + uint8 own_address_type, + uint8 peer_address_type, + uint8* peer_address, + uint8 advertising_filter_policy, + int8 advertising_tx_power, + uint8 primary_advertising_PHY, + uint8 secondary_advertising_max_skip, + uint8 secondary_advertising_PHY, + uint8 advertising_SID, + uint8 scan_request_notification_enable, + int8* selectTxPwr + ) +{ + int i; + + // TODO: add parameters range checking + if (g_llAdvMode == LL_MODE_LEGACY) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llAdvMode = LL_MODE_EXTENDED; + + if ((adv_event_properties & LE_ADV_PROP_LEGACY_BITMASK) // Legacy Adv + && (adv_event_properties != LL_EXT_ADV_PROP_ADV_IND) + && (adv_event_properties != LL_EXT_ADV_PROP_ADV_LDC_ADV) + && (adv_event_properties != LL_EXT_ADV_PROP_ADV_HDC_ADV) + && (adv_event_properties != LL_EXT_ADV_PROP_ADV_SCAN_IND) + && (adv_event_properties != LL_EXT_ADV_PROP_ADV_NOCONN_IND)) + return LL_STATUS_ERROR_BAD_PARAMETER; + + if (primary_advertising_interval_Max < primary_advertising_interval_Min + || primary_advertising_interval_Min < 0x20 + || primary_advertising_interval_Max < 0x20) + return LL_STATUS_ERROR_BAD_PARAMETER; + + // check whether aux adv pdu resource period is OK for max skip & adv interval setting + if (!(adv_event_properties & LE_ADV_PROP_LEGACY_BITMASK) // not legacy Adv + && primary_advertising_interval_Max * (secondary_advertising_max_skip + 1) * 625 < g_advSlotPeriodic) + return LL_STATUS_ERROR_BAD_PARAMETER; + + // extended advertiser memory is allocate by application, return fail if not + if (g_pExtendedAdvInfo == NULL) + return LL_STATUS_ERROR_OUT_OF_HEAP; + + // search advertisement handler list + for (i = 0; i < g_extAdvNumber; i ++) + { + if (g_pExtendedAdvInfo[i].advHandle == adv_handle) + break; + } + + // if not found, search the 1st available slot + if (i == g_extAdvNumber) + { + for (i = 0; i < g_extAdvNumber; i ++) + { + if (g_pExtendedAdvInfo[i].advHandle == LL_INVALID_ADV_SET_HANDLE) + { + uint8* scanRspData = g_pExtendedAdvInfo[i].scanRspData; + uint8* advData = g_pExtendedAdvInfo[i].data.advertisingData; + memset(&g_pExtendedAdvInfo[i], 0, sizeof(extAdvInfo_t)); + g_pExtendedAdvInfo[i].scanRspData = scanRspData; + g_pExtendedAdvInfo[i].data.advertisingData = advData; + break; + } + } + } + + if (i == g_extAdvNumber) + return LL_STATUS_ERROR_OUT_OF_HEAP; + + // save the advertisement parameters + g_pExtendedAdvInfo[i].advHandle = adv_handle; + g_pExtendedAdvInfo[i].parameter.advEventProperties = adv_event_properties; + g_pExtendedAdvInfo[i].parameter.priAdvIntMin = primary_advertising_interval_Min; + g_pExtendedAdvInfo[i].parameter.priAdvgIntMax = primary_advertising_interval_Max; + g_pExtendedAdvInfo[i].parameter.priAdvChnMap = primary_advertising_channel_map; + g_pExtendedAdvInfo[i].parameter.ownAddrType = own_address_type; + g_pExtendedAdvInfo[i].parameter.peerAddrType = peer_address_type; + memcpy(g_pExtendedAdvInfo[i].parameter.peerAddress, peer_address, LL_DEVICE_ADDR_LEN); + g_pExtendedAdvInfo[i].parameter.wlPolicy = advertising_filter_policy; + g_pExtendedAdvInfo[i].parameter.advTxPower = advertising_tx_power; + g_pExtendedAdvInfo[i].parameter.primaryAdvPHY = primary_advertising_PHY; + g_pExtendedAdvInfo[i].parameter.secondaryAdvPHY = secondary_advertising_PHY; + g_pExtendedAdvInfo[i].parameter.secondaryAdvMaxSkip= secondary_advertising_max_skip; + g_pExtendedAdvInfo[i].parameter.advertisingSID = advertising_SID; + g_pExtendedAdvInfo[i].parameter.scanReqNotificationEnable = scan_request_notification_enable; + + // =========== controller select parameters, TBD + // decide primary advertising interval. The aux PDU period is decided by global_config, the primary adv interval + // should be set considering the maximum skip AUX PDU requirement + if (primary_advertising_interval_Min * (secondary_advertising_max_skip + 1) * 625 > g_advSlotPeriodic) + g_pExtendedAdvInfo[i].primary_advertising_interval = primary_advertising_interval_Min * 625; // bug fiex 04-08, * 1250 -> * 625 + else + g_pExtendedAdvInfo[i].primary_advertising_interval = primary_advertising_interval_Max * 625; + + // select Tx power and return + g_pExtendedAdvInfo[i].tx_power = advertising_tx_power; + *selectTxPwr = advertising_tx_power; + g_pExtendedAdvInfo[i].isPeriodic = FALSE; + return( LL_STATUS_SUCCESS ); +} + + +/******************************************************************************* + @fn LL_SetExtAdvData + + @brief This function is used to set extend advertiser set data + + input parameters + + @param adv_handle - advertisement set handler + + + output parameters + + @param none + + @return LL_STATUS_SUCCESS, error code(TBD) +*/ +llStatus_t LL_SetExtAdvData( uint8 adv_handle, + uint8 operation, + uint8 fragment_preference, + uint8 advertising_data_length, + uint8* advertising_data + ) +{ + int i; + + // TODO: add parameters range checking + if (g_llAdvMode == LL_MODE_LEGACY) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llAdvMode = LL_MODE_EXTENDED; + + if (operation > BLE_EXT_ADV_OP_UNCHANGED_DATA) + return LL_STATUS_ERROR_BAD_PARAMETER; + + // extended advertiser memory is allocate by application, return fail if not + if (g_pExtendedAdvInfo == NULL) + return LL_STATUS_ERROR_OUT_OF_HEAP; + + // search advertisement handler list + for (i = 0; i < g_extAdvNumber; i ++) + { + if (g_pExtendedAdvInfo[i].advHandle == adv_handle) + break; + } + + // if not found, then adv parameter has not been set + if (i == g_extAdvNumber) + return LL_STATUS_ERROR_UNKNOWN_ADV_ID; + + // comment out 04-10, set adv data should be received after set adv parameter +// { +// for (i = 0; i < g_extAdvNumber; i ++) +// { +// if (g_pExtendedAdvInfo[i].advHandle == LL_INVALID_ADV_SET_HANDLE) +// break; +// } +// if (i == g_extAdvNumber) +// return LL_STATUS_ERROR_OUT_OF_HEAP; +// +// // set DID when 1st create the data set +// LL_Rand((uint8*)&g_pExtendedAdvInfo[i].data.DIDInfo, 2); +// } + + // check legacy ADV data length should <= 31 + if (ll_isLegacyAdv(&g_pExtendedAdvInfo[i]) + && (operation != BLE_EXT_ADV_OP_COMPLETE_DATA + || advertising_data_length > 31)) + return LL_STATUS_ERROR_BAD_PARAMETER; + + if (operation == BLE_EXT_ADV_OP_FIRST_FRAG || + operation == BLE_EXT_ADV_OP_COMPLETE_DATA) + g_pExtendedAdvInfo[i].data.advertisingDataLength = 0; + + if (g_pExtendedAdvInfo[i].data.advertisingDataLength + advertising_data_length > g_advSetMaximumLen) + { + g_pExtendedAdvInfo[i].data.advertisingDataLength = 0; + return LL_STATUS_ERROR_OUT_OF_HEAP; + } + + // fill advertising set + g_pExtendedAdvInfo[i].advHandle = adv_handle; + g_pExtendedAdvInfo[i].data.fragmentPreference = fragment_preference; + memcpy(&g_pExtendedAdvInfo[i].data.advertisingData[g_pExtendedAdvInfo[i].data.advertisingDataLength], + advertising_data, advertising_data_length); + g_pExtendedAdvInfo[i].data.advertisingDataLength += advertising_data_length; + + // last fragment or 1 segment adv data + if (operation == BLE_EXT_ADV_OP_LAST_FRAG || + operation == BLE_EXT_ADV_OP_COMPLETE_DATA ) + g_pExtendedAdvInfo[i].data.dataComplete = TRUE; + + if (operation == BLE_EXT_ADV_OP_LAST_FRAG || + operation == BLE_EXT_ADV_OP_COMPLETE_DATA || + operation == BLE_EXT_ADV_OP_UNCHANGED_DATA ) // unchange data, just update DID + { + // update DID + g_pExtendedAdvInfo[i].data.DIDInfo = ll_generateExtAdvDid(g_pExtendedAdvInfo[i].data.DIDInfo); + } + + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + @fn LL_SetExtScanRspData + + @brief This function is used to set extend scan response data + + input parameters + + @param adv_handle - advertisement set handler + + + output parameters + + @param none + + @return LL_STATUS_SUCCESS, error code(TBD) +*/ +llStatus_t LL_SetExtScanRspData( uint8 adv_handle, + uint8 operation, + uint8 fragment_preference, + uint8 scan_rsp_data_length, + uint8* scan_rsp_data + ) +{ + int i; + + if (g_llAdvMode == LL_MODE_LEGACY) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llAdvMode = LL_MODE_EXTENDED; + + if (operation != BLE_EXT_ADV_OP_COMPLETE_DATA) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + // extended advertiser memory is allocate by application, return fail if not + if (g_pExtendedAdvInfo == NULL) + return LL_STATUS_ERROR_OUT_OF_HEAP; + + // search advertisement handler list + for (i = 0; i < g_extAdvNumber; i ++) + { + if (g_pExtendedAdvInfo[i].advHandle == adv_handle) + break; + } + + // if not found, then adv parameter has not been set + if (i == g_extAdvNumber) + return LL_STATUS_ERROR_UNKNOWN_ADV_ID; + + // check legacy ADV scan rsp data length should <= 31 + if (ll_isLegacyAdv(&g_pExtendedAdvInfo[i]) + && (operation != BLE_EXT_ADV_OP_COMPLETE_DATA + || scan_rsp_data_length > 31)) + return LL_STATUS_ERROR_BAD_PARAMETER; + +// // if not found, search the 1st available slot +// if (i == g_extAdvNumber) +// { +// for (i = 0; i < g_extAdvNumber; i ++) +// { +// if (g_pExtendedAdvInfo[i].advHandle == LL_INVALID_ADV_SET_HANDLE) +// break; +// } +// if (i == g_extAdvNumber) +// return LL_STATUS_ERROR_OUT_OF_HEAP; +// } + + if (g_pExtendedAdvInfo[i].scanRspData == NULL || g_advSetMaximumLen < scan_rsp_data_length) + return LL_STATUS_ERROR_OUT_OF_HEAP; + + memcpy(&g_pExtendedAdvInfo[i].scanRspData[0], scan_rsp_data, scan_rsp_data_length); + g_pExtendedAdvInfo[i].scanRspMaxLength = scan_rsp_data_length; + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + @fn LL_SetExtAdvEnable + + @brief This function is used to enable/disable extend advertise + + input parameters + + @param enable - enable/disable + + + output parameters + + @param none + + @return LL_STATUS_SUCCESS, error code(TBD) +*/ +llStatus_t LL_SetExtAdvEnable( uint8 enable, + uint8 number_of_sets, + uint8* advertising_handle, + uint16* duration, + uint8* max_extended_advertising_events) +{ + int i, j; + extAdvInfo_t* pExtAdv[64]; + periodicAdvInfo_t* pPrdAdv[64]; + + // TODO: add more sanity checking to align to the spec + if (g_llAdvMode == LL_MODE_LEGACY) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llAdvMode = LL_MODE_EXTENDED; + + if (number_of_sets == 0 && enable == TRUE) + return LL_STATUS_ERROR_UNEXPECTED_PARAMETER; + + // the adv parameter should be present for the adv_handler, otherwise, it will return Unknown Advertising Identifier(0x42) + for (i = 0; i < number_of_sets; i++) + { + pExtAdv[i] = NULL; + pPrdAdv[i] = NULL; + + for (j = 0; j < g_extAdvNumber; j++) + { + if (g_pExtendedAdvInfo[j].advHandle == advertising_handle[i]) + { + pExtAdv[i] = &g_pExtendedAdvInfo[j]; + break; + } + } + + if (pExtAdv[i] == NULL) // adv handle not found + return LL_STATUS_ERROR_UNKNOWN_ADV_ID; + + if (ll_isLegacyAdv(pExtAdv[i])) + { + if (pExtAdv[i]->data.advertisingDataLength > 31) + return LL_STATUS_ERROR_ILLEGAL_PARAM_COMBINATION; + } + + if ((pExtAdv[i]->parameter.advEventProperties & LE_ADV_PROP_SCAN_BITMASK) + && (pExtAdv[i]->scanRspData == NULL || pExtAdv[i]->scanRspMaxLength == 0)) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + if (pExtAdv[i]->parameter.ownAddrType == LL_DEV_ADDR_TYPE_RANDOM + && pExtAdv[i]->parameter.isOwnRandomAddressSet == FALSE) + return LL_STATUS_ERROR_BAD_PARAMETER; + + // TODO: If the advertising set's Own_Address_Type parameter is set to 0x03, the + // controller's resolving list did not contain a matching entry, and the random + // address for the advertising set has not been initialized, the Controller shall + // return the error code Invalid HCI Command Parameters (0x12). + +// pExtAdv[i]->isPeriodic = FALSE; +// // if periodic adv is support, check whether the adv set is periodic adv +// if (g_pPeriodicAdvInfo != NULL) +// { +// for (j = 0; j < g_perioAdvNumber; j ++) +// { +// if (g_pPeriodicAdvInfo[j].advHandle == pExtAdv[i]->advHandle) +// { +// pExtAdv[i]->isPeriodic = TRUE; +// index = j; +// break; +// } +// } +// } + + // for periodic adv, search the period adv context + if (pExtAdv[i]->isPeriodic == TRUE) + { + for (j = 0; j < g_perioAdvNumber; j ++) + { + if (g_pPeriodicAdvInfo[j].advHandle == pExtAdv[i]->advHandle) + { + pPrdAdv[i] = &g_pPeriodicAdvInfo[j]; + break; + } + } + + if (pPrdAdv[i] == NULL) + return LL_STATUS_ERROR_UNKNOWN_ADV_ID; + } + + // for enable adv case, the adv set data should be complete, + // otherwise, it shall return Command Disallowed(0x0C) + if (enable == TRUE) + { + if ((pExtAdv[i]->isPeriodic == FALSE && pExtAdv[i]->data.dataComplete == FALSE) + || (pExtAdv[i]->isPeriodic == TRUE && pPrdAdv[i]->data.dataComplete == FALSE)) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + } + } + + // check OK, save the enable info + for (i = 0; i < number_of_sets; i++) + { + pExtAdv[i]->active = enable; + + if (enable == TRUE) + { + // only save parameters in enable case + pExtAdv[i]->duration = duration[i] * 10000; // 10000: unit 10ms, convert to us + pExtAdv[i]->maxExtAdvEvents = max_extended_advertising_events[i]; + } + } + + // ====== update extend advertiser scheduler to apply new parameters + if (enable == FALSE) + { + // case 1: number of set is 0, disable all adv case. Remove the adv from adv schduler + if (number_of_sets == 0) + { + for (i = 0; i < g_extAdvNumber; i ++) // bug fixed 04-07 + { + if (g_pAdvSchInfo[i].adv_handler == LL_INVALID_ADV_SET_HANDLE) + continue; + + ll_delete_adv_task(i); + } + + // periodic adv case, disable all EXT_ADV_IND + AUX_ADV_IND of periodic adv. It should be OK + // by set the active flag to FALSE. TO BE TEST. + for (i = 0; i < g_perioAdvNumber; i ++) + { + if (g_pAdvSchInfo_periodic[i].adv_handler == LL_INVALID_ADV_SET_HANDLE) + continue; + + g_pAdvSchInfo_periodic[i].pAdvInfo->active = FALSE; + } + } + // case 2: disable the adv in the adv set list + else + { + for (i = 0; i < number_of_sets; i ++) + { + // search the adv in the scheduler list and disable it + for (j = 0; j < g_schExtAdvNum; j++) + { + if (g_pAdvSchInfo[j].adv_handler == pExtAdv[i]->advHandle) + { + ll_delete_adv_task(j); + break; + } + } + + // for periodic adv, only de-active the extended adv part. + // for extended adv, the active flag have already been set by ll_delete_adv_task() + // but it is harmless to set it again + pExtAdv[i]->active = FALSE; + } + } + } + else // enable case + { + for (i = 0; i < number_of_sets; i++) + { + for (j = 0; j < g_schExtAdvNum; j++) + { + // check whether the adv already started + if (g_pAdvSchInfo[j].adv_handler == pExtAdv[i]->advHandle) // the adv in the scheduler list + { + // TODO: adv already enable, it should: + // If the HCI_LE_Set_Extended_Advertising_Enable command is sent again for + // an advertising set while that set is enabled, the timer used for the duration and + // the number of events counter are reset and any change to the random address + // shall take effect + break; + } + } + + // new extended adv case + if (j == g_schExtAdvNum && pExtAdv[i]->isPeriodic == FALSE) + ll_add_adv_task(pExtAdv[i]); + + // new periodic adv case + if (j == g_schExtAdvNum && pExtAdv[i]->isPeriodic == TRUE) + { + // check whether the corresponding periodic adv is enable + // 1. enable, start periodic adv + // 2. disable, do nothing + if (pPrdAdv[i]->active == TRUE) + ll_add_adv_task_periodic(pPrdAdv[i], pExtAdv[i]); + } + } + } + + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + @fn LL_ReadMaximumAdvDataLength + + @brief This function is used to read the maximum adv set data length support by controller + + input parameters + + @param adv_handle - advertisement set handler + + + output parameters + + @param length - pointer to the variable of maximum data length support + + @return LL_STATUS_SUCCESS, error code(TBD) +*/ +llStatus_t LL_ReadMaximumAdvDataLength( uint16* length ) +{ + *length = LL_MAX_ADVERTISER_SET_LENGTH; // TBD. + + if (g_llAdvMode == LL_MODE_LEGACY) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llAdvMode = LL_MODE_EXTENDED; + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + @fn LL_ReadNumberOfSupportAdvSet + + @brief This function is used to read number of adv set supported by controller + + input parameters + + @param adv_handle - advertisement set handler + + + output parameters + + @param none + + @return LL_STATUS_SUCCESS, error code(TBD) +*/ +llStatus_t LL_ReadNumberOfSupportAdvSet( uint8* number ) +{ + if (g_llAdvMode == LL_MODE_LEGACY) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llAdvMode = LL_MODE_EXTENDED; + *number = 240; // TBD + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + @fn LL_RemoveAdvSet + + @brief This function is used to remove advertisement set + + input parameters + + @param adv_handle - advertisement set handler + + + output parameters + + @param none + + @return LL_STATUS_SUCCESS, error code(TBD) +*/ +llStatus_t LL_RemoveAdvSet( uint8 adv_handle) +{ + uint8 i; + uint8 extIndex = 0xFF, prdIndex = 0xFF; + + if (g_llAdvMode == LL_MODE_LEGACY) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llAdvMode = LL_MODE_EXTENDED; + + // search extendedadvertisement handler list + for (i = 0; i < g_extAdvNumber; i ++) + { + if (g_pExtendedAdvInfo[i].advHandle == adv_handle) + { + extIndex = i; + break; + } + } + + // search advertisement handler list + for (i = 0; i < g_perioAdvNumber; i ++) + { + if (g_pPeriodicAdvInfo[i].advHandle == adv_handle) + { + prdIndex = i; + break; + } + } + + if (extIndex == 0xFF && prdIndex == 0xFF) + return LL_STATUS_ERROR_UNKNOWN_ADV_ID; + + if ((extIndex != 0xFF && g_pExtendedAdvInfo[extIndex].active == TRUE) + || (prdIndex != 0xFF && g_pPeriodicAdvInfo[prdIndex].active == TRUE)) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + if (extIndex != 0xFF) + { + uint8* scanRspData = g_pExtendedAdvInfo[extIndex].scanRspData; + uint8* advData = g_pExtendedAdvInfo[extIndex].data.advertisingData; + memset(&g_pExtendedAdvInfo[extIndex], 0, sizeof(extAdvInfo_t)); + g_pExtendedAdvInfo[extIndex].scanRspData = scanRspData; + g_pExtendedAdvInfo[extIndex].data.advertisingData = advData; + g_pExtendedAdvInfo[extIndex].advHandle = LL_INVALID_ADV_SET_HANDLE; + } + + if (prdIndex != 0xFF) + { + uint8* advData = g_pPeriodicAdvInfo[prdIndex].data.advertisingData; + memset(&g_pPeriodicAdvInfo[prdIndex], 0, sizeof(periodicAdvInfo_t)); + g_pPeriodicAdvInfo[prdIndex].data.advertisingData = advData; + g_pPeriodicAdvInfo[prdIndex].advHandle = LL_INVALID_ADV_SET_HANDLE; + } + + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + @fn LL_ClearAdvSets + + @brief This function is used to clear the stored advertisement sets in controller + + input parameters + + @param none + + + output parameters + + @param none + + @return LL_STATUS_SUCCESS, error code(TBD) +*/ +llStatus_t LL_ClearAdvSets(void) +{ + uint8 i; + + if (g_llAdvMode == LL_MODE_LEGACY) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llAdvMode = LL_MODE_EXTENDED; + + // check extendedadvertisement handler list + for (i = 0; i < g_extAdvNumber; i ++) + { + if (g_pExtendedAdvInfo[i].advHandle != LL_INVALID_ADV_SET_HANDLE + && g_pExtendedAdvInfo[i].active == TRUE) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + } + + // check periodic advertisement handler list + for (i = 0; i < g_perioAdvNumber; i ++) + { + if (g_pPeriodicAdvInfo[i].advHandle != LL_INVALID_ADV_SET_HANDLE + && g_pPeriodicAdvInfo[i].active == TRUE) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + } + + // clear adv set (extended adv part) + for (i = 0; i < g_extAdvNumber; i ++) + { + uint8* scanRspData = g_pExtendedAdvInfo[i].scanRspData; + uint8* advData = g_pExtendedAdvInfo[i].data.advertisingData; + memset(&g_pExtendedAdvInfo[i], 0, sizeof(extAdvInfo_t)); + g_pExtendedAdvInfo[i].scanRspData = scanRspData; + g_pExtendedAdvInfo[i].data.advertisingData = advData; + g_pExtendedAdvInfo[i].advHandle = LL_INVALID_ADV_SET_HANDLE; + } + + // clear adv set (periodic adv part) + for (i = 0; i < g_perioAdvNumber; i ++) + { + uint8* advData = g_pPeriodicAdvInfo[i].data.advertisingData; + memset(&g_pPeriodicAdvInfo[i], 0, sizeof(periodicAdvInfo_t)); + g_pPeriodicAdvInfo[i].data.advertisingData = advData; + g_pPeriodicAdvInfo[i].advHandle = LL_INVALID_ADV_SET_HANDLE; + } + + return( LL_STATUS_SUCCESS ); +} + + + +// ===================== extended scan/init +llStatus_t LL_SetExtendedScanParameters(uint8 own_address_type, + uint8 scanning_filter_policy, + uint8 scanning_PHYs, + uint8* scan_type, + uint16* scan_interval, + uint16* scan_window) +{ + uint8 number_phys, i; + + // TODO: sanity checking + if (g_llScanMode == LL_MODE_LEGACY ) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llScanMode = LL_MODE_EXTENDED; + + // If the Host specifies a PHY that is not supported by the Controller, including a bit that is reserved for future use, + // it should return the error code Unsupported Feature or Parameter Value(0x11). + if ((scanning_PHYs & (~(LL_SCAN_PHY_1M_BITMASK | LL_SCAN_PHY_CODED_BITMASK))) != 0) + return LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED; + + extScanInfo.ownAddrType = own_address_type; + extScanInfo.wlPolicy = scanning_filter_policy; + number_phys = 0; + + if (scanning_PHYs & LL_SCAN_PHY_1M_BITMASK) + { + extScanInfo.scanPHYs[number_phys] = PKT_FMT_BLE1M; + number_phys ++; + } + + if (scanning_PHYs & LL_SCAN_PHY_CODED_BITMASK) + { + extScanInfo.scanPHYs[number_phys] = PKT_FMT_BLR125K; + number_phys ++; + } + + for (i = 0; i < number_phys; i ++) + { + extScanInfo.scanType[i] = scan_type[i]; + extScanInfo.scanInterval[i] = scan_interval[i]; + extScanInfo.scanWindow[i] = scan_window[i]; + } + + extScanInfo.numOfScanPHY = number_phys; + return LL_STATUS_SUCCESS; +} + +llStatus_t LL_SetExtendedScanEnable(uint8 enable, + uint8 filter_duplicates, + uint16 duration, + uint16 period) +{ + // TODO: sanity checking + if (g_llScanMode == LL_MODE_LEGACY ) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llScanMode = LL_MODE_EXTENDED; + extScanInfo.enable = enable; + extScanInfo.filterDuplicate = filter_duplicates; + extScanInfo.duration = duration; + extScanInfo.period = period; + + // trigger scan task + if (enable == TRUE) + { + extScanInfo.current_index = 0; + extScanInfo.current_chn = LL_ADV_CHAN_FIRST; + extScanInfo.current_scan_PHY = extScanInfo.scanPHYs[extScanInfo.current_index]; + extScanInfo.adv_data_offset = 0; + llSetupExtScan(extScanInfo.current_chn); + } + else + { + } + + return LL_STATUS_SUCCESS; +} + +#define DBG_DISABLE_LATENCY 0 +llStatus_t LL_PLUS_DisableSlaveLatency0(uint8 connId) +{ + llConnState_t* connPtr; + uint16 next_event, elapse_event,chanMapDltEvt; + uint32 remain_time1, remain_time2; + uint32 old_timerDrift; + uint32 time_advance; + // get connection information + connPtr = &conn_param[connId]; // only 1 connection now, HZF + + // check whether it should recover from latency + if (FALSE == connPtr->active + || llState != LL_STATE_CONN_SLAVE + || llSecondaryState != LL_SEC_STATE_IDLE) + { + //LOG("==1==\n\r"); + return(LL_STATUS_DISABLE_LATENCY_INACTIVE_CONN); + } + + // TODO: if latency already disable , return + pGlobal_config[LL_SWITCH] &= ~SLAVE_LATENCY_ALLOW; + connPtr->slaveLatencyAllowed = FALSE; + + if ((AP_TIM1->ControlReg & 0x1) == 0 // timer1 not running + || llWaitingIrq + || connPtr->slaveLatency == 0) + { + //LOG("==2==%d,%d,%d\n\r",(CP_TIM1->ControlReg & 0x1),llWaitingIrq,connPtr->slaveLatency); + return (LL_STATUS_DISABLE_LATENCY_DISABLED); + } + + remain_time1 = read_LL_remainder_time(); + + if (remain_time1 <=connPtr->lastTimeToNextEvt*625* 3) // the timer will expiry soon, so not adjust it + { + //LOG("==3==\n\r"); + return(LL_STATUS_DISABLE_LATENCY_PENDING); + } + + uint16 remain_event; + remain_event=(remain_time1+connPtr->timerDrift)/(connPtr->lastTimeToNextEvt * 625); + //20190805 ZQ: + // considering the event wrap case + elapse_event= llEventDelta(connPtr->nextEvent,connPtr->currentEvent)-remain_event-(uint8)1; + // elapse_time=elapse_event*(connPtr->lastTimeToNextEvt * 625); + next_event= connPtr->currentEvent + elapse_event + (uint8)2; // additional 2 connect event for some margin + old_timerDrift = connPtr->timerDrift; + llCalcTimerDrift(connPtr->lastTimeToNextEvt, + elapse_event + 1, + connPtr->sleepClkAccuracy, + (uint32*)&(connPtr->timerDrift)); + // timer should expiry early, consider: 1. less timer drift 2. less latency event + //time_advance = connPtr->lastTimeToNextEvt * (connPtr->nextEvent - next_event) * 625 - (old_timerDrift - connPtr->timerDrift)+550; + time_advance = connPtr->lastTimeToNextEvt * (llEventDelta(connPtr->nextEvent,next_event) ) * 625 - (old_timerDrift - connPtr->timerDrift)+550; + // apply the timing advance + remain_time2 = AP_TIM1->CurrentCount >> 2; + + if(remain_time2slaveLatencyAllowed = TRUE; + return (LL_STATUS_DISABLE_LATENCY_MISS_EVT); + } + + set_timer(AP_TIM1,remain_time2 - time_advance); +// LOG("currentEvent = %d\r\n", connPtr->currentEvent); +// LOG("old next_event = %d\r\n", connPtr->nextEvent); +// LOG("new next_event = %d\r\n", next_event); + // update connection context + connPtr->currentEvent += elapse_event; + //connPtr->currentChan = old_chn; + //ZQ 20191209 : should use unmap channel + connPtr->currentChan = connPtr->lastCurrentChan; + + //ZQ 20190805 + // Max latency is 500, preChanMapUdate restore should be trigged within 500 evt + if(connPtr->preChanMapUpdate.chanMapUpdated==TRUE) + { + chanMapDltEvt = llEventDelta( connPtr->preChanMapUpdate.chanMapUpdateEvent, (connPtr->currentEvent + (uint8) 2)); + + //20190806 ZQ: + //only process the revert chanMap when chanMap Delta event with in (0 500) + if(chanMapDltEvt>0 && chanMapDltEvt<500) + { + connPtr->pendingChanUpdate = TRUE; + osal_memcpy(&(connPtr->chanMap[0]),&(connPtr->preChanMapUpdate.chanMap[0]),5); + llProcessChanMap(connPtr, connPtr->chanMap ); // 16MHz clk, cost 116us! + #if (DBG_DISABLE_LATENCY) + LOG("[Hit preChnMap] %d\n\r",connPtr->preChanMapUpdate.chanMapUpdateEvent); + #endif + } + } + + if (connPtr->channel_selection == LL_CHN_SEL_ALGORITHM_1) + connPtr->currentChan = llGetNextDataChan(connPtr, elapse_event + 2 ); + else + { + // channel selection algorithm 2 + connPtr->currentChan = llGetNextDataChanCSA2(next_event, + (( ( connPtr->accessAddr & 0xFFFF0000 )>> 16 ) ^ ( connPtr->accessAddr & 0x0000FFFF)), + connPtr->chanMap, + connPtr->chanMapTable, + connPtr->numUsedChans); + } + + //connPtr->slaveLatency -= (connPtr->nextEvent - next_event); + connPtr->slaveLatency -= llEventDelta(connPtr->nextEvent, next_event); + connPtr->nextEvent = next_event; +// +// LOG("==5==\n\r"); +// +// + #if (DBG_DISABLE_LATENCY) + LOG("new timer = %d\r\n", remain_time2 - time_advance); + LOG("old Drift = %d\,new Drift = %d \r\n", old_timerDrift,connPtr->timerDrift); + LOG("cur_event=%d,elapse_event=%d, next_event=%d,\r\n",connPtr->currentEvent, elapse_event,next_event); + LOG("RFCHN n=%d o=%d\r\n",connPtr->currentChan,connPtr->lastCurrentChan); + #endif + return(LL_STATUS_SUCCESS); +} + + +llStatus_t LL_PLUS_EnableSlaveLatency0(uint8 connId) +{ + llConnState_t* connPtr; + // get connection information + connPtr = &conn_param[connId]; // only 1 connection now. + + // check whether it should enable from disable_latency + if (FALSE == connPtr->active + || llState != LL_STATE_CONN_SLAVE + || llSecondaryState != LL_SEC_STATE_IDLE) + { + //LOG("==e1==\n\r"); + return(LL_STATUS_DISABLE_LATENCY_INACTIVE_CONN); + } + +// // check whether it should enable from disable_latency +// if ( connPtr->pendingChanUpdate == TRUE +// || connPtr->pendingParamUpdate == TRUE +// || connPtr->pendingPhyModeUpdate == TRUE) +// { +// LOG("==e2==\n\r"); +// return; +// } + pGlobal_config[LL_SWITCH] |= SLAVE_LATENCY_ALLOW; + connPtr->slaveLatencyAllowed = TRUE; + return(LL_STATUS_SUCCESS); +} + + +llStatus_t LL_ExtendedCreateConnection(uint8 initiator_filter_policy, + uint8 own_address_type, + uint8 peer_address_type, + uint8* peer_address, + uint8 initiating_PHYs, + uint16* scan_interval, + uint16* scan_window, + uint16* conn_interval_min, + uint16* conn_interval_max, + uint16* conn_latency, + uint16* supervision_timeout, + uint16* minimum_CE_length, + uint16* maximum_CE_length) +{ + uint8 number_phys, i; + llConnState_t* connPtr; + uint16 txHeader = 0x2205; + + if (g_llScanMode == LL_MODE_LEGACY ) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llScanMode = LL_MODE_EXTENDED; + + // TODO: more sanity checking + if ((initiating_PHYs & (~(LL_SCAN_PHY_1M_BITMASK | LL_CONN_PHY_2M_BITMASK | LL_SCAN_PHY_CODED_BITMASK)) != 0)) + return LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED; + + // ===== allocate a connection and assure it is valid + if ( (connPtr = llAllocConnId()) == NULL ) + { + llSecondaryState = LL_SEC_STATE_IDLE; // recover llSecondaryState + // exceeded the number of available connection structures + return( LL_STATUS_ERROR_CONNECTION_LIMIT_EXCEEDED ); + } + + // ================== save init parameters + extInitInfo.ownAddrType = own_address_type; + extInitInfo.wlPolicy = initiator_filter_policy; + number_phys = 0; + i = 0; + + if (initiating_PHYs & LL_SCAN_PHY_1M_BITMASK) + { + extInitInfo.initPHYs[number_phys] = PKT_FMT_BLE1M; + extInitInfo.scanInterval[number_phys] = scan_interval[i]; + extInitInfo.scanWindow[number_phys] = scan_window[i]; + extInitInfo.conn_latency[number_phys] = conn_latency[i]; + extInitInfo.supervision_timeout[number_phys] = supervision_timeout[i]; + extInitInfo.conn_interval_min[number_phys] = conn_interval_min[i]; + extInitInfo.conn_interval_max[number_phys] = conn_interval_max[i]; + extInitInfo.minimum_CE_length[number_phys] = minimum_CE_length[i]; + extInitInfo.maximum_CE_length[number_phys] = maximum_CE_length[i]; + number_phys ++; + i ++; + } + + if (initiating_PHYs & LL_CONN_PHY_2M_BITMASK) + { + extInitInfo.is_2M_parameter_present = TRUE; + // no scan parameters for 2M PHY, the HCI parameters are skipped + extInitInfo.conn_latency_2Mbps = conn_latency[i]; + extInitInfo.supervision_timeout_2Mbps = supervision_timeout[i]; + extInitInfo.conn_interval_min_2Mbps = conn_interval_min[i]; + extInitInfo.conn_interval_max_2Mbps = conn_interval_max[i]; + extInitInfo.minimum_CE_length_2Mbps = minimum_CE_length[i]; + extInitInfo.maximum_CE_length_2Mbps = maximum_CE_length[i]; + i ++; + } + + if (initiating_PHYs & LL_SCAN_PHY_CODED_BITMASK) + { + extInitInfo.initPHYs[number_phys] = PKT_FMT_BLR125K; + extInitInfo.scanInterval[number_phys] = scan_interval[i]; + extInitInfo.scanWindow[number_phys] = scan_window[i]; + extInitInfo.conn_latency[number_phys] = conn_latency[i]; + extInitInfo.supervision_timeout[number_phys] = supervision_timeout[i]; + extInitInfo.conn_interval_min[number_phys] = conn_interval_min[i]; + extInitInfo.conn_interval_max[number_phys] = conn_interval_max[i]; + extInitInfo.minimum_CE_length[number_phys] = minimum_CE_length[i]; + extInitInfo.maximum_CE_length[number_phys] = maximum_CE_length[i]; + number_phys ++; + } + + extInitInfo.numOfScanPHY = number_phys; + // save the peer address type + peerInfo.peerAddrType = peer_address_type; + + // save the peer address + if (peer_address != NULL) // bug fixed + LL_COPY_DEV_ADDR_LE( peerInfo.peerAddr, peer_address ); + + // save our address type + extInitInfo.ownAddrType = own_address_type; + + // check the type of own address + if ( own_address_type == LL_DEV_ADDR_TYPE_PUBLIC ) + { + // save our address + LL_COPY_DEV_ADDR_LE( extInitInfo.ownAddr, ownPublicAddr ); + } + else // LL_DEV_ADDR_TYPE_RANDOM + { + // save our address + LL_COPY_DEV_ADDR_LE( extInitInfo.ownAddr, ownRandomAddr ); + } + + // ========== update connection context + g_ll_conn_ctx.numLLMasterConns ++; + // reset connection parameters + LL_set_default_conn_params(connPtr); + // clear the connection buffer + reset_conn_buf(connPtr->connId); + // save the connection ID with Init + extInitInfo.connId = connPtr->connId; + + // set the connection channel map + for (i = 0; i < LL_NUM_BYTES_FOR_CHAN_MAP; i++) + { + connPtr->chanMap[i] = chanMapUpdate.chanMap[i]; + } + + // process connection channel map into the data channel table + llProcessChanMap( connPtr, connPtr->chanMap ); + // ramdomly generate a valid 24 bit CRC value + connPtr->initCRC = llGenerateCRC(); + // randomly generate a valid, previously unused, 32-bit access address + connPtr->accessAddr = llGenerateValidAccessAddr(); +// ============= below connection context depends on PHY index, will be selected when scan OK + #if 0 + + if (g_ll_conn_ctx.numLLMasterConns == 1) // A2 multi-connection, 1st connection, save the connection parameters + { + // determine the connection interval based on min and max values + // Note: Range not used, so assume max value. + // Note: minLength and maxLength are informational. + connPtr->curParam.connInterval = conn_interval_max; + // set the connection timeout + // Note: The spec says this begins at the end of the CONNECT_REQ, but the + // LSTO will be converted into events. + connPtr->curParam.connTimeout = supervision_timeout; + // set the slave latency + connPtr->curParam.slaveLatency = conn_latency; + // save connection parameter as global + g_ll_conn_ctx.connInterval = connPtr->curParam.connInterval; // unit: 1.25ms + g_ll_conn_ctx.slaveLatency = connPtr->curParam.slaveLatency; + g_ll_conn_ctx.connTimeout = connPtr->curParam.connTimeout; + g_ll_conn_ctx.per_slot_time = connPtr->curParam.connInterval * 2 / g_maxConnNum; // unit: 625us + } + else + { + // determine the connection interval based on min and max values + // Note: Range not used, so assume max value. + // Note: minLength and maxLength are informational. + connPtr->curParam.connInterval = g_ll_conn_ctx.connInterval; + // set the connection timeout + // Note: The spec says this begins at the end of the CONNECT_REQ, but the + // LSTO will be converted into events. + connPtr->curParam.connTimeout = g_ll_conn_ctx.connTimeout; + // set the slave latency + connPtr->curParam.slaveLatency = g_ll_conn_ctx.slaveLatency; + } + + #endif + // set the master's SCA + connPtr->sleepClkAccuracy = extInitInfo.scaValue; + // set the window size (units of 1.25ms) + // Note: Must be the lesser of 10ms and the connection interval - 1.25ms. + connPtr->curParam.winSize = pGlobal_config[LL_CONN_REQ_WIN_SIZE]; + // set the window offset (units of 1.25ms). TO change if we support multiple connections + // Note: Normally, the window offset is managed dynamically so that precise + // connection start times can be achieved (necessary for multiple + // connnections). However, sometimes it is useful to force the window + // offset to something specific for testing. This can be done by here + // when the project is built with the above define. + // Note: This define should only be used for testing one connection and will + // NOT work when multiple connections are attempted! + connPtr->curParam.winOffset = pGlobal_config[LL_CONN_REQ_WIN_OFFSET];//2;//LL_WINDOW_OFFSET; + // set the channel map hop length (5..16) + // Note: 0..255 % 12 = 0..11 + 5 = 5..16. + connPtr->hop = (uint8)( (LL_ENC_GeneratePseudoRandNum() % 12) + 5); + // =============== fill AUX_CONNECT_REQ PDU, some connection parameters depend on init PHY + { + uint8 offset = 0; + g_tx_adv_buf.txheader = txHeader; + // setup CONN REQ in connPtr->ll_buf + LL_ReadBDADDR(&g_tx_adv_buf.data[offset]); // initA, Byte 0 ~ 5 + offset += 6; + + if (peer_address != NULL) + LL_COPY_DEV_ADDR_LE(&g_tx_adv_buf.data[offset], peer_address) // AdvA, Byte 6 ~ 11 + offset += 6; + + // Access Address, Byte 12 ~ 15 + memcpy((uint8*)&g_tx_adv_buf.data[offset], (uint8*)&connPtr->accessAddr, 4); + offset += 4; + // CRC init, Byte 16 ~ 18 + memcpy((uint8*)&g_tx_adv_buf.data[offset], (uint8*)&connPtr->initCRC, 3); + offset += 3; + // WinSize, Byte 19 + g_tx_adv_buf.data[offset] = connPtr->curParam.winSize; + offset += 1; + // WinOffset, Byte 20 ~ 21 + memcpy((uint8*)&g_tx_adv_buf.data[offset], (uint8*)&connPtr->curParam.winOffset, 2); + offset += 2; + // Interval, Byte 22 ~ 23 +// memcpy((uint8 *)&g_tx_adv_buf.data[offset], (uint8 *)&connPtr->curParam.connInterval, 2); + offset += 2; + // Latency, Byte 24 ~ 25 +// memcpy((uint8 *)&g_tx_adv_buf.data[offset], (uint8 *)&connPtr->curParam.slaveLatency, 2); + offset += 2; + // Timeout, Byte 26 ~ 27 +// memcpy((uint8 *)&g_tx_adv_buf.data[offset], (uint8 *)&connPtr->curParam.connTimeout, 2); + offset += 2; + // Channel Map, Byte 28 ~ 32 + memcpy((uint8*)&g_tx_adv_buf.data[offset], (uint8*)&connPtr->chanMap[0], 5); + offset += 5; + // Hop(5bit) + SCA(3bit), Byte 33 + g_tx_adv_buf.data[offset] = (connPtr->hop & 0x1f) | ((connPtr->sleepClkAccuracy & 0x7) << 5); + } + // =============== init scan +// if ( llState == LL_STATE_IDLE ) +// // go ahead and start Init immediately + extInitInfo.current_index = 0; + extInitInfo.current_chn = LL_ADV_CHAN_FIRST; + extInitInfo.current_scan_PHY = extInitInfo.initPHYs[extInitInfo.current_index]; + // enable Init scan + extInitInfo.scanMode = LL_SCAN_START; + llSetupExtInit(); +// else +// osal_set_event(LL_TaskID, LL_EVT_SECONDARY_INIT); + return LL_STATUS_SUCCESS; +} + +// ========================= Periodic Advertiser +llStatus_t LL_SetPeriodicAdvParameter(uint8 adv_handle, + uint16 interval_min, + uint16 interval_max, + uint16 adv_event_properties) +{ + int i; + + // TODO: add parameters range checking + if (g_llAdvMode == LL_MODE_LEGACY) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llAdvMode = LL_MODE_EXTENDED; + + if (interval_max * 1250 < g_advSlotPeriodic) + return LL_STATUS_ERROR_OUT_OF_CONN_RESOURCES; + + // extended advertiser memory is allocate by application, return fail if not + if (g_pPeriodicAdvInfo == NULL) + return LL_STATUS_ERROR_OUT_OF_HEAP; + + // search advertisement handler list + for (i = 0; i < g_perioAdvNumber; i ++) + { + if (g_pPeriodicAdvInfo[i].advHandle == adv_handle) + break; + } + + // if not found, search the 1st available slot + if (i == g_perioAdvNumber) + { + for (i = 0; i < g_perioAdvNumber; i ++) + { + if (g_pPeriodicAdvInfo[i].advHandle == LL_INVALID_ADV_SET_HANDLE) + { + memset(&g_pPeriodicAdvInfo[i], 0, sizeof(periodicAdvInfo_t)); + break; + } + } + } + + if (i == g_perioAdvNumber) + return LL_STATUS_ERROR_OUT_OF_HEAP; + + // search extended advertisement handler list + for (i = 0; i < g_extAdvNumber; i ++) + { + if (g_pExtendedAdvInfo[i].advHandle == adv_handle) + break; + } + + // if not found, report error. refer Vol 4, Part E. 7.8.61 LE Set Periodic Advertising Parameters command + // The Advertising_Handle parameter identifies the advertising set whose + // periodic advertising parameters are being configured. If the corresponding + // advertising set does not already exist, then the Controller shall return the error + // code Unknown Advertising Identifier (0x42). + if (i == g_extAdvNumber) + { + return LL_STATUS_ERROR_UNKNOWN_ADV_ID; + } + else + g_pExtendedAdvInfo[i].isPeriodic = TRUE; + + // save the advertisement parameters + g_pPeriodicAdvInfo[i].advHandle = adv_handle; + g_pPeriodicAdvInfo[i].adv_event_properties = adv_event_properties; + g_pPeriodicAdvInfo[i].adv_interval_max = interval_max; + g_pPeriodicAdvInfo[i].adv_interval_min = interval_min; + // =========== controller select parameters, TBD + // decide periodic advertising interval + g_pPeriodicAdvInfo[i].adv_interval = g_advSlotPeriodic; + return LL_STATUS_SUCCESS; +} + + +llStatus_t LL_SetPeriodicAdvData(uint8 adv_handle, + uint8 operation, + uint8 advertising_data_length, + uint8* advertising_data) +{ + int i; + + // TODO: add parameters range checking + if (g_llAdvMode == LL_MODE_LEGACY) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llAdvMode = LL_MODE_EXTENDED; + + if (operation > BLE_EXT_ADV_OP_UNCHANGED_DATA) + return LL_STATUS_ERROR_BAD_PARAMETER; + + // extended advertiser memory is allocate by application, return fail if not + if (g_pPeriodicAdvInfo == NULL) + return LL_STATUS_ERROR_OUT_OF_HEAP; + + // search advertisement handler list + for (i = 0; i < g_perioAdvNumber; i ++) + { + if (g_pPeriodicAdvInfo[i].advHandle == adv_handle) + break; + } + + // if not found, return error + if (i == g_perioAdvNumber) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + if (operation == BLE_EXT_ADV_OP_FIRST_FRAG || + operation == BLE_EXT_ADV_OP_COMPLETE_DATA) + { + g_pPeriodicAdvInfo[i].data.advertisingDataLength = 0; + g_pPeriodicAdvInfo[i].data.dataComplete = FALSE; + } + + if (g_pPeriodicAdvInfo[i].data.advertisingDataLength + advertising_data_length > g_advSetMaximumLen) + { + g_pPeriodicAdvInfo[i].data.advertisingDataLength = 0; + return LL_STATUS_ERROR_OUT_OF_HEAP; + } + + // fill advertising set + g_pPeriodicAdvInfo[i].advHandle = adv_handle; + memcpy(&g_pPeriodicAdvInfo[i].data.advertisingData[g_pPeriodicAdvInfo[i].data.advertisingDataLength], + advertising_data, advertising_data_length); + g_pPeriodicAdvInfo[i].data.advertisingDataLength += advertising_data_length; + + // last fragment or 1 segment adv data + if (operation == BLE_EXT_ADV_OP_LAST_FRAG || + operation == BLE_EXT_ADV_OP_COMPLETE_DATA ) + g_pPeriodicAdvInfo[i].data.dataComplete = TRUE; + + return LL_STATUS_SUCCESS; +} + +llStatus_t LL_SetPeriodicAdvEnable(uint8 enable, + uint8 advertising_handle) +{ + int i; + periodicAdvInfo_t* pPrdAdv = NULL; + extAdvInfo_t* pExtAdv = NULL; + + if (g_llAdvMode == LL_MODE_LEGACY) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llAdvMode = LL_MODE_EXTENDED; + + if (g_pPeriodicAdvInfo == NULL) + return LL_STATUS_ERROR_OUT_OF_HEAP; + + // search advertisement handler list + for (i = 0; i < g_perioAdvNumber; i ++) + { + if (g_pPeriodicAdvInfo[i].advHandle == advertising_handle) + { + pPrdAdv = &g_pPeriodicAdvInfo[i]; + break; + } + } + + // if not found, return error + if (i == g_perioAdvNumber) + return LL_STATUS_ERROR_UNKNOWN_ADV_ID; + + if (g_pPeriodicAdvInfo[i].data.dataComplete == FALSE + && enable == TRUE) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + // TODO: check whether the adv data could be filled in the adv period(error code LL_STATUS_ERROR_PACKET_TOO_LONG) + + // ====== periodic advertiser scheduler process + if (enable == FALSE) + { + if (pPrdAdv->active == FALSE) // already disable, do nothing + return LL_STATUS_SUCCESS; + + // disable periodic adv process + // case 1: extended adv is already disable + // case 2: extended adv is not disable, it will also stop extended adv + // search the adv in the scheduler list and disable it + for (i = 0; i < g_schExtAdvNum_periodic; i++) + { + if (g_pAdvSchInfo_periodic[i].adv_handler == pPrdAdv[i].advHandle) + { + g_pAdvSchInfo_periodic[i].pAdvInfo->active = FALSE; + ll_delete_adv_task_periodic(i); + break; + } + } + } + else // enable case + { + if (pPrdAdv->active == TRUE) + { + // TODO: Enabling periodic advertising when it is already enabled can cause the + // random address to change + return LL_STATUS_SUCCESS; + } + + // search advertisement handler list + for (i = 0; i < g_extAdvNumber; i ++) + { + if (g_pExtendedAdvInfo[i].advHandle == advertising_handle) + { + pExtAdv = &g_pExtendedAdvInfo[i]; + break; + } + } + + // initial periodic adv sync info context + // ramdomly generate a valid 24 bit CRC value + pPrdAdv->crcInit = llGenerateCRC(); + // randomly generate a valid, previously unused, 32-bit access address + pPrdAdv->AA = llGenerateValidAccessAddr(); + pPrdAdv->sca = LL_SCA_MASTER_DEFAULT; + pPrdAdv->chn_map[0] = 0xFF; + pPrdAdv->chn_map[1] = 0xFF; + pPrdAdv->chn_map[2] = 0xFF; + pPrdAdv->chn_map[3] = 0xFF; + pPrdAdv->chn_map[4] = 0x1F; + + // 2020-1-7 add for CSA2 + // the used channel map uses 1 bit per data channel, or 5 bytes for 37 chans + for (i = 0; i < LL_NUM_BYTES_FOR_CHAN_MAP; i++) + { + // replace the current channel map with the update channel map + // Note: This needs to be done so that llGetNextDataChan can more + // efficiently determine if the next channel is used. + // connPtr->chanMap[i] = chanMap[i]; + + // for each channel given by a bit in each of the bytes + // Note: When i is on the last byte, only 5 bits need to be checked, but + // it is easier here to check all 8 with the assumption that the rest + // of the reserved bits are zero. + for (uint8 j = 0; j < 8; j++) + { + // check if the channel is used; only interested in used channels + if ( (pPrdAdv->chn_map[i] >> j) & 1 ) + { + // sequence used channels in ascending order + pPrdAdv->chanMapTable[pPrdAdv->numUsedChans] = (i * 8U) + j; + // count it + pPrdAdv->numUsedChans++; + } + } + } + + // case 1: extended adv is not enable, not trigger periodic adv + if (pExtAdv == NULL || pExtAdv->active == FALSE) + { + } + // case 2: extende adv is enable, start extended adv + periodic adv + else + { + pExtAdv->data.DIDInfo = ll_generateExtAdvDid(pExtAdv->data.DIDInfo); + ll_add_adv_task_periodic(pPrdAdv, pExtAdv); + } + } + + pPrdAdv->active = enable; + return( LL_STATUS_SUCCESS ); +} + +llStatus_t LL_PeriodicAdvertisingCreateSync(uint8 options, + uint8 advertising_SID, + uint8 advertiser_Address_Type, + uint8* advertiser_Address, + uint16 skip, + uint16 sync_Timeout, + uint8 sync_CTE_Type) +{ + if (g_llScanMode == LL_MODE_LEGACY ) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llScanMode = LL_MODE_EXTENDED; + + // TODO: add more sanity checking + if (scanSyncInfo.valid == TRUE) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + if (options & LL_PERIODIC_ADV_CREATE_SYNC_INIT_RPT_DISABLE_BITMASK) // we not support this mode + return LL_STATUS_ERROR_CONN_FAILED_TO_BE_ESTABLISHED; + + scanSyncInfo.options = options; + scanSyncInfo.advertising_SID = advertising_SID; + scanSyncInfo.advertiser_Address_Type = advertiser_Address_Type; + + if (advertiser_Address != NULL) + memcpy(scanSyncInfo.advertiser_Address, advertiser_Address, LL_DEVICE_ADDR_LEN); + + scanSyncInfo.skip = skip; + scanSyncInfo.sync_Timeout = sync_Timeout; + scanSyncInfo.sync_CTE_Type = sync_CTE_Type; + scanSyncInfo.valid = TRUE; + return( LL_STATUS_SUCCESS ); +} + +llStatus_t LL_PeriodicAdvertisingCreateSyncCancel(void) +{ + if (g_llScanMode == LL_MODE_LEGACY ) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llScanMode = LL_MODE_EXTENDED; + + if (scanSyncInfo.valid == FALSE) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + scanSyncInfo.valid = FALSE; + return( LL_STATUS_SUCCESS ); +} + +// TODO +llStatus_t LL_PeriodicAdvertisingTerminateSync( uint16 sync_handle) +{ + if (g_llScanMode == LL_MODE_LEGACY ) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llScanMode = LL_MODE_EXTENDED; + // TODO: search periodic scanner list and remove it from schedule list + llDeleteSyncHandle(sync_handle); + return( LL_STATUS_SUCCESS ); +} + +// ========== +llStatus_t LL_AddDevToPeriodicAdvList(uint8 addrType, + uint8* devAddr, + uint8 sid) +{ + int i; + + if (g_llScanMode == LL_MODE_LEGACY ) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llScanMode = LL_MODE_EXTENDED; + + // create Sync pending + if (scanSyncInfo.valid == TRUE) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + // check the device address type + if ( (addrType != LL_DEV_ADDR_TYPE_PUBLIC) && + (addrType != LL_DEV_ADDR_TYPE_RANDOM) ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // check if there was room for the entry + if (g_llPrdAdvDeviceNum >= LL_PRD_ADV_ENTRY_NUM) + return( LL_STATUS_ERROR_PAL_TABLE_FULL ); + + // if the entry already exist, return 0x12 error code + for (i = 0; i < LL_PRD_ADV_ENTRY_NUM; i++) + { + if (g_llPeriodicAdvlist[i].addrType == addrType + && g_llPeriodicAdvlist[i].sid == sid + && (g_llPeriodicAdvlist[i].addr[0] == devAddr[0] + && g_llPeriodicAdvlist[i].addr[1] == devAddr[1] + && g_llPeriodicAdvlist[i].addr[2] == devAddr[2] + && g_llPeriodicAdvlist[i].addr[3] == devAddr[3] + && g_llPeriodicAdvlist[i].addr[4] == devAddr[4] + && g_llPeriodicAdvlist[i].addr[5] == devAddr[5])) + return LL_STATUS_ERROR_BAD_PARAMETER; + } + + // add the device to a empty record + for (i = 0; i < LL_PRD_ADV_ENTRY_NUM; i++) + { + if (g_llPeriodicAdvlist[i].addrType == 0xff) // empty record + { + g_llPeriodicAdvlist[i].addrType = addrType; + osal_memcpy(&g_llPeriodicAdvlist[i].addr[0], &devAddr[0], LL_DEVICE_ADDR_LEN); + g_llPeriodicAdvlist[i].sid = sid; + g_llPrdAdvDeviceNum ++; + break; + } + } + + return( LL_STATUS_SUCCESS ); +} + +llStatus_t LL_RemovePeriodicAdvListDevice(uint8 addrType, + uint8* devAddr, + uint8 sid) +{ + int i; + + if (g_llScanMode == LL_MODE_LEGACY ) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llScanMode = LL_MODE_EXTENDED; + + // create Sync pending + if (scanSyncInfo.valid == TRUE) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + // search the device + for (i = 0; i < LL_PRD_ADV_ENTRY_NUM; i++) + { + if (g_llPeriodicAdvlist[i].addrType == addrType + && g_llPeriodicAdvlist[i].sid == sid + && (g_llPeriodicAdvlist[i].addr[0] == devAddr[0] + && g_llPeriodicAdvlist[i].addr[1] == devAddr[1] + && g_llPeriodicAdvlist[i].addr[2] == devAddr[2] + && g_llPeriodicAdvlist[i].addr[3] == devAddr[3] + && g_llPeriodicAdvlist[i].addr[4] == devAddr[4] + && g_llPeriodicAdvlist[i].addr[5] == devAddr[5])) + break; + } + + if (i == LL_PRD_ADV_ENTRY_NUM + || g_llPrdAdvDeviceNum == 0) + return LL_STATUS_ERROR_UNKNOWN_ADV_ID; + + g_llPeriodicAdvlist[i].addrType = 0xff; + memset(g_llPeriodicAdvlist[i].addr, 0, LL_DEVICE_ADDR_LEN); + g_llPrdAdvDeviceNum --; + return( LL_STATUS_SUCCESS ); +} + +llStatus_t LL_ClearPeriodicAdvList(void) +{ + int i; + + if (g_llScanMode == LL_MODE_LEGACY ) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llScanMode = LL_MODE_EXTENDED; + + // create Sync pending + if (scanSyncInfo.valid == TRUE) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + for (i = 0; i < LL_PRD_ADV_ENTRY_NUM; i++) + { + g_llPeriodicAdvlist[i].addrType = 0xff; + memset(g_llPeriodicAdvlist[i].addr, 0, LL_DEVICE_ADDR_LEN); + } + + g_llPrdAdvDeviceNum = 0; + return( LL_STATUS_SUCCESS ); +} + +llStatus_t LL_ReadPeriodicAdvListSize(uint8* numEntries) +{ + if (g_llScanMode == LL_MODE_LEGACY ) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llScanMode = LL_MODE_EXTENDED; + *numEntries = LL_PRD_ADV_ENTRY_NUM; + return( LL_STATUS_SUCCESS ); +} + +// ================== + +llStatus_t LL_ConnectionlessCTE_TransmitParam0( uint8 advertising_handle, + uint8 len, + uint8 type, + uint8 count, + uint8 Pattern_LEN, + uint8* AnaIDs) +{ + int i,j; + uint8 suppCTEType=0; + periodicAdvInfo_t* pPrdAdv = NULL; + + if (g_pPeriodicAdvInfo == NULL) + return LL_STATUS_ERROR_OUT_OF_HEAP; + + // search advertisement handler list + for (i = 0; i < g_perioAdvNumber; i ++) + { + if (g_pPeriodicAdvInfo[i].advHandle == advertising_handle) + { + pPrdAdv = &g_pPeriodicAdvInfo[i]; + break; + } + } + + // if period advertising set not cteate , return unknown advertising Identifier + if( i == g_perioAdvNumber ) + { + return LL_STATUS_ERROR_UNKNOWN_ADV_ID; + } + + // return error code Command Disallowed when CTE hasve been enabled + if( pPrdAdv->PrdCTEInfo.enable == TRUE ) + { + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + } + + // check Controller support CTE Type + suppCTEType = deviceFeatureSet.featureSet[LL_CTE_FEATURE_IDX] & 0x60; + pPrdAdv->PrdCTEInfo.CTE_Type = type; + + switch (type) + { + case CONNLESS_CTE_TYPE_AOA: + + // ignore Pattern_LEN and AnaIDs + if( !( suppCTEType & LL_AOA_SUPPORT ) ) + { + return LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED; + } + + break; + + case CONNLESS_CTE_TYPE_AOD_1us: + case CONNLESS_CTE_TYPE_AOD_2us: + + // TODO + // should check the Controller support AOD 1us or 2us + if( !( suppCTEType & LL_AOD_SUPPORT ) || ( Pattern_LEN > LL_CTE_MAX_PATTERN_LEN ) ) + { + return LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED; + } + else + { + pPrdAdv->PrdCTEInfo.pattern_LEN = Pattern_LEN; + + for( j = 0; j < Pattern_LEN; j++) + { + if( AnaIDs[j] > LL_CTE_MAX_ANT_ID ) + return LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED; + } + + osal_memcpy(pPrdAdv->PrdCTEInfo.AntID, AnaIDs, LL_CTE_MAX_PATTERN_LEN ); + } + + break; + + default: + // unsupported CTE Type +// return LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED; + break; + } + + // parameter len in 8us units shall not greater than LL_CTE_MAX_SUPP_LEN + // max CTE_Count check in each PA Event + if(( len < LL_CTE_MIN_SUPP_LEN ) || ( len > LL_CTE_MAX_SUPP_LEN ) || ( count > LL_CTE_MAX_PA_INTV_CNT )) + { + return LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED; + } + else + { + pPrdAdv->PrdCTEInfo.CTE_Length = len; + pPrdAdv->PrdCTEInfo.CTE_Count = count; + pPrdAdv->PrdCTEInfo.CTE_Count_Idx = 0; + } + + return LL_STATUS_SUCCESS; +} + +llStatus_t LL_ConnectionlessCTE_TransmitEnable0( uint8 advertising_handle,uint8 enable) +{ + int i,j; + uint32 ant1=0,ant0=0; + periodicAdvInfo_t* pPrdAdv = NULL; + + if (g_pPeriodicAdvInfo == NULL) + return LL_STATUS_ERROR_OUT_OF_HEAP; + + // search advertisement handler list + for (i = 0; i < g_perioAdvNumber; i ++) + { + // equal advertising_handle indicate that it has already issued LL_SetPeriodicAdvParameter command + if (g_pPeriodicAdvInfo[i].advHandle == advertising_handle) + { + pPrdAdv = &g_pPeriodicAdvInfo[i]; + break; + } + } + + // advertising set not exist return error code + if( i == g_perioAdvNumber ) + { + return LL_STATUS_ERROR_UNKNOWN_ADV_ID; + } + + // should enable periodic advertising first + // check g_pPeriodicAdvInfo[i].active means : if periodic advertising set disabled that should not enable CTE Tx + + // 2020-02-10 comment + // TODO :: only check if PA Parameter is set before CTE Transmit enable +// if( ( g_pPeriodicAdvInfo[i].active != TRUE ) ) +// { +// return LL_STATUS_ERROR_COMMAND_DISALLOWED; +// } + + // means the host has not issue LL_ConnectionlessCTE_TransmitParam before this command + if( 0 == pPrdAdv->PrdCTEInfo.CTE_Length ) + { + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + } + + // check secondary advertising PHY allow CTE + if( pPrdAdv->secondaryAdvPHY > LL_SECOND_ADV_PHY_2M ) + { + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + } + + switch ( enable ) + { + case LL_CTE_ENABLE: + pPrdAdv->PrdCTEInfo.enable = LL_CTE_ENABLE; + + switch ( pPrdAdv->PrdCTEInfo.CTE_Type ) + { + case CONNLESS_CTE_TYPE_AOA: + // AOA transmit not switching Antenna , shall not config switch timing +// ll_hw_set_ant_switch_timing(8, 40); + ll_hw_set_ant_switch_mode( LL_HW_ANT_SW_CTE_OFF ); + break; + + case CONNLESS_CTE_TYPE_AOD_1us: + case CONNLESS_CTE_TYPE_AOD_2us: + + // combination ant pattern + for( j = 0 ; j < pPrdAdv->PrdCTEInfo.pattern_LEN ; j++ ) + { + // PHY SDK 4 bit represents an Antenna ID, so uint32 represents max 8 antenna + if( j < 8 ) + { + ant0 |= ( ((uint32)pPrdAdv->PrdCTEInfo.AntID[j]) << (4*j) ); + } + else + { + ant1 |= ( ((uint32)pPrdAdv->PrdCTEInfo.AntID[j]) << (4*(j-8)) ); + } + } + + ll_hw_set_ant_pattern( ant1, ant0 ); + // antWin : 8, 1us switching + 1us sampling 8 *0.25us unit = 2us + // antWin : 16,2us switching + 2us sampling 16*0.25us unit = 4us + ll_hw_set_ant_switch_timing((pPrdAdv->PrdCTEInfo.CTE_Type==CONNLESS_CTE_TYPE_AOD_1us?8:16), 40); + ll_hw_set_ant_switch_mode( LL_HW_ANT_SW_TX_MANU ); + break; + + default: + break; + } + + // 2020-02-10 comment + // TODO: cte_txSupp instruction executed here, whether all packet contain CTEInfo field , + // and those that shall not include CTEInfo filed , eg AUX_EXT_IND +// ll_hw_set_cte_txSupp( CTE_SUPP_LEN_SET | g_pPeriodicAdvInfo[i].PrdCTEInfo.CTE_Length ); + break; + + case LL_CTE_DISABLE: + pPrdAdv->PrdCTEInfo.enable = LL_CTE_DISABLE; + break; + + default: + break; + } + + return LL_STATUS_SUCCESS; +} + +llStatus_t LL_ConnectionlessIQ_SampleEnable0( uint16 sync_handle, + uint8 enable, + uint8 slot_Duration, + uint8 MaxSampledCTEs, + uint8 pattern_len, + uint8* AnaIDs) +{ + int i,j; + uint32 ant1=0,ant0=0; + + for( i = 0; i < MAX_NUM_LL_PRD_ADV_SYNC ; i++ ) + { + if( g_llPeriodAdvSyncInfo[i].syncHandler == sync_handle ) + break; + } + + // only support 1 periodic advertising , so only support 1 IQ Sampling + // TODO + // Logic issus : JIRA BBBBLESTAC-10 issue 4 + if( ( scanSyncInfo.valid != TRUE ) || ( i == MAX_NUM_LL_PRD_ADV_SYNC ) ) + { + return LL_STATUS_ERROR_UNKNOWN_ADV_ID; + } + + if( MaxSampledCTEs > LL_CTE_MAX_IQ_SAMP_CNT) + { + return LL_STATUS_ERROR_UNEXPECTED_PARAMETER; + } + else + { + g_llPeriodAdvSyncInfo[i].IQSampleInfo.CTE_Count = MaxSampledCTEs; + } + + // PHY SDK default support 1us and 2us slot dureation, so no condition determination + g_llPeriodAdvSyncInfo[i].IQSampleInfo.slot_Duration = slot_Duration; + + switch ( enable ) + { + case LL_IQ_SAMP_ENABLE: + if( g_llPeriodAdvSyncInfo[i].IQSampleInfo.enable ) + { + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + } + else + { + g_llPeriodAdvSyncInfo[i].IQSampleInfo.enable = LL_IQ_SAMP_ENABLE; + + switch ( g_llPeriodAdvSyncInfo[i].IQSampleInfo.CTE_Type ) + { + case CONNLESS_CTE_TYPE_AOA: + g_llPeriodAdvSyncInfo[i].IQSampleInfo.pattern_LEN = pattern_len; + + for( j = 0; j < pattern_len; j++) + { + if( AnaIDs[j] > LL_CTE_MAX_ANT_ID ) + return LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED; + } + + osal_memcpy(g_llPeriodAdvSyncInfo[i].IQSampleInfo.AntID, AnaIDs, LL_CTE_MAX_PATTERN_LEN ); + ll_hw_set_ant_switch_mode( LL_HW_ANT_SW_RX_MANU ); + + // combination ant pattern + for( j = 0 ; j < g_llPeriodAdvSyncInfo[i].IQSampleInfo.pattern_LEN ; j++ ) + { + // PHY SDK 4 bit represents an Antenna ID, so uint32 represents max 8 antenna + if( j < 8 ) + { + ant0 |= ( ((uint32)g_llPeriodAdvSyncInfo[i].IQSampleInfo.AntID[j]) << (4*j) ); + } + else + { + ant1 |= ( ((uint32)g_llPeriodAdvSyncInfo[i].IQSampleInfo.AntID[j]) << (4*(j-8)) ); + } + } + + ll_hw_set_ant_pattern( ant1, ant0 ); + break; + + case CONNLESS_CTE_TYPE_AOD_1us: + case CONNLESS_CTE_TYPE_AOD_2us: + // AOD receiver not switching Antenna + ll_hw_set_ant_switch_mode( LL_HW_ANT_SW_CTE_OFF ); + ll_hw_set_ant_pattern( 0, 0 ); + break; + + default: + break; + } + + // antWin : 8, 1us switching + 1us sampling 8 *0.25us unit = 2us + // antWin : 16,2us switching + 2us sampling 16*0.25us unit = 4us + ll_hw_set_ant_switch_timing((slot_Duration==LL_IQ_SW_SAMP_1US?8:16), 40); + ll_hw_set_cte_rxSupp( CTE_SUPP_LEN_SET | g_pPeriodicAdvInfo[i].PrdCTEInfo.CTE_Length ); + } + + break; + + case LL_IQ_SAMP_DISABLE: + g_llPeriodAdvSyncInfo[i].IQSampleInfo.enable = LL_IQ_SAMP_ENABLE; + break; + + default: + break; + } + + return LL_STATUS_SUCCESS; +} + + +llStatus_t LL_Set_ConnectionCTE_ReceiveParam0( uint16 connHandle, + uint8 enable, + uint8 slot_Duration, + uint8 pattern_len, + uint8* AnaIDs) +{ + uint8 i,j; + uint32 ant1=0,ant0=0; + // llConnState_t.connid means connHandle + llConnState_t* connPtr; + + for( i = 0; i< g_maxConnNum; i++) + { + connPtr = &conn_param[i]; + + if( connPtr->connId == connHandle ) + { + break; + } + } + + if( g_maxConnNum == i ) + { + return LL_STATUS_ERROR_INACTIVE_CONNECTION; + } + + switch( enable ) + { + case LL_CONN_IQSAMP_ENABLE: + if( connPtr->llConnCTE.enable == LL_CONN_IQSAMP_ENABLE ) + { + // current connection CTE already enabled, return error + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + } + else + { + connPtr->llConnCTE.slot_Duration = slot_Duration; + connPtr->llConnCTE.enable = LL_CONN_IQSAMP_ENABLE; + connPtr->llConnCTE.pattern_LEN = pattern_len; + + for( j = 0; j < pattern_len; j++) + { + if( AnaIDs[j] > LL_CTE_MAX_ANT_ID ) + return LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED; + } + + osal_memcpy(connPtr->llConnCTE.AntID, AnaIDs, LL_CTE_MAX_PATTERN_LEN ); + + for( j = 0 ; j < connPtr->llConnCTE.pattern_LEN ; j++ ) + { + // PHY SDK 4 bit represents an Antenna ID, so uint32 represents max 8 antenna + if( j < 8 ) + { + ant0 |= ( ((uint32)connPtr->llConnCTE.AntID[j]) << (4*j) ); + } + else + { + ant1 |= ( ((uint32)connPtr->llConnCTE.AntID[j]) << (4*(j-8)) ); + } + } + + ll_hw_set_ant_pattern( ant1, ant0 ); + ll_hw_set_ant_switch_mode( LL_HW_ANT_SW_CTE_AUTO ); + // antWin : 8, 1us switching + 1us sampling 8 *0.25us unit = 2us + // antWin : 16,2us switching + 2us sampling 16*0.25us unit = 4us + ll_hw_set_ant_switch_timing((slot_Duration==LL_IQ_SW_SAMP_1US?8:16), 40); + // 2020-02-12 comment receive parameter set rxSupp len = 0 + ll_hw_set_cte_rxSupp(CTE_SUPP_NULL); +// ll_hw_set_cte_rxSupp( CTE_SUPP_LEN_SET | g_pPeriodicAdvInfo[i].PrdCTEInfo.CTE_Length ); + } + + break; + + case LL_CONN_IQSAMP_DISENABLE: + connPtr->llConnCTE.enable = LL_CONN_IQSAMP_DISENABLE; + break; + + default: + break; + } + + return LL_STATUS_SUCCESS; +} + + +llStatus_t LL_Connection_CTE_Request_Enable0( uint16 connHandle, + uint8 enable, + uint16 Interval, + uint8 len, + uint8 type) +{ + uint8 i; +// uint32 ant1=0,ant0=0; + // llConnState_t.connid means connHandle + llConnState_t* connPtr; + + for( i = 0; i< g_maxConnNum; i++) + { + connPtr = &conn_param[i]; + + if( connPtr->connId == connHandle ) + { + break; + } + } + + if( g_maxConnNum == i ) + { + return LL_STATUS_ERROR_INACTIVE_CONNECTION; + } + + // check if peer device feature set support CTE Response + if( ( connPtr->featureSetInfo.featureSet[LL_CTE_FEATURE_IDX] & LL_CONN_CTE_RSP ) != LL_CONN_CTE_RSP ) + { + return LL_STATUS_ERROR_UNSUPPORTED_REMOTE_FEATURE; + } + + switch ( enable ) + { + case LL_CONN_CTE_REQ_ENABLE: + + // if Controller already enable ,return error code LL_STATUS_ERROR_COMMAND_DISALLOWED + // if the Host issue this command before issue the LL_Set_ConnectionCTE_ReceiveParam command at least + // once on the connection , the Controller shall return error code LL_STATUS_ERROR_COMMAND_DISALLOWED + if( ( LL_CONN_CTE_REQ_ENABLE == connPtr->llCTE_ReqFlag ) || \ + !( LL_CONN_IQSAMP_ENABLE == connPtr->llConnCTE.enable )) + { + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + } + + connPtr->llCTE_ReqFlag = LL_CONN_CTE_REQ_ENABLE; + + if(( len < LL_CTE_MIN_SUPP_LEN ) || ( len > LL_CTE_MAX_SUPP_LEN )) + { + return LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED; + } + else + { + connPtr->llConnCTE.CTE_Length = len; + } + + connPtr->llConnCTE.CTE_Type = type; + + // TODO + // check connection PHY support CTE ? +// if( connPtr->llPhyModeCtrl.local ) +// { +// return LL_STATUS_ERROR_COMMAND_DISALLOWED +// } + if( 0 == Interval) + { + // CTE Request Interval = 0 , means Initiate the CTE request procedure once + } + else + { + // TODO + // shall verify when disabled slaveLatency case + if( connPtr->slaveLatencyAllowed ) + { + if( Interval <= connPtr->slaveLatency ) + { + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + } + } + } + + connPtr->llConnCTE.CTE_Request_Intv = Interval; + llEnqueueCtrlPkt( connPtr, LL_CTRL_CTE_REQ ); + break; + + case LL_CONN_CTE_REQ_DISENABLE: + connPtr->llCTE_ReqFlag = LL_CONN_CTE_REQ_DISENABLE; + break; + } + + return LL_STATUS_SUCCESS; +} + + +llStatus_t LL_Set_ConnectionCTE_TransmitParam0( uint16 connHandle, + uint8 type, + uint8 pattern_len, + uint8* AnaIDs) +{ + uint8 i,j; + uint32 ant1=0,ant0=0; + // llConnState_t.connid means connHandle + llConnState_t* connPtr; + + for( i = 0; i< g_maxConnNum; i++) + { + connPtr = &conn_param[i]; + + if( connPtr->connId == connHandle ) + { + break; + } + } + + if( g_maxConnNum == i ) + { + return LL_STATUS_ERROR_INACTIVE_CONNECTION; + } + + if( connPtr->llConnCTE.enable ) + { + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + } + + // TODO: + // if CTE Type parameter has a bit set for CTE that the controller does not support , + // the controller controller shall return error code + // return LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED + + // pattern len check + if( pattern_len > LL_CTE_MAX_PATTERN_LEN ) + { + return LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED; + } + else + { + connPtr->llConnCTE.pattern_LEN = pattern_len; + + for( j = 0; j < pattern_len; j++) + { + if( AnaIDs[j] > LL_CTE_MAX_ANT_ID ) + return LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED; + } + + osal_memcpy(connPtr->llConnCTE.AntID, AnaIDs, LL_CTE_MAX_PATTERN_LEN ); + } + + switch ( type ) + { + case CONN_CTE_TYPE_AOA: + ll_hw_set_ant_pattern( 0, 0 ); + ll_hw_set_ant_switch_mode( LL_HW_ANT_SW_CTE_OFF ); + break; + + case CONN_CTE_TYPE_AOD_1us: + case CONN_CTE_TYPE_AOD_2us: + + // combination ant pattern + for( j = 0 ; j < connPtr->llConnCTE.pattern_LEN ; j++ ) + { + // PHY SDK 4 bit represents an Antenna ID, so uint32 represents max 8 antenna + if( j < 8 ) + { + ant0 |= ( ((uint32)connPtr->llConnCTE.AntID[j]) << (4*j) ); + } + else + { + ant1 |= ( ((uint32)connPtr->llConnCTE.AntID[j]) << (4*(j-8)) ); + } + } + + ll_hw_set_ant_pattern( ant1, ant0 ); + ll_hw_set_ant_switch_timing((type==CONN_CTE_TYPE_AOD_1us?8:16), 40); + ll_hw_set_ant_switch_mode( LL_HW_ANT_SW_CTE_AUTO ); + break; + + default: + break; + } + +// ll_hw_set_cte_txSupp( CTE_SUPP_NULL); +// ll_hw_set_cte_txSupp( CTE_SUPP_LEN_SET | connPtr->llConnCTE.pattern_LEN ); + // indicate Connection CTE Transmit parameter has been set + connPtr->llConnCTE.enable = TRUE; + return LL_STATUS_SUCCESS; +} + +llStatus_t LL_Connection_CTE_Response_Enable0( uint16 connHandle,uint8 enable) +{ + uint8 i; +// uint32 ant1=0,ant0=0; + // llConnState_t.connid means connHandle + llConnState_t* connPtr; + + for( i = 0; i< g_maxConnNum; i++) + { + connPtr = &conn_param[i]; + + if( connPtr->connId == connHandle ) + { + break; + } + } + + if( g_maxConnNum == i ) + { + return LL_STATUS_ERROR_INACTIVE_CONNECTION; + } + + switch ( enable ) + { + case LL_CONN_CTE_RSP_ENABLE: + + // if the host issue this command before LL_Set_ConnectionCTE_TransmitParam at least once on the connection + // the controller shall return error code: LL_STATUS_ERROR_COMMAND_DISALLOWED + if( !connPtr->llConnCTE.enable ) + { + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + } + + // TODO + // check connection PHY support CTE ? +// if( connPtr->llPhyModeCtrl.local ) +// { +// return LL_STATUS_ERROR_COMMAND_DISALLOWED +// } + connPtr->llCTE_RspFlag = LL_CONN_CTE_RSP_ENABLE; + break; + + case LL_CONN_CTE_RSP_DISENABLE: + connPtr->llCTE_RspFlag = LL_CONN_CTE_RSP_DISENABLE; + break; + + default: + break; + } + + return LL_STATUS_SUCCESS; +} + +llStatus_t LL_READ_Anatenna_Info( uint8* param ) +{ + // PHY SDK default support + // switching_sampling_rate + param[0] = LL_CONTROLLER_SUPP_1US_AOD_TX | \ + LL_CONTROLLER_SUPP_1US_AOD_SAMP | \ + LL_CONTROLLER_SUPP_1US_AOA_TX_SAMP; + // Antenna length + param[1] = LL_CTE_MAX_ANTENNA_LEN; + // MAX Length of switch pattern + param[2] = LL_CTE_MAX_PATTERN_LEN; + // MAX CTE Length + param[3] = LL_CTE_MAX_SUPP_LEN; + return LL_STATUS_SUCCESS; +} + +// power compensation +llStatus_t LL_Read_Rf_Path_Compensation(uint8* param) +{ + param[0] = LO_UINT16(g_rfTxPathCompensation); + param[1] = HI_UINT16(g_rfTxPathCompensation); + param[2] = LO_UINT16(g_rfRxPathCompensation); + param[3] = HI_UINT16(g_rfRxPathCompensation); + return LL_STATUS_SUCCESS; +} + +llStatus_t LL_Write_Rf_Path_Compensation(int16 tx_compensation, int16 rx_compensation) +{ + g_rfTxPathCompensation = tx_compensation; + g_rfRxPathCompensation = rx_compensation; + return LL_STATUS_SUCCESS; +} + +llStatus_t LL_Read_Transmit_Power( uint8* param) +{ + int8 minTxPwr, maxTxPwr; + // temporary set as protocol range + minTxPwr = -20; + maxTxPwr = 20; + param[1] = LO_UINT16(minTxPwr); + param[2] = HI_UINT16(maxTxPwr); + return LL_STATUS_SUCCESS; +} +//////////////////////////////////////// Vendor specific command API ////////////////////////////////////// +/* +** Vendor Specific Command API +*/ + +/******************************************************************************* + @fn LL_EXT_SetRxGain Vendor Specific API + + @brief This function is used to to set the RF RX gain. + + input parameters + + @param rxGain - LL_EXT_RX_GAIN_STD, LL_EXT_RX_GAIN_HIGH + + output parameters + + @param cmdComplete - Boolean to indicate the command is still pending. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER +*/ +llStatus_t LL_EXT_SetRxGain( uint8 rxGain, + uint8* cmdComplete ) +{ + return 0; +} + + +/******************************************************************************* + @fn LL_EXT_SetTxPower0 Vendor Specific API + + @brief This function is used to to set the RF TX power. + + input parameters + + @param txPower - LL_EXT_TX_POWER_0_DBM, LL_EXT_TX_POWER_4_DBM + + output parameters + + @param cmdComplete - Boolean to indicate the command is still pending. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER +*/ +llStatus_t LL_EXT_SetTxPower0( uint8 txPower, + uint8* cmdComplete ) +{ + uint32 temp; + *cmdComplete = TRUE; + temp = *(volatile uint32*)(0x400302b8); + *(volatile uint32*)(0x400300b8) = (temp & 0xfffe0fff) | ((txPower & 0x1f) << 12); + return ( LL_STATUS_SUCCESS ); +} + + + + +/******************************************************************************* + @fn LL_EXT_ClkDivOnHalt Vendor Specific API + + @brief This function is used to enable or disable dividing down the + system clock while halted. + + Note: This command is disallowed if haltDuringRf is not defined. + + input parameters + + @param control - LL_EXT_ENABLE_CLK_DIVIDE_ON_HALT, + LL_EXT_DISABLE_CLK_DIVIDE_ON_HALT + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_COMMAND_DISALLOWED +*/ +llStatus_t LL_EXT_ClkDivOnHalt( uint8 control ) +{ + return 0; +} + + +/******************************************************************************* + @fn LL_EXT_DeclareNvUsage Vendor Specific API + + @brief This HCI Extension API is used to indicate to the Controller + whether or not the Host will be using the NV memory during BLE + operations. + + input parameters + + @param mode - HCI_EXT_NV_IN_USE, HCI_EXT_NV_NOT_IN_USE + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + LL_STATUS_ERROR_COMMAND_DISALLOWED +*/ +llStatus_t LL_EXT_DeclareNvUsage( uint8 mode ) +{ + return 0; +} + + +/******************************************************************************* + @fn LL_EXT_Decrypt API + + @brief This API is called by the HCI to request the LL to decrypt the + data in the command using the key given in the command. + + Note: The parameters are byte ordered MSO to LSO. + + input parameters + + @param *key - A 128 bit key to be used to calculate the + session key. + @param *encryptedData - A 128 bit block that is encrypted. + + output parameters + + @param *plaintextData - A 128 bit block that is to be encrypted. + + @param None. + + @return LL_STATUS_SUCCESS +*/ +llStatus_t LL_EXT_Decrypt( uint8* key, + uint8* encryptedData, + uint8* plaintextData ) +{ + return 0; +} + + +/******************************************************************************* + @fn LL_EXT_SetLocalSupportedFeatures API + + @brief This API is called by the HCI to indicate to the Controller + which features can or can not be used. + + Note: Not all features indicated by the Host to the Controller + are valid. If invalid, they shall be ignored. + + input parameters + + @param featureSet - A pointer to the Feature Set where each bit: + 0: Feature shall not be used. + 1: Feature can be used. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS +*/ +llStatus_t LL_EXT_SetLocalSupportedFeatures( uint8* featureSet ) +{ + return 0; +} + + + +/******************************************************************************* + @fn LL_EXT_ModemTestTx + + @brief This API is used start a continuous transmitter modem test, + using either a modulated or unmodulated carrier wave tone, at + the frequency that corresponds to the specified RF channel. Use + LL_EXT_EndModemTest command to end the test. + + Note: A LL reset will be issued by LL_EXT_EndModemTest! + Note: The BLE device will transmit at maximum power. + Note: This API can be used to verify this device meets Japan's + TELEC regulations. + + input parameters + + @param cwMode - LL_EXT_TX_MODULATED_CARRIER, + LL_EXT_TX_UNMODULATED_CARRIER + txFreq - Transmit RF channel k=0..39, where BLE F=2402+(k*2MHz). + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE +*/ +llStatus_t LL_EXT_ModemTestTx( uint8 cwMode, + uint8 txFreq ) +{ + return 0; +} + + +/******************************************************************************* + @fn LL_EXT_ModemHopTestTx + + @brief This API is used to start a continuous transmitter direct test + mode test using a modulated carrier wave and transmitting a + 37 byte packet of Pseudo-Random 9-bit data. A packet is + transmitted on a different frequency (linearly stepping through + all RF channels 0..39) every 625us. Use LL_EXT_EndModemTest + command to end the test. + + Note: A LL reset will be issued by LL_EXT_EndModemTest! + Note: The BLE device will transmit at maximum power. + Note: This API can be used to verify this device meets Japan's + TELEC regulations. + + input parameters + + @param None. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE +*/ +llStatus_t LL_EXT_ModemHopTestTx( void ) +{ + return 0; +} + + +/******************************************************************************* + @fn LL_EXT_ModemTestRx + + @brief This API is used to start a continuous receiver modem test + using a modulated carrier wave tone, at the frequency that + corresponds to the specific RF channel. Any received data is + discarded. Receiver gain may be adjusted using the + LL_EXT_SetRxGain command. RSSI may be read during this test by + using the LL_ReadRssi command. Use LL_EXT_EndModemTest command + to end the test. + + Note: A LL reset will be issued by LL_EXT_EndModemTest! + Note: The BLE device will transmit at maximum power. + + input parameters + + @param rxFreq - Receiver RF channel k=0..39, where BLE F=2402+(k*2MHz). + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE +*/ +llStatus_t LL_EXT_ModemTestRx( uint8 rxFreq ) +{ + return 0; +} + + +/******************************************************************************* + @fn LL_EXT_EndModemTest + + @brief This API is used to shutdown a modem test. A complete link + layer reset will take place. + + input parameters + + @param None. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE +*/ +llStatus_t LL_EXT_EndModemTest( void ) +{ + return 0; +} + + +/******************************************************************************* + @fn LL_EXT_SetFreqTune + + @brief This API is used to set the Frequncy Tuning up or down. If the + current setting is already at the max/min value, then no + update is performed. + + Note: This is a Production Test Mode only command! + + input parameters + + @param step - LL_EXT_SET_FREQ_TUNE_UP or LL_EXT_SET_FREQ_TUNE_DOWN + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER +*/ +llStatus_t LL_EXT_SetFreqTune( uint8 step ) +{ + return 0; +} + + +/******************************************************************************* + @fn LL_EXT_SaveFreqTune + + @brief This API is used to save the current Frequency Tuning value to + flash memory. It is restored on reboot or wake from sleep. + + Note: This is a Production Test Mode only command! + + input parameters + + @param None. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_COMMAND_DISALLOWED +*/ +llStatus_t LL_EXT_SaveFreqTune( void ) +{ + return 0; +} + + +/******************************************************************************* + @fn LL_EXT_SetMaxDtmTxPower Vendor Specific API + + @brief This function is used to set the max RF TX power to be used + when using Direct Test Mode. + + input parameters + + @param txPower - LL_EXT_TX_POWER_MINUS_23_DBM, + LL_EXT_TX_POWER_MINUS_6_DBM, + LL_EXT_TX_POWER_0_DBM, + LL_EXT_TX_POWER_4_DBM + + output parameters + + @param cmdComplete - Boolean to indicate the command is still pending. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER +*/ +llStatus_t LL_EXT_SetMaxDtmTxPower( uint8 txPower ) +{ + return 0; +} + + +/******************************************************************************* + @fn LL_EXT_MapPmIoPort Vendor Specific API + + @brief This function is used to configure and map a CC254x I/O Port as + a General Purpose I/O (GPIO) output signal that reflects the + Power Management (PM) state of the CC254x device. The GPIO + output will be High on Wake, and Low upon entering Sleep. This + feature can be disabled by specifying LL_EXT_PM_IO_PORT_NONE for + the ioPort (ioPin is then ignored). The system default value + upon hardware reset is disabled. This command can be used to + control an external DC-DC Converter (its actual intent) such has + the TI TPS62730 (or any similar converter that works the same + way). This command should be used with extreme care as it will + override how the Port/Pin was previously configured! This + includes the mapping of Port 0 pins to 32kHz clock output, + Analog I/O, UART, Timers; Port 1 pins to Observables, Digital + Regulator status, UART, Timers; Port 2 pins to an external 32kHz + XOSC. The selected Port/Pin will be configured as an output GPIO + with interrupts masked. Careless use can result in a + reconfiguration that could disrupt the system. It is therefore + the user's responsibility to ensure the selected Port/Pin does + not cause any conflicts in the system. + + Note: Only Pins 0, 3 and 4 are valid for Port 2 since Pins 1 + and 2 are mapped to debugger signals DD and DC. + + Note: Port/Pin signal change will only occur when Power Savings + is enabled. + + input parameters + + @param ioPort - LL_EXT_PM_IO_PORT_P0, + LL_EXT_PM_IO_PORT_P1, + LL_EXT_PM_IO_PORT_P2, + LL_EXT_PM_IO_PORT_NONE + + @param ioPin - LL_EXT_PM_IO_PORT_PIN0, + LL_EXT_PM_IO_PORT_PIN1, + LL_EXT_PM_IO_PORT_PIN2, + LL_EXT_PM_IO_PORT_PIN3, + LL_EXT_PM_IO_PORT_PIN4, + LL_EXT_PM_IO_PORT_PIN5, + LL_EXT_PM_IO_PORT_PIN6, + LL_EXT_PM_IO_PORT_PIN7 + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + LL_STATUS_ERROR_COMMAND_DISALLOWED +*/ +llStatus_t LL_EXT_MapPmIoPort( uint8 ioPort, uint8 ioPin ) +{ + return 0; +} + + + +/******************************************************************************* + @fn LL_EXT_ExtendRfRange Vendor Specific API + + @brief This function is used to Extend Rf Range using the TI CC2590 + 2.4 GHz RF Front End device. + + input parameters + + @param cmdComplete - Pointer to get indicatin if command is done. + + output parameters + + @param cmdComplete - Boolean to indicate the command is still pending. + + @return LL_STATUS_SUCCESS +*/ +//llStatus_t LL_EXT_ExtendRfRange( uint8 *cmdComplete ) +//{ +// return 0; +//} + + +/******************************************************************************* + @fn LL_EXT_HaltDuringRf Vendor Specfic API + + @brief This function is used to enable or disable halting the + CPU during RF. The system defaults to enabled. + + input parameters + + @param mode - LL_EXT_HALT_DURING_RF_ENABLE, + LL_EXT_HALT_DURING_RF_DISABLE + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_COMMAND_DISALLOWED, + LL_STATUS_ERROR_BAD_PARAMETER +*/ +llStatus_t LL_EXT_HaltDuringRf( uint8 mode ) +{ + return 0; +} + +/******************************************************************************* + @fn LL_EXT_BuildRevision Vendor Specific API + + @brief This API is used to to set a user revision number or read the + build revision number. + + input parameters + + @param mode - LL_EXT_SET_USER_REVISION | + LL_EXT_READ_BUILD_REVISION + @param userRevNum - A 16 bit value the user can set as their own + revision number + + output parameters + + @param buildRev - Pointer to returned build revision, if any. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER +*/ +llStatus_t LL_EXT_BuildRevision( uint8 mode, uint16 userRevNum, uint8* buildRev ) +{ + return 0; +} + + +/******************************************************************************* + @fn LL_EXT_DelaySleep Vendor Specific API + + @brief This API is used to to set the sleep delay. + + input parameters + + @param delay - 0 .. 1000, in milliseconds. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER +*/ +llStatus_t LL_EXT_DelaySleep( uint16 delay ) +{ + return 0; +} + + +/******************************************************************************* + @fn LL_EXT_ResetSystem Vendor Specific API + + @brief This API is used to to issue a soft or hard system reset. + + input parameters + + @param mode - LL_EXT_RESET_SYSTEM_HARD | LL_EXT_RESET_SYSTEM_SOFT + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER +*/ +llStatus_t LL_EXT_ResetSystem( uint8 mode ) +{ + return 0; +} + + +/******************************************************************************* + @fn LL_EXT_SetFastTxResponseTime API + + @brief This API is used to enable or disable the fast TX response + time feature. This can be helpful when a short connection + interval is used in combination with slave latency. In such + a scenario, the response time for sending the TX data packet + can effectively shorten or eliminate slave latency, thereby + increasing power consumption. By disabling, this feature + trades fast response time for less power consumption. + + input parameters + + @param control - LL_EXT_ENABLE_FAST_TX_RESP_TIME, + LL_EXT_DISABLE_FAST_TX_RESP_TIME + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_COMMAND_DISALLOWED, + LL_STATUS_ERROR_BAD_PARAMETER +*/ +llStatus_t LL_EXT_SetFastTxResponseTime( uint8 control ) +{ + return 0; +} + +/******************************************************************************* + @fn LL_EXT_SetSCA + + @brief This API is used to set this device's Sleep Clock Accuracy. + + Note: For a slave device, this value is directly used, but only + if power management is enabled. For a master device, this + value is converted into one of eight ordinal values + representing a SCA range, as specified in Table 2.2, + Vol. 6, Part B, Section 2.3.3.1 of the Core specification. + + Note: This command is only allowed when the device is not in a + connection. + + Note: The device's SCA value remains unaffected by a HCI_Reset. + + input parameters + + @param scaInPPM - This device's SCA in PPM from 0..500. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + LL_STATUS_ERROR_COMMAND_DISALLOWED +*/ +llStatus_t LL_EXT_SetSCA( uint16 scaInPPM ) +{ + return 0; +} + +/******************************************************************************* + @fn LL_EXT_SetSlaveLatencyOverride API + + @brief This API is used to enable or disable the suspention of slave + latency. This can be helpful when the Slave application knows + it will soon receive something that needs to be handled without + delay. + + input parameters + + @param control - LL_EXT_DISABLE_SL_OVERRIDE, + LL_EXT_ENABLE_SL_OVERRIDE + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_COMMAND_DISALLOWED, + LL_STATUS_ERROR_BAD_PARAMETER +*/ +llStatus_t LL_EXT_SetSlaveLatencyOverride( uint8 control ) +{ + return 0; +} + +/******************************************************************************* + @fn LL_EXT_AdvEventNotice Vendor Specific API + + @brief This API is called to enable or disable a notification to the + specified task using the specified task event whenever a Adv + event ends. A non-zero taskEvent value is taken to be "enable", + while a zero valued taskEvent is taken to be "disable". + + input parameters + + @param taskID - User's task ID. + @param taskEvent - User's task event. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER +*/ +llStatus_t LL_EXT_AdvEventNotice( uint8 taskID, uint16 taskEvent ) +{ + return 0; +} + +/******************************************************************************* + @fn LL_EXT_PacketErrorRate Vendor Specific API + + @brief This function is used to Reset or Read the Packet Error Rate + counters for a connection. When Reset, the counters are cleared; + when Read, the total number of packets received, the number of + packets received with a CRC error, the number of events, and the + number of missed events are returned via a callback. + + Note: The counters are only 16 bits. At the shortest connection + interval, this provides a bit over 8 minutes of data. + + input parameters + + @param connId - The LL connection ID on which to send this data. + @param command - LL_EXT_PER_RESET, LL_EXT_PER_READ + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_INACTIVE_CONNECTION +*/ +llStatus_t LL_EXT_PacketErrorRate( uint16 connId, uint8 command ) +{ + return 0; +} + + +/* +** LL Callbacks to HCI +*/ + +/******************************************************************************* + @fn LL_EXT_PacketErrorRateCback Callback + + @brief This Callback is used by the LL to notify the HCI that the + Packet Error Rate Read command has been completed. + + Note: The counters are only 16 bits. At the shortest connection + interval, this provides a bit over 8 minutes of data. + + input parameters + + @param numPkts - Number of Packets received. + @param numCrcErr - Number of Packets received with a CRC error. + @param numEvents - Number of Connection Events. + @param numPkts - Number of Missed Connection Events. + + output parameters + + @param None. + + @return None. +*/ +//void LL_EXT_PacketErrorRateCback( uint16 numPkts, +// uint16 numCrcErr, +// uint16 numEvents, +// uint16 numMissedEvts ) +//{ +// return; +//} + +llStatus_t LL_EXT_SetBDADDR( uint8* bdAddr ) +{ + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + @fn LL_InitConnectContext + + @brief This function initialize the LL connection-orient context + + input parameters + + @param pConnContext - connection-orient context, the memory is allocated by application + maxConnNum - the size of connect-orient context + maxPktPerEvent - number of packets transmit/receive per connection event + + output parameters + + @param None. + + @return None. +*/ +llStatus_t LL_InitConnectContext(llConnState_t* pConnContext, + uint8* pConnBuffer, + uint8 maxConnNum, + uint8 maxPktPerEventTx, + uint8 maxPktPerEventRx, + uint8 blePktVersion) +{ + int i, j; + int pktLen; + uint8* p; + int total = 0; + + if (maxConnNum > MAX_NUM_LL_CONN) + return LL_STATUS_ERROR_BAD_PARAMETER; + + if (pConnContext == NULL) + return LL_STATUS_ERROR_BAD_PARAMETER; + + if (pConnBuffer == NULL) + return LL_STATUS_ERROR_BAD_PARAMETER; + + if (blePktVersion == BLE_PKT_VERSION_4_0) // BLE4.0 + pktLen = BLE_PKT40_LEN; + else if (blePktVersion == BLE_PKT_VERSION_5_1) // BLE5.1 + pktLen = BLE_PKT51_LEN; + + pktLen += 6; // header + g_maxConnNum = maxConnNum; + conn_param = pConnContext; + g_maxPktPerEventTx = maxPktPerEventTx; + g_maxPktPerEventRx = maxPktPerEventRx; + g_blePktVersion = blePktVersion; + p = pConnBuffer; + + for (i = 0; i < maxConnNum; i++) + { + memset(&conn_param[i], 0, sizeof(llConnState_t)); + + for (j = 0; j < maxPktPerEventTx; j++) + { + conn_param[i].ll_buf.tx_conn_desc[j] = (struct ll_pkt_desc*)p; + p += pktLen; + total += pktLen; + } + + for (j = 0; j < maxPktPerEventRx; j++) + { + conn_param[i].ll_buf.rx_conn_desc[j] = (struct ll_pkt_desc*)p; + p += pktLen; + total += pktLen; + } + + conn_param[i].ll_buf.tx_not_ack_pkt = (struct ll_pkt_desc*)p; + p += pktLen; + total += pktLen; + + for (j = 0; j < maxPktPerEventTx; j++) + { + conn_param[i].ll_buf.tx_ntrm_pkts[j] = (struct ll_pkt_desc*)p; + p += pktLen; + total += pktLen; + } + } + +// LOG("total = %d\n", total); + return( LL_STATUS_SUCCESS ); +} + + +// necessary? +/******************************************************************************* + @fn LL_InitExtendedScan + + @brief This function initialize the extended scan context + + input parameters + + @param scanDataBuffer - + scanDataBufferLength - + + output parameters + + @param None. + + @return None. +*/ +llStatus_t LL_InitExtendedScan(uint8* scanDataBuffer, + uint16 scanDataBufferLength) +{ + extScanInfo.adv_data = scanDataBuffer; + extScanInfo.adv_data_buf_len = scanDataBufferLength; + return( LL_STATUS_SUCCESS ); +} + +// TODO: need better interface for user +/******************************************************************************* + @fn LL_InitExtendedAdv + + @brief The capability of extend advertiser is decided by application. + Application should allocate the memory for extend adv and init + LL ext advertiser + + + + input parameters + + @param extAdvInfo - pointer to memory block for extended adv info + @param extAdvNumber - size of the memory block for extended adv info + @param advSetMaxLen - maximum adv data set length + + output parameters + + @param None. + + @return None. +*/ +llStatus_t LL_InitExtendedAdv( extAdvInfo_t* extAdvInfo, + uint8 extAdvSetNumber, + uint16 advSetMaxLen) +{ + int i; + g_pExtendedAdvInfo = extAdvInfo; + g_extAdvNumber = extAdvSetNumber; + g_advSetMaximumLen = advSetMaxLen; + + for (i = 0; i < g_extAdvNumber; i ++) + { + g_pExtendedAdvInfo[i].advHandle = LL_INVALID_ADV_SET_HANDLE; + g_pExtendedAdvInfo[i].parameter.isOwnRandomAddressSet = FALSE; +// g_pExtendedAdvInfo[i].parameter.advertisingSID = LL_INVALID_ADV_SET_HANDLE; + g_pExtendedAdvInfo[i].adv_event_counter = 0; + g_pExtendedAdvInfo[i].data.fragmentPreference = 0xFF; + g_pExtendedAdvInfo[i].data.advertisingDataLength = 0; // no adv data + g_pExtendedAdvInfo[i].data.dataComplete = FALSE; + g_pExtendedAdvInfo[i].scanRspMaxLength = 0; // no scan rsp data + g_pExtendedAdvInfo[i].isPeriodic = FALSE; + } + + // init adv scheduler + g_pAdvSchInfo = (llAdvScheduleInfo_t*)osal_mem_alloc(sizeof(llAdvScheduleInfo_t) * g_extAdvNumber); + + if (g_pAdvSchInfo == NULL) + return (LL_STATUS_ERROR_OUT_OF_HEAP); + + for (i = 0; i < g_extAdvNumber; i ++) + { + g_pAdvSchInfo[i].adv_handler = LL_INVALID_ADV_SET_HANDLE; + g_pAdvSchInfo[i].pAdvInfo = NULL; + } + + g_schExtAdvNum = 0; + g_currentExtAdv = 0xFF; // invalid + // temp set, change to global_config + g_advSlotPeriodic = pGlobal_config[LL_EXT_ADV_RSC_PERIOD]; // 1 second + g_advPerSlotTick = pGlobal_config[LL_EXT_ADV_RSC_SLOT_DURATION]; // 10ms + llTaskState = LL_TASK_INVALID; + g_interAuxPduDuration = pGlobal_config[LL_EXT_ADV_INTER_SEC_CHN_INT]; + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + @fn LL_InitPediodicAdv + + @brief The capability of periodic advertiser is decided by application. + Application should allocate the memory for extend adv and init + LL ext advertiser + + + + input parameters + + @param extAdvInfo - pointer to memory block for extended adv info + @param extAdvNumber - size of the memory block for extended adv info + @param advSetMaxLen - maximum adv data set length + + output parameters + + @param None. + + @return None. +*/ +llStatus_t LL_InitPeriodicAdv(extAdvInfo_t* extAdvInfo, + periodicAdvInfo_t* periodicAdvInfo, + uint8 periodicAdvSetNumber, + uint16 advSetMaxLen) +{ + int i; + g_pExtendedAdvInfo = extAdvInfo; + g_extAdvNumber = periodicAdvSetNumber; + g_pPeriodicAdvInfo = periodicAdvInfo; + g_perioAdvNumber = periodicAdvSetNumber; + g_advSetMaximumLen = advSetMaxLen; + + for (i = 0; i < g_extAdvNumber; i ++) + { + g_pExtendedAdvInfo[i].advHandle = LL_INVALID_ADV_SET_HANDLE; + g_pExtendedAdvInfo[i].parameter.isOwnRandomAddressSet = FALSE; + g_pExtendedAdvInfo[i].parameter.advertisingSID = LL_INVALID_ADV_SET_HANDLE; + g_pExtendedAdvInfo[i].adv_event_counter = 0; + g_pExtendedAdvInfo[i].data.fragmentPreference = 0xFF; + g_pExtendedAdvInfo[i].data.advertisingDataLength = 0; // no data + g_pExtendedAdvInfo[i].data.dataComplete = FALSE; + g_pExtendedAdvInfo[i].data.advertisingData = NULL; // should not be filled + g_pExtendedAdvInfo[i].isPeriodic = FALSE; + } + + for (i = 0; i < g_perioAdvNumber; i ++) + { + g_pPeriodicAdvInfo[i].advHandle = LL_INVALID_ADV_SET_HANDLE; + g_pPeriodicAdvInfo[i].active = FALSE; + g_pPeriodicAdvInfo[i].periodic_adv_event_counter = 0; + g_pPeriodicAdvInfo[i].currentAdvOffset = 0; + g_pPeriodicAdvInfo[i].data.advertisingDataLength = 0; // no data + g_pPeriodicAdvInfo[i].data.dataComplete = FALSE; + } + + // =============== init adv scheduler + g_pAdvSchInfo_periodic = (llPeriodicAdvScheduleInfo_t*)osal_mem_alloc(sizeof(llPeriodicAdvScheduleInfo_t) * periodicAdvSetNumber); + + if (g_pAdvSchInfo_periodic == NULL) + return (LL_STATUS_ERROR_OUT_OF_HEAP); + + for (i = 0; i < g_perioAdvNumber; i ++) + { + g_pAdvSchInfo_periodic[i].adv_handler = LL_INVALID_ADV_SET_HANDLE; + g_pAdvSchInfo_periodic[i].pAdvInfo = NULL; + } + + g_schExtAdvNum_periodic = 0; + g_currentExtAdv_periodic = 0xFF; // invalid + // temp set, change to global_config + g_advSlotPeriodic = pGlobal_config[LL_PRD_ADV_RSC_PERIOD]; // 1 second + g_advPerSlotTick = pGlobal_config[LL_PRD_ADV_RSC_SLOT_DURATION]; // 10ms + // the IFS time between 2 continuous AUX PDU in the same periodic/extended adv event + g_interAuxPduDuration = pGlobal_config[LL_EXT_ADV_INTER_SEC_CHN_INT]; + llTaskState = LL_TASK_INVALID; + return( LL_STATUS_SUCCESS ); +} + + +// ======= extended adv/periodic adv PDU construction functions +//#pragma O0 + +//#define LL_PERIOD_ADV_EXT_PART_DURATION 20000 +// ADV_EXT_IND PDU construction function +void llSetupAdvExtIndPDU0(extAdvInfo_t* pAdvInfo, periodicAdvInfo_t* pPrdAdv) +{ + uint8 advMode, extHeaderFlag, length, extHdrLength; + uint8 offset = 0; + + // set AdvMode + if (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_CONN_BITMASK) + advMode = LL_EXT_ADV_MODE_CONN; + else if (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_SCAN_BITMASK) + advMode = LL_EXT_ADV_MODE_SC; + else + advMode = LL_EXT_ADV_MODE_NOCONN_NOSC; + + length = 0; + // adv PDU header + g_tx_ext_adv_buf.txheader = 0; + // PDU type, 4 bits + SET_BITS(g_tx_ext_adv_buf.txheader, ADV_EXT_TYPE, PDU_TYPE_SHIFT, PDU_TYPE_MASK); + // RFU, ChSel, TxAdd, RxAdd + SET_BITS(g_tx_ext_adv_buf.txheader, pAdvInfo->parameter.ownAddrType, TX_ADD_SHIFT, TX_ADD_MASK); + // === step 1. decide the extended header fields + extHdrLength = 0; + // extended header + extHeaderFlag = 0; + extHdrLength ++; // flag + + if (pAdvInfo->isPeriodic == FALSE && (pAdvInfo->data.dataComplete == TRUE && pAdvInfo->data.advertisingDataLength == 0)) // no aux PDU case + { + extHeaderFlag |= LE_EXT_HDR_ADVA_PRESENT_BITMASK; + extHdrLength += 6; + + if (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_DIRECT_BITMASK) + { + extHeaderFlag |= LE_EXT_HDR_TARGETA_PRESENT_BITMASK; + extHdrLength += 6; + } + } + else // with auxilary PDU case + { + extHeaderFlag |= LE_EXT_HDR_ADI_PRESENT_BITMASK | LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK; + extHdrLength += 5; + } + + if (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_TX_POWER_BITMASK) + { + extHeaderFlag |= LE_EXT_HDR_TX_PWR_PRESENT_BITMASK; + extHdrLength ++; + } + + length = 1 + extHdrLength; // 1: extended header len(6bits) + advMode(2bit) + // Length + SET_BITS(g_tx_ext_adv_buf.txheader, length, LENGTH_SHIFT, LENGTH_MASK); + // === step 2. fill extended header + offset = 0; + // Extended header length + AdvMode(1 octet) + g_tx_ext_adv_buf.data[offset] = ((advMode & 0x3) << 6) | (extHdrLength & 0x3F); + offset ++; + g_tx_ext_adv_buf.data[offset] = extHeaderFlag; + offset ++; + + // AdvA (6 octets) + if (extHeaderFlag & LE_EXT_HDR_ADVA_PRESENT_BITMASK) + { + if (pAdvInfo->parameter.ownAddrType == LL_DEV_ADDR_TYPE_RANDOM && pAdvInfo->parameter.isOwnRandomAddressSet == TRUE) + memcpy(&g_tx_ext_adv_buf.data[offset], pAdvInfo->parameter.ownRandomAddress, LL_DEVICE_ADDR_LEN); + else // public address + memcpy(&g_tx_ext_adv_buf.data[offset], ownPublicAddr, LL_DEVICE_ADDR_LEN); + + offset += LL_DEVICE_ADDR_LEN; + } + + // TargetA(6 octets) + if (extHeaderFlag & LE_EXT_HDR_TARGETA_PRESENT_BITMASK) + { + // TODO: peer addr type process check + memcpy(&g_tx_ext_adv_buf.data[offset], pAdvInfo->parameter.peerAddress, LL_DEVICE_ADDR_LEN); + offset += LL_DEVICE_ADDR_LEN; + } + + // CTEInfo(1 octets), always not present +// if (extHeaderFlag & LE_EXT_HDR_CTE_INFO_PRESENT_BITMASK) +// { +// offset += 1; +// } + + // AdvDataInfo(ADI)(2 octets) + if (extHeaderFlag & LE_EXT_HDR_ADI_PRESENT_BITMASK) + { + uint16 adi; + adi = ((pAdvInfo->parameter.advertisingSID & 0x0F) << 12) | (pAdvInfo->data.DIDInfo & 0x0FFF); + memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&adi, 2); + offset += 2; + } + + // AuxPtr(3 octets) + if (extHeaderFlag & LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK) + { + uint8 chn_idx, ca, offset_unit, aux_phy; + uint16 aux_offset; + uint32 temp = 0; + chn_idx = 3 + (pAdvInfo->advHandle & 0x0F); // temp set + ca = 0; // 50-500ppm + aux_phy = pAdvInfo->parameter.secondaryAdvPHY - 1; // HCI & LL using different enum + + // for extenede adv case, the offset is calculated by auxPduRemainder + if (pAdvInfo->isPeriodic == FALSE) + { + if (g_pAdvSchInfo[g_currentExtAdv].auxPduRemainder >= 245700) + offset_unit = 1; // 300us, for aux offset >= 245700us + else + offset_unit = 0; // 30us, for aux offset < 245700us + + // calculate elapse time since last timer trigger + //aux_offset = (g_pAdvSchInfo[g_currentExtAdv].auxPduRemainder - elapse_time) / ((offset_unit == 1) ? 300 : 30); + aux_offset = g_pAdvSchInfo[g_currentExtAdv].auxPduRemainder / ((offset_unit == 1) ? 300 : 30); + } + // for periodic adv case, the offset is fixed 1500us + 5000 * adv channel left + else + { + uint8_t temp, number; + temp = 1 << (pPrdAdv->currentChn - LL_ADV_CHAN_FIRST); // current bit mask + temp = ~(temp | (temp - 1)); + temp = pAdvInfo->parameter.priAdvChnMap & temp; // channel in the chan map to be broadcast + number = (temp & 0x0001) + + ((temp & 0x0002) >> 1) + + ((temp & 0x0004) >> 2); + // the interval between chan 37<->38, 38<->39 is 5000us, primary adv -> aux adv chn is 1500us + offset_unit = 0; // 30us, for aux offset < 245700us + aux_offset = (number * pGlobal_config[LL_EXT_ADV_INTER_PRI_CHN_INT] + pGlobal_config[LL_EXT_ADV_PRI_2_SEC_CHN_INT]) / 30; + } + +// LOG("#%d#%d# ", g_pAdvSchInfo[g_currentExtAdv].auxPduRemainder - elapse_time, aux_offset); + temp |= (chn_idx & LL_AUX_PTR_CHN_IDX_MASK) << LL_AUX_PTR_CHN_IDX_SHIFT; + temp |= (ca & LL_AUX_PTR_CA_MASK) << LL_AUX_PTR_CA_SHIFT; + temp |= (offset_unit & LL_AUX_PTR_OFFSET_UNIT_MASK) << LL_AUX_PTR_OFFSET_UNIT_SHIFT; + temp |= (aux_offset & LL_AUX_PTR_AUX_OFFSET_MASK) << LL_AUX_PTR_AUX_OFFSET_SHIFT; + temp |= (aux_phy & LL_AUX_PTR_AUX_PHY_MASK) << LL_AUX_PTR_AUX_PHY_SHIFT; + temp &= 0x00FFFFFF; + memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&temp, 3); + pAdvInfo->auxChn = chn_idx; // save secondary channel index + pAdvInfo->currentAdvOffset = 0; // reset offset in adv data set + offset += 3; + } + + // SyncInfo(18 octets) +// if (extHeaderFlag & LE_EXT_HDR_SYNC_INFO_PRESENT_BITMASK) +// { +// // TODO +// offset += 18; +// } + + // TxPower(1 octets) + if (extHeaderFlag & LE_EXT_HDR_TX_PWR_PRESENT_BITMASK) // Tx power is optional, could we only filled it in AUX_ADV_IND? + { + int16 radia_pwr; + radia_pwr = pAdvInfo->tx_power * 10 + g_rfTxPathCompensation; + + if (radia_pwr > 1270) radia_pwr = 1270; + + if (radia_pwr < -1270) radia_pwr = -1270; + + g_tx_ext_adv_buf.data[offset] = (uint8)(radia_pwr / 10); + offset += 1; + } + + // ACAD(varies) + // init adv data offset + pAdvInfo->currentAdvOffset = 0; +} + +void llSetupAuxAdvIndPDU0(extAdvInfo_t* pAdvInfo, periodicAdvInfo_t* pPrdAdv) +{ + uint8 advMode, extHeaderFlag, length, extHdrLength, advDataLen; + uint8 offset = 0; +// uint32 T2, elapse_time; + + // set AdvMode + if (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_CONN_BITMASK) + advMode = LL_EXT_ADV_MODE_CONN; + else if (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_SCAN_BITMASK) + advMode = LL_EXT_ADV_MODE_SC; + else + advMode = LL_EXT_ADV_MODE_NOCONN_NOSC; + + length = 0; + // adv PDU header + g_tx_ext_adv_buf.txheader = 0; + // PDU type, 4 bits + SET_BITS(g_tx_ext_adv_buf.txheader, ADV_EXT_TYPE, PDU_TYPE_SHIFT, PDU_TYPE_MASK); + // RFU, ChSel, TxAdd, RxAdd + SET_BITS(g_tx_ext_adv_buf.txheader, pAdvInfo->parameter.ownAddrType, TX_ADD_SHIFT, TX_ADD_MASK); + + if (pGlobal_config[LL_SWITCH] & CONN_CSA2_ALLOW) + SET_BITS(g_tx_adv_buf.txheader, 1, CHSEL_SHIFT, CHSEL_MASK); + + extHdrLength = 0; + // == step 1. decide what fields should be present in extended header + // extended header + extHeaderFlag = 0; + extHdrLength ++; + extHeaderFlag |= LE_EXT_HDR_ADI_PRESENT_BITMASK; + extHdrLength += 2; + + if (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_DIRECT_BITMASK) + { + extHeaderFlag |= LE_EXT_HDR_TARGETA_PRESENT_BITMASK; + extHdrLength += 6; + } + +// if (advMode != LL_EXT_ADV_MODE_NOCONN_NOSC) // This field is C4 for LL_EXT_ADV_MODE_NOCONN_NOSC, we will not send AdvA in EXT_ADV_IND, so it is mandatory here +// { + extHeaderFlag |= LE_EXT_HDR_ADVA_PRESENT_BITMASK; + extHdrLength += 6; +// } + + if (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_TX_POWER_BITMASK) + { + extHeaderFlag |= LE_EXT_HDR_TX_PWR_PRESENT_BITMASK; + extHdrLength ++; + } + + if (pAdvInfo->isPeriodic == TRUE) + { + extHeaderFlag |= LE_EXT_HDR_SYNC_INFO_PRESENT_BITMASK; + extHdrLength += 18; + } + + if (pAdvInfo->data.dataComplete == TRUE) + { + if (advMode == LL_EXT_ADV_MODE_NOCONN_NOSC + && (pAdvInfo->isPeriodic == FALSE) + && (pAdvInfo->data.advertisingDataLength > 255 - 1 - extHdrLength)) + { + extHeaderFlag |= LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK; + extHdrLength += 3; + // maximum payload length = 255: header len (= 1), ext header len(extHdrLength), adv data(advDataLen) + advDataLen = 255 - 1 - extHdrLength; // adv data length. TODO: check spec + } + else + advDataLen = pAdvInfo->data.advertisingDataLength; // put all adv data in field "Adv Data" + } + else // update 04-13, consider update adv data case + advDataLen = 0; + + length = 1 + extHdrLength + advDataLen; // 1: extended header len(6bits) + advMode(2bit) + // Length + SET_BITS(g_tx_ext_adv_buf.txheader, length, LENGTH_SHIFT, LENGTH_MASK); + // === step 2. fill AUX_ADV_IND PDU + // Extended header length + AdvMode(1 octet) + g_tx_ext_adv_buf.data[offset] = ((advMode & 0x3) << 6) | (extHdrLength & 0x3F); + offset ++; + g_tx_ext_adv_buf.data[offset] = extHeaderFlag; + offset ++; + + // AdvA (6 octets) + if (extHeaderFlag & LE_EXT_HDR_ADVA_PRESENT_BITMASK) + { + if (pAdvInfo->parameter.ownAddrType == LL_DEV_ADDR_TYPE_RANDOM && pAdvInfo->parameter.isOwnRandomAddressSet == TRUE) + memcpy(&g_tx_ext_adv_buf.data[offset], pAdvInfo->parameter.ownRandomAddress, LL_DEVICE_ADDR_LEN); + else // public address + memcpy(&g_tx_ext_adv_buf.data[offset], ownPublicAddr, LL_DEVICE_ADDR_LEN); + + offset += LL_DEVICE_ADDR_LEN; + } + + // TargetA(6 octets) + if (extHeaderFlag & LE_EXT_HDR_TARGETA_PRESENT_BITMASK) + { + memcpy(&g_tx_ext_adv_buf.data[offset], pAdvInfo->parameter.peerAddress, LL_DEVICE_ADDR_LEN); + offset += LL_DEVICE_ADDR_LEN; + } + + // CTEInfo(1 octets), not present for AUX_ADV_IND + if (extHeaderFlag & LE_EXT_HDR_CTE_INFO_PRESENT_BITMASK) + { + // offset += 1; + } + + // AdvDataInfo(ADI)(2 octets) + if (extHeaderFlag & LE_EXT_HDR_ADI_PRESENT_BITMASK) + { + uint16 adi; + adi = ((pAdvInfo->parameter.advertisingSID & 0x0F) << 12) | (pAdvInfo->data.DIDInfo & 0x0FFF); + memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&adi, 2); + offset += 2; + } + + // AuxPtr(3 octets) + if (extHeaderFlag & LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK) + { + uint8 chn_idx, ca, offset_unit, aux_phy; + uint16 aux_offset; + uint32 temp = 0; +// if (pAdvInfo->isPeriodic == FALSE) // no periodic adv case +// { + chn_idx = llGetNextAuxAdvChn(pAdvInfo->currentChn); + ca = 0; // 50-500ppm + offset_unit = 0; // 30us, for aux offset < 245700us + aux_phy = pAdvInfo->parameter.secondaryAdvPHY - 1; // HCI & LL using different enum + aux_offset = g_interAuxPduDuration / 30; + pAdvInfo->currentChn = chn_idx; +// } +// else // AUX_PTR field is not required for periodic adv AUX_ADV_IND +// { +// } + temp |= (chn_idx & LL_AUX_PTR_CHN_IDX_MASK) << LL_AUX_PTR_CHN_IDX_SHIFT; + temp |= (ca & LL_AUX_PTR_CA_MASK) << LL_AUX_PTR_CA_SHIFT; + temp |= (offset_unit & LL_AUX_PTR_OFFSET_UNIT_MASK) << LL_AUX_PTR_OFFSET_UNIT_SHIFT; + temp |= (aux_offset & LL_AUX_PTR_AUX_OFFSET_MASK) << LL_AUX_PTR_AUX_OFFSET_SHIFT; + temp |= (aux_phy & LL_AUX_PTR_AUX_PHY_MASK) << LL_AUX_PTR_AUX_PHY_SHIFT; + temp &= 0x00FFFFFF; + memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&temp, 3); + offset += 3; + } + else if (pAdvInfo->isPeriodic == FALSE) // only applicable to extended adv case + { + // no more aux PDU, update next channel number + int i = 0; + + while ((i < 3) && !(pAdvInfo->parameter.priAdvChnMap & (1 << i))) i ++; + + pAdvInfo->currentChn = LL_ADV_CHAN_FIRST + i; + } + else // periodic adv case + { + llPrdAdvDecideNextChn(pAdvInfo, pPrdAdv); + } + + // SyncInfo(18 octets) + if (extHeaderFlag & LE_EXT_HDR_SYNC_INFO_PRESENT_BITMASK) + { + // TODO + llSetupSyncInfo(pAdvInfo, pPrdAdv); + memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&syncInfo, 18); + offset += 18; + } + + // TxPower(1 octets) + if (extHeaderFlag & LE_EXT_HDR_TX_PWR_PRESENT_BITMASK) // Tx power is optional, could we only filled it in AUX_ADV_IND? + { + int16 radia_pwr; + radia_pwr = pAdvInfo->tx_power * 10 + g_rfTxPathCompensation; + + if (radia_pwr > 1270) radia_pwr = 1270; + + if (radia_pwr < -1270) radia_pwr = -1270; + + g_tx_ext_adv_buf.data[offset] = (uint8)(radia_pwr / 10); + offset += 1; + } + + // ACAD(varies), not present + + // copy adv data + if (pAdvInfo->isPeriodic == FALSE) + { + memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&pAdvInfo->data.advertisingData[pAdvInfo->currentAdvOffset], advDataLen); + pAdvInfo->currentAdvOffset += advDataLen; + } +} +//#pragma O0 +void llSetupAuxChainIndPDU0(extAdvInfo_t* pAdvInfo, periodicAdvInfo_t* pPrdAdv) +{ + uint8 advMode, extHeaderFlag, length, extHdrLength, advDataLen; + uint8 offset = 0; + // set AdvMode + advMode = 0; + length = 0; + // adv PDU header + g_tx_ext_adv_buf.txheader = 0; + // PDU type, 4 bits + SET_BITS(g_tx_ext_adv_buf.txheader, ADV_EXT_TYPE, PDU_TYPE_SHIFT, PDU_TYPE_MASK); + // RFU, ChSel, TxAdd, RxAdd + SET_BITS(g_tx_ext_adv_buf.txheader, pAdvInfo->parameter.ownAddrType, TX_ADD_SHIFT, TX_ADD_MASK); + extHdrLength = 0; + // extended header + extHeaderFlag = 0; + extHdrLength ++; + + // 2020-02-10 add for Connectionless CTE Info + // CTEInfo field is C5: Optional + if( pPrdAdv->PrdCTEInfo.enable == LL_CTE_ENABLE ) + { + if( pPrdAdv->PrdCTEInfo.CTE_Count > pPrdAdv->PrdCTEInfo.CTE_Count_Idx ) + { + extHeaderFlag |= LE_EXT_HDR_CTE_INFO_PRESENT_BITMASK; + extHdrLength ++; + } + } + + // ADI field is C3, it is present in our implementation + if (pAdvInfo->isPeriodic == FALSE) + { + extHeaderFlag |= LE_EXT_HDR_ADI_PRESENT_BITMASK; + extHdrLength += 2; + } + + // comment out because for periodic adv, tx pwr field is in AUX_SYNC_IND. for extended adv, txPwr field in AUX_ADV_IND +// if (((pAdvInfo->isPeriodic == FALSE) && (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_TX_POWER_BITMASK)) +// || ((pAdvInfo->isPeriodic == TRUE) && (pPrdAdv->adv_event_properties & LE_ADV_PROP_TX_POWER_BITMASK))) +// { +// extHeaderFlag |= LE_EXT_HDR_TX_PWR_PRESENT_BITMASK; +// extHdrLength ++; +// } + + // if Adv Data could not be sent completely in this PDU, need AuxPtr + if (pAdvInfo->isPeriodic == FALSE) + { + if (pAdvInfo->data.dataComplete == TRUE) + { + if (pAdvInfo->data.advertisingDataLength - pAdvInfo->currentAdvOffset > 255 - 1 - extHdrLength) + { + extHeaderFlag |= LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK; + extHdrLength += 3; + // maximum payload length = 255, header len = 1, ADI len = 2, AUX_PTR len = 2 + advDataLen = 255 - 1 - extHdrLength;; + } + else + advDataLen = pAdvInfo->data.advertisingDataLength - pAdvInfo->currentAdvOffset; // put all remain adv data in field "Adv Data" + } + else // update 04-13, adv data may be reconfigured during advertising, include no data in such case + advDataLen = 0; + } + else + { + if (pPrdAdv->data.dataComplete == TRUE) + { + if (pPrdAdv->data.advertisingDataLength - pPrdAdv->currentAdvOffset > 255 - 1 - extHdrLength) + { + extHeaderFlag |= LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK; + extHdrLength += 3; + // maximum payload length = 255, header len = 1, ADI len = 2, AUX_PTR len = 2 + advDataLen = 255 - 1 - extHdrLength;; + } + else + advDataLen = pPrdAdv->data.advertisingDataLength - pPrdAdv->currentAdvOffset; // put all remain adv data in field "Adv Data" + } + else // update 04-13, adv data may be reconfigured during advertising, include no data in such case + advDataLen = 0; + } + + length = 1 + extHdrLength + advDataLen; // 1: extended header len(6bits) + advMode(2bit) + // Length + SET_BITS(g_tx_ext_adv_buf.txheader, length, LENGTH_SHIFT, LENGTH_MASK); + // fill extended header + offset = 0; + // Extended header length + AdvMode(1 octet) + g_tx_ext_adv_buf.data[offset] = ((advMode & 0x3) << 6) | (extHdrLength & 0x3F); + offset ++; + g_tx_ext_adv_buf.data[offset] = extHeaderFlag; + offset ++; + + // CTEInfo(1 octets), not present for AUX_ADV_IND + if (extHeaderFlag & LE_EXT_HDR_CTE_INFO_PRESENT_BITMASK) + { + //LOG("\n SyC \n"); + g_tx_ext_adv_buf.data[offset] = ( ( pPrdAdv->PrdCTEInfo.CTE_Type << 6 ) | \ + ( pPrdAdv->PrdCTEInfo.CTE_Length)); + pPrdAdv->PrdCTEInfo.CTE_Count_Idx ++; + offset += 1; + } + + // AdvDataInfo(ADI)(2 octets) + if (extHeaderFlag & LE_EXT_HDR_ADI_PRESENT_BITMASK) + { + uint16 adi; + adi = ((pAdvInfo->parameter.advertisingSID & 0x0F) << 12) | (pAdvInfo->data.DIDInfo & 0x0FFF); + memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&adi, 2); + offset += 2; + } + + // AuxPtr(3 octets) + if (extHeaderFlag & LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK) + { + uint8 chn_idx, ca, offset_unit, aux_phy; + uint16 aux_offset; + uint32 temp = 0; + chn_idx = llGetNextAuxAdvChn(pAdvInfo->currentChn); + ca = 0; // 50-500ppm + offset_unit = 0; // 30us, for aux offset < 245700us + aux_phy = pAdvInfo->parameter.secondaryAdvPHY - 1; // HCI & LL using different enum + aux_offset = g_interAuxPduDuration / 30; + temp |= (chn_idx & LL_AUX_PTR_CHN_IDX_MASK) << LL_AUX_PTR_CHN_IDX_SHIFT; + temp |= (ca & LL_AUX_PTR_CA_MASK) << LL_AUX_PTR_CA_SHIFT; + temp |= (offset_unit & LL_AUX_PTR_OFFSET_UNIT_MASK) << LL_AUX_PTR_OFFSET_UNIT_SHIFT; + temp |= (aux_offset & LL_AUX_PTR_AUX_OFFSET_MASK) << LL_AUX_PTR_AUX_OFFSET_SHIFT; + temp |= (aux_phy & LL_AUX_PTR_AUX_PHY_MASK) << LL_AUX_PTR_AUX_PHY_SHIFT; + temp &= 0x00FFFFFF; + memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&temp, 3); + pAdvInfo->currentChn = chn_idx; // save secondary channel index + pPrdAdv->currentChn = chn_idx; + offset += 3; + } + else + { + // no more aux PDU, update next channel number + if (pAdvInfo->isPeriodic == FALSE) + { + int i = 0; + + while ((i < 3) && !(pAdvInfo->parameter.priAdvChnMap & (1 << i))) i ++; + + pAdvInfo->currentChn = LL_ADV_CHAN_FIRST + i; + } + else // periodic adv case + { + llPrdAdvDecideNextChn(pAdvInfo, pPrdAdv); + } + } + +// // TxPower(1 octets) +// if (extHeaderFlag & LE_EXT_HDR_TX_PWR_PRESENT_BITMASK) +// { +// // TODO +// offset += 1; +// } + + // ACAD(varies), not present + + // copy adv data + if (pAdvInfo == FALSE) + { + memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&pAdvInfo->data.advertisingData[pAdvInfo->currentAdvOffset], advDataLen); + pAdvInfo->currentAdvOffset += advDataLen; + } + else // periodic adv case + { + memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&pPrdAdv->data.advertisingData[pPrdAdv->currentAdvOffset], advDataLen); + pPrdAdv->currentAdvOffset += advDataLen; + + // if finish broad current periodic adv event, revert the read pointer of adv data + if (pPrdAdv->currentAdvOffset == pPrdAdv->data.advertisingDataLength) + { + // 2020-02-10 add logic for CTE info + if( pPrdAdv->PrdCTEInfo.enable == LL_CTE_ENABLE ) + { + if( pPrdAdv->PrdCTEInfo.CTE_Count_Idx >= pPrdAdv->PrdCTEInfo.CTE_Count ) + { + // already send all CTE info, then reset pPrdAdv->currentAdvOffset + pPrdAdv->currentAdvOffset = 0; + pPrdAdv->PrdCTEInfo.CTE_Count_Idx = 0; + // length set to zero means stop CTE + ll_hw_set_cte_txSupp( CTE_SUPP_LEN_SET | 0x0 ); + } + } + else + { + // 2020-02-21 bug fix: If CTE is not enabled, then + // subsequent packets will not be sent + pPrdAdv->currentAdvOffset = 0; + } + } + } +} + + +void llSetupAuxSyncIndPDU0(extAdvInfo_t* pAdvInfo, periodicAdvInfo_t* pPrdAdv) +{ + uint8 advMode, extHeaderFlag, length, extHdrLength, advDataLen; + uint8 offset = 0; + // set AdvMode + advMode = 0; + length = 0; + // adv PDU header + g_tx_ext_adv_buf.txheader = 0; + // PDU type, 4 bits + SET_BITS(g_tx_ext_adv_buf.txheader, ADV_EXT_TYPE, PDU_TYPE_SHIFT, PDU_TYPE_MASK); + // RFU, ChSel, TxAdd, RxAdd + SET_BITS(g_tx_ext_adv_buf.txheader, 0, TX_ADD_SHIFT, TX_ADD_MASK); // it seems TxAdd is ignored in spec + extHdrLength = 0; + // extended header + extHeaderFlag = 0; // for AUX_SYNC_IND PDU: CTE info, AuxPtr, Tx power, ACAD, Adv Data are optional, other fields are absent + extHdrLength ++; + + //extHeaderFlag |= LE_EXT_HDR_CTE_INFO_PRESENT_BITMASK; + // 2020-02-10 add for CTE transmit + // if periodic advertising CTE Enable + if( pPrdAdv->PrdCTEInfo.enable == LL_CTE_ENABLE ) + { + if( pPrdAdv->PrdCTEInfo.CTE_Count > 0 ) + { + extHeaderFlag |= LE_EXT_HDR_CTE_INFO_PRESENT_BITMASK; + extHdrLength ++; + } + } + + if (pPrdAdv->adv_event_properties & LE_ADV_PROP_TX_POWER_BITMASK) + { + extHeaderFlag |= LE_EXT_HDR_TX_PWR_PRESENT_BITMASK; + extHdrLength ++; + } + + // if Adv Data could not be sent completely in this PDU, need AuxPtr + if (pPrdAdv->data.dataComplete == TRUE) + { + if (pPrdAdv->data.advertisingDataLength - pPrdAdv->currentAdvOffset > 255 - 1 - extHdrLength) + { + extHeaderFlag |= LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK; + extHdrLength += 3; + // maximum payload length = 255, header len = 1, ADI len = 2, AUX_PTR len = 2 + advDataLen = 255 - 1 - extHdrLength; + } + else + advDataLen = pPrdAdv->data.advertisingDataLength - pPrdAdv->currentAdvOffset; // put all remain adv data in field "Adv Data" + } + else // update 04-13, adv data may be reconfigured during advertising, include no data in such case + advDataLen = 0; + + length = 1 + extHdrLength + advDataLen; // 1: extended header len(6bits) + advMode(2bit) + // Length + SET_BITS(g_tx_ext_adv_buf.txheader, length, LENGTH_SHIFT, LENGTH_MASK); + // fill extended header + offset = 0; + // Extended header length + AdvMode(1 octet) + g_tx_ext_adv_buf.data[offset] = ((advMode & 0x3) << 6) | (extHdrLength & 0x3F); + offset ++; + g_tx_ext_adv_buf.data[offset] = extHeaderFlag; + offset ++; + + // CTEInfo(1 octets), not present for AUX_ADV_IND + if (extHeaderFlag & LE_EXT_HDR_CTE_INFO_PRESENT_BITMASK) + { + g_tx_ext_adv_buf.data[offset] = ( ( pPrdAdv->PrdCTEInfo.CTE_Type << 6 ) | \ + ( pPrdAdv->PrdCTEInfo.CTE_Length)); + pPrdAdv->PrdCTEInfo.CTE_Count_Idx ++; + ll_hw_set_cte_txSupp( CTE_SUPP_LEN_SET | pPrdAdv->PrdCTEInfo.CTE_Length ); + offset += 1; +// LOG("\n Sy \n"); + } + + // AuxPtr(3 octets) + if (extHeaderFlag & LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK) + { + uint8 chn_idx, ca, offset_unit, aux_phy; + uint16 aux_offset; + uint32 temp = 0; + chn_idx = llGetNextAuxAdvChn(pPrdAdv->currentChn); + // fixed interval between periodic PDUs now + ca = 0; // 50-500ppm + offset_unit = 0; // 30us, for aux offset < 245700us + aux_offset = g_interAuxPduDuration / 30; + aux_phy = pAdvInfo->parameter.secondaryAdvPHY - 1; // HCI & LL using different enum + temp |= (chn_idx & LL_AUX_PTR_CHN_IDX_MASK) << LL_AUX_PTR_CHN_IDX_SHIFT; + temp |= (ca & LL_AUX_PTR_CA_MASK) << LL_AUX_PTR_CA_SHIFT; + temp |= (offset_unit & LL_AUX_PTR_OFFSET_UNIT_MASK) << LL_AUX_PTR_OFFSET_UNIT_SHIFT; + temp |= (aux_offset & LL_AUX_PTR_AUX_OFFSET_MASK) << LL_AUX_PTR_AUX_OFFSET_SHIFT; + temp |= (aux_phy & LL_AUX_PTR_AUX_PHY_MASK) << LL_AUX_PTR_AUX_PHY_SHIFT; + temp &= 0x00FFFFFF; + memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&temp, 3); + pPrdAdv->currentChn = chn_idx; // save secondary channel index + offset += 3; + } + else + { + // no more aux PDU, update next channel number + if (pAdvInfo->isPeriodic == FALSE) + { + int i = 0; + + while ((i < 3) && !(pAdvInfo->parameter.priAdvChnMap & (1 << i))) i ++; + + pAdvInfo->currentChn = LL_ADV_CHAN_FIRST + i; + } + else // periodic adv case + { + llPrdAdvDecideNextChn(pAdvInfo, pPrdAdv); + } + } + + // TxPower(1 octets) + if (extHeaderFlag & LE_EXT_HDR_TX_PWR_PRESENT_BITMASK) // Tx power is optional, could we only filled it in AUX_ADV_IND? + { + int16 radia_pwr; + radia_pwr = pAdvInfo->tx_power * 10 + g_rfTxPathCompensation; + + if (radia_pwr > 1270) radia_pwr = 1270; + + if (radia_pwr < -1270) radia_pwr = -1270; + + g_tx_ext_adv_buf.data[offset] = (uint8)(radia_pwr / 10); + offset += 1; + } + + // ACAD(varies), not present + // copy adv data + memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&pPrdAdv->data.advertisingData[pPrdAdv->currentAdvOffset], advDataLen); + pPrdAdv->currentAdvOffset += advDataLen; + + // if finish broad current periodic adv event, revert the read pointer of adv data + if (pPrdAdv->currentAdvOffset == pPrdAdv->data.advertisingDataLength) + { + // 2020-02-10 add logic for CTE info + if( pPrdAdv->PrdCTEInfo.enable == LL_CTE_ENABLE ) + { + if( pPrdAdv->PrdCTEInfo.CTE_Count_Idx >= pPrdAdv->PrdCTEInfo.CTE_Count ) + { + // already send all CTE info, then reset pPrdAdv->currentAdvOffset + pPrdAdv->currentAdvOffset = 0; + // length set to zero means stop CTE + ll_hw_set_cte_txSupp( CTE_SUPP_LEN_SET | 0x0 ); + } + } + else + { + // 2020-02-21 bug fix: If CTE is not enabled, then + // subsequent packets will not be sent + pPrdAdv->currentAdvOffset = 0; + } + } +} + +void llSetupAuxScanRspPDU0(extAdvInfo_t* pAdvInfo) +{ + uint8 advMode, extHeaderFlag, length, extHdrLength, advDataLen; + uint8 offset = 0; + // set AdvMode + advMode = 0; + length = 0; + // adv PDU header + g_tx_ext_adv_buf.txheader = 0; + // PDU type, 4 bits + SET_BITS(g_tx_ext_adv_buf.txheader, ADV_EXT_TYPE, PDU_TYPE_SHIFT, PDU_TYPE_MASK); + // RFU, ChSel, TxAdd, RxAdd + SET_BITS(g_tx_ext_adv_buf.txheader, 0, TX_ADD_SHIFT, TX_ADD_MASK); // it seems TxAdd is ignored in spec + extHdrLength = 0; + // extended header + extHeaderFlag = 0; // for AUX_SYNC_IND PDU: CTE info, AuxPtr, Tx power, ACAD, Adv Data are optional, other fields are absent + extHdrLength ++; + extHeaderFlag |= LE_EXT_HDR_ADVA_PRESENT_BITMASK; + extHdrLength += 6; + advDataLen = pAdvInfo->scanRspMaxLength; + length = 1 + extHdrLength + advDataLen; // 1: extended header len(6bits) + advMode(2bit) + // Length + SET_BITS(g_tx_ext_adv_buf.txheader, length, LENGTH_SHIFT, LENGTH_MASK); + // fill extended header + offset = 0; + // Extended header length + AdvMode(1 octet) + g_tx_ext_adv_buf.data[offset] = ((advMode & 0x3) << 6) | (extHdrLength & 0x3F); + offset ++; + g_tx_ext_adv_buf.data[offset] = extHeaderFlag; + offset ++; + + // AdvA (6 octets) + if (extHeaderFlag & LE_EXT_HDR_ADVA_PRESENT_BITMASK) + { + if (pAdvInfo->parameter.ownAddrType == LL_DEV_ADDR_TYPE_RANDOM && pAdvInfo->parameter.isOwnRandomAddressSet == TRUE) + memcpy(&g_tx_ext_adv_buf.data[offset], pAdvInfo->parameter.ownRandomAddress, LL_DEVICE_ADDR_LEN); + else // public address + memcpy(&g_tx_ext_adv_buf.data[offset], ownPublicAddr, LL_DEVICE_ADDR_LEN); + + offset += LL_DEVICE_ADDR_LEN; + } + + // copy adv data + memcpy(&g_tx_ext_adv_buf.data[offset], (uint8*)&pAdvInfo->scanRspData[0], pAdvInfo->scanRspMaxLength); +} + +//#pragma O2 +void llSetupAuxConnectReqPDU0(void) +{ + uint8 offset; + llConnState_t* connPtr; + connPtr = &conn_param[extInitInfo.connId]; + + if ((extInitInfo.current_scan_PHY == PKT_FMT_BLE1M) + || (extInitInfo.current_scan_PHY == PKT_FMT_BLR125K)) + { + connPtr->curParam.connInterval = extInitInfo.conn_interval_max[extInitInfo.current_index]; + connPtr->curParam.slaveLatency = extInitInfo.conn_latency[extInitInfo.current_index]; + connPtr->curParam.connTimeout = extInitInfo.supervision_timeout[extInitInfo.current_index]; + } + else // 2Mbps case + { + connPtr->curParam.connInterval = extInitInfo.conn_interval_max_2Mbps; + connPtr->curParam.slaveLatency = extInitInfo.conn_latency_2Mbps; + connPtr->curParam.connTimeout = extInitInfo.supervision_timeout_2Mbps; + } + + offset = 22; + // Interval, Byte 22 ~ 23 + memcpy((uint8*)&g_tx_adv_buf.data[offset], (uint8*)&connPtr->curParam.connInterval, 2); + offset += 2; + // Latency, Byte 24 ~ 25 + memcpy((uint8*)&g_tx_adv_buf.data[offset], (uint8*)&connPtr->curParam.slaveLatency, 2); + offset += 2; + // Timeout, Byte 26 ~ 27 + memcpy((uint8*)&g_tx_adv_buf.data[offset], (uint8*)&connPtr->curParam.connTimeout, 2); +} + +void llSetupAuxConnectRspPDU0(extAdvInfo_t* pAdvInfo) +{ + uint8 advMode, extHeaderFlag, length, extHdrLength; + uint8 offset = 0; + length = 14; + // adv PDU header + g_tx_adv_buf.txheader = 0; + // PDU type, 4 bits + SET_BITS(g_tx_adv_buf.txheader, ADV_AUX_CONN_RSP, PDU_TYPE_SHIFT, PDU_TYPE_MASK); + // RFU, ChSel, TxAdd, RxAdd + SET_BITS(g_tx_adv_buf.txheader, pAdvInfo->parameter.ownAddrType, TX_ADD_SHIFT, TX_ADD_MASK); + // Length + SET_BITS(g_tx_adv_buf.txheader, length, LENGTH_SHIFT, LENGTH_MASK); + offset = 0; + extHdrLength = 13; // ext header flag(1byte) + advA(6 octets) + targetA(6octets) + // set AdvMode + advMode = LL_EXT_ADV_MODE_AUX_CONN_RSP; + g_tx_adv_buf.data[offset] = ((advMode & 0x3) << 6) | (extHdrLength & 0x3F); + offset ++; + // extended header + extHeaderFlag = LE_EXT_HDR_ADVA_PRESENT_BITMASK | LE_EXT_HDR_TARGETA_PRESENT_BITMASK; + g_tx_adv_buf.data[offset] = extHeaderFlag; + offset ++; + + if (pAdvInfo->parameter.ownAddrType == LL_DEV_ADDR_TYPE_RANDOM && pAdvInfo->parameter.isOwnRandomAddressSet == TRUE) + memcpy(&g_tx_adv_buf.data[offset], pAdvInfo->parameter.ownRandomAddress, LL_DEVICE_ADDR_LEN); + else // public address + memcpy(&g_tx_adv_buf.data[offset], ownPublicAddr, LL_DEVICE_ADDR_LEN); + + offset += LL_DEVICE_ADDR_LEN; + // TargetA(6 octets) + osal_memcpy(&g_tx_adv_buf.data[offset], g_rx_adv_buf.data, 6); + offset += LL_DEVICE_ADDR_LEN; +} + + +// for periodic adv, when finish extended adv part broadcast, or finish periodic adv part broadcase +// controller should decide next broadcast channel and PDU. +// extended adv part: ADV_EXT_IND + AUX_ADV_IND +// periodic adv part: AUX_SYNC_IND + AUX_CHAIN_IND(optional, for long adv data) +void llPrdAdvDecideNextChn(extAdvInfo_t* pAdvInfo, periodicAdvInfo_t* pPrdAdv) +{ + llPeriodicAdvScheduleInfo_t* p_scheduler = NULL; + p_scheduler = &g_pAdvSchInfo_periodic[g_currentExtAdv_periodic]; + + if (p_scheduler->nextEventRemainder == LL_INVALID_TIME) + { + pPrdAdv->currentChn = llGetNextDataChanCSA2(pPrdAdv->periodic_adv_event_counter,\ + (( ( pPrdAdv->AA & 0xFFFF0000 )>> 16 ) ^ ( pPrdAdv->AA & 0x0000FFFF)),\ + pPrdAdv->chn_map,\ + pPrdAdv->chanMapTable,\ + pPrdAdv->numUsedChans); + pPrdAdv->pa_current_chn = pPrdAdv->currentChn; + return; + } + + if (p_scheduler->auxPduRemainder > p_scheduler->nextEventRemainder + pGlobal_config[LL_EXT_ADV_TASK_DURATION]) + { + int i = 0; + + while ((i < 3) && !(pAdvInfo->parameter.priAdvChnMap & (1 << i))) i ++; + + pPrdAdv->currentChn = LL_ADV_CHAN_FIRST + i; + } + else if (p_scheduler->auxPduRemainder > p_scheduler->nextEventRemainder) // no enough margin for ext adv + { + // skip 1 primary adv event + p_scheduler->nextEventRemainder += pAdvInfo->primary_advertising_interval; + pAdvInfo->adv_event_counter ++; + pAdvInfo->adv_event_duration += pAdvInfo->primary_advertising_interval; + // to simplify the process, here not check ext adv duration & counter, TO be add if required + pPrdAdv->currentChn = llGetNextDataChanCSA2(pPrdAdv->periodic_adv_event_counter,\ + (( ( pPrdAdv->AA & 0xFFFF0000 )>> 16 ) ^ ( pPrdAdv->AA & 0x0000FFFF)),\ + pPrdAdv->chn_map,\ + pPrdAdv->chanMapTable,\ + pPrdAdv->numUsedChans); + pPrdAdv->pa_current_chn = pPrdAdv->currentChn; + } + else + { + pPrdAdv->currentChn = llGetNextDataChanCSA2(pPrdAdv->periodic_adv_event_counter,\ + (( ( pPrdAdv->AA & 0xFFFF0000 )>> 16 ) ^ ( pPrdAdv->AA & 0x0000FFFF)),\ + pPrdAdv->chn_map,\ + pPrdAdv->chanMapTable,\ + pPrdAdv->numUsedChans); + pPrdAdv->pa_current_chn = pPrdAdv->currentChn; + } +} + + + +void llSetupSyncInfo(extAdvInfo_t* pAdvInfo, periodicAdvInfo_t* pPrdAdv) +{ + uint32 T2, elapse_time, remainder; + llPeriodicAdvScheduleInfo_t* p_scheduler = NULL; + p_scheduler = &g_pAdvSchInfo_periodic[g_currentExtAdv_periodic]; + memcpy(syncInfo.chn_map, pPrdAdv->chn_map, 4); + syncInfo.chn_map4.chn_map = pPrdAdv->chn_map[4]; + syncInfo.chn_map4.sca = pPrdAdv->sca; + syncInfo.AA[0] = pPrdAdv->AA & 0xff; + syncInfo.AA[1] = (pPrdAdv->AA >> 8) & 0xff; + syncInfo.AA[2] = (pPrdAdv->AA >> 16) & 0xff; + syncInfo.AA[3] = (pPrdAdv->AA >> 24) & 0xff; + syncInfo.crcInit[0] = pPrdAdv->crcInit & 0xff; + syncInfo.crcInit[1] = (pPrdAdv->crcInit >> 8) & 0xff; + syncInfo.crcInit[2] = (pPrdAdv->crcInit >> 16) & 0xff; + syncInfo.offset.rfu = 0; + syncInfo.interval = pPrdAdv->adv_interval_max;// adv_interval; + syncInfo.event_counter = pPrdAdv->periodic_adv_event_counter; + + if (p_scheduler->auxPduRemainder >= 245700) + syncInfo.offset.offsetUnit = 1; // 300us, for aux offset >= 245700us + else + syncInfo.offset.offsetUnit = 0; // 30us, for aux offset < 245700us + + syncInfo.offset.offsetAdj = 0; + // calculate elapse time since last timer trigger + T2 = read_current_fine_time(); + elapse_time = LL_TIME_DELTA(g_timerExpiryTick, T2); + + if (p_scheduler->auxPduRemainder > 2457600 + elapse_time) // if > 2.4576 second + { + remainder = p_scheduler->auxPduRemainder - 2457600; + syncInfo.offset.offsetAdj = 1; + } + else + remainder = p_scheduler->auxPduRemainder; + + syncInfo.offset.syncPacketOffset = (remainder - elapse_time) / ((syncInfo.offset.offsetUnit == 1) ? 300 : 30); +} + +void LL_EXT_Init_IQ_pBuff(uint16* ibuf,uint16* qbuf) +{ + if( ( ibuf != NULL ) && ( qbuf != NULL) ) + { + g_pLLcteISample = ibuf; + g_pLLcteQSample = qbuf; + } +} + + diff --git a/src/lib/ble_controller/ll_common.c b/src/lib/ble_controller/ll_common.c new file mode 100644 index 0000000..5b44717 --- /dev/null +++ b/src/lib/ble_controller/ll_common.c @@ -0,0 +1,4972 @@ +/******************************************************************************* + Filename: ll_common.c + Revised: + Revision: + + Description: This file contains common functions used by the Link Layer + Bluetooth Low Energy (BLE) Controller. + + + + IMPORTANT: +*******************************************************************************/ + +#include +#include "timer.h" +#include "ll_buf.h" +#include "ll_def.h" +#include "ll.h" +#include "ll_common.h" +#include "hci_event.h" +#include "osal_bufmgr.h" +#include "bus_dev.h" +#include "ll_enc.h" +#include "jump_function.h" +#include "global_config.h" +#include "ll_debug.h" +#include "ll_hw_drv.h" +#include "att.h" +#include "OSAL_Memory.h" +#include "log.h" + +/******************************************************************************* + MACROS +*/ + +#define ADV_BASE_IDX 37 + +/******************************************************************************* + CONSTANTS +*/ +// Master Sleep Clock Accurracy, in PPM +// Note: Worst case range value is assumed. +const uint16 SCA[] = {500, 250, 150, 100, 75, 50, 30, 20}; + + +/******************************************************************************* + TYPEDEFS +*/ + +/******************************************************************************* + LOCAL VARIABLES +*/ + +/******************************************************************************* + GLOBAL VARIABLES +*/ + + +extAdvHdr_t ext_adv_hdr; + +extern void* taskEndCauses[]; + +//extern int current_base_time; // uint is s +//extern int current_fine_time; // uint is us +extern uint32 llWaitingIrq; +extern uint32_t llScanT1; +extern uint8 g_dle_taskID; +extern uint16 g_dle_taskEvent; +extern uint8 g_phyChg_taskID; +extern uint16 g_phyChg_taskEvent; +extern uint8_t llSecondaryState; // secondary state of LL + +extern struct buf_tx_desc g_tx_ext_adv_buf; +extern uint8 g_llWlDeviceNum; +//ctrl_packet_buf ctrlData; + + +//uint8_t ctrlDataIsProcess = 0; // seding a control packet or not +//uint8_t ctrlDataIsPending = 0; // control packet is pending to be sent + + +//uint8 onePktPerEvt; // flag indicates if only one packet allowed per event + +//uint8_t tx_conn_idx=0; // point to first tx buf +//uint8_t tx_head_idx=0; // point to first free tx buf + +//uint8_t rx_conn_idx=0; // point to first free rx buf +//uint8_t rx_head_idx=0; // point to first received valid buf + +extern llConns_t g_ll_conn_ctx; + +extern syncInfo_t syncInfo; + + + +/******************************************************************************* + Functions +*/ + + +/******************************************************************************* + @fn llMemCopySrc + + @brief Generic memory copy. This function copies the source location to + the destination location in bytes, and returns the next source + address. + + input parameters + + @param pDst - Destination address. + @param pSrc - Source address. + @param len - Number of bytes to copy. + + output parameters + + @param None. + + @return Pointer to next source address. +*/ +uint8* llMemCopySrc( uint8* pDst, uint8* pSrc, uint8 len ) +{ + while ( len-- ) + { + *pDst++ = *pSrc++; + } + + return( pSrc ); // return pSrc +} + +/******************************************************************************* + @fn llMemCopyDst + + @brief Generic memory copy. This function copies the destination + location to the source location in bytes, and returns the + next destination address. + + input parameters + + @param pDst - Destination address. + @param pSrc - Source address. + @param len - Number of bytes to copy. + + output parameters + + @param None. + + @return Pointer to next destination address. +*/ +uint8* llMemCopyDst( uint8* pDst, uint8* pSrc, uint8 len ) +{ + while ( len-- ) + { + *pDst++ = *pSrc++; + } + + return( pDst ); // return pDst +} + +/******************************************************************************* + @fn llProcessChanMap + + @brief This function is used to convert the channel map provided by + the HCI from a bit map format of used data channels, to a table + of consecutively ordered entries. This is needed by the + getNextDataChan algorithm, and should be done whenever the data + channel map is updated. + + The following connection globals are side effected: + numUsedChans - Count of the number of used data channels found. + chanMapTable - Table of used data channels in ascending order. + + input parameters + + @param connPtr - A pointer to the current LL connection data. + @param chanMap - A five byte array containing one bit per data channel + where a 1 means the channel is "used". + + output parameters + + @param None. + + @return None. +*/ +void llProcessChanMap( llConnState_t* connPtr, + uint8* chanMap ) +{ + uint8_t i, j; + // channels 37..39 are not data channels and these bits should not be set + chanMap[LL_NUM_BYTES_FOR_CHAN_MAP - 1] &= 0x1F; + // clear the count of the number of used channels + connPtr->numUsedChans = 0; + + // the used channel map uses 1 bit per data channel, or 5 bytes for 37 chans + for (i = 0; i < LL_NUM_BYTES_FOR_CHAN_MAP; i++) + { + // replace the current channel map with the update channel map + // Note: This needs to be done so that llGetNextDataChan can more + // efficiently determine if the next channel is used. + connPtr->chanMap[i] = chanMap[i]; + + // for each channel given by a bit in each of the bytes + // Note: When i is on the last byte, only 5 bits need to be checked, but + // it is easier here to check all 8 with the assumption that the rest + // of the reserved bits are zero. + for (j=0; j<8; j++) + { + // check if the channel is used; only interested in used channels + if ( (chanMap[i] >> j) & 1 ) + { + // sequence used channels in ascending order + connPtr->chanMapTable[ connPtr->numUsedChans ] = (i*8U)+j; + // count it + connPtr->numUsedChans++; + } + } + } +} +// get next channel + +/******************************************************************************* + @fn llGetNextDataChan + + @brief This function returns the next data channel for a LL connection + based on the previous data channel, the hop length, and the + number of connection intervals to the next active event. If the + derived channel is "used", then it is returned. If the derived + channel is "unused", then a remapped data channel is returned. + + The following connection globals are side effected: + connEvtChan - The calculated connection event channel. + + Note: connEvtChan is left updated even if the remapped channel + is returned. + + Note: It is assumed it is safe to check i to see if the entire + table was searched. + + input parameters + + @param connPtr - A pointer to the current LL connection data. + @param numEvents - The number of skipped events to base the next + data channel calculation on. + output parameters + + @param None. + + @return The next data channel to use. +*/ +uint8 llGetNextDataChan( llConnState_t* connPtr, + uint16 numEvents ) +{ + connPtr->nextChan = ( connPtr->currentChan + + (connPtr->hop *numEvents) ) % LL_MAX_NUM_DATA_CHAN; + + if ( connPtr->chanMap[ connPtr->nextChan >> 3 ] & (1 << (connPtr->nextChan % 8)) ) + { + // used channel + return( connPtr->nextChan ); + } + else // unused channel + { + return( connPtr->chanMapTable[ connPtr->nextChan % connPtr->numUsedChans ] ); + } +} + + +static uint8_t chan_rev_8(uint8_t b) +{ + b = (((uint32_t)b * 0x0802LU & 0x22110LU) | + ((uint32_t)b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16; + return b; +} + +static uint16_t chan_perm(uint16_t i) +{ + return (chan_rev_8((i >> 8) & 0xFF) << 8) | chan_rev_8(i & 0xFF); +} + +static uint16_t chan_mam(uint16_t a, uint16_t b) +{ + return ((uint32_t)a * 17U + b) & 0xFFFF; +} + +static uint16_t chan_prn(uint16_t counter, uint16_t chan_id) +{ + uint8_t iterate; + uint16_t prn_e; + prn_e = counter ^ chan_id; + + for (iterate = 0U; iterate < 3; iterate++) + { + prn_e = chan_perm(prn_e); + prn_e = chan_mam(prn_e, chan_id); + } + + prn_e ^= chan_id; + return prn_e; +} + +uint8 llGetNextDataChanCSA2(uint16_t counter,uint16_t chan_id,uint8* chan_map,uint8* cMap_tab,uint8 chanCnt) +{ +// hal_gpio_write(GPIO_P23, 1); + uint16_t prn_e = chan_prn(counter,chan_id); + uint8 next_chan = 0; + next_chan = prn_e % LL_MAX_NUM_DATA_CHAN; + + if ( chan_map[ next_chan >> 3 ] & (1 << (next_chan % 8)) ) + { + // used channel +// hal_gpio_write(GPIO_P23, 0); +// printf("csa2_0:chan:%d,counter:%d,chanIdtify:%d,chanCnt:%d,prn:%d\n",next_chan,counter,chan_id,chanCnt,prn_e); + return( next_chan ); + } + else // unused channel + { + uint8_t chanIdx = (chanCnt * prn_e)>>16; + next_chan = cMap_tab[ chanIdx % chanCnt ]; +// hal_gpio_write(GPIO_P23, 0); +// printf("csa2_1:chan:%d,counter:%d,chanIdtify:%d,chanCnt:%d,prn:%d\n",next_chan,counter,chan_id,chanCnt,prn_e); + return( next_chan ); + } +} + +/******************************************************************************* + @fn llSetNextDataChan + + @brief This function finds and sets the data channel for the next + active connection event. This routine also checks if a data + channel update procedure is pending, and if so, whether it + will take place between the current event (exclusive) and the + next active event (inclusive). If so, the next data is adjusted + for the next active event keeping slave latency in effect. + + input parameters + + @param *connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return None. +*/ +void llSetNextDataChan0( llConnState_t* connPtr ) +{ + uint16 numEvents; +// uint8 connId; +// +// connId = connPtr->connId; + /* + ** Check for a Data Channel Update and Set the Next Data Channel + ** + ** Note: The Data Channel Update must come after the Parameters Update in + ** case the latter updates the next event count. + */ + // before finding the next channel, save it as the current channel + // Note: nextChan is now called unmappedChannel in the spec. + // Note: currentChan is now called lastUnmappedChannel in the spec. + connPtr->currentChan = connPtr->nextChan; + // find the number of events to the next event + numEvents = llEventDelta( connPtr->nextEvent, connPtr->currentEvent ); + + // check if there's a pending update to the data channel for next event and + // whether the update event count is prior to the next active event count + if ( ( connPtr->pendingChanUpdate == TRUE ) && + ( llEventInRange( connPtr->currentEvent, + connPtr->nextEvent, + connPtr->chanMapUpdateEvent ) ) ) + { + //================================================================= + //20190803 ZQ: + // store the old chanMap for restore in manualy disable slave latency + //20190806 ZQ: + //store the old chanMap while nextEvent-chanMapUpdateEvt > 3 + if(llEventDelta(connPtr->nextEvent,connPtr->chanMapUpdateEvent )>3) + { + connPtr->preChanMapUpdate.chanMapUpdated = TRUE; + connPtr->preChanMapUpdate.chanMapUpdateEvent = connPtr->chanMapUpdateEvent; + osal_memcpy(&(connPtr->preChanMapUpdate.chanMap[0]), &(connPtr->chanMap[0]), 5); + //LOG("[ST preChanMap] c%d n%d u%d\r\n",connPtr->currentEvent,connPtr->nextEvent,connPtr->chanMapUpdateEvent); + } + + //================================================================= + //update data channel table based on pending data channel update + //ZQ 20200207 + //llProcessChanMap(connPtr, chanMapUpdate.chanMap); + llProcessChanMap(connPtr, connPtr->chanMapUpdate.chanMap); + connPtr->pendingChanUpdate = FALSE; + } + + //20190806 ZQ + //clear the preChanMapUpdate flg + //when current_event is runover the chanMapUpdated_evt, clear flg + if(connPtr->preChanMapUpdate.chanMapUpdated ==TRUE) + { + if(llEventDelta(connPtr->preChanMapUpdate.chanMapUpdateEvent, connPtr->currentEvent )>32768) + { + connPtr->preChanMapUpdate.chanMapUpdated =FALSE; + //LOG("[END preChanMap] c%d n%d u%d\r\n",connPtr->currentEvent,connPtr->nextEvent,connPtr->chanMapUpdateEvent); + } + } + + if (connPtr->channel_selection == LL_CHN_SEL_ALGORITHM_1) + connPtr->currentChan = llGetNextDataChan(connPtr, numEvents ); + else + { + // channel selection algorithm 2 + connPtr->currentChan = llGetNextDataChanCSA2(connPtr->nextEvent, + (( connPtr->accessAddr & 0xFFFF0000 )>> 16 ) ^ ( connPtr->accessAddr & 0x0000FFFF), + connPtr->chanMap, + connPtr->chanMapTable, + connPtr->numUsedChans); + } + + return; +} + +void llSetNextPhyMode0( llConnState_t* connPtr ) +{ +// uint16 numEvents; + uint8 lastPhyMode; + + // find the number of events to the next event +// numEvents = llEventDelta( connPtr->nextEvent, connPtr->currentEvent ); + + // check if there's a pending update to the data channel for next event and + // whether the update event count is prior to the next active event count + if ( ( connPtr->pendingPhyModeUpdate == TRUE ) && + ( llEventInRange( connPtr->currentEvent, + connPtr->nextEvent, + connPtr->phyModeUpdateEvent ) ) ) + { + lastPhyMode = connPtr->llRfPhyPktFmt; + + // update data channel table based on pending data channel update + if((connPtr->phyUpdateInfo.m2sPhy & LE_1M_PHY) >0) + { + connPtr->llRfPhyPktFmt = PKT_FMT_BLE1M; + } + else if((connPtr->phyUpdateInfo.m2sPhy & LE_2M_PHY) >0) + { + connPtr->llRfPhyPktFmt = PKT_FMT_BLE2M; + } + else if((connPtr->phyUpdateInfo.m2sPhy & LE_CODED_PHY) >0) + { + connPtr->llRfPhyPktFmt = PKT_FMT_BLR500K; + } + + if(lastPhyMode != connPtr->llRfPhyPktFmt) + connPtr->llPhyModeCtrl.isChanged=TRUE; + + // clear the pending flag + connPtr->pendingPhyModeUpdate = FALSE; + } + + return; +} + + + +/******************************************************************************* + @fn llSetupInit + + @brief This function + + input parameters + + @param connId - Connection ID that Init will attempt to start. + + output parameters + + @param None. + + @return None. +*/ +void llSetupInit( uint8 connId ) +{ + // Hold off interrupts. + HAL_ENTER_CRITICAL_SECTION( ); + // construct CONN REQ message + // configure scan + // reset all FIFOs; all data is forfeit + ll_hw_rst_tfifo(); + ll_hw_rst_rfifo(); + set_crc_seed(ADV_CRC_INIT_VALUE); // crc seed for adv is same for all channels + set_access_address(ADV_SYNCH_WORD); + set_channel(initInfo.nextScanChan); + set_whiten_seed(initInfo.nextScanChan); + set_max_length(0xff); + ll_hw_set_rx_timeout(10000); + ll_hw_set_srx(); + ll_hw_go(); + llScanT1 = read_current_fine_time(); + llWaitingIrq = TRUE; + // set LL state + llState = LL_STATE_INIT; + HAL_EXIT_CRITICAL_SECTION(); + ll_debug_output(DEBUG_LL_STATE_INIT); + return; +} + +/******************************************************************************* + @fn llSetupScan + + @brief This function readies the device as a Scanner. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void llSetupScan0( uint8 chan ) +{ + // Hold off interrupts. + HAL_ENTER_CRITICAL_SECTION( ); + + // check if the Scanner should be initialized + if ( scanInfo.initPending == TRUE ) + { + // setup Scan initalization + llSetupScanInit(); + // only need to do this once + scanInfo.initPending = FALSE; + } + + //support rf phy change + rf_phy_change_cfg(g_rfPhyPktFmt); + // reset all FIFOs; all data is forfeit + ll_hw_rst_tfifo(); + ll_hw_rst_rfifo(); + set_crc_seed(ADV_CRC_INIT_VALUE); // crc seed for adv is same for all channels + set_access_address(ADV_SYNCH_WORD); + set_channel(chan); + set_whiten_seed(chan); + set_max_length(0xff); + ll_hw_set_rx_timeout(10000); // 10000us + ll_hw_set_srx(); + ll_hw_ign_rfifo(LL_HW_IGN_CRC|LL_HW_IGN_EMP); + ll_hw_go(); + llScanT1 = read_current_fine_time(); + llWaitingIrq = TRUE; + HAL_EXIT_CRITICAL_SECTION(); + ll_debug_output(DEBUG_LL_STATE_SCAN); + return; +} + +/******************************************************************************* + @fn llSetupScanInit + + @brief This function performs common initialization for when the device + is being setup as a Scanner. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void llSetupScanInit( void ) +{ + // set scan backoff upper limit + scanInfo.scanBackoffUL = 1; + // set the backoff counter. Note: Initially, this value is set to one, per the spec. + scanInfo.currentBackoff = 1; + return; +} + + +/******************************************************************************* + @fn llSetupExtScan + + @brief This function readies the device as a Scanner. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void llSetupExtScan( uint8 chan ) +{ +// LOG("S %d ", chan); + // Hold off interrupts. + HAL_ENTER_CRITICAL_SECTION( ); + //support rf phy change + rf_phy_change_cfg(extScanInfo.current_scan_PHY); + // reset all FIFOs; all data is forfeit + ll_hw_rst_tfifo(); + ll_hw_rst_rfifo(); + set_crc_seed(ADV_CRC_INIT_VALUE); // crc seed for adv is same for all channels + set_access_address(ADV_SYNCH_WORD); + set_channel(chan); + set_whiten_seed(chan); + set_max_length(0xff); + ll_hw_set_rx_timeout(10000); // 10000us + ll_hw_set_srx(); + ll_hw_ign_rfifo(LL_HW_IGN_CRC|LL_HW_IGN_EMP); + ll_hw_go(); + llScanT1 = read_current_fine_time(); + llWaitingIrq = TRUE; + llTaskState = LL_TASK_EXTENDED_SCAN; + HAL_EXIT_CRITICAL_SECTION(); + return; +} +//#pragma O0 +/******************************************************************************* + @fn llSetupPrdScan + + @brief This function readies the device as a Scanner. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void llSetupPrdScan( void) +{ + uint8 chan; + llPeriodicScannerInfo_t* pPrdScanInfo; + uint32 crcInit, accessAddress; + pPrdScanInfo = &g_llPeriodAdvSyncInfo[0]; // only 1 period scanner + chan = pPrdScanInfo->current_channel; + crcInit = (pPrdScanInfo->crcInit[2] << 16) + | (pPrdScanInfo->crcInit[1] << 8) + | pPrdScanInfo->crcInit[0]; + accessAddress = (pPrdScanInfo->accessAddress[3] << 24) + | (pPrdScanInfo->accessAddress[2] << 16) + | (pPrdScanInfo->accessAddress[1] << 8) + | pPrdScanInfo->accessAddress[0]; +// LOG("P %d ", chan); + // Hold off interrupts. + HAL_ENTER_CRITICAL_SECTION( ); + //support rf phy change + rf_phy_change_cfg(pPrdScanInfo->advPhy); + // reset all FIFOs; all data is forfeit + ll_hw_rst_tfifo(); + ll_hw_rst_rfifo(); + set_crc_seed(crcInit); // crc seed for adv is same for all channels + set_access_address(accessAddress); + set_channel(chan); + set_whiten_seed(chan); + set_max_length(0xff); + ll_hw_set_rx_timeout(10000); // 10000us + ll_hw_set_srx(); + ll_hw_ign_rfifo(LL_HW_IGN_CRC|LL_HW_IGN_EMP); + ll_hw_go(); + llScanT1 = read_current_fine_time(); + llWaitingIrq = TRUE; + llTaskState = LL_TASK_PERIODIC_SCAN; + HAL_EXIT_CRITICAL_SECTION(); + return; +} +//#pragma O2 +/******************************************************************************* + @fn llSetupExtInit + + @brief This function + + input parameters + + @param connId - Connection ID that Init will attempt to start. + + output parameters + + @param None. + + @return None. +*/ +void llSetupExtInit(void) // TODO: the parameter channel idx needed? +{ + // TODO: if there are multi connections, we may need add guard code here +// LOG("S %d ", extInitInfo.current_chn); + // Hold off interrupts. + HAL_ENTER_CRITICAL_SECTION( ); + rf_phy_change_cfg(extInitInfo.current_scan_PHY); + // reset all FIFOs; all data is forfeit + ll_hw_rst_tfifo(); + ll_hw_rst_rfifo(); + set_crc_seed(ADV_CRC_INIT_VALUE); // crc seed for adv is same for all channels + set_access_address(ADV_SYNCH_WORD); + set_channel(extInitInfo.current_chn); + set_whiten_seed(extInitInfo.current_chn); + set_max_length(0xff); + ll_hw_set_rx_timeout(10000); + ll_hw_set_srx(); + ll_hw_go(); + llScanT1 = read_current_fine_time(); + llWaitingIrq = TRUE; + llTaskState = LL_TASK_EXTENDED_INIT; + HAL_EXIT_CRITICAL_SECTION(); +// ll_debug_output(DEBUG_LL_STATE_INIT); + return; +} + + +/******************************************************************************* + This function dequeues a TX data packet from the front of the data queue. + + Public function defined in hci_c_data.h. +*/ +txData_t* llDequeueDataQ( llDataQ_t* pDataQ ) +{ + txData_t* pTxData = NULL; + HAL_ENTER_CRITICAL_SECTION(); + + // check if the data queue is not empty + if ( pDataQ->head != NULL ) + { + // at least one entry already on the data queue, so remove packet + pTxData = pDataQ->head; + pDataQ->head = pTxData->pNext; + pTxData->pNext = NULL; + + // check if queue is now empty + if ( pDataQ->head == NULL ) + { + pDataQ->tail = NULL; + } + } + + HAL_EXIT_CRITICAL_SECTION(); + return( pTxData ); +} + +/******************************************************************************* + @fn llAllocConnId + + @brief This function is called to get the next free LL connection. If + all available connections are in use, NULL is returned. + + input parameters + + @param None. + + output parameters + + @param None. + + @return A valid connection pointer, or NULL. +*/ +llConnState_t* llAllocConnId( void ) +{ + uint8 i; + + // check if there's a resource available + if ( g_ll_conn_ctx.numLLConns == g_maxConnNum ) + { + // unable to add another connection + return( NULL ); + } + + // find first free connection + for (i = 0; i < g_maxConnNum; i++) + { + llConnState_t* connPtr = &conn_param[i]; + + if (connPtr->allocConn == FALSE) + { +// g_ll_conn_ctx.currentConn = i; + g_ll_conn_ctx.numLLConns ++; + connPtr->allocConn = TRUE; + llResetConnId(connPtr->connId); + return( connPtr ); + } + } + + return( NULL ); + #if 0 + + // find first free connection + for (i=0; iallocConn = TRUE; + connPtr->activeConn = FALSE; + connPtr->connId = i; + connPtr->txDataEnabled = TRUE; + connPtr->rxDataEnabled = TRUE; + connPtr->currentEvent = 0; + connPtr->nextEvent = 0; + connPtr->firstPacket = 1; + connPtr->rx_timeout = 0; + connPtr->currentChan = 0; + connPtr->lastTimeToNextEvt = 0; + connPtr->slaveLatencyAllowed = FALSE; + connPtr->slaveLatency = 0; + connPtr->pendingChanUpdate = FALSE; + connPtr->pendingParamUpdate = FALSE; + connPtr->lastRssi = LL_RF_RSSI_UNDEFINED; + connPtr->ctrlPktInfo.ctrlPktActive = FALSE; + connPtr->ctrlPktInfo.ctrlPktCount = 0; + connPtr->verExchange.peerInfoValid = FALSE; + connPtr->verExchange.hostRequest = FALSE; + connPtr->verExchange.verInfoSent = FALSE; + connPtr->verInfo.verNum = 0; + connPtr->verInfo.comId = 0; + connPtr->verInfo.subverNum = 0; + connPtr->termInfo.termIndRcvd = FALSE; + connPtr->encEnabled = FALSE; + connPtr->encInfo.SKValid = FALSE; + connPtr->encInfo.LTKValid = FALSE; + connPtr->encInfo.txPktCount = 0; + connPtr->encInfo.rxPktCount = 0; + connPtr->encInfo.startEncRspRcved = FALSE; + connPtr->encInfo.encReqRcved = FALSE; + connPtr->encInfo.encRestart = FALSE; + connPtr->encInfo.startEncReqRcved = FALSE; + connPtr->encInfo.rejectIndRcved = FALSE; + connPtr->perInfo.numPkts = 0; + connPtr->perInfo.numCrcErr = 0; + connPtr->perInfo.numEvents = 0; + connPtr->perInfo.numMissedEvts = 0; + + // set packet queue to undefined values + // Note: This is used for debugging purposes. + for (i=0; ictrlPktInfo.ctrlPkts[i] = LL_CTRL_UNDEFINED_PKT; + } + + // initialize the channel map + for (i=0; icurChanMap.chanMap[i] = chanMapUpdate.chanMap[i]; + } + + // set the connection Feature Set based on this device's default + for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + + // count the number of active connections + if ( ++llConns.numLLConns == 1 ) + { + // this is the only connection, so make it the current connection + llConns.currentConn = connPtr->connId; + } + + return( connPtr ); + } + } + + #endif +} + +/******************************************************************************* + @fn llReleaseConnId0 + + @brief This function is called to mark a connection resource as free. + + Note: If there are other active connections, the scheduler will + find the next one to schedule, and will set currentConn. + + input parameters + + @param connPtr - A pointer to the connection resource to free. + + output parameters + + @param None. + + @return None. +*/ +void llReleaseConnId0( llConnState_t* connPtr ) +{ + uint8_t next; + + // check that this connection is active + // Note: If a cancel is issued, this connection may be released even though + // it isn't yet active. + if ( connPtr->active ) + { + // mark connection as inactive + connPtr->active = FALSE; + } + + if (connPtr->allocConn == TRUE) + { + connPtr->allocConn = FALSE; + g_ll_conn_ctx.numLLConns --; +// g_ll_conn_ctx.currentConn = ll_get_next_active_conn(connPtr->connId); + next = ll_get_next_active_conn(connPtr->connId); + + if (next == LL_INVALID_CONNECTION_ID) + { + // no more active connection + llState = LL_STATE_IDLE; + + // if secondary state not idle/pending state, transit it to main state + // pending states are processed in LL_IRQHandler + if ((llSecondaryState == LL_SEC_STATE_INIT) || (llSecondaryState == LL_SEC_STATE_INIT_PENDING)) + { + llState = LL_STATE_INIT; + llSecondaryState = LL_SEC_STATE_IDLE; + } + else if ( (llSecondaryState == LL_SEC_STATE_SCAN) || (llSecondaryState == LL_SEC_STATE_SCAN_PENDING)) + { + llState = LL_STATE_SCAN; + llSecondaryState = LL_SEC_STATE_IDLE; + } + } + +// // ============ to check +// else +// { +// if ( (llSecondaryState == LL_SEC_STATE_INIT) || (llSecondaryState == LL_SEC_STATE_INIT_PENDING)) +// { +// llSecondaryState = LL_SEC_STATE_IDLE; +// } +// else if ( (llSecondaryState == LL_SEC_STATE_SCAN) || (llSecondaryState == LL_SEC_STATE_SCAN_PENDING)) +// { +// llSecondaryState = LL_SEC_STATE_IDLE; +// } +// } + } + + #if 0 // comment out 2019-7-10, consider whether we need it later + + if(adv_param .advMode == LL_ADV_MODE_ON) // HZF: normally should not be here. 2018-12-14 + { + switch(adv_param .advEvtType) + { + case LL_ADV_CONNECTABLE_UNDIRECTED_EVT: + llState = LL_STATE_ADV_UNDIRECTED; + ll_debug_output(DEBUG_LL_STATE_ADV_UNDIRECTED); + break; + + case LL_ADV_CONNECTABLE_HDC_DIRECTED_EVT: + case LL_ADV_CONNECTABLE_LDC_DIRECTED_EVT: + llState = LL_STATE_ADV_DIRECTED; + ll_debug_output(DEBUG_LL_STATE_ADV_DIRECTED); + break; + + case LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT: + llState = LL_STATE_ADV_NONCONN; + ll_debug_output(DEBUG_LL_STATE_ADV_NONCONN); + break; + + case LL_ADV_SCANNABLE_UNDIRECTED_EVT: + llState = LL_STATE_ADV_SCAN; + ll_debug_output(DEBUG_LL_STATE_SCAN); + break; + + default: + llState = LL_STATE_IDLE; + ll_debug_output(DEBUG_LL_STATE_IDLE); + break; + } + } + else + { + llState = LL_STATE_IDLE; + ll_debug_output(DEBUG_LL_STATE_IDLE); + } + + #endif + // add by HZF + llResetConnId(connPtr->connId); + connPtr->ctrlDataIsProcess = 0; // seding a control packet or not + connPtr->ctrlDataIsPending = 0; // control packet is pending to be sent + reset_conn_buf(connPtr->connId); + //add by ZQ 20181030 for DLE feature + //only free the segment pkt, clear the fragment_flag and buffer +// L2CAP_SegmentPkt_Reset(); +//// L2CAP_ReassemblePkt_Reset(); +// +// llPduLengthManagmentReset(); +// llPhyModeCtrlReset(); + memset((uint8_t*)&connPtr->pmCounter, 0, sizeof(llLinkStatistics_t) ); +// // reset connect context except conn id +// uint8 temp = connPtr->connId; +// memset((uint8_t *)connPtr , 0, sizeof(llConnState_t) ); +// connPtr->connId = temp; + //add by Zhang Zhufei +// conn_param[connPtr->connId].llPduLen.local.MaxRxOctets=LL_PDU_LENGTH_INITIAL_MAX_RX_OCTECTS; +// conn_param[connPtr->connId].llPduLen.local.MaxTxOctets=LL_PDU_LENGTH_INITIAL_MAX_TX_OCTECTS; +// conn_param[connPtr->connId].llPduLen.local.MaxRxTime =LL_PDU_LENGTH_INITIAL_MAX_RX_TIME; +// conn_param[connPtr->connId].llPduLen.local.MaxTxTime =LL_PDU_LENGTH_INITIAL_MAX_TX_TIME; +// +// conn_param[connPtr->connId].llPduLen.remote.MaxRxOctets=LL_PDU_LENGTH_INITIAL_MAX_RX_OCTECTS; +// conn_param[connPtr->connId].llPduLen.remote.MaxTxOctets=LL_PDU_LENGTH_INITIAL_MAX_TX_OCTECTS; +// conn_param[connPtr->connId].llPduLen.remote.MaxRxTime =LL_PDU_LENGTH_INITIAL_MAX_RX_TIME; +// conn_param[connPtr->connId].llPduLen.remote.MaxTxTime =LL_PDU_LENGTH_INITIAL_MAX_TX_TIME; +// conn_param[connPtr->connId].llPduLen.isProcessingReq=FALSE; +// conn_param[connPtr->connId].llPduLen.isWatingRsp =FALSE; +// conn_param[connPtr->connId].llPduLen.isChanged =FALSE; + //add by ZQ for preChannMapUpdate + //conn_param[connPtr->connId].preChanMapUpdate.chanMapUpdated = FALSE; + return; +} + +/******************************************************************************* + @fn llConnCleanup + + @brief This function is used to clean up the LL connection data + structures, queued Tx data packet, and the connection task. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return None. +*/ +void llConnCleanup( llConnState_t* connPtr ) +{ + // free any pending Tx data queue headers and buffers, if any + while( connPtr->txDataQ.head != NULL ) + { + txData_t* pTxData; + // okay to remove from the front of the data queue + pTxData = llDequeueDataQ( &connPtr->txDataQ ); + // free the memory allocated in higher layer + osal_bm_free( pTxData ); + // inc the number completed + numComplPkts++; + } + + // release the connection + // Note: Releasing the connection resets the TX/RX FIFOs. + llReleaseConnId( connPtr ); + // free the associated task block + //llFreeTask( &connPtr->llTask ); + return; +} + +/******************************************************************************* + @fn llReleaseAllConnId + + @brief This function is called to free all connection resources. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void llReleaseAllConnId( void ) +{ + #if 0 + uint8 i; + + // mark all connections as inactive + for (i=0; iconnId, reason ); + + // A2 multi-connection + if (g_ll_conn_ctx.scheduleInfo[connPtr->connId].linkRole == LL_ROLE_MASTER) + g_ll_conn_ctx.numLLMasterConns --; + + // cleanup the connection data structures and task + llConnCleanup( connPtr ); + // secondary state is allow for multiconnection, it will be transfer to main state in next event + /* + // add in A2 for simultaneous conn event + adv + // if slave conn termainte, the secondary adv also terminated + if (llSecondaryState != LL_SEC_STATE_IDLE) + { + // TO consider: if previous LL state is MASTER, allow adv + // if previous LL state is SLAVE, disallow adv + llSecondaryState = LL_SEC_STATE_IDLE; + adv_param.advMode = LL_ADV_MODE_OFF; + osal_stop_timerEx( LL_TaskID, LL_EVT_SECONDARY_ADV ); // timer may be running, stop it + } + */ + return; +} + +#if 0 +uint32_t calculateTimeDelta(int base_time, int fine_time) +{ + uint32_t time; + time= (current_base_time - base_time ) * BASE_TIME_UNITS ; + time += read_current_fine_time () - fine_time; + return time; +} +#endif + + +/******************************************************************************* + @fn llWriteTxData0 + + @brief This function is used to place Host/HCI data in the TX FIFO for + transmission. If there is no reason to stall transmission (due + to encryption control procedures, physical flow control, etc.), + then the data is placed in the TX FIFO for transmission. + + input parameters + + @param *connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_OUT_OF_TX_MEM, + LL_STATUS_WARNING_TX_DISABLED +*/ +uint8 llWriteTxData0( llConnState_t* connPtr, + uint8 pktHdr, + uint8 pktLen, + uint8* pBuf ) +{ + uint8_t idx; + + // check if data output is allowed + // Note: Data output can be disabled so that the TX FIFO can empty. + // This is needed for encryption pause, for example. + if ( connPtr->txDataEnabled == TRUE ) + { + // check if there's enough space in TX FIFO + if(getTxBufferFree(connPtr) > 0) + { + // check if packet needs to be encrypted + if ( connPtr->encEnabled ) + { + LL_ENC_Encrypt( connPtr, + pktHdr, + pktLen, + pBuf ); + // add the MIC to length + pktLen += LL_PKT_MIC_LEN; + } + + idx = get_tx_write_ptr(connPtr);//find_free_tx_buf(); + connPtr->ll_buf.tx_conn_desc[idx]->header = pktLen<<8 | pktHdr; + memcpy (connPtr->ll_buf.tx_conn_desc[idx]->data, pBuf, pktLen ); + connPtr->ll_buf.tx_conn_desc[idx]->valid =1; + //buf.tx_conn_pkts++; + //MOVE_IDX_ONE (tx_head_idx ); + update_tx_write_ptr(connPtr); + //tx_head_idx = (uint8_t)get_tx_write_ptr(); + return( LL_STATUS_SUCCESS ); + } + else + { + return( LL_STATUS_ERROR_OUT_OF_TX_MEM ); + } + } + else // TX is disabled + { + return( LL_STATUS_WARNING_TX_DISABLED ); + } +} + +/******************************************************************************* + @fn llProcessTxData + + @brief This function is used to check if HCI TX data that has been + previously stalled from sending (due to encryption control + procedures, physical flow control, etc.) can now be transmitted. + If so, it attempts to send it, and if successful, notifies the + HCI that the buffer has been transmitted, and the LL is ready + for more data. + + input parameters + + @param *connPtr - Pointer to a connection. + @param context - LL_TX_DATA_CONTEXT_SEND_DATA | + LL_TX_DATA_CONTEXT_TX_ISR | + LL_TX_DATA_CONTEXT_POST_PROCESSING + + output parameters + + @param None. + + @return None. +*/ +void llProcessTxData0( llConnState_t* connPtr, uint8 context ) +{ + uint8* pBuf; + HAL_ENTER_CRITICAL_SECTION(); + + // try to put as many packets into the TX FIFO as possible + while( connPtr->txDataQ.head != NULL ) + { + // point to packet header + pBuf = (uint8*)(connPtr->txDataQ.head + 1); + + // check if TX is enabled and if there is room in TX FIFO + + if ( llWriteTxData( connPtr, pBuf[1], pBuf[0], &pBuf[2] ) == LL_STATUS_SUCCESS ) + { + // remove entry from TX queue and free the buffer + osal_bm_free( llDequeueDataQ( &connPtr->txDataQ ) ); + numComplPkts ++; + // update counter + connPtr->pmCounter.ll_hci_to_ll_pkt_cnt += numComplPkts; +// LOG("TX:%d\n", connPtr->connId); + continue; + } + + // unable to complete the write, so keep packet on queue + break; + } + + // check if we completed any packets + // The Number of Completed Packets event is sent when the number of completed + // packets is equal to or greater than the user specified limit, which can + // range from 1 to the LL_MAX_NUM_DATA_BUFFERS (default is one). If the + // number of completed packets is less than the limit, then this event is only + // sent if the user indicated that this event to be sent at the end of the + // connection event. + // Note: Spec indicates that while the Controller has HCI data packets in its + // buffer, it must keep sending the Number Of Completed Packets event + // to the Host at least periodically, until it finally reports that all + // the pending ACL Data Packets have been transmitted or flushed. + // However, this can potentially waste a lot of time sending events + // with a number of completed packets set to zero, so for now, this + // will not be supported. + if ( (numComplPkts > 0) && + (numComplPkts >= numComplPktsLimit) ) // || + //((context == LL_TX_DATA_CONTEXT_POST_PROCESSING) && numComplPktsFlush)) ) + { + uint16 connId = connPtr->connId; + uint16 numCompletedPackets = numComplPkts; + // and send credits to the Host + HCI_NumOfCompletedPacketsEvent( 1, + &connId, + &numCompletedPackets ); + // clear count + numComplPkts = 0; + } + + HAL_EXIT_CRITICAL_SECTION(); + return; +} + +/******************************************************************************* + @fn llCtrlAllowInEncProc + + @brief This routine check whether the received control PDU type is allowed + during start encrypt procedure. Ref to 5.1.3.1 Encryption Start Procedure + "After these Data Channel PDUs are acknowledged, + the Link Layer of the master shall only send Empty PDUs or LL_ENC_REQ, + LL_START_ENC_RSP, LL_TERMINATE_IND, LL_REJECT_IND or + LL_REJECT_EXT_IND PDUs." + + input parameters + + @param None. + + output parameters + + @param None. + + @return TRUE: Rx packet processed. + FALSE: Unable to process packet. +*/ +static uint8 llCtrlAllowInEncProc(uint8 opCode) +{ + if (opCode == LL_CTRL_ENC_REQ || // normally should not received + opCode == LL_CTRL_START_ENC_RSP || + opCode == LL_CTRL_TERMINATE_IND || + opCode == LL_CTRL_REJECT_IND) + return TRUE; + else + return FALSE; +} + +/******************************************************************************* + @fn llProcessRxData0 + + @brief This routine is called by the RF_NormalIsr when an Rx packet + has been received. It can also be called by the Master or + Slave post-processing software. + + input parameters + + @param None. + + output parameters + + @param None. + + @return TRUE: Rx packet processed. + FALSE: Unable to process packet. +*/ +uint8 llProcessRxData0( void ) +{ + llConnState_t* connPtr; + uint8_t i; + // get current connection + connPtr = &conn_param[g_ll_conn_ctx.currentConn]; + + if(getRxBufferSize(connPtr) > 0) + { + uint8 pktLen; + uint8 pktHdr; + uint8* pBuf; + uint8* hciRxBuffer = NULL; // for data packet + // process the data packet + i = get_rx_read_ptr (connPtr); + pBuf = connPtr->ll_buf.rx_conn_desc[i]->data; + // read length first; placed this way by RF hardware for DMA optimization + pktLen = (connPtr->ll_buf.rx_conn_desc[i]->header & 0xff00) >> 8; + // read header + pktHdr = connPtr->ll_buf.rx_conn_desc[i]->header & 0x3; + + // check if we have received a data packet during an encryption procedure + // Note: This requirement is based on ESR05 V1.0, Erratum 3565. + // Note: Technically, an empty packet will never be received since they + // are flushed. + // Note: Also end if the packet type is invalid. + if (LL_INVALID_LLID(pktHdr) || // bug fixed 2018-04-08 + ((LL_DATA_PDU(pktHdr) && (pktLen != 0) && (connPtr->rxDataEnabled == FALSE))))// || // receive no-empty Data PDU in start enc procedure + { + //non-empty data packet or an invalid packet received ruing encryption + // procedure, so terminate immediately per + llConnTerminate( connPtr, LL_MIC_FAILURE_TERM ); + connPtr->pmCounter.ll_recv_invalid_pkt_cnt++; + return( FALSE ); + } + + // adjust pointer to buffer based on packet type + // Note: If a control PDU, then the generic pPkt buffer will be used + // whether encryption is enabled or not. For a data PDU, the generic + // pPkt buffer will only be used if encryption is enabled. + if ( LL_DATA_PDU(pktHdr) ) + { + connPtr->pmCounter.ll_to_hci_pkt_cnt++; + // check if we have a data packet and the receive flow control is enabled + // Note: This is in support of Controller to Host flow control. + // yes, so request a Rx buffer from the HCI, sans the MIC bytes if enc is enabled + hciRxBuffer = LL_RX_bm_alloc( pktLen - ((connPtr->encEnabled)? 4 : 0) ); + + // check that we have a buffer + if ( hciRxBuffer == NULL ) + { + connPtr->pmCounter.ll_hci_buffer_alloc_err_cnt ++; // A1 ROM metal change add + // abort processing the Rx PDU, not update Rx FIFO read ptr in this case. It will be processed next connection event + return( FALSE ); + } + } + + // check if we have to decrypt the PDU + if ( connPtr->encEnabled ) + { + // subtract the MIC size from the packet length, LL_ENC_Decrypt will add back + pktLen -= LL_ENC_MIC_LEN; + + // decrypt PDU with authentication check + if ( LL_ENC_Decrypt( connPtr, + pktHdr, + pktLen, + pBuf ) == FALSE ) + { + // free the packet buffer + osal_bm_free( hciRxBuffer ); + // authentication failed; terminate immediately + llConnTerminate( connPtr, LL_MIC_FAILURE_TERM ); + return( FALSE ); + } + } + + // check if this was a data PDU + if ( LL_DATA_PDU(pktHdr) ) + { + connPtr->pmCounter.ll_recv_data_pkt_cnt ++; + // restore decrypted PDU to data buffer + memcpy(hciRxBuffer, pBuf, pktLen ); + // call the HCI to process the received data + LL_RxDataCompleteCback( (uint16)conn_param[g_ll_conn_ctx.currentConn].connId, + hciRxBuffer, //pBuf, + pktLen, + pktHdr, + connPtr->lastRssi); + connPtr->ll_buf.rx_conn_desc[i]->valid = 0; + connPtr->ll_buf.rx_conn_desc[i]->header = 0; + update_rx_read_ptr(connPtr); + } + else // a control PDU + { + connPtr->pmCounter.ll_recv_ctrl_pkt_cnt++; + update_rx_read_ptr(connPtr); //Attention: correct bug 2017-04-20. in llProcessSlaveControlPacket, the link may be terminated and reset so this staement should not be put after terminate + + if ( llState == LL_STATE_CONN_MASTER ) + { + llProcessMasterControlPacket( connPtr, pBuf ); + } + else // LL_STATE_CONN_SLAVE + { + // bug fixed 2018-04-08 , receive no expected Ctrl PDU in start enc procedure + if (LL_CTRL_PDU(pktHdr) && (!llCtrlAllowInEncProc(*pBuf)) && (connPtr->rxDataEnabled == FALSE) + && !(connPtr->encInfo.encRestart)) // bug fixed 2018-4-20, consider pause enc case + { + llConnTerminate( connPtr, LL_MIC_FAILURE_TERM ); + connPtr->pmCounter.ll_recv_invalid_pkt_cnt++; + return( FALSE ); + } + + llProcessSlaveControlPacket( connPtr, pBuf ); + connPtr->ll_buf.rx_conn_desc[i]->valid = 0; + connPtr->ll_buf.rx_conn_desc[i]->header = 0; + } + } // if data or control packet + } + + return( TRUE ); +} + +/******************************************************************************* + @fn llEnqueueCtrlPkt + + @brief This function is used to add a control packet for subsequent + processing. How the control packet is handled depends on + whether it is part of a control procedure, and whether there's + a control packet timeout associated with it. + + Note: Duplicate entries are filtered. + + Note: Can be called via the HCI interface or from the LL. + + input parameters + + @param connPtr - Pointer to the current connection. + @param ctrlType - Control packet type. + + + output parameters + + @param None. + + @return None. +*/ +void llEnqueueCtrlPkt( llConnState_t* connPtr, + uint8 ctrlType ) +{ + uint8 i; + HAL_ENTER_CRITICAL_SECTION(); + + // filter duplicates + for (i=0; ictrlPktInfo.ctrlPktCount; i++) + { + if ( connPtr->ctrlPktInfo.ctrlPkts[ i ] == ctrlType ) + { + // already present, so we're done here + HAL_EXIT_CRITICAL_SECTION(); + return; + } + } + + // add to queue + connPtr->ctrlPktInfo.ctrlPkts[ connPtr->ctrlPktInfo.ctrlPktCount ] = ctrlType; + // bump the count + connPtr->ctrlPktInfo.ctrlPktCount++; + HAL_EXIT_CRITICAL_SECTION(); + return; +} + +/******************************************************************************* + @fn llDequeueCtrlPkt + + @brief This function is used to remove a control packet that has + completed processing. The control packet at the head of the + queue is "removed" by moving remaining packets up. + + input parameters + + @param connPtr - Pointer to the current connection. + + + output parameters + + @param None. + + @return None. +*/ +void llDequeueCtrlPkt( llConnState_t* connPtr ) +{ + uint8 i; + + if (connPtr->ctrlPktInfo.ctrlPktCount == 0) // add by HZF + return; + + HAL_ENTER_CRITICAL_SECTION(); + // decrement the number of control packets left + connPtr->ctrlPktInfo.ctrlPktCount--; + + // shift remaining packets, if any, up one spot + // ALT: COULD UNROLL LOOP TO OPTIMIZE. + for (i=0; ictrlPktInfo.ctrlPktCount; i++) + { + connPtr->ctrlPktInfo.ctrlPkts[i] = connPtr->ctrlPktInfo.ctrlPkts[i+1]; + } + + // stuff an undefined packet at the end of the queue + connPtr->ctrlPktInfo.ctrlPkts[LL_MAX_NUM_CTRL_PROC_PKTS-1] = LL_CTRL_UNDEFINED_PKT; + // set the control processing to inactive for next packet, if there is one + connPtr->ctrlPktInfo.ctrlPktActive = FALSE; + HAL_EXIT_CRITICAL_SECTION(); + return; +} + +/******************************************************************************* + @fn llReplaceCtrlPkt + + @brief This function is used to replace the current control packet at + the head of the queue with the next control packet for the same + control procedure. This is used to ensure that a new control + procedure enqueued doesn't interleave with a control procedure + that is already in progress. + + input parameters + + @param connPtr - Pointer to the current connection. + @param ctrlType - Control packet type. + + + output parameters + + @param None. + + @return None. +*/ +void llReplaceCtrlPkt( llConnState_t* connPtr, + uint8 ctrlType ) +{ + HAL_ENTER_CRITICAL_SECTION(); + // replace control packet at head of queue + connPtr->ctrlPktInfo.ctrlPkts[0] = ctrlType; + // set the control processing to inactive + connPtr->ctrlPktInfo.ctrlPktActive = FALSE; + HAL_EXIT_CRITICAL_SECTION(); + return; +} + + +/******************************************************************************* + @fn llConvertCtrlProcTimeoutToEvent + + @brief This function is used to convert the control procedure timeout, + which is a constant 40s, into an expiration event count. This + routine is called when a new connection is formed, or when the + connection update parameters have been changed. + + Note: It is assumed here that connInterval has already been + converted into units of 625us. + + Note: Based on Core V4.0, the termination control procedure + timeout is based on the Connection Supervision Timeout + value. + + Side Effects: + ctrlPktInfo.ctrlTimeoutVal - Updated with number of events to + expiration. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return None. +*/ +void llConvertCtrlProcTimeoutToEvent( llConnState_t* connPtr ) +{ + // find the number of connection intervals in the control procedure timeout + // Note: 1600 coarse ticks per second + connPtr->ctrlPktInfo.ctrlTimeoutVal = (uint16)LL_MAX_CTRL_PROC_TIMEOUT / + (connPtr->curParam.connInterval); + + // take the ceiling + if ( (uint16)LL_MAX_CTRL_PROC_TIMEOUT % (connPtr->curParam.connInterval) ) // 40 s + { + // there's overage, so bump the count + connPtr->ctrlPktInfo.ctrlTimeoutVal++; + } + + return; +} + + +#if 0 +uint8_t llTimeCompare(int base_time, int fine_time) +{ + if( base_time < current_base_time || (base_time ==current_base_time && fine_time < read_current_fine_time ())) + return TRUE; + + return FALSE; +} +#endif + +// TODO: to decide whether change llTimeCompare to ll24BitTimeCompare or not +#define LL_MAX_24BIT_TIME_IN_625US 0xC800 // 32s in 625us ticks (LSTO limit) +/******************************************************************************* + @fn ll24BitTimeCompare + + @brief This function determines if the first time parameter is greater + than the second time parameter, taking timer counter wrap into + account. If so, TRUE is returned. Both values are 24-bit times. + + input parameters + + @param time1 - First 24-bit time. + @param time2 - Second 24-bit time. + + output parameters + + @param None. + + @return TRUE: When first parameter is greater than second. + FALSE: When first parmaeter is less than or equal to + the second. +*/ +uint8 ll24BitTimeCompare( uint32 time1, + uint32 time2 ) +{ + time1 &= 0x00FFFFFF; + time2 &= 0x00FFFFFF; + + if ( time1 > time2 ) + { + // check if time1 is greater than time2 due to wrap; that is, time2 is + // actually greater than time1 + return ( (uint8)((time1-time2) <= LL_MAX_24BIT_TIME_IN_625US) ); + } + else // time2 >= time1 + { + // check if time2 is greater than time1 due to wrap; that is, time1 is + // actually greater than time2 + return( (uint8)((time2-time1) > LL_MAX_24BIT_TIME_IN_625US) ); + } +} + +#if 0 +/******************************************************************************* + @fn llAdjustForMissedEvent + + @brief This function determines if it is now too late to make the next + scheduled radio task. If so, then the next connection event + is skipped. The current time is padded for two coarse time + ticks. One is required as the radio task setup time begins one + coarse time tick before the radio starts. One is required as the + current time's fine tick value may be very close to rolling + over. + + Note: Slave latency is assumed to be zero because if it is not, + then presumably there would be enough time to post + process and a missed event won't be detected. + + Note: The additional amount of timer drift correction for the + missed event is assumed to be insignificant as the + interval is presumably short. Worst case (Master SCA of + 500ppm and Slave SCA of 40ppm) is less than 10us. This + is covered by the pad already allocated. + + input parameters + + @param connPtr - Pointer to the current connection. + @param timeToNextEvent - Number of coarse ticks to the next event. + + output parameters + + @param None. + + @return Indicates whether a LSTO is going to occur during slave latency: + TRUE: Terminate due to a link supervision timeout. + FALSE: Do not terminate. +*/ +uint8 llAdjustForMissedEvent( llConnState_t* connPtr, + uint32 timeToNextEvent ) // we needn't this function +{ + // check if the task start time is ahead of the current cut off time + // (i.e. llTask.t2e1.coarse > cutoffTime) + // Note: Routine handles wrap condition, and returns TRUE if the first + // parameter is greater than the second parameter. + if (llTimeCompare( conn_param [0].next_event_base_time, conn_param [0].anchor_point_fine_time )) + { + // advance to next event + // Note: The fine time isn't touched as we have not yet done a delta correction. +// connPtr->llTask->t2e1.coarse += timeToNextEvent; +// connPtr->llTask->t2e1.coarse &= 0x00FFFFFF; + conn_param[0].next_event_base_time += conn_param [0].curParam .connInterval * 625/BASE_TIME_UNITS ; + conn_param[0].next_event_fine_time += conn_param [0].curParam .connInterval * 625%BASE_TIME_UNITS ; + conn_param[0].next_event_base_time += conn_param[0].next_event_fine_time / BASE_TIME_UNITS; + conn_param[0].next_event_fine_time = conn_param[0].next_event_fine_time % BASE_TIME_UNITS; + ll_schedule_next_event ( (conn_param[0].next_event_base_time-current_base_time)* BASE_TIME_UNITS + conn_param[0].next_event_fine_time-read_current_fine_time () - 500); + + // check if we have a LSTO expiration as a result + // Note: The skipped is taken as an event with no received packets. + if ( connPtr->expirationEvent == (connPtr->currentEvent+(uint16)1) ) + { + return( TRUE); + } + + // adjust the next event count + connPtr->nextEvent++; + + // check if the skipped event is the event where we detect a parameter update + // Note: This check must come after we advance nextEvent again. + if ( (connPtr->pendingParamUpdate == TRUE) && + (connPtr->paramUpdateEvent == connPtr->nextEvent) ) + { + // then advance the instant to the next active event + connPtr->paramUpdateEvent++; + } + + // check if the skipped event is the event where we detect a data channel update + // Note: This check must come after we advance nextEvent again. + if ( (connPtr->pendingChanUpdate == TRUE) && + (connPtr->chanMapUpdateEvent == connPtr->nextEvent) ) + { + // then advance the instant to the next active event + connPtr->chanMapUpdateEvent++; + } + + // check if the skipped event is the event where we detect a phy updatee + // Note: This check must come after we advance nextEvent again. + if ( (connPtr->pendingPhyModeUpdate == TRUE) && + (connPtr->phyModeUpdateEvent == connPtr->nextEvent) ) + { + // then advance the instant to the next active event + connPtr->phyModeUpdateEvent++; + } + } + + return( FALSE ); +} +#endif +/******************************************************************************* + @fn llEventDelta + + @brief This function returns the difference between two 16 bit event + counters. It is used to find the number of events between some + future event (event A) and the current event (event B). + + input parameters + + @param eventA - The first event count. + @param eventB - The second event count. + + output parameters + + @param None. + + @return The absolute number of events: | eventA - eventB | +*/ +uint16 llEventDelta( uint16 eventA, + uint16 eventB ) +{ + // first check if we don't need to worry about wrapping + if ( eventA >= eventB ) + { + // we don't, so take a straight difference + return( eventA - eventB ); + } + else // we have to handle wrap + { + // so combine the two ranges + return( (uint16)((0x10000 - eventB) + eventA) ); + } +} + +/******************************************************************************* + @fn llEventInRange + + @brief This function determines if a connection update event count is + between the current event count (exclusive) and the next event + count (inclusive), given 16 bit event counters are used. It is + used when the next active event count is beyond the current + event count plus one (possible due to slave latency) but an + update event is pending before that and must be handled. + + input parameters + + @param curEvent - The current event that just completed. + @param nextEvent - The next active event based on slave latency. + @param updateEvent - The event when an update needs to take place. + + output parameters + + @param None. + + @return Indicates whether is between current event and next event: + TRUE: current event < update event <= next event + FALSE: update event > next event +*/ +uint8 llEventInRange( uint16 curEvent, + uint16 nextEvent, + uint16 updateEvent ) +{ + // first check if we don't need to worry about wrapping + if ( nextEvent > curEvent ) + { + // we don't, so check if the instant is between curEvent and nextEvent + // Note: Need to check that the instant is greater than the curEvent in + // case the instant has wrapped! + return( (uint8) ((updateEvent <= nextEvent) && (updateEvent > curEvent)) ); + } + else // we have to handle wrap + { + // so compare either the upper range exclusive or the lower range inclusive + return( (uint8)((updateEvent > curEvent) || (updateEvent <= nextEvent)) ); + } +} + +/******************************************************************************* + @fn llConvertLstoToEvent + + @brief This function is used to convert the LSTO, which is given + in integer multiples of 10ms from 100ms to 32s, into an + expiration event count. + + Note: It is assumed here that connInterval and connTimeout have + already been converted into units of 625us. + + Side Effects: + expirationValue - The connection expiration value is updated. + + input parameters + + @param connPtr - Pointer to the current connection. + @param connParams - Pointer to the connection parameters. + + output parameters + + @param None. + + @return None. +*/ +void llConvertLstoToEvent( llConnState_t* connPtr, + connParam_t* connParams ) +{ + // find the number of connection intervals in the LSTO + connPtr->expirationValue = connParams->connTimeout / connParams->connInterval; + + // take the ceiling + if ( connParams->connTimeout % connParams->connInterval ) + { + // there's overage, so bump the count + connPtr->expirationValue++; + } + + return; +} +/******************************************************************************* + @fn llSetupDataLenghtReq + + @brief This function is used to setup the data length request. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Boolean to indicate whether the setup was successfully + completed: + TRUE: Success + FALSE: Not Done +*/ +uint8 llSetupDataLenghtReq( llConnState_t* connPtr ) +{ + uint8 pktLen; + uint8* pBuf = connPtr->ctrlData.data; + + if(!connPtr->ctrlDataIsPending && !connPtr->ctrlDataIsProcess ) // new by phyplus, change to ctrl data queue? + { + pktLen = LL_LENGTH_REQ_PAYLOAD_LEN; + // write control type as payload + *pBuf++ = LL_LENGTH_REQ; + pBuf = llMemCopyDst( pBuf, (uint8*)& (g_llPduLen.suggested.MaxRxOctets), 2 ); + pBuf = llMemCopyDst( pBuf, (uint8*)& (g_llPduLen.suggested.MaxRxTime), 2 ); + pBuf = llMemCopyDst( pBuf, (uint8*)& (g_llPduLen.suggested.MaxTxOctets), 2 ); + pBuf = llMemCopyDst( pBuf, (uint8*)& (g_llPduLen.suggested.MaxTxTime), 2 ); + + // encrypt TX packet in place in the TX FIFO + if ( connPtr->encEnabled ) + { + // encrypt PDU with authentication check + LL_ENC_Encrypt( connPtr, + LL_DATA_PDU_HDR_LLID_CONTROL_PKT, + pktLen, + connPtr->ctrlData.data ); + // increase length by size of MIC + pktLen += LL_ENC_MIC_LEN; + } + + connPtr->ctrlDataIsPending = 1; + connPtr->ctrlData .header = pktLen << 8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + return( TRUE ); + } + + return( FALSE ); +} + +/******************************************************************************* + @fn llSetupDataLenghtRsp + + @brief This function is used to setup the data length response. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Boolean to indicate whether the setup was successfully + completed: + TRUE: Success + FALSE: Not Done +*/ +uint8 llSetupDataLenghtRsp( llConnState_t* connPtr ) +{ + uint8 pktLen; + uint8* pBuf = connPtr->ctrlData.data; + + if(!connPtr->ctrlDataIsPending && !connPtr->ctrlDataIsProcess ) // new by phyplus, change to ctrl data queue? + { + pktLen = LL_LENGTH_RSP_PAYLOAD_LEN; + // write control type as payload + *pBuf++ = LL_LENGTH_RSP; + pBuf = llMemCopyDst( pBuf, (uint8*)& (g_llPduLen.suggested.MaxRxOctets), 2 ); + pBuf = llMemCopyDst( pBuf, (uint8*)& (g_llPduLen.suggested.MaxRxTime), 2 ); + pBuf = llMemCopyDst( pBuf, (uint8*)& (g_llPduLen.suggested.MaxTxOctets), 2 ); + pBuf = llMemCopyDst( pBuf, (uint8*)& (g_llPduLen.suggested.MaxTxTime), 2 ); + + // encrypt TX packet in place in the TX FIFO + if ( connPtr->encEnabled ) + { + // encrypt PDU with authentication check + LL_ENC_Encrypt( connPtr, + LL_DATA_PDU_HDR_LLID_CONTROL_PKT, + pktLen, + connPtr->ctrlData.data ); + // increase length by size of MIC + pktLen += LL_ENC_MIC_LEN; + } + + connPtr->ctrlDataIsPending = 1; + connPtr->ctrlData .header = pktLen << 8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + return( TRUE ); + } + + return( FALSE ); +} + +/******************************************************************************* + @fn llSetupPhyReq + + @brief This function is used to setup the phy update request. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Boolean to indicate whether the setup was successfully + completed: + TRUE: Success + FALSE: Not Done +*/ +uint8 llSetupPhyReq( llConnState_t* connPtr ) +{ + uint8 pktLen; + uint8* pBuf = connPtr->ctrlData.data; + + if(!connPtr->ctrlDataIsPending && !connPtr->ctrlDataIsProcess ) // new by phyplus, change to ctrl data queue? + { + pktLen = LL_PHY_REQ_PAYLOAD_LEN; + // write control type as payload + *pBuf++ = LL_PHY_REQ; + *pBuf++ = connPtr->llPhyModeCtrl.req.txPhy; + *pBuf++ = connPtr->llPhyModeCtrl.req.rxPhy;; + + // encrypt TX packet in place in the TX FIFO + if ( connPtr->encEnabled ) + { + // encrypt PDU with authentication check + LL_ENC_Encrypt( connPtr, + LL_DATA_PDU_HDR_LLID_CONTROL_PKT, + pktLen, + connPtr->ctrlData.data ); + // increase length by size of MIC + pktLen += LL_ENC_MIC_LEN; + } + + connPtr->ctrlDataIsPending = 1; + connPtr->ctrlData .header = pktLen << 8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + return( TRUE ); + } + + return( FALSE ); +} + +/******************************************************************************* + @fn llSetupPhyReq + + @brief This function is used to setup the phy update response. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Boolean to indicate whether the setup was successfully + completed: + TRUE: Success + FALSE: Not Done +*/ +uint8 llSetupPhyRsp( llConnState_t* connPtr ) +{ + uint8 pktLen; + uint8* pBuf = connPtr->ctrlData.data; + + if(!connPtr->ctrlDataIsPending && !connPtr->ctrlDataIsProcess ) // new by phyplus, change to ctrl data queue? + { + pktLen = LL_PHY_RSP_PAYLOAD_LEN; + // write control type as payload + *pBuf++ = LL_PHY_RSP; + *pBuf++ = connPtr->llPhyModeCtrl.def.txPhy; + *pBuf++ = connPtr->llPhyModeCtrl.def.rxPhy; + + // encrypt TX packet in place in the TX FIFO + if ( connPtr->encEnabled ) + { + // encrypt PDU with authentication check + LL_ENC_Encrypt( connPtr, + LL_DATA_PDU_HDR_LLID_CONTROL_PKT, + pktLen, + connPtr->ctrlData.data ); + // increase length by size of MIC + pktLen += LL_ENC_MIC_LEN; + } + + connPtr->ctrlDataIsPending = 1; + connPtr->ctrlData .header = pktLen << 8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + return( TRUE ); + } + + return( FALSE ); +} + +/******************************************************************************* + @fn llSetupPhyUpdateInd + + @brief This function is used to setup the phy update indicate. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Boolean to indicate whether the setup was successfully + completed: + TRUE: Success + FALSE: Not Done +*/ +uint8 llSetupPhyUpdateInd( llConnState_t* connPtr ) +{ + uint8 pktLen; + uint8* pBuf = connPtr->ctrlData.data; + + if(!connPtr->ctrlDataIsPending && !connPtr->ctrlDataIsProcess ) // new by phyplus, change to ctrl data queue? + { + pktLen = LL_PHY_UPDATE_IND_PAYLOAD_LEN; + // write control type as payload + *pBuf++ = LL_PHY_UPDATE_IND; + *pBuf++ = connPtr->phyUpdateInfo.m2sPhy; + *pBuf++ = connPtr->phyUpdateInfo.s2mPhy; + // we are writing to the FIFO, so convert relative instant number to an + // absolute event number + connPtr->phyModeUpdateEvent+= connPtr->currentEvent; + pBuf = llMemCopyDst( pBuf, (uint8*)& (connPtr->phyModeUpdateEvent), 2 ); + + // encrypt TX packet in place in the TX FIFO + if ( connPtr->encEnabled ) + { + // encrypt PDU with authentication check + LL_ENC_Encrypt( connPtr, + LL_DATA_PDU_HDR_LLID_CONTROL_PKT, + pktLen, + connPtr->ctrlData.data ); + // increase length by size of MIC + pktLen += LL_ENC_MIC_LEN; + } + + connPtr->ctrlDataIsPending = 1; + connPtr->ctrlData .header = pktLen << 8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + return( TRUE ); + } + + return( FALSE ); +} + +/******************************************************************************* + @fn llSetupUpdateParamReq + + @brief This function is used to setup the update parameter request. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Boolean to indicate whether the setup was successfully + completed: + TRUE: Success + FALSE: Not Done +*/ +uint8 llSetupUpdateParamReq( llConnState_t* connPtr ) +{ + uint8 pktLen; + uint8* pBuf = connPtr->ctrlData.data; + + if(!connPtr->ctrlDataIsPending && !connPtr->ctrlDataIsProcess ) // new by phyplus, change to ctrl data queue? + { + pktLen = LL_CONN_UPDATE_REQ_PAYLOAD_LEN; + // write control type as payload + *pBuf++ = LL_CTRL_CONNECTION_UPDATE_REQ; + // write the window size + *pBuf++ = connPtr->paramUpdate.winSize >> 1; + // write the window offset + pBuf = llMemCopyDst( pBuf, (uint8*)&connPtr->paramUpdate.winOffset, 2 ); + // write the connection interval + pBuf = llMemCopyDst( pBuf, (uint8*)&connPtr->paramUpdate.connInterval, 2 ); + // write the slave latency + pBuf = llMemCopyDst( pBuf, (uint8*)&connPtr->paramUpdate.slaveLatency, 2 ); + // write the connection timeout + pBuf = llMemCopyDst( pBuf, (uint8*)&connPtr->paramUpdate.connTimeout, 2 ); + // we are writing to the FIFO, so convert relative instant number to an + // absolute event number + connPtr->paramUpdateEvent += connPtr->currentEvent; + // write the update event count + pBuf = llMemCopyDst( pBuf, (uint8*)&connPtr->paramUpdateEvent, 2 ); + + // encrypt TX packet in place in the TX FIFO + if ( connPtr->encEnabled ) + { + // encrypt PDU with authentication check + LL_ENC_Encrypt( connPtr, + LL_DATA_PDU_HDR_LLID_CONTROL_PKT, + pktLen, + connPtr->ctrlData.data ); + // increase length by size of MIC + pktLen += LL_ENC_MIC_LEN; + } + + connPtr->ctrlDataIsPending = 1; + connPtr->ctrlData .header = pktLen << 8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + return( TRUE ); + } + + return( FALSE ); +} + +/******************************************************************************* + @fn llSetupUpdateChanReq + + @brief This function is used to setup the update channel request. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Boolean to indicate whether the setup was successfully + completed: + TRUE: Success + FALSE: Not Done +*/ +uint8 llSetupUpdateChanReq( llConnState_t* connPtr ) +{ + uint8 pktLen; + uint8* pBuf = connPtr->ctrlData.data; + + if(!connPtr->ctrlDataIsPending && !connPtr->ctrlDataIsProcess ) // new by phyplus, change to ctrl data queue? + { + pktLen = LL_CHAN_MAP_REQ_PAYLOAD_LEN; + // write control type as payload + *pBuf++ = LL_CTRL_CHANNEL_MAP_REQ; + // write the new channel map + pBuf = llMemCopyDst( pBuf, chanMapUpdate.chanMap, LL_NUM_BYTES_FOR_CHAN_MAP ); + // we are writing to the FIFO, so convert relative instant number to an + // absolute event number + connPtr->chanMapUpdateEvent += connPtr->currentEvent; + // write the update event count + pBuf = llMemCopyDst( pBuf, (uint8*)&connPtr->chanMapUpdateEvent, 2 ); + + // encrypt TX packet in place in the TX FIFO + if ( connPtr->encEnabled ) + { + // encrypt PDU with authentication check + LL_ENC_Encrypt( connPtr, + LL_DATA_PDU_HDR_LLID_CONTROL_PKT, + pktLen, + connPtr->ctrlData.data ); + // increase length by size of MIC + pktLen += LL_ENC_MIC_LEN; + } + + connPtr->ctrlDataIsPending = 1; + connPtr->ctrlData .header = pktLen << 8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + return( TRUE ); + } + + return( FALSE ); +} + +/******************************************************************************* + @fn llSetupEncReq + + @brief This function is used to setup the start encryption request. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Boolean to indicate whether the setup was successfully + completed: + TRUE: Success + FALSE: Not Done +*/ +uint8 llSetupEncReq( llConnState_t* connPtr ) +{ + uint8 pktLen; + uint8* pBuf = connPtr->ctrlData.data; + + // first we need to verify that all pending transmissions have finished and + if (getTxBufferSize(connPtr) == 0 + && !connPtr->ctrlDataIsPending // TX FIFO empty, of course, no ctrl data is pending + && !connPtr->ctrlDataIsProcess) // TODO: change to check physical Tx FIFO done, then could setup enc + { + pktLen = LL_ENC_REQ_PAYLOAD_LEN; + // write control type as payload + *pBuf++ = LL_CTRL_ENC_REQ; + // rand + pBuf = llMemCopyDst( pBuf, (uint8*)&connPtr->encInfo.RAND, LL_ENC_RAND_LEN ); + // EDIV + pBuf = llMemCopyDst( pBuf, (uint8*)&connPtr->encInfo.EDIV, LL_ENC_EDIV_LEN ); + // SKDm + pBuf = llMemCopyDst( pBuf, (uint8*)&connPtr->encInfo.SKD[LL_ENC_SKD_M_OFFSET], LL_ENC_SKD_M_LEN ); + // IVm + pBuf = llMemCopyDst( pBuf, (uint8*)&connPtr->encInfo.IV[LL_ENC_IV_M_OFFSET], LL_ENC_IV_M_LEN ); + // bug fixed 2018-8-6, need reverse the SKDm & IVm byte order + // bytes are generated LSO..MSO, but need to be maintained as + // MSO..LSO, per FIPS 197 (AES), so reverse the bytes + LL_ENC_ReverseBytes( (uint8*)&connPtr->encInfo.SKD[LL_ENC_SKD_M_OFFSET], + LL_ENC_SKD_M_LEN ); + // bytes are generated LSO..MSO, but need to be maintained as + // MSO..LSO, per FIPS 197 (AES), so reverse the bytes + // ALT: POSSIBLE TO MAINTAIN THE IV IN LSO..MSO ORDER SINCE THE NONCE IS + // FORMED THAT WAY. + LL_ENC_ReverseBytes( (uint8*)&connPtr->encInfo.IV[LL_ENC_IV_M_OFFSET], + LL_ENC_IV_M_LEN ); + connPtr->ctrlDataIsPending = 1; + connPtr->ctrlData .header = pktLen << 8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + // set the control packet timeout for 40s relative to our present time + // Note: This is done in terms of connection events. + connPtr->ctrlPktInfo.ctrlTimeout = connPtr->ctrlPktInfo.ctrlTimeoutVal; + return( TRUE ); + } + + return( FALSE ); +} + +/******************************************************************************* + @fn llSetupEncRsp + + @brief This function is used to setup the encryption response. This + can only be done when all pending transmissions have first been + completed (i.e. the TX FIFO is empty). + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Boolean to indicate whether the setup was successfully + completed: + TRUE: Success + FALSE: Not Done +*/ +uint8 llSetupEncRsp( llConnState_t* connPtr ) +{ + uint8 pktLen; + uint8* pBuf = connPtr->ctrlData.data; + + // first we need to verify that all pending transmissions have finished and + if (getTxBufferSize(connPtr) == 0 + && !connPtr->ctrlDataIsPending // TX FIFO empty, of course, no ctrl data is pending + && !connPtr->ctrlDataIsProcess) // TODO: change to check physical Tx FIFO done, then could setup enc + { + uint8 i; + // ============== update 2018-1-24 + // write control type as payload + *pBuf++ = LL_CTRL_ENC_RSP; + // SKDs + pBuf = llMemCopyDst( pBuf, (uint8*)&connPtr->encInfo.SKD[LL_ENC_SKD_S_OFFSET], LL_ENC_SKD_S_LEN ); + // IVs + pBuf = llMemCopyDst( pBuf, (uint8*)&connPtr->encInfo.IV[LL_ENC_IV_S_OFFSET], LL_ENC_IV_S_LEN); + // ========= update 2018-1-24 end + // bytes are generated LSO..MSO, but need to be maintained as + // MSO..LSO, per FIPS 197 (AES), so reverse the bytes + LL_ENC_ReverseBytes( (uint8*)&connPtr->encInfo.SKD[LL_ENC_SKD_S_OFFSET], + LL_ENC_SKD_S_LEN ); + // bytes are generated LSO..MSO, but need to be maintained as + // MSO..LSO, per FIPS 197 (AES), so reverse the bytes + // ALT: POSSIBLE TO MAINTAIN THE IV IN LSO..MSO ORDER SINCE THE NONCE IS + // FORMED THAT WAY. + LL_ENC_ReverseBytes( (uint8*)&connPtr->encInfo.IV[LL_ENC_IV_S_OFFSET], + LL_ENC_IV_S_LEN ); + + // place the IV into the Nonce to be used for this connection + // Note: If a Pause Encryption control procedure is started, the + // old Nonce value will be used until encryption is disabled. + // Note: The IV is sequenced LSO..MSO within the Nonce. + // ALT: POSSIBLE TO MAINTAIN THE IV IN LSO..MSO ORDER SINCE THE NONCE IS + // FORMED THAT WAY. + for (i=0; iencInfo.nonce[ LL_END_NONCE_IV_OFFSET+i ] = + connPtr->encInfo.IV[ (LL_ENC_IV_LEN-i)-1 ]; + } + + pktLen = LL_ENC_RSP_PAYLOAD_LEN; + connPtr->ctrlDataIsPending = 1; + connPtr->ctrlData .header = pktLen << 8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + // set the control packet timeout for 40s relative to our present time + // Note: This is done in terms of connection events. + // Note: For a Encryption Setup procedure that follows an Encryption Pause, + // this is a Restart Timer operation as the timer was already started + // when LL_PAUSE_ENC_RSP was enqueued for transmission. For a normal + // Encryption Setup procedure, this will have no effect as the timer + // was never started before. + // Note: Upon re-examination of the previous "Note", and given the most + // recent changes to the Controller spec (D09R31), it isn't clear + // why the timer should be started or re-started when a + // LL_PAUSE_ENC_RSP or LL_ENC_RSP packet is sent for a re-start enc. + // Or given + connPtr->ctrlPktInfo.ctrlTimeout = connPtr->ctrlPktInfo.ctrlTimeoutVal; + return( TRUE ); + } + + return( FALSE ); +} + +/******************************************************************************* + @fn llSetupStartEncReq + + @brief This function is used to handle placing the Start Encryption + Request into the TX FIFO. + + Note: The TX FIFO should already be empty. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Boolean to indicate whether the setup was successfully + completed: + TRUE: Success + FALSE: Not Done +*/ +uint8 llSetupStartEncReq( llConnState_t* connPtr ) +{ + uint8 pktLen; + uint8* pBuf = connPtr->ctrlData.data; + // Note: No need to check if there's enough room in the TX FIFO since it was + // forced to empty prior to beginning encryption control procedure. + pktLen = LL_START_ENC_REQ_PAYLOAD_LEN; + // write control type as payload + *pBuf++ = LL_CTRL_START_ENC_REQ; + connPtr->ctrlDataIsPending = 1; + connPtr->ctrlData .header = pktLen << 8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + // set the control packet timeout for 40s relative to our present time + // Note: This is done in terms of connection events. + // Note: For a Encryption Setup procedure that follows an Encryption Pause, + // this is a Restart Timer operation. For a normal Encryption Setup + // procedure, this is a Start Timer operation. Effectively, there is + // no difference between the two. + connPtr->ctrlPktInfo.ctrlTimeout = connPtr->ctrlPktInfo.ctrlTimeoutVal; + return( TRUE ); +} + +#ifdef USE_UNPATCHED +/******************************************************************************* + @fn llSetupStartEncRsp + + @brief This function is used to handle the placement of the Encryption + Response packet in the TX FIFO. + + Note: The TX FIFO should already be empty. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Boolean to indicate whether the setup was successfully + completed: + TRUE: Success + FALSE: Not Done +*/ +uint8 llSetupStartEncRsp( llConnState_t* connPtr ) +{ + uint8 pktLen; + uint8* pBuf = connPtr->ctrlData.data; + // Note: No need to check if there's enough room in the TX FIFO since it was + // forced to empty prior to beginning encryption control procedure. + // write control type as payload + *pBuf = LL_CTRL_START_ENC_RSP; + // encrypt PDU with authentication check + LL_ENC_Encrypt( connPtr, + LL_DATA_PDU_HDR_LLID_CONTROL_PKT, + LL_START_ENC_RSP_PAYLOAD_LEN, + pBuf ); // input no-encrypt data pBuf, output in the same buffer + pktLen = LL_START_ENC_RSP_PAYLOAD_LEN + LL_ENC_MIC_LEN; + connPtr->ctrlDataIsPending = 1; + connPtr->ctrlData .header = pktLen << 8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + + // control procedure timeout value only needed for Master after Start Enc Response + if ( llState == LL_STATE_CONN_MASTER ) + { + // set the control packet timeout for 40s relative to our present time + // Note: This is done in terms of connection events. + // Note: Core Spec V4.0 now indicates that each LL control PDU that is queued + // for transmission resets the procedure response timeout timer. + connPtr->ctrlPktInfo.ctrlTimeout = connPtr->ctrlPktInfo.ctrlTimeoutVal; + } + + return( TRUE ); +} +#endif // USE_UNPATCHED + + +/******************************************************************************* + @fn llSetupPauseEncReq + + @brief This function is used to handle the placement of the Encryption + Pause Request packet in the TX FIFO. + + Note: The TX FIFO should already be empty. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Boolean to indicate whether the setup was successfully + completed: + TRUE: Success + FALSE: Not Done +*/ +uint8 llSetupPauseEncReq( llConnState_t* connPtr ) +{ + uint8 pktLen; + uint8* pBuf = connPtr->ctrlData.data; + + // first we need to verify that all pending transmissions have finished and + //if ( PHY_TX_FIFO_LEN() == 0 ) + if (getTxBufferSize(connPtr) == 0 + && !connPtr->ctrlDataIsPending // TX FIFO empty, of course, no ctrl data is pending + && !connPtr->ctrlDataIsProcess) // TODO: change to check physical Tx FIFO done, then could setup enc + { + // Note: No need to check if there's enough room in the TX FIFO since it was + // forced to empty prior to beginning encryption control procedure. + // write control type as payload + *pBuf = LL_CTRL_PAUSE_ENC_REQ; + // encrypt PDU with authentication check + LL_ENC_Encrypt( connPtr, + LL_DATA_PDU_HDR_LLID_CONTROL_PKT, + LL_PAUSE_ENC_REQ_PAYLOAD_LEN, + pBuf ); + pktLen = LL_PAUSE_ENC_REQ_PAYLOAD_LEN + LL_ENC_MIC_LEN; + connPtr->ctrlDataIsPending = 1; + connPtr->ctrlData .header = pktLen << 8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + // set the control packet timeout for 40s relative to our present time + // Note: This is done in terms of connection events. + // Note: Core Spec V4.0 now indicates that each LL control PDU that is queued + // for transmission resets the procedure response timeout timer. + connPtr->ctrlPktInfo.ctrlTimeout = connPtr->ctrlPktInfo.ctrlTimeoutVal; + return( TRUE ); + } + + return( FALSE ); +} + + +/******************************************************************************* + @fn llSetupPauseEncRsp + + @brief This function is used to handle the placement of the Pause + Encryption packet in the TX FIFO. This can only be done when + all pending transmissions have first been completed (i.e. + the TX FIFO is empty). + + Note: The TX FIFO should already be empty. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Boolean to indicate whether the setup was successfully done: + TRUE: Success + FALSE: Not Done +*/ +uint8 llSetupPauseEncRsp( llConnState_t* connPtr ) +{ + uint8 pktLen; + uint8* pBuf = connPtr->ctrlData.data; + + // first we need to verify that all pending transmissions have finished + // Note: On the Master, the FIFO should already be empty. + //if ( PHY_TX_FIFO_LEN() == 0 ) + if (getTxBufferSize(connPtr) == 0 + && !connPtr->ctrlDataIsPending // TX FIFO empty, of course, no ctrl data is pending + && !connPtr->ctrlDataIsProcess) // TODO: change to check physical Tx FIFO done, then could setup enc + { + pktLen = LL_PAUSE_ENC_RSP_PAYLOAD_LEN; + // write control type as payload + *pBuf = LL_CTRL_PAUSE_ENC_RSP; + + // only the Slave encrypts the Pause Encryption Response + if ( llState == LL_STATE_CONN_SLAVE ) + { + // encrypt PDU with authentication check + LL_ENC_Encrypt( connPtr, + LL_DATA_PDU_HDR_LLID_CONTROL_PKT, + pktLen, + pBuf ); + // increase length by size of MIC + pktLen += LL_ENC_MIC_LEN; + } + + connPtr->ctrlDataIsPending = 1; + connPtr->ctrlData .header = pktLen << 8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + // set the control packet timeout for 40s relative to our present time + // Note: This is done in terms of connection events. + // Note: Core Spec V4.0 now indicates that each LL control PDU that is + // queued for transmission resets the procedure response timeout + // timer. + connPtr->ctrlPktInfo.ctrlTimeout = connPtr->ctrlPktInfo.ctrlTimeoutVal; + return( TRUE ); + } + + return( FALSE ); +} + +/******************************************************************************* + @fn llSetupRejectInd + + @brief This function is used to setup the Reject Indications procedure + which results when encryption has been started, but the LTK + request was negative. Once the rejection indication is sent + and acknowledged, the connection remains unencrypted and TX + is re-enabled. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Boolean to indicate whether the setup was successfully + completed: + TRUE: Success + FALSE: Not Done +*/ +uint8 llSetupRejectInd( llConnState_t* connPtr,uint8 errCode) +{ + uint8 pktLen; + uint8* pBuf = connPtr->ctrlData.data; + pktLen = LL_REJECT_IND_PAYLOAD_LEN; + // write control type as payload + *pBuf = LL_CTRL_REJECT_IND; + //*(pBuf + 1) = connPtr->encInfo.encRejectErrCode; // TP/SEC/SLA/BV-04-C, reject cause should be filled + *(pBuf + 1) = errCode; // TP/SEC/SLA/BV-04-C, reject cause should be filled + connPtr->ctrlDataIsPending = 1; + // set the control packet timeout for 40s relative to our present time + // Note: This is done in terms of connection events. + connPtr->ctrlPktInfo.ctrlTimeout = connPtr->ctrlPktInfo.ctrlTimeoutVal; + connPtr->ctrlData .header = pktLen << 8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + return( TRUE ); +} + +/******************************************************************************* + @fn llSetupRejectExtInd + + @brief This function is used to setup the Reject Indications procedure + which results when encryption has been started, but the LTK + request was negative. Once the rejection indication is sent + and acknowledged, the connection remains unencrypted and TX + is re-enabled. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Boolean to indicate whether the setup was successfully + completed: + TRUE: Success + FALSE: Not Done +*/ +uint8 llSetupRejectExtInd( llConnState_t* connPtr,uint8 errCode) +{ + uint8 pktLen; + uint8* pBuf = connPtr->ctrlData.data; + pktLen = LL_REJECT_EXT_IND_PAYLOAD_LEN; + // write control type as payload + *pBuf = LL_CTRL_REJECT_EXT_IND; + *(pBuf + 1) = connPtr->rejectOpCode; // TP/SEC/SLA/BV-04-C, reject cause should be filled + *(pBuf + 1) = errCode; // TP/SEC/SLA/BV-04-C, reject cause should be filled + connPtr->ctrlDataIsPending = 1; + // set the control packet timeout for 40s relative to our present time + // Note: This is done in terms of connection events. + connPtr->ctrlPktInfo.ctrlTimeout = connPtr->ctrlPktInfo.ctrlTimeoutVal; + connPtr->ctrlData .header = pktLen << 8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + return( TRUE ); +} + +/******************************************************************************* + @fn llSetupVersionIndReq + + @brief This function is used to setup the version information + indication. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Boolean to indicate whether the setup was successfully + completed: + TRUE: Success + FALSE: Not Done +*/ +uint8 llSetupVersionIndReq( llConnState_t* connPtr ) +{ + uint8 pktLen; + uint8* pBuf; + + if(!connPtr->ctrlDataIsPending && !connPtr->ctrlDataIsProcess ) // new by phyplus, change to ctrl data queue? + { + pBuf= connPtr->ctrlData.data ; + // write payload length first + // Note: The Radio expects length to have been set one more than the + // actual payload size (to support DMA), which it will decrement by + // one before transmitting. Since DMA isn't being used here, the + // length is bumped by one to offset this decrement. + pktLen = LL_VERSION_IND_PAYLOAD_LEN; + // write control type as payload + *pBuf++ = LL_CTRL_VERSION_IND; + // write the version number + *pBuf++ = verInfo.verNum; + // write the company ID + pBuf = llMemCopyDst( pBuf, (uint8*)&verInfo.comId, 2 ); + // write the subversion number + pBuf = llMemCopyDst( pBuf, (uint8*)&verInfo.subverNum, 2 ); + + // encrypt TX packet in place in the TX FIFO + if ( connPtr->encEnabled ) + { + // encrypt PDU with authentication check + LL_ENC_Encrypt( connPtr, + LL_DATA_PDU_HDR_LLID_CONTROL_PKT, + pktLen, + connPtr->ctrlData.data ); + // increase length by size of MIC + pktLen += LL_ENC_MIC_LEN; + } + + connPtr->ctrlDataIsPending = 1; + connPtr->ctrlData .header = pktLen << 8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + connPtr->ctrlPktInfo.ctrlTimeout = connPtr->ctrlPktInfo.ctrlTimeoutVal; + return (TRUE); + } + + return( FALSE ); +} + +/******************************************************************************* + @fn llSetupFeatureSetReq + + @brief This function is used to setup the feature set request. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Boolean to indicate whether the setup was successfully + completed: + TRUE: Success + FALSE: Not Done +*/ +uint8 llSetupFeatureSetReq( llConnState_t* connPtr ) +{ + uint8 pktLen; + uint8* pBuf; + + if(!connPtr->ctrlDataIsPending && !connPtr->ctrlDataIsProcess ) // new by phyplus, change to ctrl data queue? + { + pBuf= connPtr->ctrlData.data ; + pktLen = LL_FEATURE_REQ_PAYLOAD_LEN; + // write control type as payload + *pBuf++ = LL_CTRL_FEATURE_REQ; + // write the feature set + pBuf = llMemCopyDst( pBuf, connPtr->featureSetInfo.featureSet, LL_MAX_FEATURE_SET_SIZE ); + + // encrypt TX packet in place in the TX FIFO + if ( connPtr->encEnabled ) + { + // encrypt PDU with authentication check + LL_ENC_Encrypt( connPtr, + LL_DATA_PDU_HDR_LLID_CONTROL_PKT, + pktLen, + connPtr->ctrlData.data ); + // increase length by size of MIC + pktLen += LL_ENC_MIC_LEN; + } + + connPtr->ctrlDataIsPending =1; + connPtr->ctrlData .header = pktLen << 8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + // set the control packet timeout for 40s relative to our present time + // Note: This is done in terms of connection events. + connPtr->ctrlPktInfo.ctrlTimeout = connPtr->ctrlPktInfo.ctrlTimeoutVal; + return( TRUE ); + } + + return( FALSE ); +} + +/******************************************************************************* + @fn llSetupFeatureSetRsp + + @brief This function is used to setup the Feature Set Response packet. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Boolean to indicate whether the setup was successfully + completed: + TRUE: Success + FALSE: Not Done +*/ +uint8 llSetupFeatureSetRsp( llConnState_t* connPtr ) +{ + uint8 pktLen; + uint8* pBuf; + + if(!connPtr->ctrlDataIsPending && !connPtr->ctrlDataIsProcess ) + { + pBuf= connPtr->ctrlData.data; + pktLen = LL_FEATURE_RSP_PAYLOAD_LEN; + // write control type as payload + *pBuf++ = LL_CTRL_FEATURE_RSP; + // write the feature set response payload + pBuf = llMemCopyDst( pBuf, connPtr->featureSetInfo.featureSet, LL_MAX_FEATURE_SET_SIZE ); + + // encrypt TX packet + if ( connPtr->encEnabled ) + { + // encrypt PDU with authentication check + LL_ENC_Encrypt( connPtr, + LL_DATA_PDU_HDR_LLID_CONTROL_PKT, + pktLen, + connPtr->ctrlData .data ); + // increase length by size of MIC + pktLen += LL_ENC_MIC_LEN; + } + + // deactivate slave latency, if it was enabled. TI setting, it seems useless? + // Note: Not used by Master. + connPtr->slaveLatency = 0; + connPtr->ctrlDataIsPending = 1; + connPtr->ctrlData .header = pktLen <<8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + return( TRUE ); + } + + return( FALSE ); +} + + + +/***************************************************************************************** + fn: llSetupCTEReq + + date:2020-01-20 + + brief: this function is used to setup the LL_CTE_REQ packet + + input parameters: + connPtr - Pointer to the current connection. + + output parameters: + None + + return Boolean to indicate whether the setup was successfully + completed: + TRUE: Success + FALSE: Not Done + + *****************************************************************************************/ +uint8 llSetupCTEReq( llConnState_t* connPtr ) +{ + uint8 pktLen; + uint8* pBuf; + uint8 j; + uint32 ant1=0,ant0=0; + + if(!connPtr->ctrlDataIsPending && !connPtr->ctrlDataIsProcess ) + { + pBuf= connPtr->ctrlData.data; + pktLen = LL_CTE_REQ_LEN; + // write control type as payload + *pBuf++ = LL_CTRL_CTE_REQ; + // write the feature set response payload + *pBuf++ = ( (connPtr->llConnCTE.CTE_Type << 6) & 0xC0 ) | connPtr->llConnCTE.CTE_Length ; + + // encrypt TX packet + if ( connPtr->encEnabled ) + { + // encrypt PDU with authentication check + LL_ENC_Encrypt( connPtr, + LL_DATA_PDU_HDR_LLID_CONTROL_PKT, + pktLen, + connPtr->ctrlData.data ); + // increase length by size of MIC + pktLen += LL_ENC_MIC_LEN; + } + + connPtr->ctrlDataIsPending = 1; + connPtr->ctrlData.header = pktLen <<8 | 0x20 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + + for( j = 0 ; j < connPtr->llConnCTE.pattern_LEN ; j++ ) + { + // PHY SDK 4 bit represents an Antenna ID, so uint32 represents max 8 antenna + if( j < 8 ) + { + ant0 |= ( ((uint32)connPtr->llConnCTE.AntID[j]) << (4*j) ); + } + else + { + ant1 |= ( ((uint32)connPtr->llConnCTE.AntID[j]) << (4*(j-8)) ); + } + } + + ll_hw_set_ant_pattern( ant1, ant0 ); + ll_hw_set_ant_switch_mode( LL_HW_ANT_SW_CTE_AUTO ); + // antWin : 8, 1us switching + 1us sampling 8 *0.25us unit = 2us + // antWin : 16,2us switching + 2us sampling 16*0.25us unit = 4us + ll_hw_set_ant_switch_timing((connPtr->llConnCTE.slot_Duration==LL_IQ_SW_SAMP_1US?8:16), 40); + ll_hw_set_cte_rxSupp( CTE_SUPP_LEN_SET | connPtr->llConnCTE.CTE_Length ); + // config timeout + connPtr->ctrlPktInfo.ctrlTimeout = connPtr->ctrlPktInfo.ctrlTimeoutVal; + return( TRUE ); + } + + return( FALSE ); +} + + +/***************************************************************************************** + fn: llSetupCTERsp + + date:2020-01-20 + + brief: + + input parameters: + connPtr - Pointer to the current connection. + + output parameters: + None + + return Boolean to indicate whether the setup was successfully + completed: + TRUE: Success + FALSE: Not Done + + *****************************************************************************************/ +uint8 llSetupCTERsp( llConnState_t* connPtr ) +{ + uint8 pktLen; + uint8* pBuf; + uint8 j; + uint32 ant1=0,ant0=0; + + if(!connPtr->ctrlDataIsPending && !connPtr->ctrlDataIsProcess ) + { + pBuf= connPtr->ctrlData.data; + pktLen = LL_CTE_RSP_LEN; + // write control type as payload + *pBuf++ = LL_CTRL_CTE_RSP; + + // encrypt TX packet + if ( connPtr->encEnabled ) + { + // encrypt PDU with authentication check + LL_ENC_Encrypt( connPtr, + LL_DATA_PDU_HDR_LLID_CONTROL_PKT, + pktLen, + connPtr->ctrlData .data ); + // increase length by size of MIC + pktLen += LL_ENC_MIC_LEN; + } + + connPtr->ctrlDataIsPending = 1; + connPtr->ctrlData.header = pktLen <<8 | 0x20 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + + switch ( connPtr->llConnCTE.CTE_Type ) + { + case CTE_REQ_TYPE_AOA: + ll_hw_set_ant_switch_mode( LL_HW_ANT_SW_CTE_OFF ); + break; + + case CTE_REQ_TYPE_AOD_1US: + case CTE_REQ_TYPE_AOD_2US: + for( j = 0 ; j < connPtr->llConnCTE.pattern_LEN ; j++ ) + { + // PHY SDK 4 bit represents an Antenna ID, so uint32 represents max 8 antenna + if( j < 8 ) + { + ant0 |= ( ((uint32)connPtr->llConnCTE.AntID[j]) << (4*j) ); + } + else + { + ant1 |= ( ((uint32)connPtr->llConnCTE.AntID[j]) << (4*(j-8)) ); + } + } + + ll_hw_set_ant_pattern(ant1,ant0); + ll_hw_set_ant_switch_mode( LL_HW_ANT_SW_CTE_AUTO ); + // antWin : 8, 1us switching + 1us sampling 8 *0.25us unit = 2us + // antWin : 16,2us switching + 2us sampling 16*0.25us unit = 4us + ll_hw_set_ant_switch_timing((connPtr->llConnCTE.CTE_Type==CTE_REQ_TYPE_AOD_1US?8:16), 40); + break; + + default: + break; + } + + ll_hw_set_cte_txSupp( CTE_SUPP_LEN_SET | connPtr->llConnCTE.CTE_Length ); + return( TRUE ); + } + + return( FALSE ); +} + + +/******************************************************************************* + @fn llSetupUnknownRsp + + @brief This function is used to setup the Unknown Response packet. + + Note: There is no control procedure timeout associated with + the Unknown Response control packet. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Boolean to indicate whether the setup was successfully + completed: + TRUE: Success + FALSE: Not Done +*/ +uint8 llSetupUnknownRsp( llConnState_t* connPtr ) +{ + uint8 pktLen; + uint8* pBuf; + + if(!connPtr->ctrlDataIsPending && !connPtr->ctrlDataIsProcess ) + { + pBuf= connPtr->ctrlData .data; + pktLen = LL_UNKNOWN_RSP_PAYLOAD_LEN; + // write control type as payload + *pBuf++ = LL_CTRL_UNKNOWN_RSP; + // write unknown control type as payload + *pBuf = connPtr->unknownCtrlType; + + // encrypt TX packet in place in the TX FIFO + if ( connPtr->encEnabled ) + { + // encrypt PDU with authentication check + LL_ENC_Encrypt( connPtr, + LL_DATA_PDU_HDR_LLID_CONTROL_PKT, + pktLen, + connPtr->ctrlData .data ); + // increase length by size of MIC + pktLen += LL_ENC_MIC_LEN; + } + + connPtr->ctrlDataIsPending = 1; + connPtr->ctrlData .header = pktLen <<8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + return( TRUE ); + } + + return( FALSE ); +} + +/******************************************************************************* + @fn llSetupTermInd + + @brief This function is used to setup the Connection Termination + procedure that has been requested by the Host. This function + is called before the start of the next Slave task. The + Connection Termination procedure requires that the Slave send + a TERMINATE_IND packet and receive an ACK from the Master. In + addition, a control packet timeout must be started. + + To simplify this procedure, all packets will be removed from + the TX FIFO before writing the TERMINATE_IND packet there. This + simplifies how can determine the terminate packet has been sent + by making the number of expected ACKs deterministic. However, + since it is possible that the NR may be retransmitting a prior + packet (which we can not remove), we have to first determine + when the terminate packet is sent before waiting for its ACK. + This is the same as waiting for either one or two ACKs, + depending on whether there is a retransmit packet or not. + This can be determined by first checking if the TX FIFO is empty + after removing all pending packets (the retransmit packet, if + present, is unaffected), and setting the number of expected + packets accordingly. When the task ends, the number of ACKS + received can be checked. + + Please note that the NR might also be retransmitting a prior + auto-empty packet (please see section 6.5.1 of the NR spec + for more detail), however in this case, the number of expected + ACKs would still be one since the BLE_L_NTXDONE counter is only + incremented when an ACK is received for a packet that is in the + TX FIFO. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Boolean to indicate whether the setup was successfully + completed: + TRUE: Success + FALSE: Not Done +*/ +uint8 llSetupTermInd( llConnState_t* connPtr ) +{ + uint8 pktLen; + uint8* pBuf; + + if(!connPtr->ctrlDataIsPending && !connPtr->ctrlDataIsProcess ) + { + pBuf= connPtr->ctrlData.data; + pktLen = LL_TERM_IND_PAYLOAD_LEN; + // write control type as payload + *pBuf++ = LL_CTRL_TERMINATE_IND; + // write the reason code + *pBuf = connPtr->termInfo.reason; + + // encrypt TX packet in place in the TX FIFO + if ( connPtr->encEnabled ) + { + // encrypt PDU with authentication check + LL_ENC_Encrypt( connPtr, + LL_DATA_PDU_HDR_LLID_CONTROL_PKT, + pktLen, + connPtr->ctrlData .data ); + // increase length by size of MIC + pktLen += LL_ENC_MIC_LEN; + } + + // disable the update parameter and update data channel pending flags + // just in case they happen to be set + // Note: Technically, these flags should not be set as only one active + // control procedure is permitted at a time. + connPtr->pendingParamUpdate = FALSE; + connPtr->pendingChanUpdate = FALSE; + connPtr->pendingPhyModeUpdate = FALSE; + // deactivate slave latency, if it was enabled + // Note: Not used by Master. + connPtr->slaveLatency = 0; + // Per Core V4.0 spec change, the termination timeout is the LSTO + connPtr->ctrlPktInfo.ctrlTimeout = connPtr->expirationValue; + connPtr->ctrlDataIsPending =1; + connPtr->ctrlData.header = pktLen <<8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + return( TRUE ); + } + + return( FALSE ); +} + +/******************************************************************************* + This function enqueues a TX data packet to the back of the data queue. + + Public function defined in hci_c_data.h. +*/ +uint8 llEnqueueDataQ( llDataQ_t* pDataQ, txData_t* pTxData ) +{ + HAL_ENTER_CRITICAL_SECTION(); + + // check if the data queue is not empty + if ( pDataQ->head != NULL ) + { + // at least one entry already on the data queue, so append packet + pDataQ->tail->pNext = pTxData; + } + else // data queue is empty + { + // so add first packet + pDataQ->head = pTxData; + } + + // either way, the tail gets this packet, and its next pointer is NULL + pDataQ->tail = pTxData; + pTxData->pNext = NULL; + HAL_EXIT_CRITICAL_SECTION(); + return( LL_STATUS_SUCCESS ); +} + + + +/******************************************************************************* + @fn llResetConnId + + @brief reset the global conn_param[0] , refer to llAllocConnId + + + input parameters + + @param None. + + output parameters + + @param None. + + @return none +*/ +void llResetConnId( uint8 connId ) +{ + int i; + llConnState_t* connPtr; + connPtr = &conn_param[connId]; + //connPtr->allocConn = TRUE; +// connPtr->connId = 0; + connPtr->txDataEnabled = TRUE; + connPtr->rxDataEnabled = TRUE; + connPtr->currentEvent = 0; + connPtr->nextEvent = 0; + connPtr->rx_timeout = 0; + connPtr->firstPacket = 1; + connPtr->currentChan = 0; + connPtr->lastCurrentChan = 0; + connPtr->lastTimeToNextEvt = 0; + connPtr->slaveLatencyAllowed = FALSE; + connPtr->slaveLatency = 0; + connPtr->pendingChanUpdate = FALSE; + connPtr->pendingParamUpdate = FALSE; + connPtr->pendingPhyModeUpdate = FALSE; + connPtr->isCollision = FALSE; + //connPtr->lastRssi = LL_RF_RSSI_UNDEFINED; + connPtr->ctrlPktInfo.ctrlPktActive = FALSE; + connPtr->ctrlPktInfo.ctrlPktCount = 0; + connPtr->verExchange.peerInfoValid = FALSE; + connPtr->verExchange.hostRequest = FALSE; + connPtr->verExchange.verInfoSent = FALSE; + connPtr->verInfo.verNum = 0; + connPtr->verInfo.comId = 0; + connPtr->verInfo.subverNum = 0; + connPtr->termInfo.termIndRcvd = FALSE; + connPtr->encEnabled = FALSE; + connPtr->encInfo.SKValid = FALSE; + connPtr->encInfo.LTKValid = FALSE; + connPtr->encInfo.txPktCount = 0; + connPtr->encInfo.rxPktCount = 0; + connPtr->encInfo.startEncRspRcved = FALSE; + connPtr->encInfo.encReqRcved = FALSE; + connPtr->encInfo.encRestart = FALSE; + connPtr->encInfo.startEncReqRcved = FALSE; + connPtr->encInfo.rejectIndRcved = FALSE; + connPtr->perInfo.numPkts = 0; + connPtr->perInfo.numCrcErr = 0; + connPtr->perInfo.numEvents = 0; + connPtr->perInfo.numMissedEvts = 0; + // PHY mode ctrl + connPtr->llPhyModeCtrl.local.txPhy=LE_1M_PHY; + connPtr->llPhyModeCtrl.local.rxPhy=LE_1M_PHY; + connPtr->llPhyModeCtrl.isProcessingReq = FALSE; + connPtr->llPhyModeCtrl.isWatingRsp = FALSE; + connPtr->llPhyModeCtrl.isChanged = FALSE; + // PDU len + connPtr->llPduLen.local.MaxRxOctets=LL_PDU_LENGTH_INITIAL_MAX_RX_OCTECTS; + connPtr->llPduLen.local.MaxTxOctets=LL_PDU_LENGTH_INITIAL_MAX_TX_OCTECTS; + connPtr->llPduLen.local.MaxRxTime =LL_PDU_LENGTH_INITIAL_MAX_RX_TIME; + connPtr->llPduLen.local.MaxTxTime =LL_PDU_LENGTH_INITIAL_MAX_TX_TIME; + connPtr->llPduLen.remote.MaxRxOctets=LL_PDU_LENGTH_INITIAL_MAX_RX_OCTECTS; + connPtr->llPduLen.remote.MaxTxOctets=LL_PDU_LENGTH_INITIAL_MAX_TX_OCTECTS; + connPtr->llPduLen.remote.MaxRxTime =LL_PDU_LENGTH_INITIAL_MAX_RX_TIME; + connPtr->llPduLen.remote.MaxTxTime =LL_PDU_LENGTH_INITIAL_MAX_TX_TIME; + connPtr->llPduLen.isProcessingReq=FALSE; + connPtr->llPduLen.isWatingRsp =FALSE; + connPtr->llPduLen.isChanged =FALSE; + // add 2020-03-17 + connPtr->llRfPhyPktFmt = LE_1M_PHY; + // add 2020-04-21 + connPtr->channel_selection = LL_CHN_SEL_ALGORITHM_1; + //add by ZQ for preChannMapUpdate + connPtr->preChanMapUpdate.chanMapUpdated = FALSE; + + // set packet queue to undefined values + // Note: This is used for debugging purposes. + for (i = 0; i < LL_MAX_NUM_CTRL_PROC_PKTS; i++) + { + connPtr->ctrlPktInfo.ctrlPkts[i] = LL_CTRL_UNDEFINED_PKT; + } + +// // initialize the channel map +// for (i=0; icurChanMap.chanMap[i] = chanMapUpdate.chanMap[i]; +// } + + // set the connection Feature Set based on this device's default + for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } +} + +/******************************************************************************* + @fn llPendingUpdateParam + + @brief This function is used to check if any active connections have + an Update Parameter control procedure pending. + + input parameters + + @param None. + + output parameters + + @param None + + @return TRUE: There is an update control procedure for at least one + active connection. + FALSE: There is no update control procedure on any active + connection. +*/ +uint8 llPendingUpdateParam( void ) +{ + uint8 i; + + // check if an update parameter control procedure is active on any connections + for (i = 0; i < g_maxConnNum; i++) + { + llConnState_t* connPtr = &conn_param[i]; // only 1 connection now, HZF + + // check if this connection is active + if ( connPtr->active ) + { + // check if an Update Parameter control procedure is pending + if ( (connPtr->ctrlPktInfo.ctrlPktCount > 0) && + (connPtr->ctrlPktInfo.ctrlPkts[0] == LL_CTRL_CONNECTION_UPDATE_REQ) ) + { + return( TRUE ); + } + } + } + + return( FALSE ); +} + + +/******************************************************************************* + @fn llInitFeatureSet + + @brief This function initializes this device's Feature Set. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void llInitFeatureSet( void ) +{ + uint8 i; + + // clear Feature Set data for this device + for (i=0; i 1 ) + { + return( TRUE ); + } + + // save if any channels are set in case only one byte is non-zero + if ( chanMap[i] ) + { + x = chanMap[i]; + } + } + + // check if no channels are used + // Note: Value is either zero or one as we would have exited if greater + // than one. + if ( nonZeroBytes != 0 ) + { + // exactly one byte is non-zero; check if not a power of two + return( (x & (x-1)) != 0); // С¼¼ÇÉ + } + + // no channel bits are set + return( FALSE ); +} + + +/******************************************************************************* + @fn llCheckWhiteListUsage + + @brief This routine is used to check if it is okay to use the white + list for routines LL_ClearWhiteList, LL_AddWhiteListDevice, + and LL_RemoveWhiteListDevice. + + input parameters + + @param None. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_COMMAND_DISALLOWED +*/ +llStatus_t llCheckWhiteListUsage( void ) +{ +//#if defined(CTRL_CONFIG) && (CTRL_CONFIG & SCAN_CFG) +// // check if any white list +// if ( ((scanInfo.scanMode == LL_SCAN_START) && +// (scanInfo.wlPolicy == LL_SCAN_WL_POLICY_USE_WHITE_LIST)) || +// ((scanInfo.scanMode == LL_SCAN_START) && +// (scanInfo.wlPolicy == LL_SCAN_WL_POLICY_ANY_ADV_PKTS) && +// (scanInfo.filterReports == LL_FILTER_REPORTS_ENABLE)) ) +// { +// // yes, so white list is in use and can't be touched +// return( LL_STATUS_ERROR_COMMAND_DISALLOWED ); +// } +//#endif // CTRL_CONFIG=SCAN_CFG + +//#if defined(CTRL_CONFIG) && (CTRL_CONFIG & INIT_CFG) +// // check if any white list +// if ( ((initInfo.scanMode == LL_SCAN_START) && +// (initInfo.wlPolicy == LL_INIT_WL_POLICY_USE_WHITE_LIST)) ) +// { +// // yes, so white list is in use and can't be touched +// return( LL_STATUS_ERROR_COMMAND_DISALLOWED ); +// } +//#endif // CTRL_CONFIG=INIT_CFG + + // check if any white list + if ( ((adv_param.advMode == LL_ADV_MODE_ON) && + (adv_param.wlPolicy != LL_ADV_WL_POLICY_ANY_REQ)) ) + { + // yes, so white list is in use and can't be touched + return( LL_STATUS_ERROR_COMMAND_DISALLOWED ); + } + + return( LL_STATUS_SUCCESS );; +} + +/******************************************************************************* + @fn llResetRfCounters + + @brief This routine is used to reset global "rfCounters" + these are per connection event counters and should be reset when start of event + + + input parameters + + @param None. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_COMMAND_DISALLOWED +*/ +void llResetRfCounters(void) +{ + osal_memset(&rfCounters, 0, sizeof(rfCounters)); +// rfCounters.numTxDone = 0; +// rfCounters.numTxAck = 0; +// rfCounters.numTxCtrlAck = 0; +// rfCounters.numTxCtrl = 0; +// rfCounters.numTxRetrans = 0; +// rfCounters.numTx = 0; +// rfCounters.numRxOk = 0; +// rfCounters.numRxCtrl = 0; +// rfCounters.numRxNotOk = 0; +// rfCounters.numRxIgnored = 0; +// rfCounters.numRxEmpty = 0; +// rfCounters.numRxFifoFull = 0; +} + + +/******************************************************************************* + @fn llCalcScaFactor + + @brief This function is used when a connection is formed to calculate + the timer drift divisor (called a timer drift factor) based on + the combined SCA of the Master (as received in the CONNECT_REQ + packet) and the Slave (based on either the default value of + 40ppm or the value set by HCI_EXT_SetSCA, from 0..500). + + Note: In order to limit the number of build configurations, + POWER_SAVINGS is always defined, so this define can no + longer be used to determine if the Slave's SCA should be + included in timer drift calculations. Instead, the global + pwrmgr_device will be used instead. + Note: When PM is not used, the Slave's SCA is zero and the + active clock accuracy is included in the overhead. + + input parameters + + @param masterSCA - An ordinal value from 0..7 that corresponds to a + SCA range per Vol. 6, Part B, Section 2.3.3.1, + Table 2.2. + + output parameters + + @param None. + + @return The timer drift factor. +*/ +uint16 llCalcScaFactor( uint8 masterSCA ) +{ + uint16 sca = 0; + uint32 tdFactor; + // include the Slave's SCA in timer drift correction + sca = adv_param.scaValue; + // convert master's SCA to PPM and combine with slave + sca += SCA[ masterSCA ]; + // calculate the Slave SCA factor + //tdFactor = llDivide31By16To16( 1000000, sca ); + tdFactor = 1000000 / sca ; + return( (uint16)tdFactor ); +} + + +// add by HZF +/******************************************************************************* + @fn llGetNextAdvChn + + @brief This function is used to get the next advertisement channel ascend. If current + advertisement channel is not set, it will return the lowest advertisement + channel according to advertisement channel map setting + + + + input parameters + + @param cur_chn - current adv channel No. + + output parameters + + @param None + + @return next advertise channel number. +*/ +uint8 llGetNextAdvChn(uint8 cur_chn) +{ + uint8 temp, next_chn; + uint8 i; + + // sanity check, should not be here + if ((adv_param.advChanMap & LL_ADV_CHAN_ALL ) == 0) + return 0xff; + + // if cur_chn adv channel number invalid, return the 1st vaild adv channel No. + if (cur_chn > 39 || cur_chn < 37) + { + i = 0; + + while (!(adv_param.advChanMap & (1 << i))) i ++; + + return (ADV_BASE_IDX + i); + } + + // duplicate adv channel map + temp = ((adv_param.advChanMap & LL_ADV_CHAN_ALL ) << 3) | (adv_param.advChanMap & LL_ADV_CHAN_ALL ); + // shift from next possible channel + i = cur_chn - 36; + + while (!(temp & (1 << i)) && i < 6) + i ++ ; + + i = (i >= 3)? (i - 3) : i; + next_chn = ADV_BASE_IDX + i; + return next_chn; +} + +/******************************************************************************* + @fn llGetNextAdvChn + + + + input parameters + + @param index - index of conn context + + output parameters + + @param None + + @return None +*/ +void reset_conn_buf(uint8 index) +{ + int i; + llConnState_t* connPtr; + connPtr = &conn_param[index]; + + for(i = 0; i < g_maxPktPerEventTx; i++) + { + connPtr->ll_buf.tx_conn_desc[i]->valid = 0; + connPtr->ll_buf.tx_conn_desc[i]->header = 0; + } + + for(i = 0; i < g_maxPktPerEventRx; i++) + { + connPtr->ll_buf.rx_conn_desc[i]->valid = 0; + connPtr->ll_buf.rx_conn_desc[i]->header = 0; + } + + connPtr->ll_buf.tx_write = 0; + connPtr->ll_buf.tx_read = 0; + connPtr->ll_buf.tx_loop = 0; + connPtr->ll_buf.rx_write = 0; + connPtr->ll_buf.rx_read = 0; + connPtr->ll_buf.rx_loop = 0; + connPtr->ll_buf.ntrm_cnt = 0; + connPtr->ll_buf.tx_not_ack_pkt->valid = 0; // bug fix 2018-05-21. In slave initiate conn term case, android mobile may not send ACK, and this status will be kept +} + +// Tx loop buffer +void update_tx_write_ptr(llConnState_t* connPtr) +{ + connPtr->ll_buf.tx_write ++; + + if (connPtr->ll_buf.tx_write >= g_maxPktPerEventTx) + { + connPtr->ll_buf.tx_loop = 1; // exceed the bank 0, then enter bank 1 + connPtr->ll_buf.tx_write = 0; + } +} + +void update_tx_read_ptr(llConnState_t* connPtr) +{ + connPtr->ll_buf.tx_read ++; + + if (connPtr->ll_buf.tx_read >= g_maxPktPerEventTx) + { + if ( connPtr->ll_buf.tx_loop == 1) + { + connPtr->ll_buf.tx_read = 0; // now read ptr & write ptr in the same bank, clear flag + connPtr->ll_buf.tx_loop = 0; + } + else + { + // error, should not be here. Don't increase read ptr + connPtr->ll_buf.tx_read --; + } + } +} + +uint8_t getTxBufferSize(llConnState_t* connPtr) +{ + if (connPtr->ll_buf.tx_loop) + return g_maxPktPerEventTx + connPtr->ll_buf.tx_write - connPtr->ll_buf.tx_read; + else + return connPtr->ll_buf.tx_write - connPtr->ll_buf.tx_read; +} + +uint8_t getTxBufferFree(llConnState_t* connPtr) +{ + return (g_maxPktPerEventTx - getTxBufferSize(connPtr) ); +} + +uint8_t get_tx_read_ptr(llConnState_t* connPtr) +{ + return connPtr->ll_buf.tx_read; +} + +uint8_t get_tx_write_ptr(llConnState_t* connPtr) +{ + return connPtr->ll_buf.tx_write; +} + +// Rx loop buffer +void update_rx_write_ptr(llConnState_t* connPtr) +{ + connPtr->ll_buf.rx_write ++; + + if (connPtr->ll_buf.rx_write >= g_maxPktPerEventRx) + { + connPtr->ll_buf.rx_loop = 1; // exceed the bank 0, then enter bank 1 + connPtr->ll_buf.rx_write = 0; + } +} + +void update_rx_read_ptr(llConnState_t* connPtr) +{ + connPtr->ll_buf.rx_read ++; + + if (connPtr->ll_buf.rx_read >= g_maxPktPerEventRx ) + { + if (connPtr->ll_buf.rx_loop == 1) + { + connPtr->ll_buf.rx_read = 0; // now read ptr & write ptr in the same bank, clear flag + connPtr->ll_buf.rx_loop = 0; + } + else + { + // error, should not be here. Don't increase read + connPtr->ll_buf.rx_read --; + } + } +} + +// get Rx buffer packet number +uint8_t getRxBufferSize(llConnState_t* connPtr) +{ + if (connPtr->ll_buf.rx_loop) + return g_maxPktPerEventRx + connPtr->ll_buf.rx_write - connPtr->ll_buf.rx_read; + else + return connPtr->ll_buf.rx_write - connPtr->ll_buf.rx_read; +} + +// get Rx buffer free packet number +uint8_t getRxBufferFree(llConnState_t* connPtr) +{ + return (g_maxPktPerEventRx - getRxBufferSize(connPtr) ); +} + +uint8_t get_rx_read_ptr(llConnState_t* connPtr) +{ + return connPtr->ll_buf.rx_read; +} + +uint8_t get_rx_write_ptr(llConnState_t* connPtr) +{ + return connPtr->ll_buf.rx_write; +} + +/******************************************************************************* + @fn llSetupConn + + @brief This function is used to determine the proper start time for the + new master connection, and from this and the start time of the + initiator, determine the initial window offset that will be + adjusted dynamically each system tick until the CONNECT_REQ is + transmitted. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void llSetupConn( void ) +{ + #if 0 + uint32 connST; + uint16 connCI; + uint16 winOffset; + uint16 adjustment; + uint32 initST = initInfo.llTask->t2e1.coarse; + #if defined(LL_MANUAL_WINOFFSET) + // Note: Normally, the window offset is managed dynamically so that precise + // connection start times can be achieved (necessary for multiple + // connnections). However, sometimes it is useful to force the window + // offset to something specific for testing. This can be done when the + // project is built with the above define. + // Note: This define should only be used for testing one connection and will + // NOT work when multiple connections are attempted! +#pragma diag_suppress=Pe111 // suppress unreachable statement warning + return; + #endif // LL_MANUAL_WINOFFSET + // get the new connections connection interval + // Note: Warning! When this statement was placed in the declaration, the + // value of newCI was set to zero! Moving it hear seems to solve this + // but this may be a IAR bug. + connCI = (llConns.llConnection[ initInfo.connId ].curParam.connInterval << 1); + // calculate the number of ticks the Init start time is past the last + // multiple of the new connection's interval (i.e. initST mod CI) + // Note: Lower 16 bits is the remainder. + // Note: Using separate variable because the assembly routine sometimes does + // not return the correct value when used together in the next + // statement. + // ALT: COULD MODIFY llDivide31By16To16 TO HANDLE QUOTIENT LARGER THAN 16 BITS + // TO SPEED UP. + //adjustment = llDivide31By16To16( initST, connCI ) & 0xFFFF; + adjustment = (uint16)((initST % connCI) & 0xFFFF); + // calc new connection start time based on Init start time, the connection + // interval and an offset associated with the connection, less the adjustment + // Note: connST can never be less than or equal to initTask start time. + connST = (initST + connCI - adjustment + (initInfo.connId * NUM_SLOTS_PER_MASTER)) & 0x00FFFFFF; + #ifdef DEBUG + LL_ASSERT( connST > initST ); + #endif // DEBUG + // calc the window offset for the new connection + // Note: Subtract the 1.25ms the Slave will add on per the spec, plus + // additional time to ensure the Slave starts before the Masters + // receive window in case of start time variablity in the Master due + // to the dynamic window offset. Any extra ticks subtracted here by + // LL_LINK_WIN_OFFSET_ADJ will have to be added back on in Init when + // the connection is formed. + // Note: The subtraction from the newConnST is done by adding to the initTask + // start time. + winOffset = ll24BitTimeDelta( connST, + initST + + LL_LINK_MIN_WIN_OFFSET + + LL_LINK_WIN_OFFSET_ADJ ); + + // check for wrap + // Note: If the delta between the new connection start time and the initTask + // start time is less than the adjustments, readjust the window offset + // by the modulo connection interval. + if ( winOffset > connCI ) + { + // yes, so put back one connection interval + winOffset += connCI; + } + + // configure the nR to use dynamic window offset feature + PHY_SET_DYN_WINOFFSET( winOffset, connCI ); + // DEBUG: SAVE FOR COMPARISON IN INIT TASKDONE WHEN CONN FORMS. + // subtract the LL_LINK_WIN_OFFSET_ADJ from the calculated connST as this is + // the connection ST as it appears to the Slave, so in Init, the Master connST + // should appear to be exactly +LL_LINK_WIN_OFFSET_ADJ ticks more + //newConnST_debug = connST - LL_LINK_WIN_OFFSET_ADJ; + //newWinOffset_debug = winOffset; + //initST_debug = initST; + return; + #endif +} + +/******************************************************************************* + @fn llGenerateCRC + + @brief This function is used to generate an initial 24-bit CRC value. + + input parameters + + @param None. + + output parameters + + @param None. + + @return A 24-bit CRC value. +*/ +uint32 llGenerateCRC( void ) +{ + uint32 crcInit = 0; + // generate 24 bit CRC init value + // Note: Generating true random numbers requires the use of the radio. + ((uint8*)&crcInit)[0] = LL_ENC_GeneratePseudoRandNum(); + ((uint8*)&crcInit)[1] = LL_ENC_GeneratePseudoRandNum(); + ((uint8*)&crcInit)[2] = LL_ENC_GeneratePseudoRandNum(); + return( crcInit ); +} + +uint8 llValidAccessAddr( uint32 accessAddr ); +uint8 llGtSixConsecZerosOrOnes( uint32 accessAddr); +uint8 llEqSynchWord( uint32 accessAddr); +uint8 llOneBitSynchWordDiffer( uint32 accessAddr); +uint8 llEqualBytes( uint32 accessAddr); +uint8 llGtTwentyFourTransitions( uint32 accessAddr); +uint8 llLtTwoChangesInLastSixBits( uint32 accessAddr); +uint8 llEqAlreadyValidAddr( uint32 accessAddr ); + + +/******************************************************************************* + @fn llValidAccessAddr + + @brief This function is called to check if an access address is a + valid access address. + + input parameters + + @param accessAddr - Connection synchronization word. + + output parameters + + @param None. + + @return Indication of valid access address: + TRUE: Access address is valid. + FALSE: Access address is invalid. +*/ +uint8 llValidAccessAddr( uint32 accessAddr ) +{ + // check if this access address has already been chosen before + if ( !llEqAlreadyValidAddr( accessAddr ) ) + { + // test if the access address meets all the requirements + if ( !llGtSixConsecZerosOrOnes(accessAddr) && // test if there are greater than six consecutive zeros + !llEqSynchWord(accessAddr) && // test if equal to advertising packet sync word + !llOneBitSynchWordDiffer(accessAddr) && // test if it differs only in one bit from the advertising packet sync word + !llEqualBytes(accessAddr) && // test if all four bytes are equal + !llGtTwentyFourTransitions(accessAddr) && // test that there aren't more than 24 transitions + !llLtTwoChangesInLastSixBits(accessAddr) ) // test there's a minimum of two changes in the last six bit portion + { + return( TRUE ); + } + } + + return( FALSE ); +} + + +/******************************************************************************* + @fn llGenerateValidAccessAddr + + @brief This function is called to randomly generate a valid access + address. + + input parameters + + @param None. + + output parameters + + @param None. + + @return A valid 32-bit access address. +*/ +uint32 llGenerateValidAccessAddr( void ) +{ + uint32 accessAddr; + + // generate a valid access address + do + { + // generate a true random 32 bit number + // Note: Generating true random numbers requires the use of the radio. + ((uint8*)&accessAddr)[0] = LL_ENC_GeneratePseudoRandNum(); + ((uint8*)&accessAddr)[1] = LL_ENC_GeneratePseudoRandNum(); + ((uint8*)&accessAddr)[2] = LL_ENC_GeneratePseudoRandNum(); + ((uint8*)&accessAddr)[3] = LL_ENC_GeneratePseudoRandNum(); + // verify if it is valid + } + while( !llValidAccessAddr( accessAddr ) ); + + return( accessAddr ); +} + + +/******************************************************************************* + @fn llGtSixConsecZerosOrOnes + + @brief This function is called to check if there are more than six + consecutive zeros or ones in the access address. + + input parameters + + @param accessAddr - Connection synchronization word. + + output parameters + + @param None. + + @return Indicates if access address meets criteria: + TRUE: Access address meets criteria. + FALSE: Access address does not meet criteria. +*/ +uint8 llGtSixConsecZerosOrOnes( uint32 accessAddr ) +{ + uint8 prevBit, nextBit, count, i; + // init count + count = 1; + // init first bit + prevBit = (uint8)(accessAddr & 1); + + // for each subsequent bit + for (i=1; i<32; i++) + { + // get the next bit + nextBit = (uint8)( (accessAddr >> i) & 1 ); + + // check if it is the same as previous bit + if (nextBit == prevBit) + { + // same, so increment count and check if more than six + if (++count > 6) + { + // yep, more than six ones or zeros in a row + return( TRUE ); + } + } + else // different from prev + { + // so replace prev with this bit, reset count, and keep checking + prevBit = nextBit; + count = 1; + } + } + + return( FALSE ); +} + + +/******************************************************************************* + @fn llEqSynchWord + + @brief This function is called to check if the access address is equal + to the pre-defined Advertiser synch word. + + input parameters + + @param accessAddr - Connection synchronization word. + + output parameters + + @param None. + + @return Indicates if access address meets criteria: + TRUE: Access address meets criteria. + FALSE: Access address does not meet criteria. +*/ +uint8 llEqSynchWord( uint32 accessAddr ) +{ + return ( (uint8)(accessAddr == (uint32)ADV_SYNCH_WORD) ); +} + + +/******************************************************************************* + @fn llOneBitSynchWordDiffer + + @brief This function is called to check if the access address differs + from the pre-defined Advertiser synch word by only one bit. + + input parameters + + @param accessAddr - Connection synchronization word. + + output parameters + + @param None. + + @return Indicates if access address meets criteria: + TRUE: Access address meets criteria. + FALSE: Access address does not meet criteria. +*/ +uint8 llOneBitSynchWordDiffer( uint32 accessAddr ) +{ + uint32 numOnes; + // exclusive or + numOnes = (accessAddr ^ (uint32)ADV_SYNCH_WORD); + // check if a power of two (i.e. only one bit is set) + // Note: If accessAddr is ADV_SYNCH_WORD, the this routine will return TRUE + // even though there are no bits that differ. But note that the routine + // llEqSynchWord will catch this case, so we don't really need to + // check for it here. However, to be thorough, the explict check for + // no bits differing is made here. + return( (numOnes != 0) && ((numOnes & (numOnes-1)) == 0) ); +} + + +/******************************************************************************* + @fn llEqualBytes + + @brief This function is called to check if the access address's four + bytes are equal. + + input parameters + + @param accessAddr - Connection synchronization word. + + output parameters + + @param None. + + @return Indicates if access address meets criteria: + TRUE: Access address meets criteria. + FALSE: Access address does not meet criteria. +*/ +uint8 llEqualBytes( uint32 accessAddr) +{ + uint8 b0, b1, b2, b3; + b0 = ((uint8*)&accessAddr)[0]; //((accessAddr >> 0) & 0xFF); + b1 = ((uint8*)&accessAddr)[1]; //((accessAddr >> 8) & 0xFF); + b2 = ((uint8*)&accessAddr)[2]; //((accessAddr >> 16) & 0xFF); + b3 = ((uint8*)&accessAddr)[3]; //((accessAddr >> 24) & 0xFF); + return( (uint8)((b0 == b1) && (b0 == b2) && (b0 == b3)) ); +} + + +/******************************************************************************* + @fn llGtTwentyFourTransitions + + @brief This function is called to check if the access address has more + than 24 bit transitions. + + input parameters + + @param accessAddr - Connection synchronization word. + + output parameters + + @param None. + + @return Indicates if access address meets criteria: + TRUE: Access address meets criteria. + FALSE: Access address does not meet criteria. +*/ +uint8 llGtTwentyFourTransitions( uint32 accessAddr ) +{ + uint8 prevBit, nextBit, count, i; + // init count + count = 0; + // init first bit + prevBit = (uint8)(accessAddr & 1); + + // for each subsequent bit + for (i=1; i<32; i++) + { + // check if next bit is same as previous bit + nextBit = (uint8)((accessAddr >> i) & 1); + + // check if we have a transition or not + if (nextBit != prevBit) + { + // transition, so increment count and check if more than 24 + if (++count > 24) + { + // yep, more than 24 transitions + return( TRUE ); + } + + // replace prev with this bit + prevBit = nextBit; + } + } + + return( FALSE ); +} + + +/******************************************************************************* + @fn llLtTwoChangesInLastSixBits + + @brief This function is called to check if the access address has a + minimum of two changes in the last six bits. + + input parameters + + @param accessAddr - Connection synchronization word. + + output parameters + + @param None. + + @return Indicates if access address meets criteria: + TRUE: Access address meets criteria. + FALSE: Access address does not meet criteria. +*/ +uint8 llLtTwoChangesInLastSixBits( uint32 accessAddr ) +{ + uint8 prevBit, nextBit, count, i; + // init count + count = 0; + // init first bit, which is bit 27 as we want only the last six bits + prevBit = (uint8)((accessAddr >> 26) & 1); + + // for each subsequent bit + for (i=27; i<32; i++) + { + // check if next bit is same as previous bit + nextBit = (uint8)((accessAddr >> i) & 1); + + // check if we have a transition or not + if (nextBit != prevBit) + { + // transition, so increment count and check if equal to 2 + if (++count == 2) + { + // yep, at least 2 transitions in last six bits + return( FALSE ); + } + + // replace prev with this bit + prevBit = nextBit; + } + } + + // less than 2 transitions in last six bits + return( TRUE ); +} + + +/******************************************************************************* + @fn llEqAlreadyValidAddr + + @brief This function is called to check if the access address is the + the same as any already existing valid access address. + + Note: It is assumed that a LL connection data structure has not + yet been allocated as this is a potential connection. The + the check of already existing identical access addresses + is restricted to only already existing connections. + + input parameters + + @param accessAddr - Connection synchronization word. + + output parameters + + @param None. + + @return Indicates if access address meets criteria: + TRUE: Access address meets criteria. + FALSE: Access address does not meet criteria. +*/ +uint8 llEqAlreadyValidAddr( uint32 accessAddr ) +{ + #if 0 + uint8 i; + + // check any already existing connections don't have the same access address + for (i=0; i 4s(not use 4.096 to ease the caculation) +#define LL_MAX_ALLOW_TIMER 4000000 +void llAdjSlaveLatencyValue( llConnState_t* connPtr ) +{ + while ((connPtr->slaveLatencyValue + 1) * connPtr->curParam.connInterval > (LL_MAX_ALLOW_TIMER / 625) + && (connPtr->slaveLatencyValue > 0)) + { + connPtr->slaveLatencyValue --; + } +} +//add by ZQ 20181030 for DLE feature +void llPduLengthManagmentReset(void) +{ +// // to remove +// g_llPduLen.local.MaxRxOctets=LL_PDU_LENGTH_INITIAL_MAX_RX_OCTECTS; +// g_llPduLen.local.MaxTxOctets=LL_PDU_LENGTH_INITIAL_MAX_TX_OCTECTS; +// g_llPduLen.local.MaxRxTime =LL_PDU_LENGTH_INITIAL_MAX_RX_TIME; +// g_llPduLen.local.MaxTxTime =LL_PDU_LENGTH_INITIAL_MAX_TX_TIME; +// +// // to remove +// g_llPduLen.remote.MaxRxOctets=LL_PDU_LENGTH_INITIAL_MAX_RX_OCTECTS; +// g_llPduLen.remote.MaxTxOctets=LL_PDU_LENGTH_INITIAL_MAX_TX_OCTECTS; +// g_llPduLen.remote.MaxRxTime =LL_PDU_LENGTH_INITIAL_MAX_RX_TIME; +// g_llPduLen.remote.MaxTxTime =LL_PDU_LENGTH_INITIAL_MAX_TX_TIME; + g_llPduLen.suggested.MaxRxOctets=LL_PDU_LENGTH_SUPPORTED_MAX_RX_OCTECTS; + g_llPduLen.suggested.MaxTxOctets=LL_PDU_LENGTH_SUPPORTED_MAX_TX_OCTECTS; + g_llPduLen.suggested.MaxRxTime =LL_PDU_LENGTH_SUPPORTED_MAX_RX_TIME; + g_llPduLen.suggested.MaxTxTime =LL_PDU_LENGTH_SUPPORTED_MAX_TX_TIME; + + for (int i = 0; i < g_maxConnNum; i++) + { + conn_param[i].llPduLen.local.MaxRxOctets=LL_PDU_LENGTH_INITIAL_MAX_RX_OCTECTS; + conn_param[i].llPduLen.local.MaxTxOctets=LL_PDU_LENGTH_INITIAL_MAX_TX_OCTECTS; + conn_param[i].llPduLen.local.MaxRxTime =LL_PDU_LENGTH_INITIAL_MAX_RX_TIME; + conn_param[i].llPduLen.local.MaxTxTime =LL_PDU_LENGTH_INITIAL_MAX_TX_TIME; + conn_param[i].llPduLen.remote.MaxRxOctets=LL_PDU_LENGTH_INITIAL_MAX_RX_OCTECTS; + conn_param[i].llPduLen.remote.MaxTxOctets=LL_PDU_LENGTH_INITIAL_MAX_TX_OCTECTS; + conn_param[i].llPduLen.remote.MaxRxTime =LL_PDU_LENGTH_INITIAL_MAX_RX_TIME; + conn_param[i].llPduLen.remote.MaxTxTime =LL_PDU_LENGTH_INITIAL_MAX_TX_TIME; + conn_param[i].llPduLen.isProcessingReq=FALSE; + conn_param[i].llPduLen.isWatingRsp =FALSE; + conn_param[i].llPduLen.isChanged =FALSE; + } + + llTrxNumAdaptiveConfig(); + return; +} + + +// to consider we should adjust global configuration here +// comment out +void llTrxNumAdaptiveConfig0(void ) +{ +// uint8 pktNum; +// +// if(pGlobal_config[LL_TRX_NUM_ADAPTIVE_CONFIG]>0) +// { +// pktNum = 2048/(MAX(g_llPduLen.local.MaxTxOctets,g_llPduLen.local.MaxRxOctets)+20) - 1;//reseved 1 for ack +// +// if(pktNum>pGlobal_config[LL_TRX_NUM_ADAPTIVE_CONFIG]) +// pktNum = pGlobal_config[LL_TRX_NUM_ADAPTIVE_CONFIG]; +// +// pGlobal_config[LL_TX_PKTS_PER_CONN_EVT]=pktNum; +// pGlobal_config[LL_RX_PKTS_PER_CONN_EVT]=pktNum; +// +// AT_LOG("[TrxNum] t%d r%d n%d\n",g_llPduLen.local.MaxTxOctets,g_llPduLen.local.MaxRxOctets,pktNum); +// +// } +} + +//add by ZQ 20181030 for DLE feature +void llPduLengthUpdate0(uint16 connHandle) +{ + llConnState_t* connPtr; + connPtr = &conn_param[connHandle]; + connPtr->llPduLen.isChanged =FALSE; + + if( connPtr->llPduLen.remote.MaxRxOctets < LL_PDU_LENGTH_INITIAL_MAX_RX_OCTECTS + || connPtr->llPduLen.remote.MaxRxTime < LL_PDU_LENGTH_INITIAL_MAX_RX_TIME + || connPtr->llPduLen.remote.MaxTxOctets < LL_PDU_LENGTH_INITIAL_MAX_TX_OCTECTS + || connPtr->llPduLen.remote.MaxTxTime < LL_PDU_LENGTH_INITIAL_MAX_TX_TIME ) + { + //should not be here + } + else + { + //compare remote Tx with suggested Rx + if( connPtr->llPduLen.local.MaxRxOctets + !=MIN( g_llPduLen.suggested.MaxRxOctets,connPtr->llPduLen.remote.MaxTxOctets)) + { + connPtr->llPduLen.local.MaxRxOctets = MIN( g_llPduLen.suggested.MaxRxOctets, connPtr->llPduLen.remote.MaxTxOctets); + connPtr->llPduLen.isChanged =TRUE; + } + + if( connPtr->llPduLen.local.MaxRxTime + !=MIN( g_llPduLen.suggested.MaxRxTime,connPtr->llPduLen.remote.MaxTxTime)) + { + connPtr->llPduLen.local.MaxRxTime = MIN( g_llPduLen.suggested.MaxRxTime, connPtr->llPduLen.remote.MaxTxTime); + connPtr->llPduLen.isChanged =TRUE; + } + + //compare remote Rx with suggested Tx + if(connPtr->llPduLen.local.MaxTxOctets + !=MIN( g_llPduLen.suggested.MaxTxOctets, connPtr->llPduLen.remote.MaxRxOctets)) + { + connPtr->llPduLen.local.MaxTxOctets = MIN(g_llPduLen.suggested.MaxTxOctets, connPtr->llPduLen.remote.MaxRxOctets); + connPtr->llPduLen.isChanged =TRUE; + } + + if(connPtr->llPduLen.local.MaxTxTime + !=MIN( g_llPduLen.suggested.MaxTxTime, connPtr->llPduLen.remote.MaxRxTime)) + { + connPtr->llPduLen.local.MaxTxTime = MIN( g_llPduLen.suggested.MaxTxTime, connPtr->llPduLen.remote.MaxRxTime); + connPtr->llPduLen.isChanged =TRUE; + } + } + + llTrxNumAdaptiveConfig(); + + //------------------------------------------------------------ + //nofify upper layer + if(connPtr->llPduLen.isChanged) + { + LL_DataLengthChangeCback(connHandle, + connPtr->llPduLen.local.MaxTxOctets, + connPtr->llPduLen.local.MaxTxTime, + connPtr->llPduLen.local.MaxRxOctets, + connPtr->llPduLen.local.MaxRxTime); + } + + if(g_dle_taskID!=0) + osal_set_event(g_dle_taskID,g_dle_taskEvent); + + return; +} + +#if 0 +// comment out this function temporary +uint8 LL_PLUS_GetLocalPduDataLength(ll_pdu_length_ctrl_t* pduLen) +{ +// pduLen->MaxRxOctets = g_llPduLen.local.MaxRxOctets; +// pduLen->MaxTxOctets = g_llPduLen.local.MaxTxOctets; +// pduLen->MaxRxTime = g_llPduLen.local.MaxRxTime; +// pduLen->MaxTxTime = g_llPduLen.local.MaxTxTime; +// +// return(g_llPduLen.isChanged); + return 1; +} +#endif + + +//add by ZQ 20181106 for PHY MODE Update feature +void llPhyModeCtrlReset(void) +{ + // For symmetric connection, + // it should make both fields the same, only specifiying a single PHY + for (int i = 0; i < g_maxConnNum; i ++) + { + conn_param[i].llPhyModeCtrl.local.txPhy=LE_1M_PHY; + conn_param[i].llPhyModeCtrl.local.rxPhy=LE_1M_PHY; + conn_param[i].llPhyModeCtrl.isProcessingReq = FALSE; + conn_param[i].llPhyModeCtrl.isWatingRsp = FALSE; + conn_param[i].llPhyModeCtrl.isChanged = FALSE; + } + + g_rfPhyPktFmt = PKT_FMT_BLE1M; // to consider whether should move to connection context + return; +} + +void llPhyModeCtrlUpdateNotify(llConnState_t* connPtr, uint8 status) +{ + if(status==LL_STATUS_SUCCESS) + { + connPtr->llPhyModeCtrl.local.txPhy = connPtr->phyUpdateInfo.s2mPhy; + connPtr->llPhyModeCtrl.local.rxPhy = connPtr->phyUpdateInfo.m2sPhy; + } + + LL_PhyUpdateCompleteCback((uint16)(connPtr->connId), + status, + connPtr->phyUpdateInfo.s2mPhy, + connPtr->phyUpdateInfo.m2sPhy); + + if(g_phyChg_taskID!=0) + osal_set_event(g_phyChg_taskID,g_phyChg_taskEvent); + + return; +} + +#if 0 +// comment out this function temporary +llStatus_t LL_PLUS_GetLocalPhyMode(ll_phy_ctrl_t* phyCtrl) +{ +// phyCtrl->txPhy = g_llPhyModeCtrl.local.txPhy; +// phyCtrl->rxPhy = g_llPhyModeCtrl.local.rxPhy; +// +// return (g_llPhyModeCtrl.status); + return 1; +} +#endif + +uint8 ll_isAddrInWhiteList(uint8 addrType, uint8* addr) +{ + int i; + + if (g_llWlDeviceNum == 0) + return FALSE; + + for (i = 0; i < LL_WHITELIST_ENTRY_NUM; i++) + { + if (addrType != g_llWhitelist[i].peerAddrType + || addr[0] != g_llWhitelist[i].peerAddr[0] + || addr[1] != g_llWhitelist[i].peerAddr[1] + || addr[2] != g_llWhitelist[i].peerAddr[2] + || addr[3] != g_llWhitelist[i].peerAddr[3] + || addr[4] != g_llWhitelist[i].peerAddr[4] + || addr[5] != g_llWhitelist[i].peerAddr[5]) + { + // not match, check next + continue; + } + else + return TRUE; + } + + return FALSE; +} + +//#pragma O0 +#define LEN_24BIT 3 // Number of bytes in a 24 bit number +#define PRAND_SIZE LEN_24BIT // PRAND size in the Private Resolvable Address calculation + +// Address header bits +#define RANDOM_ADDR_HDR 0xC0 // Used for LL RANDOM Address +#define STATIC_ADDR_HDR 0xC0 // Host Static Address, same as RANDOM address +#define PRIVATE_RESOLVE_ADDR_HDR 0x40 + +/********************************************************************* + Calculate a new Private Resolvable address. + + LSB MSB + +---------------------------+----------------------+---+---+ + | Hash(24bits) | Rand(22bits) | 1 | 0 | + +---------------------------+----------------------+---+---+ +*/ +uint8_t ll_CalcRandomAddr( uint8* pIRK, uint8* pNewAddr ) +{ + uint8 PRand[PRAND_SIZE]; // Place to hold the PRAND + + // parameter validation + if ( (pIRK == NULL) || (pNewAddr == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + // Generate Random number + LL_Rand( PRand, PRAND_SIZE ); + // Clear the Random Address header bits and force the address type + PRand[PRAND_SIZE-1] &= ~(RANDOM_ADDR_HDR); + PRand[PRAND_SIZE-1] |= PRIVATE_RESOLVE_ADDR_HDR; + // Create the new address + // pNewAddr[0-2] for Hash + LL_ENC_sm_ah( pIRK, PRand, pNewAddr ); + // attach the PRAND to the new address + // pNewAddr[3-5] for hash + VOID osal_memcpy( &(pNewAddr[PRAND_SIZE]), PRand, PRAND_SIZE ); + return ( SUCCESS ); +} + +// resolve Resolvable private address using the input IRK, return SUCCESS if match +uint8_t ll_ResolveRandomAddrs(uint8* pIRK, uint8* pAddr) +{ + uint8 rand[PRAND_SIZE]; // place for PRAND + uint8 hash[PRAND_SIZE]; // place for hash (calc PRAND) + + // Parameter check + if ((pIRK == NULL) || (pAddr == NULL)) + { + return (INVALIDPARAMETER); + } + + // Get PRAND out of address + VOID osal_memcpy(rand, &(pAddr[PRAND_SIZE]), PRAND_SIZE); + + // random private address header checking + if ((rand[PRAND_SIZE - 1] & RANDOM_ADDR_HDR) != PRIVATE_RESOLVE_ADDR_HDR) + return FAILURE; + + // TODO: smp code clear the random address header when resolveing the address, remove. Correct??? + // Clear the Random Address header bits and force the address type +// rand[PRAND_SIZE - 1] &= ~(RANDOM_ADDR_HDR); +// rand[PRAND_SIZE - 1] |= PRIVATE_RESOLVE_ADDR_HDR; + // Calculate Hash from PRAND + LL_ENC_sm_ah(pIRK, rand, hash); + + // Compare hash to address portion of address + if (osal_memcmp(hash, pAddr, LEN_24BIT) == TRUE) + { + // Matched + return (SUCCESS); + } + else + { + // not Matched + return (FAILURE); + } +} + +uint8_t ll_isIrkAllZero(uint8* irk) +{ + int i; + + for (i = 0; i < 16; i ++) + { + if (irk[i] != 0) + return FALSE; + } + + return TRUE; +} + +#define INVALID_RL_INDEX 0xFF +uint8_t ll_getRPAListEntry(uint8* peerAddr) +{ + uint8 i; + uint8 rand[PRAND_SIZE]; // place for PRAND + uint8 hash[PRAND_SIZE]; // place for hash (calc PRAND) + + if (g_llRlDeviceNum == 0 || + peerAddr == NULL ) + return (INVALID_RL_INDEX); + + // Get PRAND out of address + VOID osal_memcpy(rand, &(peerAddr[PRAND_SIZE]), PRAND_SIZE); + + // random private address header checking + if ((rand[PRAND_SIZE - 1] & RANDOM_ADDR_HDR) != PRIVATE_RESOLVE_ADDR_HDR) + return INVALID_RL_INDEX; + + for (i = 0; i < LL_RESOLVINGLIST_ENTRY_NUM; i++) + { + if (g_llResolvinglist[i].peerAddrType == LL_DEV_ADDR_TYPE_PUBLIC || + g_llResolvinglist[i].peerAddrType == LL_DEV_ADDR_TYPE_RANDOM) + { + // Calculate Hash from PRAND + LL_ENC_sm_ah(g_llResolvinglist[i].peerIrk, rand, hash); + + if (osal_memcmp(hash, peerAddr, LEN_24BIT) == TRUE) + { + // Matched + return i; + } + } + } + + return INVALID_RL_INDEX; +} + +// search resolveing list to get local IRK +uint8 ll_readLocalIRK(uint8** localIrk, uint8* peerAddr, uint8 peerAddrType) +{ + int i, j; + + if (g_llRlDeviceNum == 0 || + peerAddr == NULL || + ((peerAddrType != LL_DEV_ADDR_TYPE_PUBLIC) && + (peerAddrType != LL_DEV_ADDR_TYPE_RANDOM))) + return (FALSE); + + for (i = 0; i < LL_RESOLVINGLIST_ENTRY_NUM; i++) + { + if (g_llResolvinglist[i].peerAddrType == peerAddrType) + { + for (j = 0; j < LL_DEVICE_ADDR_LEN; j++) // check whether the address is the same + { + if (g_llResolvinglist[i].peerAddr[j] != peerAddr[j]) + break; + } + + if (j == LL_DEVICE_ADDR_LEN) // found it + { + *localIrk = g_llResolvinglist[i].localIrk; + return( TRUE ); + } + } + } + + return( FALSE ); +} + +// search resolveing list to get peer IRK +uint8 ll_readPeerIRK(uint8** peerIrk, uint8* peerAddr, uint8 peerAddrType) +{ + int i, j; + + if (g_llRlDeviceNum == 0 || + peerAddr == NULL || + ((peerAddrType != LL_DEV_ADDR_TYPE_PUBLIC) && + (peerAddrType != LL_DEV_ADDR_TYPE_RANDOM))) + return (FALSE); + + for (i = 0; i < LL_RESOLVINGLIST_ENTRY_NUM; i++) + { + if (g_llResolvinglist[i].peerAddrType == peerAddrType) + { + for (j = 0; j < LL_DEVICE_ADDR_LEN; j++) // check whether the address is the same + { + if (g_llResolvinglist[i].peerAddr[j] != peerAddr[j]) + break; + } + + if (j == LL_DEVICE_ADDR_LEN) // found it + { + *peerIrk = g_llResolvinglist[i].peerIrk; + return( TRUE ); + } + } + } + + return( FALSE ); +} + +// ADI info: Advertising Data ID(DID, 12bits) + Advertising Set ID(SID, 4bits) +uint16 ll_generateExtAdvDid(uint16 old) +{ + uint16 newDid; + newDid = (old + 1) & 0x0FFF; + return newDid; +} + +// function to decide whether the channel is the 1st primary adver channel +uint8 ll_isFirstAdvChn(uint8 chnMap, uint8 chan) +{ + uint8 temp; + + if (chan < LL_ADV_CHAN_FIRST) + return FALSE; + + temp = chan - LL_ADV_CHAN_FIRST; + + if (temp == 0) + return TRUE; + + if (chnMap & ((1 << temp) - 1)) + return FALSE; + + return TRUE; +} + +// function to get the 1st primary adver channel +uint8 ll_getFirstAdvChn(uint8 chnMap) +{ + uint8 temp, chan; + temp = chnMap; +// chanNumber = (temp & 0x01) + ((temp & 0x02) >> 1) + ((temp & 0x04) >> 2); + chan = ((temp & ((~temp) + 1)) >> 1) + 37; // calculate 1st adv channel + return chan; +} + + +void ll_parseExtHeader(uint8* payload, uint16 length) +{ + uint8 extHeaderFlag; + uint8 offset = 0; + + if (length <= 1) + return; + + offset = 0; + extHeaderFlag = payload[offset]; + offset ++; + ext_adv_hdr.header = extHeaderFlag; + + // AdvA (6 octets) + if (extHeaderFlag & LE_EXT_HDR_ADVA_PRESENT_BITMASK) + { + memcpy(&ext_adv_hdr.advA[0], &payload[offset], LL_DEVICE_ADDR_LEN); + offset += LL_DEVICE_ADDR_LEN; + } + + // TargetA(6 octets) + if (extHeaderFlag & LE_EXT_HDR_TARGETA_PRESENT_BITMASK) + { + memcpy(&ext_adv_hdr.targetA[0], &payload[offset], LL_DEVICE_ADDR_LEN); + offset += LL_DEVICE_ADDR_LEN; + } + + // CTEInfo(1 octets), always not present + if (extHeaderFlag & LE_EXT_HDR_CTE_INFO_PRESENT_BITMASK) + { + ext_adv_hdr.cteInfo = payload[offset]; + offset += 1; + } + + // AdvDataInfo(ADI)(2 octets) + if (extHeaderFlag & LE_EXT_HDR_ADI_PRESENT_BITMASK) + { + ext_adv_hdr.adi = BUILD_UINT16(payload[offset], payload[offset + 1]); + offset += 2; + } + + // AuxPtr(3 octets) + if (extHeaderFlag & LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK) + { + ext_adv_hdr.auxPtr.chn_idx = payload[offset] & 0x3F; + ext_adv_hdr.auxPtr.ca = (payload[offset] & 0x40) >> 6; + ext_adv_hdr.auxPtr.offset_unit = (payload[offset] & 0x80) >> 7; + ext_adv_hdr.auxPtr.aux_offset = BUILD_UINT16(payload[offset + 1], (payload[offset + 2] & 0x1F)); + ext_adv_hdr.auxPtr.aux_phy = (payload[offset + 2] & 0xE0) >> 5; + ext_adv_hdr.auxPtr.aux_phy ++; // convert to LL HW define + + if (ext_adv_hdr.auxPtr.aux_phy == 3) + ext_adv_hdr.auxPtr.aux_phy = PKT_FMT_BLR125K; + + offset += 3; + } + + // SyncInfo(18 octets) + if (extHeaderFlag & LE_EXT_HDR_SYNC_INFO_PRESENT_BITMASK) + { + memcpy(&ext_adv_hdr.syncInfo[0], &payload[offset], 18); + memcpy(&syncInfo, &payload[offset], 18); + offset += 18; + } + + // TxPower(1 octets) + if (extHeaderFlag & LE_EXT_HDR_TX_PWR_PRESENT_BITMASK) + { + ext_adv_hdr.txPower = payload[offset]; + offset += 1; + } + + // ACAD(varies) + // ignore it now +} + +// calculate next channel of AUX_CHAIN_IND, the hopping channel algorithm TBD +uint8 llGetNextAuxAdvChn0(uint8 current) +{ + uint8 next; + next = current + 1; + + if (next >= LL_ADV_CHAN_FIRST) + next = 0; + + return next; +} + + +uint16 llAllocateSyncHandle(void) +{ + uint16 i; + + for (i = 0; i < MAX_NUM_LL_PRD_ADV_SYNC; i++) + { + if (g_llPeriodAdvSyncInfo[i].valid == FALSE) + { + g_llPeriodAdvSyncInfo[i].valid = TRUE; + return i; + } + } + + return 0xFFFF; +} + +uint8 llDeleteSyncHandle(uint16 sync_handle) +{ + uint16 i; + + for (i = 0; i < MAX_NUM_LL_PRD_ADV_SYNC; i++) + { + if (g_llPeriodAdvSyncInfo[i].syncHandler == sync_handle) + { + g_llPeriodAdvSyncInfo[i].valid = FALSE; + g_llPeriodAdvSyncInfo[i].syncHandler = 0xFFFF; + return TRUE; + } + } + + return FALSE; +} + +// decide whether extended adv using legacy adv PDU or not +uint8 ll_isLegacyAdv(extAdvInfo_t* pExtAdv) +{ + if (pExtAdv->parameter.advEventProperties & LE_ADV_PROP_LEGACY_BITMASK) + return TRUE; + else + return FALSE; +} + +///////////////// end of file ////////////////////////////////// + diff --git a/src/lib/ble_controller/ll_enc.c b/src/lib/ble_controller/ll_enc.c new file mode 100644 index 0000000..051dc15 --- /dev/null +++ b/src/lib/ble_controller/ll_enc.c @@ -0,0 +1,719 @@ +/******************************************************************************* + Filename: ll_enc.c + Revised: + Revision: + + Description: This file contains the BLE encryption API for the LL. + + +*******************************************************************************/ + +/******************************************************************************* + INCLUDES +*/ +#include "ll_common.h" +#include "ll.h" +#include "ll_enc.h" +#include "string.h" +#include "jump_function.h" + +/******************************************************************************* + MACROS +*/ +#define ADJUST_PKT_LEN( len ) \ + (((len)<=LL_ENC_BLOCK_LEN)?LL_ENC_BLOCK_LEN-(len):(2*LL_ENC_BLOCK_LEN)-(len)) + +#define LL_ENC_BASE 0x40040000 // LL HW AES engine Base address + +#define LL_ENC_ENCRYPT_DONE_MASK 0x0001 +#define LL_ENC_DECRYPT_FAIL_MASK 0x0002 +#define LL_ENC_DECRYPT_SUCC_MASK 0x0004 +#define LL_ENC_SINGLE_MODE_DONE_MASK 0x0008 + +/******************************************************************************* + CONSTANTS +*/ + +#define LL_ENC_MAX_RF_ADC_WAIT_COUNT 250 + +/******************************************************************************* + TYPEDEFS +*/ + +/******************************************************************************* + LOCAL VARIABLES +*/ + +// generic packet for cyrptography: length, hdr, payload including MIC +// Note: One extra byte so besides length and header, there is a multiple of +// two 16 byte blocks available. +uint8 dataPkt[2*LL_ENC_BLOCK_LEN]; + +/******************************************************************************* + GLOBAL VARIABLES +*/ + +// cache of FIPS compliant true random numbers for IV and SKD formation +uint8 cachedTRNGdata[ LL_ENC_TRUE_RAND_BUF_SIZE ]; + +#ifdef DEBUG_ENC +const uint8 testSKD[] = { 0x79, 0x68, 0x57, 0x46, 0x35, 0x24, 0x13, 0x02, // slave + 0x13, 0x02, 0xF1, 0xE0, 0xDF, 0xCE, 0xBD, 0xAC + }; // master +const uint8 testIV[] = { 0xBE, 0xBA, 0xAF, 0xDE, // slave + 0x24, 0xAB, 0xDC, 0xBA + }; // master +#endif // DEBUG_ENC + + +// generic zero block used for encryption +const uint8 zeroBlock[32] = {0}; + +/******************************************************************************* + PROTOTYPES +*/ + +void LL_ENC_StartAES( uint8 aesCmd ); + +/******************************************************************************* + API +*/ + + +/******************************************************************************* + @fn LL_ENC_ReverseBytes API + + @brief This function is used to reverse the order of the bytes in + an array in place. + + Note: The max length is 128 bytes; the min length is > 0. + + input parameters + + @param buf - Pointer to buffer containing bytes to be reversed. + @param len - Number of bytes in buffer. + + output parameters + + @param buf - Pointer to buffer containing reversed bytes. + + @return None. +*/ +void LL_ENC_ReverseBytes( uint8* buf, + uint8 len ) +{ + uint8 temp; + uint8 index = (uint8)(len - 1); + uint8 i; + // adjust length as only half the operations are needed + len >>= 1; + + // reverse the order of the bytes + for (i=0; i> 24) & 0xff; + ciphertext[1] = (temp >> 16) & 0xff; + ciphertext[2] = (temp >> 8) & 0xff; + ciphertext[3] = temp & 0xff; + ciphertext += 4; + temp = *(volatile uint32_t*)(LL_ENC_BASE + 0x58); + ciphertext[0] = (temp >> 24) & 0xff; + ciphertext[1] = (temp >> 16) & 0xff; + ciphertext[2] = (temp >> 8) & 0xff; + ciphertext[3] = temp & 0xff; + ciphertext += 4; + temp = *(volatile uint32_t*)(LL_ENC_BASE + 0x54); + ciphertext[0] = (temp >> 24) & 0xff; + ciphertext[1] = (temp >> 16) & 0xff; + ciphertext[2] = (temp >> 8) & 0xff; + ciphertext[3] = temp & 0xff; + ciphertext += 4; + temp = *(volatile uint32_t*)(LL_ENC_BASE + 0x50); + ciphertext[0] = (temp >> 24) & 0xff; + ciphertext[1] = (temp >> 16) & 0xff; + ciphertext[2] = (temp >> 8) & 0xff; + ciphertext[3] = temp & 0xff; + // disable AES + *(int*) 0x40040000 = 0x0; + return; +} + +// Note: The hardware RNG is failed in some boards, need investigate the issue +// before using this function +/******************************************************************************* + @fn LL_ENC_GenerateTrueRandNum API + + @brief This function is used to generate a sequence of true random + bytes. The result is FIPS compliant. This routine also re-seeds + the PRNG, ensuring an improper seed isn't used. + + Note: This is done using the radio. Care must be taken when + using this function to ensure that there are no conflicts + with RF. + + Note: This algorithm was not checked for FIPS compliance over + voltage change. + + input parameters + + @param len - The number of true random bytes desired (1..255). + + output parameters + + @param buf - A pointer to a buffer for storing true random bytes. + + @return LL_STATUS_SUCCESS, LL_STATUS_ERROR_BAD_PARAMETER, + LL_STATUS_ERROR_RNG_FAILURE +*/ +uint8 LL_ENC_GenerateTrueRandNum0( uint8* buf, + uint8 len ) +{ + //need to be replaced by TRNG_Rand + return( LL_Rand(buf,len) ); +} + +/******************************************************************************* + @fn LL_ENC_GenDeviceSKD API + + @brief This function is used to generate a device's half of the SKD. + + input parameters + + @param None. + + output parameters + + @param SKD - A pointer to a buffer in which to place the device's SKD. + + @return None. +*/ +void LL_ENC_GenDeviceSKD0( uint8* SKD ) +{ + uint8 i; + + // used cached FIPS compliant TRNG data + // Note: SKD (master or slave) ues first LL_ENC_SKD_LEN/2 of the bytes. + // Note: Calling routine will schedule a cache update as a postRF operation. + for (i=0; i> 0) & 0xFF; + nonce[1] = ((uint8*)&pktCnt)[1]; //(pktCnt >> 8) & 0xFF; + nonce[2] = ((uint8*)&pktCnt)[2]; //(pktCnt >> 16) & 0xFF; + nonce[3] = ((uint8*)&pktCnt)[3]; //(pktCnt >> 24) & 0xFF; + // add direction bit to MSO + // Note: Last 7 bits of 39-bit packet count are assumed to be zero as only + // a 32 bit counter is currently supported. + nonce[4] = (direction << 7); + return; +} + + + +/******************************************************************************* + @fn LL_ENC_LoadKey API + + @brief This function is used to load the cryptography key into the + AES engine. + + input parameters + + @param key - Pointer to 16 byte cryptography key. + + output parameters + + @param None. + + @return None. +*/ +void LL_ENC_LoadKey( uint8* key ) +{ + //config KEY + *(volatile uint32_t*)(LL_ENC_BASE + 0x2c) = key[0] << 24 | key[1] << 16 | key[2] << 8 | key[3]; + key += 4; + *(volatile uint32_t*)(LL_ENC_BASE + 0x28) = key[0] << 24 | key[1] << 16 | key[2] << 8 | key[3]; + key += 4; + *(volatile uint32_t*)(LL_ENC_BASE + 0x24) = key[0] << 24 | key[1] << 16 | key[2] << 8 | key[3]; + key += 4; + *(volatile uint32_t*)(LL_ENC_BASE + 0x20) = key[0] << 24 | key[1] << 16 | key[2] << 8 | key[3]; + return; +} + + +/******************************************************************************* + @fn LL_ENC_Encrypt API + + @brief This function is used to encrypt a packet. It loads the key, + generates the nonce, generates the MIC, and encrypts the data + and MIC. + + Note: This routine assumes that the buffer is 32 bytes and has + already been zero padded. + + input parameters + + @param connPtr - A pointer to this connection's information. + @param pktHdr - Packet header, LLID only. + @param pktLen - Length of buffer to be encrypted. + @param pBuf - Pointer to buffer to be encrypted. + + output parameters + + @param pBuf - Pointer to encrypted buffer. + + @return None. +*/ +void LL_ENC_Encrypt0( llConnState_t* connPtr, + uint8 pktHdr, + uint8 pktLen, + uint8* pBuf ) +{ + uint8* pByte = NULL; + uint8 index; + int i, len; + uint32_t temp; + // disable AES + *(int*) 0x40040000 = 0x0; + // Load Key + // Note: Normally this would only need to be done once when the SK is derived + // from the LTK and SKD. However, when in sleep, the AES block loses + // this key. Also, when multiple connections are supported, the key + // will be different. + LL_ENC_LoadKey( connPtr->encInfo.SK ); + + if ( llState == LL_STATE_CONN_MASTER ) + { + // generate the nonce based on packet count, IV, and direction + LL_ENC_GenerateNonce( connPtr->encInfo.txPktCount, + LL_ENC_TX_DIRECTION_MASTER, + connPtr->encInfo.nonce ); + } + else // assumed llState == LL_STATE_CONN_SLAVE + { + // generate the nonce based on packet count, IV, and direction + LL_ENC_GenerateNonce( connPtr->encInfo.txPktCount, + LL_ENC_TX_DIRECTION_SLAVE, + connPtr->encInfo.nonce ); + } + + // confiig nounce + pByte = connPtr->encInfo.nonce; + *(volatile uint32_t*)(LL_ENC_BASE + 0x3c) = pByte[0] ; + pByte ++; + *(volatile uint32_t*)(LL_ENC_BASE + 0x38) = pByte[0] << 24 | pByte[1] << 16 | pByte[2] << 8 | pByte[3]; + pByte += 4; + *(volatile uint32_t*)(LL_ENC_BASE + 0x34) = pByte[0] << 24 | pByte[1] << 16 | pByte[2] << 8 | pByte[3]; + pByte += 4; + *(volatile uint32_t*)(LL_ENC_BASE + 0x30) = pByte[0] << 24 | pByte[1] << 16 | pByte[2] << 8 | pByte[3]; + // config plen & aad + *(volatile uint32_t*)(LL_ENC_BASE + 0x0c) = (pktLen << 8) | pktHdr; + // write packet to FIFO + len = pktLen; + index = 0; + + while (len >= 4) + { + *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + index) + = pBuf[index + 3] << 24 | pBuf[index + 2] << 16 | pBuf[index + 1] << 8 | pBuf[index]; + index += 4; + len -= 4; + } + + // to check the byte order + if(len == 3) + { + *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + index) + = pBuf[index + 2] << 16 | pBuf[index + 1] << 8 | pBuf[index]; + index += 4; + } + else if(len == 2) + { + *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + index) + = pBuf[index + 1] << 8 | pBuf[index] ; + index += 4; + } + else if(len == 1) + { + *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + index) + = pBuf[index] ; + index += 4; + } + + // AES FIFO legth is 256 bytes, set other bytes 0 + for (i = index; i < 0x100; i += 4) + { + *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + i) = 0x0; + } + + // set AES ctrl reg + *(int*) 0x40040004 = 0xf00; + // set interrupt enable + *(int*) 0x40040010 = 0xf; + // enable AES + *(int*) 0x40040000 = 0x1; + + // insert delay +// delay = 200; +// while (delay --); + + // query AES interrupt status register + while (*(volatile uint32_t*)(LL_ENC_BASE + 0x0014) == 0) ; + + // disable AES, if not disable AES, there is no output in FIFO + *(int*) 0x40040000 = 0x0; + // read back the encrypt result + index = 0; + len = pktLen + 4; // include 4 bytes MIC + + while (len > 0) + { + temp = *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + index); + pBuf[index ++] = temp & 0xff; + pBuf[index ++] = (temp >> 8) & 0xff; + pBuf[index ++] = (temp >> 16) & 0xff; + pBuf[index ++] = (temp >> 24) & 0xff; + len -= 4; + } + + // up the count for the next TX'ed data packet + // Note: This is supposed to be 39 bit counter, but for now, we don't + // envision receiving 550 billion packets during a connection! + connPtr->encInfo.txPktCount++; + return; +} + +/******************************************************************************* + @fn LL_ENC_Decrypt API + + @brief This function is used to decrypt a packet. It loads the key, + generates the nonce, decrypts the data and MIC, generates a + MIC based on the decrypted data, and authenticates the packet + by comparing the two MIC values. + + Note: This routine assumes that the buffer is 32 bytes, + regardless of the number of bytes of data. + + input parameters + + @param connPtr - A pointer to this connection's information. + @param pktHdr - Packet header, LLID only. + @param pktLen - Length of buffer to be decrypted. + @param pBuf - Pointer to buffer to be decrypted. + + output parameters + + @param pBuf - Pointer to decrypted buffer. + + @return None. +*/ +uint8 LL_ENC_Decrypt0( llConnState_t* connPtr, + uint8 pktHdr, + uint8 pktLen, + uint8* pBuf ) +{ + uint8* pByte = NULL; + uint8 index; + int i, len; + uint32_t temp; + // disable AES + *(int*) 0x40040000 = 0x0; + // Load Key + // Note: Normally this would only need to be done once when the SK is derived + // from the LTK and SKD. However, when in sleep, the AES block loses + // this key. Also, when multiple connections are supported, the key + // will be different. + LL_ENC_LoadKey( connPtr->encInfo.SK ); + + if ( llState == LL_STATE_CONN_MASTER ) + { + // generate the nonce based on packet count, IV, and direction + LL_ENC_GenerateNonce( connPtr->encInfo.rxPktCount, + LL_ENC_RX_DIRECTION_MASTER, + connPtr->encInfo.nonce ); + } + else // assumed llState == LL_STATE_CONN_SLAVE + { + // generate the nonce based on packet count, IV, and direction + LL_ENC_GenerateNonce( connPtr->encInfo.rxPktCount, + LL_ENC_RX_DIRECTION_SLAVE, + connPtr->encInfo.nonce ); + } + + // confiig nounce + pByte = connPtr->encInfo.nonce; + *(volatile uint32_t*)(LL_ENC_BASE + 0x3c) = pByte[0]; // << 24 ; + pByte ++; + *(volatile uint32_t*)(LL_ENC_BASE + 0x38) = pByte[0] << 24 | pByte[1] << 16 | pByte[2] << 8 | pByte[3]; + pByte += 4; + *(volatile uint32_t*)(LL_ENC_BASE + 0x34) = pByte[0] << 24 | pByte[1] << 16 | pByte[2] << 8 | pByte[3]; + pByte += 4; + *(volatile uint32_t*)(LL_ENC_BASE + 0x30) = pByte[0] << 24 | pByte[1] << 16 | pByte[2] << 8 | pByte[3]; + // config plen & aad + *(volatile uint32_t*)(LL_ENC_BASE + 0x0c) = (pktLen << 8) | pktHdr; + // write packet to FIFO + len = pktLen + 4; // decrypt, add 4 for MIC field length + index = 0; + + while (len >= 4) + { + *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + index) + = pBuf[index + 3] << 24 | pBuf[index + 2] << 16 | pBuf[index + 1] << 8 | pBuf[index]; + index += 4; + len -= 4; + } + + // fill others bytes < 1 word + if(len == 3) + { + *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + index) + = pBuf[index + 2] << 16 | pBuf[index + 1] << 8 | pBuf[index]; + index += 4; + } + else if(len == 2) + { + *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + index) + = pBuf[index + 1] << 8 | pBuf[index] ; + index += 4; + } + else if(len == 1) + { + *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + index) + = pBuf[index] ; + index += 4; + } + + // AES FIFO legth is 256 bytes, set other bytes 0 + for (i = index; i < 0x100; i += 4) + { + *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + i) = 0x0; + } + + // set AES ctrl reg + *(int*) 0x40040004 = 0xf08; + // set interrupt enable + *(int*) 0x40040010 = 0xf; + // enable AES + *(int*) 0x40040000 = 0x1; + + // insert delay +// delay = 200; +// while (delay --); + + // query AES interrupt status register and wait decrypt finish + while (*(volatile uint32_t*)(LL_ENC_BASE + 0x0014) == 0) ; + + // read interrupt status reg + temp = *(volatile uint32_t*)(LL_ENC_BASE + 0x0014); + + if ((temp & LL_ENC_DECRYPT_FAIL_MASK) + || ((temp & LL_ENC_DECRYPT_SUCC_MASK) == 0)) + { + return FALSE; + } + + // disable AES + *(int*) 0x40040000 = 0x0; + // read the decrypt result + index = 0; + len = pktLen; + + while (len > 0) + { + temp = *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + index); + pBuf[index ++] = temp & 0xff; + pBuf[index ++] = (temp >> 8) & 0xff; + pBuf[index ++] = (temp >> 16) & 0xff; + pBuf[index ++] = (temp >> 24) & 0xff; + len -= 4; + } + + // up the count for the next RX'ed data packet + // Note: This is supposed to be 39 bit counter, but for now, we don't + // envision receiving 550 billion packets during a connection! + connPtr->encInfo.rxPktCount++; + return( TRUE ); +} + +#define LEN_24BIT 3 // Number of bytes in a 24 bit number +#define PRAND_SIZE LEN_24BIT // PRAND size in the Private Resolvable Address calculation + +/********************************************************************* + @fn LL_ENC_sm_ah + + @brief Random address hash function. + + @param pK - key is 128 bits, LSByte first + @param pR - 24 bit, LSByte first + @param pAh - pointer to 24 bit results space + + @return None +*/ +void LL_ENC_sm_ah( uint8* pK, uint8* pR, uint8* pAh ) +{ + uint8 key[KEYLEN]; // Key to encrypt with + uint8 plainTextData[KEYLEN]; // Plain Text data to encrypt + uint8 result[KEYLEN]; // Result of encrypt (key + Plain Text data) + memset(plainTextData, 0, KEYLEN); + // Copy the encrypt variables + VOID osal_revmemcpy( key, pK, KEYLEN ); + VOID osal_revmemcpy( &(plainTextData[KEYLEN - LEN_24BIT]), + pR, LEN_24BIT ); + LL_ENC_AES128_Encrypt(key, plainTextData, result); + // Copy the results + VOID osal_revmemcpy( pAh, &(result[KEYLEN - LEN_24BIT]), LEN_24BIT ); +} + +/******************************************************************************* +*/ + diff --git a/src/lib/ble_controller/ll_hwItf.c b/src/lib/ble_controller/ll_hwItf.c new file mode 100644 index 0000000..1b13880 --- /dev/null +++ b/src/lib/ble_controller/ll_hwItf.c @@ -0,0 +1,7960 @@ + +// this file is temporary, most new chip code will be wrote in this file +// after stable, the functions should be move to other LL files +/******************************************************************************* + Filename: ll_hwItf.c + Revised: + Revision: + + Description: Interface functions to LL HW. + + Copyright 2017-2020 Phyplus Incorporated. All rights reserved. + + IMPORTANT: +*******************************************************************************/ + +#include +#include +#include + +#include "ll_hw_drv.h" + +#include "timer.h" +#include "ll_buf.h" +#include "ll_def.h" +#include "ll.h" +#include "ll_common.h" +#include "hci_event.h" +#include "osal_bufmgr.h" +#include "bus_dev.h" +#include "ll_enc.h" +#include "rf_phy_driver.h" +#include "jump_function.h" +#include "global_config.h" +#include "ll_debug.h" +#include "log.h" + +// =============== compile flag, comment out if not required below feature +//#define PRD_ADV_ENABLE +//#define EXT_ADV_ENABLE +//#define EXT_SCAN_ENABLE + +// ============== + +/******************************************************************************* + MACROS +*/ + +// add by HZF, merge with ll_hw_drv.h later +#define LL_HW_MODE_STX 0x00 +#define LL_HW_MODE_SRX 0x01 +#define LL_HW_MODE_TRX 0x02 +#define LL_HW_MODE_RTX 0x03 +#define LL_HW_MODE_TRLP 0x04 +#define LL_HW_MODE_RTLP 0x05 + +// =========== A1 ROM metal change add +#define MAX_HDC_DIRECT_ADV_TIME 1280000 // 1.28s in unit us + +#define LL_CALC_NEXT_SCAN_CHN(chan) { chan ++; \ + chan = (chan > LL_SCAN_ADV_CHAN_39) ? LL_SCAN_ADV_CHAN_37 : chan;} + +/******************************************************************************* + CONSTANTS +*/ +// Master Sleep Clock Accurracy, in PPM +// Note: Worst case range value is assumed. +extern const uint16 SCA[] ;//= {500, 250, 150, 100, 75, 50, 30, 20}; +extern uint8 ownPublicAddr[]; // index 0..5 is LSO..MSB +extern uint8 ownRandomAddr[]; +/******************************************************************************* + TYPEDEFS +*/ + +/******************************************************************************* + LOCAL VARIABLES +*/ + +///******************************************************************************* +// * GLOBAL VARIABLES +// */ + +uint32 llWaitingIrq = FALSE; +uint32 ISR_entry_time = 0; +int slave_conn_event_recv_delay = 0; +// for HCI ext command: enable/disable notify for connection/adv event +uint8 g_adv_taskID = 0; +uint16 g_adv_taskEvent = 0; +uint8 g_conn_taskID = 0; +uint16 g_conn_taskEvent = 0; +uint8 g_dle_taskID = 0; +uint16 g_dle_taskEvent = 0; +uint8 g_phyChg_taskID = 0; +uint16 g_phyChg_taskEvent = 0; + + +// =========== A2 metal change add, to move to llConnState_t(per connection parameters) +uint32_t g_smartWindowLater = 0; +uint32_t g_smartWindowSize = 0; +uint32_t g_smartWindowSizeNew = 0; // to omit +bool g_smartWindowActive = 0; +uint32_t g_smartWindowActiveCnt = 0; +uint32_t g_smartWindowPreAnchPoint = 0; +uint8_t g_smartWindowRTOCnt = 0; + + +volatile uint32 g_getPn23_cnt = 0; +volatile uint32 g_getPn23_seed = 0x12345678; + +// ======= A2 multi-connection ======================== +struct buf_tx_desc g_tx_adv_buf; +struct buf_tx_desc g_tx_ext_adv_buf; +struct buf_tx_desc tx_scanRsp_desc; + +struct buf_rx_desc g_rx_adv_buf; +uint32 g_new_master_delta; + + +// ======= A2 multi-connection end ===================== + +// ============== BBB change +uint32 g_interAuxPduDuration = 5000; // aux PUD duration: PDU + IFS + +// ====== RPA +uint8 g_currentLocalRpa[LL_DEVICE_ADDR_LEN]; +uint8 g_currentPeerRpa[LL_DEVICE_ADDR_LEN]; +uint8 g_currentPeerAddrType; +uint8 g_currentLocalAddrType; + +uint8 isPeerRpaStore = FALSE; +uint8 storeRpaListIndex; +uint8 currentPeerRpa[LL_DEVICE_ADDR_LEN]; + + +//20180523 by ZQ +//path for tx_rx_offset issue in scan_rsq +volatile uint8_t g_same_rf_channel_flag = FALSE; //path for tx_rx_offset config in scan_rsp + +// for scan +uint32_t llScanT1; +uint32_t llScanTime = 0; +uint32_t llCurrentScanChn; + +//===================== external +//extern ctrl_packet_buf ctrlData; + +extern uint32 osal_sys_tick; +extern uint32 hclk_per_us, hclk_per_us_shift; +extern peerInfo_t g_llWhitelist[]; + +// RX Flow Control +extern uint8 rxFifoFlowCtrl; + +// ============== A1 ROM metal change add +extern uint32_t g_llHdcDirAdvTime; // for HDC direct adv + +// ===== A2 metal change add +extern uint8_t llSecondaryState; // secondary state of LL +perStatsByChan_t* p_perStatsByChan = NULL; + +extern llConns_t g_ll_conn_ctx; + +extern syncInfo_t syncInfo; +extern scannerSyncInfo_t scanSyncInfo; + +uint8 llTaskState; + +// RF path compensation, to be move to rf_phy_driver.c ? +int16 g_rfTxPathCompensation = 0; +int16 g_rfRxPathCompensation = 0; + + +/******************************************************************************* + Functions +*/ +uint32_t ll_hw_get_loop_time(void); + +int ll_hw_get_rfifo_depth(void); +uint16_t ll_hw_get_tfifo_wrptr(void); + +// A2 metal change add +uint32_t getPN23RandNumber(void); +void ll_adptive_smart_window(uint32_t irq_status,uint32_t anchor_point); +////////////// For Master +void move_to_master_function(void); + +void LL_master_conn_event(void); + +void ll_hw_read_tfifo_trlp(void); + +///////////// For avtive scan +static void llAdjBoffUpperLimitSuccess( void ); + +static void llAdjBoffUpperLimitFailure( void ); + +static void llGenerateNextBackoffCount( void ); + + +LL_PLUS_AdvDataFilterCB_t LL_PLUS_AdvDataFilterCBack=NULL; +LL_PLUS_ScanRequestFilterCB_t LL_PLUS_ScanRequestFilterCBack=NULL; + +void LL_PLUS_PerStats_Init(perStatsByChan_t* p_per); +void LL_PLUS_PerStatsReset(void); + +void LL_PLUS_PerStasReadByChn(uint8 chnId,perStats_t* perStats); + +void ll_hw_tx2rx_timing_config(uint8 pkt); +void ll_hw_trx_settle_config(uint8 pkt); +// externel +extern uint32_t get_timer_count(AP_TIM_TypeDef* TIMx); +extern uint8 ll_processMissMasterEvt(uint8 connId); +extern uint8 ll_processMissSlaveEvt(uint8 connId); + +// local function +uint32 read_ll_adv_remainder_time(void); +uint8 ll_processExtAdvIRQ(uint32_t irq_status); +uint8 ll_processPrdAdvIRQ(uint32_t irq_status); +uint8 ll_processExtScanIRQ(uint32_t irq_status); +uint8 ll_processExtInitIRQ(uint32_t irq_status); +uint8 ll_processPrdScanIRQ(uint32_t irq_status); +uint8 ll_processBasicIRQ(uint32_t irq_status); + +uint8 llSetupExtAdvLegacyEvent(extAdvInfo_t* pAdvInfo); + +// add by HZF, to move to ll_hw_drv.c +/************************************************************************************** + @fn ll_hw_get_tr_mode + + @brief This function get the current LL HW engine TR mode. + + input parameters + + @param None. + + output parameters + + @param None. + + @return mode - STX(0), SRX(1), TRX(2), RTX(3), TRLP(4), RTLP(5). +*/ +uint8 ll_hw_get_tr_mode(void) +{ + uint8 mode; + mode = (*(volatile uint32_t*)(LL_HW_BASE+ 0x04)) & 0x0f; //[3:0] RW 4'b0 Mode + return mode; +} + +/******************************************************************************* + @fn LL_IRQHandler + + @brief Interrupt Request Handler for Link Layer + + input parameters + + @param None. + + output parameters + + @param None. + + @return None +*/ +void LL_IRQHandler(void) +{ + uint32 irq_status; + int8 ret; + ISR_entry_time = read_current_fine_time(); + ll_debug_output(DEBUG_ISR_ENTRY); + irq_status = ll_hw_get_irq_status(); + + if (!(irq_status & LIRQ_MD)) // only process IRQ of MODE DONE + { + ll_hw_clr_irq(); // clear irq status + return; + } + + llWaitingIrq = FALSE; + + if (llTaskState == LL_TASK_EXTENDED_ADV) + { + ret = ll_processExtAdvIRQ(irq_status); + + // TODO: consider whether need process secondary adv/scan here + if (ret == TRUE) + return; + } + else if (llTaskState == LL_TASK_EXTENDED_SCAN) + { + ret = ll_processExtScanIRQ(irq_status); + + // TODO: consider whether need process secondary adv/scan here + if (ret == TRUE) + return; + } + else if (llTaskState == LL_TASK_EXTENDED_INIT) + { + ret = ll_processExtInitIRQ(irq_status); + + // TODO: consider whether need process secondary adv/scan here + if (ret == TRUE) + return; + } + else if (llTaskState == LL_TASK_PERIODIC_ADV) + { + ret = ll_processPrdAdvIRQ(irq_status); + + // TODO: consider whether need process secondary adv/scan here + if (ret == TRUE) + return; + } + else if (llTaskState == LL_TASK_PERIODIC_SCAN) + { + ret = ll_processPrdScanIRQ(irq_status); + + // TODO: consider whether need process secondary adv/scan here + if (ret == TRUE) + return; + } + else + { + ret = ll_processBasicIRQ(irq_status); +// if (ret == TRUE) +// return; + } + + // ================ Post ISR process: secondary pending state process + // conn-adv case 2: other ISR, there is pending secondary advertise event, make it happen + if (llSecondaryState == LL_SEC_STATE_ADV_PENDING) + { + if (llSecAdvAllow()) // for multi-connection case, it is possible still no enough time for adv + { + llSetupSecAdvEvt(); + llSecondaryState = LL_SEC_STATE_ADV; + } + } + // there is pending scan event, make it happen, note that it may stay pending if there is no enough idle time + else if (llSecondaryState == LL_SEC_STATE_SCAN_PENDING) + { + // trigger scan + llSetupSecScan(scanInfo.nextScanChan); + } + // there is pending init event, make it happen, note that it may stay pending if there is no enough idle time + else if (llSecondaryState == LL_SEC_STATE_INIT_PENDING) + { + // trigger scan + llSetupSecInit(initInfo.nextScanChan); + } + + ll_debug_output(DEBUG_ISR_EXIT); +} + +/* + this function is implemented per interval, it include multi loops of M->S and S->M within one interval + +*/ +// to check whether we need it later +void LL_set_default_conn_params0(llConnState_t* connPtr) +{ + connPtr->sn_nesn = 0; + connPtr->rx_timeout = 0; +// connPtr->connected = 0; + connPtr->firstPacket = 1; + connPtr->txDataEnabled = TRUE; + connPtr->rxDataEnabled = TRUE; // bug fixed 218-04-08 + connPtr->lastTimeToNextEvt = 0; + connPtr->lastSlaveLatency = 0; + connPtr->encEnabled = FALSE; + connPtr->lastRssi = 0; // A1 ROM metal change add + connPtr->expirationEvent = LL_LINK_SETUP_TIMEOUT; +} + +/******************************************************************************* + @fn move_to_slave_function0 + + @brief This function is used to process CONN_REQ and move the llState to slave + + + input parameters + + @param None. + + output parameters + + @param None. + + @return None, + +*/ +void move_to_slave_function0(void) +{ + llConnState_t* connPtr; + uint8_t* pBuf; + uint8_t tempByte; + uint8_t chnSel; + uint32_t calibra_time, T2; + +// hal_gpio_write(GPIO_P15, 1); + + if ( (connPtr = llAllocConnId()) == NULL ) + { + return; + } + + adv_param.connId = connPtr->connId; + chnSel = (g_rx_adv_buf.rxheader & CHSEL_MASK) >> CHSEL_SHIFT; + + if (pGlobal_config[LL_SWITCH] & CONN_CSA2_ALLOW) + connPtr->channel_selection = chnSel; + else + connPtr->channel_selection = LL_CHN_SEL_ALGORITHM_1; + + pBuf = g_rx_adv_buf.data; + // reset connection parameters + LL_set_default_conn_params(connPtr); + // clear the connection buffer + reset_conn_buf(connPtr->connId); + + // switch off the adv, will be switch on after link terminate by GAP + if (llTaskState == LL_TASK_EXTENDED_ADV) + { + // TODO: ext advertiser process + } + else + adv_param.advMode = LL_ADV_MODE_OFF; + + pBuf += 12; // skip initA and AdvA + pBuf = llMemCopySrc( (uint8*)&connPtr->accessAddr, pBuf, 4 ); + pBuf = llMemCopySrc( (uint8*)&connPtr->initCRC, pBuf, 3 ); + pBuf = llMemCopySrc( (uint8*)&connPtr->curParam.winSize, pBuf, 1 ); + pBuf = llMemCopySrc( (uint8*)&connPtr->curParam.winOffset, pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)&connPtr->curParam.connInterval, pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)&connPtr->curParam.slaveLatency, pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)&connPtr->curParam.connTimeout, pBuf, 2 ); + // TI style: convert to 625us tick + connPtr->curParam.winSize <<= 1; + connPtr->curParam.winOffset <<= 1; + connPtr->curParam.connInterval <<= 1; + connPtr->curParam.connTimeout <<= 4; + llConvertLstoToEvent( connPtr, &(connPtr->curParam) ); // 16MHz CLK, need 56.5us + // bug fixed 2018-4-4, calculate control procedure timeout value when connection setup + // convert the Control Procedure timeout into connection event count + llConvertCtrlProcTimeoutToEvent(connPtr); + + if (((connPtr->curParam.connTimeout <= ((connPtr->curParam.slaveLatency ) * connPtr->curParam.connInterval << 1))) + || (connPtr->curParam.connInterval == 0) ) + { + // schedule LL Event to notify the Host a connection was formed with + // a bad parameter + // Note: This event doesn't take parameters, so it is assumed there that + // the reason code was due to an unacceptable connection interval. + (void)osal_set_event( LL_TaskID, LL_EVT_SLAVE_CONN_CREATED_BAD_PARAM ); + return; + } + + pBuf = llMemCopySrc( (uint8*)connPtr->chanMap, pBuf, 5 ); + pBuf = llMemCopySrc( &tempByte, pBuf, 1 ); + connPtr->hop = tempByte & 0x1F; + connPtr->sleepClkAccuracy = (tempByte >> 5) & 0x07; + // calculate channel for data + llProcessChanMap(connPtr, connPtr->chanMap ); // 16MHz clk, cost 116us! + connPtr->slaveLatency = 0; //correct 05-09, no latency before connect + connPtr->slaveLatencyValue = connPtr->curParam.slaveLatency; + connPtr->accuTimerDrift = 0; + llAdjSlaveLatencyValue(connPtr); + // combine slave SCA with master's SCA and calculate timer drift factor + //connPtr->scaFactor = llCalcScaFactor( connPtr->sleepClkAccuracy ); + //connPtr->currentChan = llGetNextDataChan(1); + llState = LL_STATE_CONN_SLAVE; + ll_debug_output(DEBUG_LL_STATE_CONN_SLAVE); + connPtr->active = TRUE; + connPtr->sn_nesn = 0; // 1st rtlp, init sn/nesn as 0 + connPtr->llMode = LL_HW_RTLP_1ST; // set as RTLP_1ST for the 1st connection event + // calculate the 1st channel + connPtr->currentChan = 0; +//hal_gpio_write(GPIO_P15, 1); +// BM_SET(reg_gpio_ioe_porta, BIT(GPIO_P15)); +// BM_SET(reg_gpio_swporta_dr, BIT(GPIO_P15)); + + if (connPtr->channel_selection == LL_CHN_SEL_ALGORITHM_1) + connPtr->currentChan = llGetNextDataChan(connPtr, 1); + else + { + // channel selection algorithm 2 + connPtr->currentChan = llGetNextDataChanCSA2(0, + (( connPtr->accessAddr & 0xFFFF0000 )>> 16 ) ^ ( connPtr->accessAddr & 0x0000FFFF), + connPtr->chanMap, + connPtr->chanMapTable, + connPtr->numUsedChans); + } + +// hal_gpio_write(GPIO_P15, 0); +// BM_SET(reg_gpio_ioe_porta, BIT(GPIO_P15)); +// BM_CLR(reg_gpio_swporta_dr, BIT(GPIO_P15)); + // calculate timer drift + llCalcTimerDrift(connPtr->curParam.winOffset + 2, // 1250us + win offset, in 625us tick + connPtr->slaveLatency, + connPtr->sleepClkAccuracy, + (uint32*)&(connPtr->timerDrift)); + T2 = read_current_fine_time(); + // calculate the SW delay from ISR to here + calibra_time = (T2 > ISR_entry_time) ? (T2 - ISR_entry_time) : (BASE_TIME_UNITS - ISR_entry_time + T2); + // other delay: conn req tail -> ISR: 32us, timing advance: 50us, HW engine startup: 60us + // start slave event SW process time: 50us + // soft parameter: pGlobal_config[CONN_REQ_TO_SLAVE_DELAY] + calibra_time += pGlobal_config[CONN_REQ_TO_SLAVE_DELAY]; //(32 + 50 + 60 + 50 + pGlobal_config[CONN_REQ_TO_SLAVE_DELAY]); + // TODO: need consider the case: 0ms window offset, sometimes timer offset will < 0, +// timer1 = 1250 + conn_param[connId].curParam.winOffset * 625 - calibra_time - conn_param[connId].timerDrift; +// if (timer1 < 0) +// while(1); +// +// ll_schedule_next_event(timer1); +//#ifdef MULTI_ROLE + uint32_t temp; + + if (g_ll_conn_ctx.numLLConns == 1) // 1st connection, time1 is for adv event + clear_timer(AP_TIM1); // stop the timer between different adv channel + + temp = 1250 + connPtr->curParam.winOffset * 625 - calibra_time - connPtr->timerDrift; + ll_addTask(connPtr->connId, temp); +// ll_addTask(connPtr->connId, 1250 + connPtr->curParam.winOffset * 625 - calibra_time - connPtr->timerDrift); + g_ll_conn_ctx.scheduleInfo[connPtr->connId].task_duration = 3000; // slave task duration: 150 + 80 + 150 + 2120 + window + + // current link id may be updated in ll_addTask, update the ll state + if (g_ll_conn_ctx.scheduleInfo[g_ll_conn_ctx.currentConn].linkRole == LL_ROLE_MASTER) + llState = LL_STATE_CONN_MASTER; + else if (g_ll_conn_ctx.scheduleInfo[g_ll_conn_ctx.currentConn].linkRole == LL_ROLE_SLAVE) + llState = LL_STATE_CONN_SLAVE; + + llSecondaryState = LL_SEC_STATE_IDLE; +// LOG("M2S:%d\n", temp); +//#else +// ll_schedule_next_event(1250 + connPtr->curParam.winOffset * 625 - calibra_time - connPtr->timerDrift); +// g_ll_conn_ctx.currentConn = connPtr->connId; +//#endif + g_ll_conn_ctx.scheduleInfo[connPtr->connId].linkRole = LL_ROLE_SLAVE; + (void)osal_set_event( LL_TaskID, LL_EVT_SLAVE_CONN_CREATED); + g_pmCounters.ll_conn_succ_cnt ++; // move to anchor point catch ? +// hal_gpio_write(GPIO_P15, 0); +} + + +/******************************************************************************* + @fn LL_slave_conn_event + + @brief This function process slave connection event + + + input parameters + + @param None. + + output parameters + + @param None. + + @return None, + +*/ +void LL_slave_conn_event0(void) // TODO: update connection context select +{ + uint16_t ll_rdCntIni; + uint32_t tx_num, rx_num; + llConnState_t* connPtr; + g_ll_conn_ctx.timerExpiryTick = read_current_fine_time(); // A2 multiconnection +// hal_gpio_write(GPIO_P14, 1); + connPtr = &conn_param[g_ll_conn_ctx.currentConn]; + // time critical process, disable interrupt + HAL_ENTER_CRITICAL_SECTION(); + tx_num = pGlobal_config[LL_TX_PKTS_PER_CONN_EVT]; + rx_num = pGlobal_config[LL_RX_PKTS_PER_CONN_EVT]; + + if (tx_num > g_maxPktPerEventTx || tx_num == 0) tx_num = g_maxPktPerEventTx; + + if (rx_num > g_maxPktPerEventRx || rx_num == 0) rx_num = g_maxPktPerEventRx; + + connPtr->pmCounter.ll_conn_event_cnt ++; + + if(p_perStatsByChan!=NULL) + p_perStatsByChan->connEvtCnt[connPtr->currentChan]++; + + //ZQ 20191209 + //restore the currentChan for disable slavelatency + //ZQ20200207 should use nextChan + connPtr->lastCurrentChan = connPtr->nextChan; + // counter for one connection event + llResetRfCounters(); + //support rf phy change + rf_phy_change_cfg(connPtr->llRfPhyPktFmt); + ll_hw_tx2rx_timing_config(connPtr->llRfPhyPktFmt); + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + // channel physical configuration + set_crc_seed(connPtr->initCRC ); // crc seed for data PDU is from CONNECT_REQ + set_access_address(connPtr->accessAddr); // access address + set_channel(connPtr->currentChan ); // set channel + set_whiten_seed(connPtr->currentChan); // set whiten seed + // A2-multiconn + ll_hw_set_rx_timeout(88); + set_max_length(0xff); // add 2020-03-10 + + // win size for 1st packet + if (connPtr->firstPacket) // not received the 1st packet, CRC error or correct + { + //ll_hw_set_rx_timeout_1st(conn_param[connId].curParam.winSize * 625 + conn_param[connId].timerDrift * 2 ); + //20180412 enlarge the connectInd or connect_update timing tolerence + uint32_t first_window_timout=pGlobal_config[LL_SMART_WINDOW_FIRST_WINDOW] + connPtr->curParam.winSize * 625 + connPtr->timerDrift * 2 ; + //The transmitWindowOffset shall be a multiple of 1.25 ms in the range of 0 ms + //to connInterval. The transmitWindowSize shall be a multiple of 1.25 ms in the + //range of 1.25 ms to the lesser of 10 ms and (connInterval - 1.25 ms). + //ZQ 20200208 + uint32_t winSizeLimt = MIN(10000, (connPtr->curParam.connInterval * 625 - 1250) ); + + if(winSizeLimtrx_timeout) // timeout case + ll_hw_set_rx_timeout_1st(pGlobal_config[LL_HW_RTLP_1ST_TIMEOUT] + pGlobal_config[SLAVE_CONN_DELAY_BEFORE_SYNC] * 2 + (connPtr->timerDrift + connPtr->accuTimerDrift) * 2 ); + else + ll_hw_set_rx_timeout_1st(pGlobal_config[LL_HW_RTLP_1ST_TIMEOUT] + pGlobal_config[SLAVE_CONN_DELAY] * 2 + connPtr->timerDrift * 2 ); + } + + // configure loop timeout + // considering the dle case + uint32_t temp = connPtr->curParam.connInterval * 625 - connPtr->llPduLen.local.MaxRxTime- pGlobal_config[LL_HW_RTLP_TO_GAP]; // 500us: margin for timer1 IRQ + ll_hw_set_loop_timeout(temp > pGlobal_config[LL_HW_RTLP_LOOP_TIMEOUT] ? + pGlobal_config[LL_HW_RTLP_LOOP_TIMEOUT] : temp); // 2018-6-20, global config for the parameter + // now we support 4 RT in one RTLP, if PDU size is 256Byte, need (256*8 + 150) * 8 = 17684us, + // not consider Rx packet size + ll_hw_trx_settle_config(connPtr->llRfPhyPktFmt); + // retransmit count limit + ll_hw_set_loop_nack_num( 4 ); + //set the rfifo ign control + ll_hw_ign_rfifo(LL_HW_IGN_ALL); + // write packets to Tx FIFO + tx_num = ll_generateTxBuffer(tx_num, &ll_rdCntIni); + // TODO: consider Rx flow control here +// if (LL_RX_FLOW_CONTROL_ENABLED == rxFifoFlowCtrl) +// { +// // configure LL HW to keep NESN +// } + ll_hw_config( LL_HW_RTLP, //connPtr->llMode, + connPtr->sn_nesn, // sn,nesn init + tx_num, // ll_txNum + rx_num, // ll_rxNum + 1, // ll_mdRx + ll_rdCntIni); // rdCntIni + uint8 temp_rf_fmt = g_rfPhyPktFmt; + g_rfPhyPktFmt = connPtr->llRfPhyPktFmt; + // start LL HW engine + ll_hw_go(); + llWaitingIrq = TRUE; + g_rfPhyPktFmt = temp_rf_fmt; + HAL_EXIT_CRITICAL_SECTION(); +// hal_gpio_write(GPIO_P14, 0); +// LOG("%d-%d ", g_ll_conn_ctx.numLLConns, g_ll_conn_ctx.currentConn); +// LOG("%d ", g_ll_conn_ctx.currentConn); + ll_debug_output(DEBUG_LL_HW_SET_RTLP); +} + +/******************************************************************************* + @fn LL_evt_schedule0 + + @brief Link layer event process entry + + + input parameters + + @param None. + + output parameters + + @param None. + + @return None, + +*/ +void LL_evt_schedule0(void) +{ + if (llWaitingIrq == TRUE) + { + // normally should not be here + //LOG("event collision detect\n"); + g_pmCounters.ll_evt_shc_err++; + } + + switch(llState) + { + // adv envent entry + case LL_STATE_ADV_UNDIRECTED: + case LL_STATE_ADV_DIRECTED: + case LL_STATE_ADV_NONCONN: + case LL_STATE_ADV_SCAN: + VOID llSetupAdv(); + break; + + // slave connect event entry + case LL_STATE_CONN_SLAVE: // TO update + + // set_default_conn_data(); + if(g_ll_conn_ctx.currentConn != LL_INVALID_CONNECTION_ID && conn_param [g_ll_conn_ctx.currentConn].active) + { + LL_slave_conn_event(); + } + else + { + // add by HZF on 2017-12-12, if connection is not active, release + llReleaseConnId(&conn_param[g_ll_conn_ctx.currentConn]); + } + + break; + + case LL_STATE_SCAN: + llScanTime = 0; + llSetupScan(scanInfo.nextScanChan); + break; + + case LL_STATE_INIT: + llScanTime = 0; + llSetupScan(initInfo.nextScanChan); + break; + + case LL_STATE_CONN_MASTER: + if(g_ll_conn_ctx.currentConn != LL_INVALID_CONNECTION_ID && conn_param [g_ll_conn_ctx.currentConn].active) + { + LL_master_conn_event(); + } + else + { + // add by ZQ 20181125 necessary??? + llReleaseConnId(&conn_param[g_ll_conn_ctx.currentConn]); + g_ll_conn_ctx.numLLMasterConns --; + } + + break; + + case LL_STATE_IDLE: + default: +// ll_schedule_next_event(20000); // add by HZF, period trigger LL task when IDLE and other not process ll state + // it may useful when some application change the ll state but not trigger ll loop + break; + } +} + +/******************************************************************************* + @fn llSetupAdv0 + + @brief This routine is used to setup the Controller for Advertising + based on the Advertising event type. + + input parameters + + @param None. + + output== parameters + + @param None. + + @return LL_STATUS_SUCCESS +*/ +llStatus_t llSetupAdv0( void ) +{ + if ((llState == LL_STATE_ADV_DIRECTED && (adv_param.advEvtType != LL_ADV_CONNECTABLE_HDC_DIRECTED_EVT) && (adv_param.advEvtType != LL_ADV_CONNECTABLE_LDC_DIRECTED_EVT)) + || (llState == LL_STATE_ADV_UNDIRECTED && (adv_param.advEvtType != LL_ADV_CONNECTABLE_UNDIRECTED_EVT) ) + || (llState == LL_STATE_ADV_NONCONN && (adv_param.advEvtType != LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT) ) + || (llState == LL_STATE_ADV_SCAN && (adv_param.advEvtType != LL_ADV_SCANNABLE_UNDIRECTED_EVT) )) + { + // sanity check failure + } + + g_rfPhyPktFmt = LE_1M_PHY; + //support rf phy change + rf_phy_change_cfg(g_rfPhyPktFmt); + ll_hw_ign_rfifo(LL_HW_IGN_CRC|LL_HW_IGN_EMP); + ll_hw_set_rx_timeout(88); + // reset all FIFOs; all data is forfeit + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + + // setup and start the advertising task based on the Adv event + switch( adv_param.advEvtType ) + { + // can only get a CONNECT_REQ + case LL_ADV_CONNECTABLE_HDC_DIRECTED_EVT: + case LL_ADV_CONNECTABLE_LDC_DIRECTED_EVT: + // setup a Directed Advertising Event + llSetupDirectedAdvEvt(); + break; + + // can get a SCAN_REQ or a CONNECT_REQ + case LL_ADV_CONNECTABLE_UNDIRECTED_EVT: + // setup a Undirected Advertising Event + llSetupUndirectedAdvEvt(); + break; + + // neither a SCAN_REQ nor a CONNECT_REQ can be received + case LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT: + // setup a Undirected Advertising Event + llSetupNonConnectableAdvEvt(); + break; + + // can only get a SCAN_REQ + case LL_ADV_SCANNABLE_UNDIRECTED_EVT: + // setup a Discoverable Undirected Advertising Event + llSetupScannableAdvEvt(); + break; + + default: + // Note: this should not ever happen as the params are checked by + // LL_SetAdvParam() + return( LL_STATUS_ERROR_UNKNOWN_ADV_EVT_TYPE ); + } + + // notify upper layer if required + if (g_adv_taskID != 0) + { + uint8_t firstAdvChan = (adv_param.advChanMap & LL_ADV_CHAN_37) != 0 ? 37 : + (adv_param.advChanMap & LL_ADV_CHAN_38) != 0 ? 38 : 39; + + if(adv_param.advNextChan == firstAdvChan) + { + osal_set_event(g_adv_taskID, g_adv_taskEvent); + } + } + + return( LL_STATUS_SUCCESS ); +} +/******************************************************************************* + @fn llSetupUndirectedAdvEvt0 + + @brief This function process for Undirected Advertising. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void llSetupUndirectedAdvEvt0(void) +{ + uint32_t ch_idx; + int i; + + // next adv channel invalid, get 1st adv chn + if (adv_param.advNextChan > LL_ADV_CHAN_LAST || adv_param.advNextChan < LL_ADV_CHAN_FIRST) + adv_param.advNextChan = llGetNextAdvChn(0); // get 1st adv chn + + ch_idx = adv_param.advNextChan; + adv_param.advNextChan = llGetNextAdvChn(adv_param.advNextChan); + + // schedule next adv time + if (ch_idx >= adv_param.advNextChan) + { + // next adv event + int random_delay = get_timer_count(AP_TIM3) & 0x3ff; // random adv event delay to avoid collision in the air, 0 - 1023us + i = (adv_param.advChanMap & 0x01) + + ((adv_param.advChanMap & 0x02) >> 1) + + ((adv_param.advChanMap & 0x04) >> 2) + - 1; + ll_schedule_next_event(adv_param.advInterval * 625 - (i * pGlobal_config[ADV_CHANNEL_INTERVAL]) + (getPN23RandNumber()>>11)+random_delay); + } + else + { + ll_schedule_next_event(pGlobal_config[ADV_CHANNEL_INTERVAL]); + } + + // set proposed state + llState = LL_STATE_ADV_UNDIRECTED; + ll_debug_output(DEBUG_LL_STATE_ADV_UNDIRECTED); + //============== configure and trigger LL HW engine, LL HW work in Tx - Rx mode ================== + set_crc_seed(ADV_CRC_INIT_VALUE); // crc seed for adv is same for all channels + set_access_address(ADV_SYNCH_WORD); // access address + set_channel(ch_idx); // channel + set_whiten_seed(ch_idx); // whiten seed + set_max_length(50); // rx PDU max length, may receive SCAN_REQ/CONN_REQ + ll_hw_set_trx_settle (pGlobal_config[LL_HW_BB_DELAY_ADV], + pGlobal_config[LL_HW_AFE_DELAY_ADV], + pGlobal_config[LL_HW_PLL_DELAY_ADV]); //TxBB,RxAFE,PLL + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + ll_hw_set_trx(); // set LL HW as Tx - Rx mode + ll_hw_ign_rfifo(LL_HW_IGN_EMP | LL_HW_IGN_CRC); //set the rfifo ign control + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(g_tx_adv_buf.txheader), ((g_tx_adv_buf.txheader & 0xff00) >> 8) + 2); + ll_hw_go(); + llWaitingIrq = TRUE; + g_pmCounters.ll_send_undirect_adv_cnt ++; + ll_debug_output(DEBUG_LL_HW_SET_TRX); +} + +/******************************************************************************* + @fn llSetupNonConnectableAdvEvt0 + + @brief This function process for Nonconnectable Advertising. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void llSetupNonConnectableAdvEvt0( void ) +{ + uint32_t ch_idx; + int i; + + // next adv channel invalid, get 1st adv chn + if (adv_param.advNextChan > LL_ADV_CHAN_LAST || adv_param.advNextChan < LL_ADV_CHAN_FIRST) + adv_param.advNextChan = llGetNextAdvChn(0); // get 1st adv chn + + ch_idx = adv_param.advNextChan; + adv_param.advNextChan = llGetNextAdvChn(adv_param.advNextChan); + + // schedule next adv time + if (ch_idx >= adv_param.advNextChan) + { + // next adv event + int random_delay = get_timer_count(AP_TIM3) & 0x3ff;; // random adv event delay to avoid collision in the air + i = (adv_param.advChanMap & 0x01) + + ((adv_param.advChanMap & 0x02) >> 1) + + ((adv_param.advChanMap & 0x04) >> 2) + - 1; + ll_schedule_next_event(adv_param.advInterval * 625 - (i * pGlobal_config[NON_ADV_CHANNEL_INTERVAL]) + random_delay); + } + else + ll_schedule_next_event(pGlobal_config[NON_ADV_CHANNEL_INTERVAL]); + + // set proposed state + llState = LL_STATE_ADV_NONCONN; + ll_debug_output(DEBUG_LL_STATE_ADV_NONCONN); + //============== configure and trigger LL HW engine, LL HW work in Single Tx mode ================== + set_crc_seed(ADV_CRC_INIT_VALUE); // crc seed for adv is same for all channels + set_access_address(ADV_SYNCH_WORD); // access address + set_channel(ch_idx); // channel + set_whiten_seed(ch_idx); // whiten seed + set_max_length(0xff); // rx PDU max length + ll_hw_set_trx_settle(pGlobal_config[LL_HW_BB_DELAY_ADV], + pGlobal_config[LL_HW_AFE_DELAY_ADV], + pGlobal_config[LL_HW_PLL_DELAY_ADV]); //TxBB,RxAFE,PLL + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + ll_hw_set_stx(); // set LL HW as Tx - Rx mode + ll_hw_ign_rfifo(LL_HW_IGN_ALL); //set the rfifo ign control + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(g_tx_adv_buf.txheader), ((g_tx_adv_buf.txheader & 0xff00) >> 8) + 2); + ll_hw_go(); + llWaitingIrq = TRUE; + g_pmCounters.ll_send_nonconn_adv_cnt ++; + ll_debug_output(DEBUG_LL_HW_SET_STX); +} /* end of function */ + +/******************************************************************************* + @fn llSetupScannableAdvEvt0 + + @brief This function process Discoverable Undirected + Advertising. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void llSetupScannableAdvEvt0( void ) +{ + uint32_t ch_idx; + int i; + + // next adv channel invalid, get 1st adv chn + if (adv_param.advNextChan > LL_ADV_CHAN_LAST || adv_param.advNextChan < LL_ADV_CHAN_FIRST) + adv_param.advNextChan = llGetNextAdvChn(0); // get 1st adv chn + + ch_idx = adv_param.advNextChan; + adv_param.advNextChan = llGetNextAdvChn(adv_param.advNextChan); + + // schedule next adv time + if (ch_idx >= adv_param.advNextChan) + { + // next adv event + int random_delay = get_timer_count(AP_TIM3) & 0x3ff;; // random adv event delay to avoid collision in the air + i = (adv_param.advChanMap & 0x01) + + ((adv_param.advChanMap & 0x02) >> 1) + + ((adv_param.advChanMap & 0x04) >> 2) + - 1; + ll_schedule_next_event(adv_param.advInterval * 625 - (i * pGlobal_config[ADV_CHANNEL_INTERVAL]) + random_delay); + } + else + ll_schedule_next_event(pGlobal_config[ADV_CHANNEL_INTERVAL]); + + // set proposed state + llState = LL_STATE_ADV_SCAN; + ll_debug_output(DEBUG_LL_STATE_SCAN); + //============== configure and trigger LL HW engine, LL HW work in Tx - Rx mode ================== + set_crc_seed(ADV_CRC_INIT_VALUE); // crc seed for adv is same for all channels + set_access_address(ADV_SYNCH_WORD); // access address + set_channel(ch_idx); // channel + set_whiten_seed(ch_idx); // whiten seed + set_max_length(50); // rx PDU max length, may receive SCAN_REQ + ll_hw_set_trx_settle(pGlobal_config[LL_HW_BB_DELAY_ADV], + pGlobal_config[LL_HW_AFE_DELAY_ADV], + pGlobal_config[LL_HW_PLL_DELAY_ADV]); //TxBB,RxAFE,PLL + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + ll_hw_set_trx(); // set LL HW as Tx - Rx mode + ll_hw_ign_rfifo(LL_HW_IGN_EMP | LL_HW_IGN_CRC); //set the rfifo ign control + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(g_tx_adv_buf.txheader), ((g_tx_adv_buf.txheader & 0xff00) >> 8) + 2); + ll_hw_go(); + llWaitingIrq = TRUE; + g_pmCounters.ll_send_scan_adv_cnt ++; + ll_debug_output(DEBUG_LL_HW_SET_TRX); +} + + +/******************************************************************************* + @fn llSetupDirectedAdvEvt0 + + @brief This function process for Directed Advertising. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +// for high duty cycle, should send pdu in all adv channels in 3.75ms +void llSetupDirectedAdvEvt0( void ) +{ + uint32 ch_idx, interval; + int i; + + if (adv_param.advEvtType == LL_ADV_CONNECTABLE_HDC_DIRECTED_EVT) + interval = pGlobal_config[HDC_DIRECT_ADV_INTERVAL]; // adv event < 3.75ms + else + interval = pGlobal_config[LDC_DIRECT_ADV_INTERVAL]; // should < 10ms according to spec + +// 2020-5-7, g_tx_adv_buf should be filled in function LL_SetAdvParam0. To test + #if 0 + // construct transmit PDU + osal_memset(g_tx_adv_buf.data, 0, sizeof(g_tx_adv_buf.data)); + SET_BITS(g_tx_adv_buf.txheader, ADV_DIRECT_IND, PDU_TYPE_SHIFT, PDU_TYPE_MASK); + SET_BITS(g_tx_adv_buf.txheader, adv_param.ownAddrType, TX_ADD_SHIFT, TX_ADD_MASK); + SET_BITS(g_tx_adv_buf.txheader, peerInfo.peerAddrType, RX_ADD_SHIFT, RX_ADD_MASK); + SET_BITS(g_tx_adv_buf.txheader, 12, LENGTH_SHIFT, LENGTH_MASK); + osal_memcpy(g_tx_adv_buf.data, adv_param.ownAddr, 6); + osal_memcpy((uint8_t*) &(g_tx_adv_buf.data[6]), peerInfo.peerAddr, 6); + #endif + + // next adv channel invalid, get 1st adv chn + if (adv_param.advNextChan > LL_ADV_CHAN_LAST || adv_param.advNextChan < LL_ADV_CHAN_FIRST) + adv_param.advNextChan = llGetNextAdvChn(0); // get 1st adv chn + + ch_idx = adv_param.advNextChan; + adv_param.advNextChan = llGetNextAdvChn(adv_param.advNextChan); + + // schedule next adv time + if (adv_param.advEvtType == LL_ADV_CONNECTABLE_HDC_DIRECTED_EVT) + { + g_llHdcDirAdvTime += interval + pGlobal_config[DIR_ADV_DELAY] ; + + if (g_llHdcDirAdvTime >= MAX_HDC_DIRECT_ADV_TIME) // for HDC direct adv, should not adv more than 1.28s + { + llState = LL_STATE_IDLE; // back to idle + adv_param.advMode = LL_ADV_MODE_OFF; + (void)osal_set_event( LL_TaskID, LL_EVT_DIRECTED_ADV_FAILED ); + return; + } + + ll_schedule_next_event(interval); + } + else if (ch_idx >= adv_param.advNextChan) + { + // next adv event + i = (adv_param.advChanMap & 0x01) + + ((adv_param.advChanMap & 0x02) >> 1) + + ((adv_param.advChanMap & 0x04) >> 2) + - 1; + ll_schedule_next_event(adv_param.advInterval * 625 - i * interval); + } + else + ll_schedule_next_event(interval); + + // set proposed state + llState = LL_STATE_ADV_DIRECTED; + ll_debug_output(DEBUG_LL_STATE_ADV_DIRECTED); + //============== configure and trigger LL HW engine, LL HW work in Tx - Rx mode ================== + set_crc_seed(ADV_CRC_INIT_VALUE); // crc seed for adv is same for all channels + set_access_address(ADV_SYNCH_WORD); // access address + set_channel(ch_idx); // channel + set_whiten_seed(ch_idx); // whiten seed + set_max_length(0xff); // rx PDU max length + ll_hw_set_trx_settle(pGlobal_config[LL_HW_BB_DELAY_ADV], + pGlobal_config[LL_HW_AFE_DELAY_ADV], + pGlobal_config[LL_HW_PLL_DELAY_ADV]); //TxBB,RxAFE,PLL + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + ll_hw_set_trx(); // set LL HW as Tx - Rx mode + ll_hw_ign_rfifo(LL_HW_IGN_EMP | LL_HW_IGN_CRC); //set the rfifo ign control + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(g_tx_adv_buf.txheader), ((g_tx_adv_buf.txheader & 0xff00) >> 8) + 2); + ll_hw_go(); + llWaitingIrq = TRUE; + + if (adv_param.advEvtType == LL_ADV_CONNECTABLE_HDC_DIRECTED_EVT) + g_pmCounters.ll_send_hdc_dir_adv_cnt ++; + else + g_pmCounters.ll_send_ldc_dir_adv_cnt ++; + + ll_debug_output(DEBUG_LL_HW_SET_TRX); +} /* end of function */ + +/******************************************************************************* + @fn llCalcTimerDrift0 + + @brief This function is used to calculate the timer drift based on a + given time interval and a Sleep Clock Accuracy (SCA) for the + connection. + + Note: This routine assumes that the scaValue index is valid. + + + + input parameters + + @param connInterval - The connection interval in 625us ticks. + @param slaveLatency - Number of skipped events. + @param sleepClkAccuracy - SCA of peer + @param timerDrift - Pointer for storing the timer drift adjustment. + + output parameters + + @param timerDrift - The timer drift adjustment (coarse/fine ticks). + + @return None. +*/ +void llCalcTimerDrift0( uint32 connInterval, + uint16 slaveLatency, + uint8 sleepClkAccuracy, + uint32* timerDrift ) // HZF, it seems we need't corse & fine time, change to uint32 +{ + uint32 time; + uint16 sca = 0; + // adjust the connection interval by the slave latency + time = (uint32)connInterval * (uint32)(slaveLatency + 1); + // include the Slave's SCA in timer drift correction + sca = adv_param.scaValue; + // convert master's SCA to PPM and combine with slave + sca += SCA[sleepClkAccuracy ]; + time *= sca; + time = time / 1600; // time * 625 / 1000 000 => time / 1600 + *timerDrift = time; + return; +} + +/******************************************************************************* + @fn ll_generateTxBuffer0 + + @brief This function generate Tx data and find in Tx FIFO + there are 4 kinds of data: + 1. control data + 2. last no-ack data + 3. last no-transmit data + 4. new data + in the new RTLP buffer, the data should be in the below sequence: + 2 --> 1 --> 3 --> 4 + + input parameters + + @param txFifo_vacancy - allow max tx packet number. + + output parameters + + @param None. + + @return the pointer of 1st not transmit packet/new packet. + +*/ +uint16 ll_generateTxBuffer0(int txFifo_vacancy, uint16* pSave_ptr) +{ + int i, new_pkts_num, tx_num = 0; + llConnState_t* connPtr; + connPtr = &conn_param[g_ll_conn_ctx.currentConn]; + + // 0. write empty packet + if(connPtr->llMode == LL_HW_RTLP_EMPT + || connPtr->llMode == LL_HW_TRLP_EMPT) // TRLP case, to be confirmed/test + { + LL_HW_WRT_EMPTY_PKT; + connPtr->ll_buf.tx_not_ack_pkt->valid = 0; // empty mode, tx_not_ack buffer null or empty packet + tx_num ++; + } + // 1. write last not-ACK packet + else if (connPtr->ll_buf.tx_not_ack_pkt->valid != 0) // TODO: if the valid field could omit, move the not-ACK flag to buf. + { + ll_hw_write_tfifo((uint8*)&(connPtr->ll_buf.tx_not_ack_pkt->header), ((connPtr->ll_buf.tx_not_ack_pkt->header & 0xff00) >> 8) + 2); + //txFifo_vacancy --; + tx_num ++; + connPtr->ll_buf.tx_not_ack_pkt->valid = 0; + } + + // 1st RTLP event, no porcess 0/1, it should be 0 because we have reset the TFIFO + // other case, it is 1st not transmit packet/new packet + *pSave_ptr = ll_hw_get_tfifo_wrptr(); + rfCounters.numTxCtrl = 0; // add on 2017-11-15, set tx control packet number 0 + + // 2. write control packet + if ((connPtr->ll_buf.tx_not_ack_pkt->valid == 0 || // no tx not_ack packet, add on 2017-11-15 + (connPtr->ll_buf.tx_not_ack_pkt->header & 0x3) != LL_DATA_PDU_HDR_LLID_CONTROL_PKT) // last nack packet is not a control packet + && connPtr->ctrlDataIsPending // we only support 1 control procedure per connection + && !connPtr->ctrlDataIsProcess + && txFifo_vacancy > connPtr->ll_buf.ntrm_cnt) // tricky here: if the Tx FIFO is full and nothing is sent in last event, then it can't fill new packet(include ctrl pkt) in new event + { + // not in a control procedure, and there is control packet pending + // fill ctrl packet + ll_hw_write_tfifo((uint8*)&(connPtr->ctrlData .header), ((connPtr->ctrlData .header & 0xff00) >> 8) + 2); + txFifo_vacancy --; + tx_num ++; + // put Ctrl packet in TFIFO, change the control procedure status + connPtr->ctrlDataIsPending = 0; + connPtr->ctrlDataIsProcess = 1; + rfCounters.numTxCtrl = 1; // add 2017-11-15, if put new ctrl packet in FIFO, add the counter + } + + // 3. write last not transmit packets + if (connPtr->ll_buf.ntrm_cnt > 0 + && txFifo_vacancy >= connPtr->ll_buf.ntrm_cnt) + { + for (i = 0; i < connPtr->ll_buf.ntrm_cnt ; i++) + { + ll_hw_write_tfifo((uint8*)&(connPtr->ll_buf.tx_ntrm_pkts[i]->header), ((connPtr->ll_buf.tx_ntrm_pkts[i]->header & 0xff00) >> 8) + 2); + } + + txFifo_vacancy -= connPtr->ll_buf.ntrm_cnt; + tx_num += connPtr->ll_buf.ntrm_cnt; + connPtr->ll_buf.ntrm_cnt = 0; + } + + if (connPtr->ll_buf.ntrm_cnt != 0) + { + // should not be here, new packets should not be sent if there is not-transmit packets + return tx_num; + } + + // 4. write new data packets to FIFO + new_pkts_num = getTxBufferSize(connPtr); + + if ((new_pkts_num > 0) + && txFifo_vacancy > 0) + { + // fill the data packet to Tx FIFO + for (i = 0; i < new_pkts_num && i < txFifo_vacancy; i++) + { + uint8_t idx = get_tx_read_ptr(connPtr); + ll_hw_write_tfifo((uint8*)&(connPtr->ll_buf.tx_conn_desc[idx]->header), ((connPtr->ll_buf.tx_conn_desc[idx]->header & 0xff00) >> 8) + 2); + update_tx_read_ptr(connPtr); + tx_num++; + // update PM counter, add A1 ROM metal change + connPtr->pmCounter.ll_send_data_pkt_cnt ++; + } + } + + // 2020-02-13 periodic cte req & rsp + if( ( connPtr->llConnCTE.enable ) && ( connPtr->llCTE_ReqFlag )) + { + if( connPtr->llConnCTE.CTE_Request_Intv > 0 ) + { + if( connPtr->llConnCTE.CTE_Count_Idx < connPtr->llConnCTE.CTE_Request_Intv ) + connPtr->llConnCTE.CTE_Count_Idx++; + else + { + connPtr->llConnCTE.CTE_Count_Idx = 0; + llEnqueueCtrlPkt(connPtr, LL_CTRL_CTE_REQ ); + } + } + } + + return tx_num; +} + + +/******************************************************************************* + @fn ll_read_rxfifo0 + + @brief This function read HW Rx FIFO to internal buffer + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void ll_read_rxfifo0(void) +{ + uint8_t packet_len, idx; + uint16_t pktLen; + uint32_t pktFoot0, pktFoot1; + int depth; + llConnState_t* connPtr; + connPtr = &conn_param[g_ll_conn_ctx.currentConn]; // TODO + depth = ll_hw_get_rfifo_depth(); + + // read packet + while (getRxBufferFree(connPtr) > 0 // SW rx buffer has vacancy + && depth > 0) // something to read from HW Rx FIFO + { + idx = get_rx_write_ptr(connPtr); + packet_len = ll_hw_read_rfifo((uint8_t*)(&(connPtr->ll_buf.rx_conn_desc[idx]->header)), + &pktLen, + &pktFoot0, + &pktFoot1); + + if (packet_len == 0) + { + break; + } + + connPtr->ll_buf.rx_conn_desc[idx]->valid = 1; + update_rx_write_ptr(connPtr); // increment write pointer + depth -= (packet_len + 2) ; + } + + connPtr->lastRssi = pktFoot1 >> 24; // RSSI , -dBm + + // TODO: get other information from pktFoot0/pktFoot1 + + if (depth > 0) + { + // warning: some data in Rx FIFO is not read, normal this should not happen + connPtr->pmCounter.ll_recv_abnormal_cnt ++; + } +} + + +/******************************************************************************* + @fn ll_hw_read_tfifo_rtlp0 + + @brief This function read not-ack packet and untransmit packets in RT Loop + This function is also used in TR Loop mode, note that for TRLP, + Tx_fifo_rd_addr_last == Tx_fifo_rd_addr, no not-ACK packet + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_read_tfifo_rtlp0(void) +{ + uint32_t tmp, irq_status; + uint32_t last_rd_addr, current_wr_addr; + uint32_t current_rd_addr; + int depth, len; + llConnState_t* connPtr; + connPtr = &conn_param[g_ll_conn_ctx.currentConn]; + // reset the not-ACK buf & not-transmit buf status + connPtr->ll_buf.tx_not_ack_pkt->valid = 0; + connPtr->ll_buf.ntrm_cnt = 0; + // read registers for LL HW status + last_rd_addr = (*(volatile uint32_t*)(LL_HW_BASE + 0x4c)) & 0x7ff; + current_wr_addr = 0x07ff & ((*(volatile uint32_t*)(LL_HW_BASE + 0x50)) >> 16); + current_rd_addr = 0x07ff & ((*(volatile uint32_t*)(LL_HW_BASE + 0x50))); + // revert HW read pointer + tmp = *(volatile uint32_t*)(LL_HW_BASE + 0x5C); + *(volatile uint32_t*)(LL_HW_BASE + 0x5C) = (tmp & 0x7ff0000) | last_rd_addr; // set rd_cnt_ini as Tx_fifo_rd_addr_last + // calculate depth in Tx FIFO, include not-ack + not-transmit packets, note that the depth in 4bytes unit + depth = current_wr_addr - last_rd_addr; // Tx_fifo_wr_addr - Tx_fifo_rd_addr_last + + //read not ack packet + if (depth > 0) + { + if (current_rd_addr != last_rd_addr) + { + len = ll_hw_read_tfifo_packet((uint8*)&(connPtr->ll_buf.tx_not_ack_pkt->header)); + depth -= len; + connPtr->ll_buf.tx_not_ack_pkt->valid = 1; // set not ack packet buffer valid + } + else // current_rd_addr == last_rd_addr + { + irq_status = ll_hw_get_irq_status(); + + if (irq_status & LIRQ_CERR2) // double CRC error, HW will not send packet when 2nd CRC error + { + len = ll_hw_read_tfifo_packet((uint8*)&(connPtr->ll_buf.tx_not_ack_pkt->header)); + depth -= len; + connPtr->ll_buf.tx_not_ack_pkt->valid = 1; // set not ack packet buffer valid + } + else + { + // should not be here + } + } + } + + // read not transmit packets + while (depth > 0 + && connPtr->ll_buf.ntrm_cnt < g_maxPktPerEventTx) // A1 ROM metal change: change to MAX_LL_BUF_LEN // 05-19: change size from (MAX_CONN_BUF - 1) to MAX_CONN_BUF. not ack packet is not part of tx num + { + len = ll_hw_read_tfifo_packet((uint8*)&(connPtr->ll_buf.tx_ntrm_pkts[connPtr->ll_buf.ntrm_cnt]->header)); // read a packet from Tx FIFO + depth -= len; + connPtr->ll_buf.ntrm_cnt ++; + } +} + +/******************************************************************************* + @fn ll_hw_read_tfifo_packet0 + + @brief This function read a packet form HW Tx FIFO + + input parameters + + @param pkt - packet buffer pointer + + output parameters + + @param None. + + @return length of pkt in 4bytes unit. +*/ +int ll_hw_read_tfifo_packet0(uint8* pkt) +{ + int j, len; + *((uint32_t*)&pkt[0]) = *(volatile uint32_t*)(LL_HW_TFIFO); + uint8_t sp =BLE_HEAD_WITH_CTE(pkt[0]); + len = (pkt[1] + 2 + 3 +sp ) & 0x1fc; //+2 for Header, +3 to get ceil + + for(j = 4; j < len; j += 4) + { + *((uint32_t*)&pkt[j]) = *(volatile uint32_t*)(LL_HW_TFIFO); + } + + return (len >> 2); +} + + +/******************************************************************************* + @fn ll_hw_process_RTO0 + + @brief This function will update the TFIFO last read pointer in receive time out case + + input parameters + + @param ack_num + + output parameters + + @param None. + + @return None. + @Note if receive timeout in 1st connection event and there is data in TFIFO, there should be no + Not-ACK packet. This function not consider this because we will not send data packet in 1st event +*/ +void ll_hw_process_RTO0(uint32 ack_num) +{ + uint32_t tmp; + uint32_t last_rd_addr; + uint32_t current_rd_addr; + int len, i; + // read registers for LL HW status + last_rd_addr = 0; + //current_wr_addr = 0x07ff & ((*(volatile uint32_t *)(LL_HW_BASE + 0x50)) >> 16); + //current_rd_addr = 0x07ff & ((*(volatile uint32_t *)(LL_HW_BASE + 0x50))); // equal last_rd_addr in RTO case + + //*(volatile uint32_t *)0x40030068 = current_rd_addr; + + // 1. get last rd addr + for (i = 0; i < ack_num; i ++) + { + tmp = *(volatile uint32_t*)(LL_HW_BASE + 0x5C); + *(volatile uint32_t*)(LL_HW_BASE + 0x5C) = (tmp & 0x7ff0000) | last_rd_addr; // set rd_cnt_ini as Tx_fifo_rd_addr_last + tmp = *(volatile uint32*)(LL_HW_TFIFO); + len = (tmp >> 8) & 0xff; // length of the packet + len = ((len + 2 + 3 ) >> 2) ; // +2 for Header, +3 to get ceil + last_rd_addr += len ; + } + + // 2. get current rd addr + tmp = *(volatile uint32_t*)(LL_HW_BASE + 0x5C); + *(volatile uint32_t*)(LL_HW_BASE + 0x5C) = (tmp & 0x7ff0000) | last_rd_addr; // set rd_cnt_ini as Tx_fifo_rd_addr_last + tmp = *(volatile uint32*)(LL_HW_TFIFO); + len = (tmp >> 8) & 0xff; // length of the packet + len = ((len + 2 + 3 ) >> 2) ; // +2 for Header, +3 to get ceil + current_rd_addr = last_rd_addr + len; + // set HW read pointer + *(volatile uint32_t*)(LL_HW_BASE + 0x5C) = (last_rd_addr << 16) | current_rd_addr; +} + +/************************************************************************************** + @fn ll_hw_get_tfifo_wrptr + + @brief This function process for HW LL getting tx fifo information + + input parameters + + @param + + output parameters + + @param rdPtr : read pointer. + wrPtr : write pointer + wrDepth: fifo depth can be writen + + @return None. +*/ +uint16_t ll_hw_get_tfifo_wrptr(void) +{ + uint16_t wrPtr; + wrPtr = 0x07ff & ((*(volatile uint32_t*)(LL_HW_BASE + 0x50)) >>16); + return wrPtr; +} + +/************************************************************************************** + @fn ll_hw_get_loop_time + + @brief This function get the loop timeout timer counter + + input parameters + + @param None. + + output parameters + + @param None. + + + + @return loop timer counter. +*/ +uint32_t ll_hw_get_loop_time(void) +{ + return (*(volatile uint32_t*)(LL_HW_BASE + 0x70)); +} + +/************************************************************************************** + @fn ll_hw_get_rfifo_depth + + @brief This function get the HW LL rx fifo depth + + input parameters + + @param + + output parameters + + @param None. + + + + @return Rx FIFO depth(i.e. words available) in 4bytes unit +*/ +int ll_hw_get_rfifo_depth(void) +{ + uint16_t rdPtr, wrPtr; + uint32_t tmp = *(volatile uint32_t*)(LL_HW_BASE + 0x54); + rdPtr = 0x07ff & tmp; + wrPtr = 0x07ff & (tmp>>16); + return ( wrPtr - rdPtr); +} + + + +/******************************************************************************* + @fn ll_adptive_smart_window + + @brief will adptive modified following var to adjust the rx window in RTLP + 1.slave_conn_event_recv_delay + 2.pGlobal_config[LL_HW_RTLP_1ST_TIMEOUT + + input parameters + @param irq_status + @param anchor_point + + output parameters + + @param None + + @return None. +*/ +void ll_adptive_smart_window0(uint32 irq_status,uint32 anchor_point) +{ + if(irq_status & LIRQ_TD ) + { + //tracking anchpoint + if(( irq_status & LIRQ_COK) + && (0== conn_param[g_ll_conn_ctx.currentConn].firstPacket) ) + { + //========================================================== + // when the anchor point change litter, active smartwindow + uint32_t anchPre_anchCurrent; + anchPre_anchCurrent = (g_smartWindowPreAnchPoint>anchor_point) + ? g_smartWindowPreAnchPoint-anchor_point + : anchor_point-g_smartWindowPreAnchPoint; + + if(anchPre_anchCurrent < pGlobal_config[LL_SMART_WINDOW_ACTIVE_RANGE]) + { + g_smartWindowActiveCnt = (g_smartWindowActiveCnt > pGlobal_config[LL_SMART_WINDOW_ACTIVE_THD]) + ? g_smartWindowActiveCnt : g_smartWindowActiveCnt+1; + } + } + else + { + g_smartWindowLater = 0; + g_smartWindowActiveCnt = 0; + } + } + else + { + g_smartWindowLater = 0; + g_smartWindowActiveCnt = 0; + } + + //record the pre anchor point + if(irq_status& LIRQ_TD && irq_status & LIRQ_COK) + { + g_smartWindowPreAnchPoint = anchor_point; + } + + if(g_smartWindowActiveCnt > pGlobal_config[LL_SMART_WINDOW_ACTIVE_THD]) + { + int dlt_anchPoint = anchor_point - pGlobal_config[LL_SMART_WINDOW_TARGET]; + g_smartWindowLater = g_smartWindowLater + (dlt_anchPoint >> pGlobal_config[LL_SMART_WINDOW_COEF_ALPHA]); + slave_conn_event_recv_delay -= g_smartWindowLater; + } + + //------------------------------------------------------------------------------- + //enlarge the RX WINDOW when rxtimeout + if(irq_status & LIRQ_TD ) + { + g_smartWindowRTOCnt = 0; + } + else + { + g_smartWindowRTOCnt = (g_smartWindowRTOCnt > 5) ? g_smartWindowRTOCnt : (g_smartWindowRTOCnt + 1); + } +} + +uint32_t getPN23RandNumber(void) +{ + g_getPn23_cnt++; + uint32_t feedback = ((g_getPn23_seed & (1<<23))>>23) + ((g_getPn23_seed&(1<<18))>>18) & 0x01; + g_getPn23_seed = ((0x007fffff & g_getPn23_seed)<<1) + feedback; + return (g_getPn23_seed); +} + +////////////////////////// +void ll_schedule_next_event(int time) +{ + set_timer(AP_TIM1, time); +} + +void ll_ext_adv_schedule_next_event(int time) +{ + set_timer(AP_TIM4, time); + g_currentAdvTimer = time; + g_currentTimerTask = LL_TASK_EXTENDED_ADV; +} + +void ll_prd_adv_schedule_next_event(int time) +{ + set_timer(AP_TIM4, time); + g_currentAdvTimer = time; + g_currentTimerTask = LL_TASK_PERIODIC_ADV; +} + +void ll_ext_scan_schedule_next_event(int time) +{ + set_timer(AP_TIM4, time); + g_currentTimerTask = LL_TASK_EXTENDED_SCAN; +} + +void ll_prd_scan_schedule_next_event(int time) +{ + set_timer(AP_TIM4, time); + g_currentTimerTask = LL_TASK_PERIODIC_SCAN; +} + +void ll_ext_init_schedule_next_event(int time) +{ + set_timer(AP_TIM4, time); + g_currentTimerTask = LL_TASK_EXTENDED_INIT; +} + +/************************************************************************************** + @fn ll_debug_output + + @brief update the debug state + + input parameters + + @param state - the LL status, the SRAM project will interpret the status and dirve GPIO, UART, memory print, ... + + output parameters + + @param None + + + @return None +*/ +void ll_debug_output(uint32 state) +{ + if (pGlobal_config[LL_SWITCH] & LL_DEBUG_ALLOW) + { + debug_print(state); + } +} + + +///================ for master ======================================= +/******************************************************************************* + @fn move_to_master_function + + @brief LL processing function for transit from init state to master state + + + input parameters + + @param None. + + output parameters + + @param None. + + @return None, + +*/ +void move_to_master_function0(void) +{ + int calibrate; + llConnState_t* connPtr; +// hal_gpio_write(GPIO_P15, 1); + connPtr = &conn_param[initInfo.connId]; +// LOG("move_to_master_function\r\n"); + // set connection parameters + LL_set_default_conn_params(connPtr); + // clear the connection buffer + reset_conn_buf(connPtr->connId); + // configure rx timeout once + ll_hw_set_rx_timeout(268); + initInfo.scanMode = LL_SCAN_STOP; + extInitInfo.scanMode = LL_SCAN_STOP; + // adjust time units to 625us + connPtr->curParam.winSize <<= 1; // in 1.25ms units so convert to 625us + connPtr->curParam.winOffset <<= 1; // in 1.25ms units so convert to 625us + connPtr->curParam.connInterval <<= 1; // in 1.25ms units so convert to 625us + connPtr->curParam.connTimeout <<= 4; // in 10ms units so convert to 625us + // convert the LSTO from time to an expiration connection event count + llConvertLstoToEvent( connPtr, &connPtr->curParam ); + // set the expiration connection event count to a specified limited number + // Note: This is required in case the Master never sends that first packet. + connPtr->expirationEvent = LL_LINK_SETUP_TIMEOUT; + // convert the Control Procedure timeout into connection event count + llConvertCtrlProcTimeoutToEvent( connPtr ); +// // calculate channel for data +// llProcessChanMap(&conn_param[connId], conn_param[connId].chanMap ); + // need? +// connPtr->slaveLatency = connPtr->curParam.slaveLatency ; +// connPtr->slaveLatencyValue = connPtr->curParam.slaveLatency; + connPtr->currentEvent = 0; + connPtr->nextEvent = 0; + connPtr->active = 1; + connPtr->sn_nesn = 0; // 1st rtlp, init sn/nesn as 0 + connPtr->llMode = LL_HW_TRLP; // set as RTLP_1ST for the 1st connection event + connPtr->currentChan = 0; + + if (connPtr->channel_selection == LL_CHN_SEL_ALGORITHM_1) + connPtr->currentChan = llGetNextDataChan(connPtr, 1); + else + { + // channel selection algorithm 2 + connPtr->currentChan = llGetNextDataChanCSA2(0, + (( connPtr->accessAddr & 0xFFFF0000 )>> 16 ) ^ ( connPtr->accessAddr & 0x0000FFFF), + connPtr->chanMap, + connPtr->chanMapTable, + connPtr->numUsedChans); + } + + llState = LL_STATE_CONN_MASTER; + llSecondaryState = LL_SEC_STATE_IDLE; // add for multi-connection + // wait to the next event start + calibrate = pGlobal_config[LL_MOVE_TO_MASTER_DELAY]; + uint32 schedule_time; + +// margin = 2500; + // get current allocate ID delta time to ID 0 + if (g_ll_conn_ctx.currentConn != LL_INVALID_CONNECTION_ID) + { + schedule_time = g_new_master_delta;// * 625; // delta timing to previous connection slot + ll_addTask(connPtr->connId, schedule_time); // shcedule new connection + g_ll_conn_ctx.scheduleInfo[connPtr->connId].task_duration = 2700; // master task duration + + // current link id may be updated in ll_addTask, update the ll state + if (g_ll_conn_ctx.scheduleInfo[g_ll_conn_ctx.currentConn].linkRole == LL_ROLE_MASTER) + llState = LL_STATE_CONN_MASTER; + else if (g_ll_conn_ctx.scheduleInfo[g_ll_conn_ctx.currentConn].linkRole == LL_ROLE_SLAVE) + llState = LL_STATE_CONN_SLAVE; + } + else // 1st connection + { + schedule_time = 1250 + connPtr->curParam.winOffset * 625 + 352 + calibrate;// 352(us): CONN_REQ duration + ll_addTask(connPtr->connId, schedule_time); + g_ll_conn_ctx.scheduleInfo[connPtr->connId].task_duration = 2700; // master task duration + + // current link id may be updated in ll_addTask, update the ll state + if (g_ll_conn_ctx.scheduleInfo[g_ll_conn_ctx.currentConn].linkRole == LL_ROLE_MASTER) + llState = LL_STATE_CONN_MASTER; + else if (g_ll_conn_ctx.scheduleInfo[g_ll_conn_ctx.currentConn].linkRole == LL_ROLE_SLAVE) + llState = LL_STATE_CONN_SLAVE; + } + + g_ll_conn_ctx.scheduleInfo[connPtr->connId].linkRole = LL_ROLE_MASTER; + (void)osal_set_event( LL_TaskID, LL_EVT_MASTER_CONN_CREATED ); + g_pmCounters.ll_conn_succ_cnt ++; +// hal_gpio_write(GPIO_P15, 0); +// LOG("M2M "); +} + +void llWaitUs(uint32_t wtTime); +/******************************************************************************* + @fn LL_master_conn_event + + @brief This function process master connection event + + + input parameters + + @param None. + + output parameters + + @param None. + + @return None, + +*/ +void LL_master_conn_event0(void) +{ + uint16_t ll_rdCntIni; + uint32_t tx_num, rx_num; + uint32_t temp; + uint32_t T1, T2, delta; + llConnState_t* connPtr; + T1 = read_current_fine_time(); + + if (llWaitingIrq) + g_pmCounters.ll_tbd_cnt3++; + + connPtr = &conn_param[g_ll_conn_ctx.currentConn]; +// hal_gpio_write(GPIO_P18, 1); + // time critical process, disable interrupt + HAL_ENTER_CRITICAL_SECTION(); + g_ll_conn_ctx.timerExpiryTick = T1; // A2 multiconnection +//#ifdef MULTI_ROLE +//#else +// schedule_time = ll_get_next_timer(g_ll_conn_ctx.currentConn); +// +// // next TRLP event start, 10 for timer ISR delay --> to evaluate changing it to periodic timer? NO for multi-connection reason +//// ll_schedule_next_event(connPtr->curParam.connInterval * 625 - 20); // 10us: rough delay from timer expire to here +// ll_schedule_next_event(schedule_time - 10); +//#endif +// + connPtr->pmCounter.ll_conn_event_cnt ++; + + if(p_perStatsByChan!=NULL) + p_perStatsByChan->connEvtCnt[connPtr->currentChan]++; + + tx_num = pGlobal_config[LL_TX_PKTS_PER_CONN_EVT]; + rx_num = pGlobal_config[LL_RX_PKTS_PER_CONN_EVT]; + + if (tx_num > g_maxPktPerEventTx || tx_num == 0) tx_num = g_maxPktPerEventTx; + + if (rx_num > g_maxPktPerEventRx || rx_num == 0) rx_num = g_maxPktPerEventRx; + + // counter for one connection event + llResetRfCounters(); + //support rf phy change + rf_phy_change_cfg(connPtr->llRfPhyPktFmt); + ll_hw_tx2rx_timing_config(connPtr->llRfPhyPktFmt); + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + // channel physical configuration + set_crc_seed(connPtr->initCRC ); // crc seed for data PDU is from CONNECT_REQ + set_access_address(connPtr->accessAddr); // access address + set_channel(connPtr->currentChan ); // set channel + set_whiten_seed(connPtr->currentChan); // set whiten seed + // A2 multi-conn + ll_hw_set_rx_timeout(88); + ll_hw_set_rx_timeout_1st(88); +// set_max_length(40); + set_max_length(0xff); + // configure loop timeout + temp = connPtr->curParam.connInterval * 625 - connPtr->llPduLen.local.MaxRxTime - pGlobal_config[LL_HW_TRLP_TO_GAP]; // 500us: margin for timer1 IRQ + temp = temp >> 3; // maximum 8 connections, HZF + ll_hw_set_loop_timeout(temp > pGlobal_config[LL_HW_TRLP_LOOP_TIMEOUT] ? + pGlobal_config[LL_HW_TRLP_LOOP_TIMEOUT] : temp); // 2018-6-20, global config for the parameter + // retransmit count limit + ll_hw_set_loop_nack_num( 4 ); + //set the rfifo ign control + ll_hw_ign_rfifo(LL_HW_IGN_ALL); + // write packets to Tx FIFO + tx_num = ll_generateTxBuffer(tx_num, &ll_rdCntIni); + // config TRLP + ll_hw_config( LL_HW_TRLP,//conn_param[connId].llMode, // LL HW logical mode + connPtr->sn_nesn, // sn,nesn init + tx_num, // ll_txNum + rx_num, // ll_rxNum + 1, // ll_mdRx + 0); // rdCntIni + T2 = read_current_fine_time(); + delta = LL_TIME_DELTA(T1, T2); // software process delay + delta += pGlobal_config[LL_MASTER_TIRQ_DELAY]; // compensate the timer IRQ pending -> timer ISR delay + temp = (pGlobal_config[LL_MASTER_PROCESS_TARGET] > delta) ? (pGlobal_config[LL_MASTER_PROCESS_TARGET] - delta) : 0; + llWaitUs(temp); // insert delay to make process time equal PROCESS_TARGET + ll_hw_trx_settle_config(connPtr->llRfPhyPktFmt); + uint8 temp_rf_fmt = g_rfPhyPktFmt; + g_rfPhyPktFmt = connPtr->llRfPhyPktFmt; + // start LL HW engine + ll_hw_go(); + g_rfPhyPktFmt = temp_rf_fmt; + llWaitingIrq = TRUE; +// hal_gpio_write(GPIO_P18, 0); + HAL_EXIT_CRITICAL_SECTION(); +// LOG("%d-%d ", g_ll_conn_ctx.numLLConns, g_ll_conn_ctx.currentConn); +// LOG("%d ", g_ll_conn_ctx.currentConn); +// LOG(" %d> ", schedule_time); + ll_debug_output(DEBUG_LL_HW_SET_TRLP); +} + +// ======================== scan back off process function +/******************************************************************************* + @fn llAdjBoffUpperLimitSuccess + + @brief This function is used to handle the calculation of the Scan + backoff counter upper limit based on the number of successfully + received Scan Responses to our Scan Requests. When two + consecutive Scan Responses are successfully received, the upper + limit of the Scan backoff counter is halfed (but no less than + one). + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +static void llAdjBoffUpperLimitSuccess( void ) +{ + // first, since this is a success, clear the number of consecutive failures + scanInfo.numFailure = 0; + + // check if we received two successful in a row + if ( ++scanInfo.numSuccess == 2 ) + { + // yes, so half backoff upper limit + scanInfo.scanBackoffUL >>= 1; + + // however, the minimum is 1 + if ( scanInfo.scanBackoffUL == 0 ) + { + scanInfo.scanBackoffUL = 1; + } + + // reset consecutive count + scanInfo.numSuccess = 0; + } + + return; +} + + +/******************************************************************************* + @fn llAdjBoffUpperLimitFailure + + @brief This function is used to handle the calculation of the Scan + backoff counter upper limit based on the number of failured to + receive Scan Responses to our Scan Requests. When two + consecutive Scan Responses fail to be received, the upper + limit of the Scan backoff counter is doubled (but no more than + 256). + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +static void llAdjBoffUpperLimitFailure( void ) +{ + // first, since this was a failure, clear the number of consecutive successes + scanInfo.numSuccess = 0; + + // check if we received two failures in a row + if ( ++scanInfo.numFailure == 2 ) + { + // yes, so double backoff upper limit + scanInfo.scanBackoffUL <<= 1; + + // maximum is 256 + if ( scanInfo.scanBackoffUL > 256 ) + { + scanInfo.scanBackoffUL = 256; + } + + // reset consecutive count + scanInfo.numFailure = 0; + } + + g_pmCounters.ll_tbd_cnt4++; + return; +} + + +/******************************************************************************* + @fn llGenerateNextBackoffCount + + @brief This function is used to find the next Scan backoff + count which determines when the next Scan Request will be sent + when the appropriate Adv packet is correctly received. The + backoff count is just to limit collisions. The backoff count + is randomly generated, but must be between 1 and the backoff + count upper limit (max 256). The upper limit changes based on + the number of consecutive successful or failed Scan Responses. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +static void llGenerateNextBackoffCount( void ) +{ + // determine the new backoff count constrained by upper limit + // Note: Backoff and Upper Limit can be 1..256. + if ( scanInfo.scanBackoffUL == 1 ) + { + scanInfo.currentBackoff = 1; + } + else // backoff count is a random number from 1..UL + { + scanInfo.currentBackoff = ((uint16)LL_ENC_GeneratePseudoRandNum() % scanInfo.scanBackoffUL) + 1; + } + +// hal_uart_tx("scanBackoffUL = "); +// hal_uart_send_int(scanInfo.scanBackoffUL); +// hal_uart_tx(",currentBackoff = "); +// hal_uart_send_int(scanInfo.currentBackoff); +// hal_uart_tx("\r\n"); + return; +} + +// =============================== + +void llWaitUs(uint32_t wtTime) +{ + uint32_t T1, T2, deltTick; + + if (wtTime == 0) + return; + + T1 = read_current_fine_time(); + + while(1) + { + T2 = read_current_fine_time(); + deltTick = (T2 >= T1) ? (T2 - T1) : (BASE_TIME_UNITS - T1 + T2); + + if(deltTick > wtTime) + break; + } +} + +uint8_t* LL_PLUS_GetAdvDataExtendData(void) +{ +// llConnState_t *connPtr; +// connPtr = &conn_param[0]; + return((uint8_t*)&g_rx_adv_buf.data[0]); +} + +void LL_PLUS_SetAdvDataFilterCB(LL_PLUS_AdvDataFilterCB_t AdvDataFilterCBack) +{ + LL_PLUS_AdvDataFilterCBack=AdvDataFilterCBack; +} + +void LL_PLUS_SetScanRequestData(uint8 dLen, uint8* pData) +{ +// llConnState_t *connPtr; + +// connPtr = &conn_param[0]; + for(int i=0; i>8)-12; + + for(uint8 i=0; irxNumPkts =p_perStatsByChan->rxNumPkts[chnId]; + perStats->rxNumCrcErr =p_perStatsByChan->rxNumCrcErr[chnId]; + perStats->txNumRetry =p_perStatsByChan->txNumRetry[chnId]; + perStats->TxNumAck =p_perStatsByChan->TxNumAck[chnId]; + perStats->rxToCnt =p_perStatsByChan->rxToCnt[chnId]; + perStats->connEvtCnt =p_perStatsByChan->connEvtCnt[chnId]; + } +} + +void ll_hw_tx2rx_timing_config(uint8 pkt) +{ + if(pkt==PKT_FMT_BLE1M) + { + ll_hw_set_rx_tx_interval( pGlobal_config[LL_HW_Rx_TO_TX_INTV]); //T_IFS=150us for BLE 1M + ll_hw_set_tx_rx_interval( pGlobal_config[LL_HW_Tx_TO_RX_INTV]); //T_IFS=150us for BLE 1M + } + else if(pkt==PKT_FMT_BLE2M) + { + ll_hw_set_rx_tx_interval( pGlobal_config[LL_HW_Rx_TO_TX_INTV_2MPHY]); //T_IFS=150us for BLE 1M + ll_hw_set_tx_rx_interval( pGlobal_config[LL_HW_Tx_TO_RX_INTV_2MPHY]); + } + else if(pkt==PKT_FMT_BLR500K) + { + ll_hw_set_rx_tx_interval( pGlobal_config[LL_HW_Rx_TO_TX_INTV_500KPHY]); //T_IFS=150us for BLE 1M + ll_hw_set_tx_rx_interval( pGlobal_config[LL_HW_Tx_TO_RX_INTV_500KPHY]); + } + else + { + ll_hw_set_rx_tx_interval( pGlobal_config[LL_HW_Rx_TO_TX_INTV_125KPHY]); //T_IFS=150us for BLE 1M + ll_hw_set_tx_rx_interval( pGlobal_config[LL_HW_Tx_TO_RX_INTV_125KPHY]); + } +} + +void ll_hw_trx_settle_config(uint8 pkt) +{ + if(pkt==PKT_FMT_BLE1M) + { + ll_hw_set_trx_settle(pGlobal_config[LL_HW_BB_DELAY], + pGlobal_config[LL_HW_AFE_DELAY], + pGlobal_config[LL_HW_PLL_DELAY]); // TxBB, RxAFE, PLL + } + else if(pkt==PKT_FMT_BLE2M) + { + ll_hw_set_trx_settle(pGlobal_config[LL_HW_BB_DELAY_2MPHY], + pGlobal_config[LL_HW_AFE_DELAY_2MPHY], + pGlobal_config[LL_HW_PLL_DELAY_2MPHY]); // TxBB, RxAFE, PLL + } + else if(pkt==PKT_FMT_BLR500K) + { + ll_hw_set_trx_settle(pGlobal_config[LL_HW_BB_DELAY_500KPHY], + pGlobal_config[LL_HW_AFE_DELAY_500KPHY], + pGlobal_config[LL_HW_PLL_DELAY_500KPHY]); // TxBB, RxAFE, PLL + } + else + { + ll_hw_set_trx_settle(pGlobal_config[LL_HW_BB_DELAY_125KPHY], + pGlobal_config[LL_HW_AFE_DELAY_125KPHY], + pGlobal_config[LL_HW_PLL_DELAY_125KPHY]); // TxBB, RxAFE, PLL + } +} + + +// multi-connection +/******************************************************************************* + @fn llSetupSecAdvEvt0 + + @brief This function process for Nonconnectable Advertising. + + input parameters + + @param None. + + output parameters + + @param None. + + @return uint8 - TRUE(send success), FALSE(send fail). +*/ +uint8 llSetupSecAdvEvt0( void ) +{ + uint8 ret = FALSE; + + if (llState == LL_STATE_IDLE) + { + if (adv_param.advEvtType == LL_ADV_CONNECTABLE_UNDIRECTED_EVT) + llState = LL_STATE_ADV_UNDIRECTED; + else if (adv_param.advEvtType == LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT) + llState = LL_STATE_ADV_NONCONN; + else if (adv_param.advEvtType == LL_ADV_SCANNABLE_UNDIRECTED_EVT) + llState = LL_STATE_ADV_SCAN; + + llSetupAdv(); + llSecondaryState = LL_SEC_STATE_IDLE; + return TRUE; + } + + if (adv_param.advEvtType == LL_ADV_CONNECTABLE_UNDIRECTED_EVT) + ret = llSetupSecConnectableAdvEvt(); + else if (adv_param.advEvtType == LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT) + ret = llSetupSecNonConnectableAdvEvt(); + else if (adv_param.advEvtType == LL_ADV_SCANNABLE_UNDIRECTED_EVT) + ret = llSetupSecScannableAdvEvt(); + else + return FALSE; // other type adv should not here + + return ret; +} + +/******************************************************************************* + @fn llSetupSecConnectableAdvEvt + + @brief This function process for set up sec undirect Advertising. + + input parameters + + @param None. + + output parameters + + @param None. + + @return uint8 - TRUE(send success), FALSE(send fail). +*/ +uint8 llSetupSecConnectableAdvEvt0( void ) +{ + uint32_t ch_idx; + // Hold off interrupts. + HAL_ENTER_CRITICAL_SECTION( ); + + if (llWaitingIrq) + { + g_pmCounters.ll_tbd_cnt1++; + HAL_EXIT_CRITICAL_SECTION( ); + return FALSE; + } + + // next adv channel invalid, get 1st adv chn + if (adv_param.advNextChan > LL_ADV_CHAN_LAST || adv_param.advNextChan < LL_ADV_CHAN_FIRST) + adv_param.advNextChan = llGetNextAdvChn(0); // get 1st adv chn + + ch_idx = adv_param.advNextChan; + adv_param.advNextChan = llGetNextAdvChn(adv_param.advNextChan); + //============== configure and trigger LL HW engine, LL HW work in Single Tx mode ================== + set_crc_seed(ADV_CRC_INIT_VALUE); // crc seed for adv is same for all channels + set_access_address(ADV_SYNCH_WORD); // access address + set_channel(ch_idx); // channel + set_whiten_seed(ch_idx); // whiten seed + set_max_length(0xff); // rx PDU max length + ll_hw_set_trx_settle(pGlobal_config[LL_HW_BB_DELAY_ADV], + pGlobal_config[LL_HW_AFE_DELAY_ADV], + pGlobal_config[LL_HW_PLL_DELAY_ADV]); //TxBB,RxAFE,PLL + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + ll_hw_set_trx(); // set LL HW as Tx - Rx mode + ll_hw_ign_rfifo(LL_HW_IGN_EMP | LL_HW_IGN_CRC); //set the rfifo ign control + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(g_tx_adv_buf.txheader), ((g_tx_adv_buf.txheader & 0xff00) >> 8) + 2); + ll_hw_go(); + llWaitingIrq = TRUE; + HAL_EXIT_CRITICAL_SECTION( ); + g_pmCounters.ll_send_conn_adv_cnt ++; // adv in conn state counter + g_pmCounters.ll_send_undirect_adv_cnt ++; + #ifdef DEBUG_LL + LOG("c%d ", ch_idx); + #endif + return TRUE; +} /* end of function */ + + +/******************************************************************************* + @fn llSetupSecScannableAdvEvt0 + + @brief This function process for setup scannable Advertising. + + input parameters + + @param None. + + output parameters + + @param None. + + @return uint8 - TRUE(send success), FALSE(send fail). +*/ +uint8 llSetupSecScannableAdvEvt0( void ) +{ + uint32_t ch_idx; + // Hold off interrupts. + HAL_ENTER_CRITICAL_SECTION( ); + + if (llWaitingIrq) + { + g_pmCounters.ll_tbd_cnt1++; // to update the conuter name + HAL_EXIT_CRITICAL_SECTION( ); + return FALSE; + } + + // next adv channel invalid, get 1st adv chn + if (adv_param.advNextChan > LL_ADV_CHAN_LAST || adv_param.advNextChan < LL_ADV_CHAN_FIRST) + adv_param.advNextChan = llGetNextAdvChn(0); // get 1st adv chn + + ch_idx = adv_param.advNextChan; + adv_param.advNextChan = llGetNextAdvChn(adv_param.advNextChan); + //============== configure and trigger LL HW engine, LL HW work in Single Tx mode ================== + set_crc_seed(ADV_CRC_INIT_VALUE); // crc seed for adv is same for all channels + set_access_address(ADV_SYNCH_WORD); // access address + set_channel(ch_idx); // channel + set_whiten_seed(ch_idx); // whiten seed + set_max_length(0xff); // rx PDU max length + ll_hw_set_trx_settle(pGlobal_config[LL_HW_BB_DELAY_ADV], + pGlobal_config[LL_HW_AFE_DELAY_ADV], + pGlobal_config[LL_HW_PLL_DELAY_ADV]); //TxBB,RxAFE,PLL + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + ll_hw_set_trx(); // set LL HW as Tx - Rx mode + ll_hw_ign_rfifo(LL_HW_IGN_EMP | LL_HW_IGN_CRC); //set the rfifo ign control + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(g_tx_adv_buf.txheader), ((g_tx_adv_buf.txheader & 0xff00) >> 8) + 2); + ll_hw_go(); + llWaitingIrq = TRUE; + HAL_EXIT_CRITICAL_SECTION( ); + g_pmCounters.ll_send_conn_adv_cnt ++; // adv in conn state counter + g_pmCounters.ll_send_scan_adv_cnt ++; + #ifdef DEBUG_LL + LOG("c%d ", ch_idx); + #endif + return TRUE; +} /* end of function */ + + +// add in A2 +/******************************************************************************* + @fn llSetupSecNonConnectableAdvEvt + + @brief This function process for Nonconnectable Advertising. + + input parameters + + @param None. + + output parameters + + @param None. + + @return uint8 - TRUE(send success), FALSE(send fail). +*/ +uint8 llSetupSecNonConnectableAdvEvt0( void ) +{ + uint32_t ch_idx; + // Hold off interrupts. + HAL_ENTER_CRITICAL_SECTION( ); + + if (llWaitingIrq) + { + g_pmCounters.ll_tbd_cnt1++; + HAL_EXIT_CRITICAL_SECTION(); + return FALSE; + } + + // next adv channel invalid, get 1st adv chn + if (adv_param.advNextChan > LL_ADV_CHAN_LAST || adv_param.advNextChan < LL_ADV_CHAN_FIRST) + adv_param.advNextChan = llGetNextAdvChn(0); // get 1st adv chn + + ch_idx = adv_param.advNextChan; + adv_param.advNextChan = llGetNextAdvChn(adv_param.advNextChan); + //============== configure and trigger LL HW engine, LL HW work in Single Tx mode ================== + set_crc_seed(ADV_CRC_INIT_VALUE); // crc seed for adv is same for all channels + set_access_address(ADV_SYNCH_WORD); // access address + set_channel(ch_idx); // channel + set_whiten_seed(ch_idx); // whiten seed + set_max_length(0xff); // rx PDU max length + ll_hw_set_trx_settle(pGlobal_config[LL_HW_BB_DELAY_ADV], + pGlobal_config[LL_HW_AFE_DELAY_ADV], + pGlobal_config[LL_HW_PLL_DELAY_ADV]); //TxBB,RxAFE,PLL + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + ll_hw_set_stx(); // set LL HW as Tx - Rx mode + ll_hw_ign_rfifo(LL_HW_IGN_ALL); //set the rfifo ign control + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(g_tx_adv_buf.txheader), ((g_tx_adv_buf.txheader & 0xff00) >> 8) + 2); + ll_hw_go(); + llWaitingIrq = TRUE; + HAL_EXIT_CRITICAL_SECTION(); + g_pmCounters.ll_send_conn_adv_cnt ++; // adv in conn state counter + g_pmCounters.ll_send_nonconn_adv_cnt ++; + #ifdef DEBUG_LL + LOG("nc%d ", ch_idx); + #endif + return TRUE; +} /* end of function */ + +/******************************************************************************* + @fn llSecAdvAllow + + @brief Decision the remain time to next LL conn interval is enough + for no_conn adv, consider the time for no conn advertisement + in channel 37/38/39. Plus some margin. + + + + input parameters + + @param None. + + output parameters + + @param None. + + @return TRUE: Secondary advertisement allow + FALSE: Secondary advertisement NOT allow +*/ +uint8 llSecAdvAllow0(void) +{ + uint32 advTime, margin; + uint32 remainTime; + uint8 ret = FALSE; + // Hold off interrupts. + HAL_ENTER_CRITICAL_SECTION( ); + // read global config to get advTime and margin + advTime = pGlobal_config[LL_NOCONN_ADV_EST_TIME]; + margin = pGlobal_config[LL_NOCONN_ADV_MARGIN]; + // remain time before trigger LL HW + remainTime = read_LL_remainder_time(); + + if ((remainTime > advTime + margin) + && !llWaitingIrq) + ret = TRUE; + else + { + llSecondaryState = LL_SEC_STATE_ADV_PENDING; + g_pmCounters.ll_conn_adv_pending_cnt ++; + } + + HAL_EXIT_CRITICAL_SECTION(); + return ret; +} + +/******************************************************************************* + @fn llCalcMaxScanTime + + @brief Decide the maximum scan time, consider remain time and + the margin + + + input parameters + + @param None. + + output parameters + + @param None. + + @return allow maximum scan time in us + +*/ +uint32 llCalcMaxScanTime0(void) +{ + uint32 margin, scanTime; + uint32 remainTime; + margin = pGlobal_config[LL_SEC_SCAN_MARGIN]; + // Hold off interrupts. + HAL_ENTER_CRITICAL_SECTION( ); + // remain time before trigger LL HW + remainTime = read_LL_remainder_time(); + scanTime = 0; + + if (remainTime > margin + pGlobal_config[LL_MIN_SCAN_TIME] + && !llWaitingIrq) + scanTime = remainTime - margin; + + HAL_EXIT_CRITICAL_SECTION(); + return (scanTime); +} + +/******************************************************************************* + @fn llSetupSecScan + + @brief This function readies the device as a Scanner. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void llSetupSecScan0( uint8 chan ) +{ + uint32 scanTime; + // Hold off interrupts. + HAL_ENTER_CRITICAL_SECTION( ); + scanTime = scanInfo.scanWindow * 625; + +// if(llWaitingIrq) +// { +// LOG("==== error, mode: %d\n", scanInfo.scanMode); +// } + + if (llState == LL_STATE_IDLE) + { + llState = LL_STATE_SCAN; + llSecondaryState = LL_SEC_STATE_IDLE; + } + else + { + // calculate scan time + scanTime = llCalcMaxScanTime(); + + if (scanTime) // trigger scan + { + llSecondaryState = LL_SEC_STATE_SCAN; + } + else // no enough time to scan, pending + { + llSecondaryState = LL_SEC_STATE_SCAN_PENDING; + g_pmCounters.ll_conn_scan_pending_cnt ++; + HAL_EXIT_CRITICAL_SECTION( ); + return; + } + } + + if (scanTime > scanInfo.scanWindow * 625) + scanTime = scanInfo.scanWindow * 625; + + // reset all FIFOs; all data is forfeit + ll_hw_rst_tfifo(); + ll_hw_rst_rfifo(); + set_crc_seed(ADV_CRC_INIT_VALUE); // crc seed for adv is same for all channels + set_access_address(ADV_SYNCH_WORD); + set_channel(chan); + set_whiten_seed(chan); + set_max_length(0xff); + ll_hw_set_rx_timeout(scanTime); // maximum scan time, note that actual scan time may exceed the limit if timer expiry when LL engine receiving a report + ll_hw_set_srx(); + ll_hw_ign_rfifo(LL_HW_IGN_CRC|LL_HW_IGN_EMP); + ll_hw_go(); + llScanT1 = read_current_fine_time(); + llWaitingIrq = TRUE; + HAL_EXIT_CRITICAL_SECTION(); +// uint32 remainTime = read_LL_remainder_time(); +// LOG("<%d %d>", scanTime, remainTime); + return; +} + + +/******************************************************************************* + @fn llSetupSecInit + + @brief This function readies the device as a Scanner. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void llSetupSecInit( uint8 chan ) +{ + uint32 scanTime; + // Hold off interrupts. + HAL_ENTER_CRITICAL_SECTION( ); + scanTime = scanInfo.scanWindow * 625; + + if (llState == LL_STATE_IDLE) + { + llState = LL_STATE_INIT; + llSecondaryState = LL_SEC_STATE_IDLE; + } + else + { + // calculate scan time + scanTime = llCalcMaxScanTime(); + + if (scanTime) // trigger scan + { + llSecondaryState = LL_SEC_STATE_INIT; + } + else // no enough time to scan, pending + { + llSecondaryState = LL_SEC_STATE_INIT_PENDING; +// g_pmCounters.ll_conn_scan_pending_cnt ++; + HAL_EXIT_CRITICAL_SECTION( ); + return; + } + } + + if (scanTime > initInfo.scanWindow * 625) + scanTime = initInfo.scanWindow * 625; + + // reset all FIFOs; all data is forfeit + ll_hw_rst_tfifo(); + ll_hw_rst_rfifo(); + set_crc_seed(ADV_CRC_INIT_VALUE); // crc seed for adv is same for all channels + set_access_address(ADV_SYNCH_WORD); + set_channel(chan); + set_whiten_seed(chan); + set_max_length(0xff); + // A2 multi-conn + ll_hw_set_rx_timeout(88); +// ll_hw_set_rx_timeout_1st(88); + ll_hw_set_rx_timeout(scanTime); // maximum scan time, note that actual scan time may exceed the limit if timer expiry when LL engine receiving a report + ll_hw_set_srx(); + ll_hw_ign_rfifo(LL_HW_IGN_CRC|LL_HW_IGN_EMP); + ll_hw_go(); + llScanT1 = read_current_fine_time(); +//hal_gpio_write(GPIO_P18, 1); + llWaitingIrq = TRUE; + HAL_EXIT_CRITICAL_SECTION( ); + return; +} + +uint8_t ll_get_next_active_conn(uint8_t current_conn_id) +{ + int i; + uint8_t next_conn_id = LL_INVALID_CONNECTION_ID; + + if (g_ll_conn_ctx.numLLConns != 0) + { + // get next active connection as current connection + i = current_conn_id + 1; + + while (i < g_maxConnNum) + { + if (conn_param[i].active == TRUE) + break; + + i ++; + } + + if (i != g_maxConnNum) + next_conn_id = i; + else + { + for (i = 0; i <= current_conn_id; i ++) + { + if (conn_param[i].active == TRUE) + break; + } + + if (i != current_conn_id + 1) + next_conn_id = i; + } + } + else + return LL_INVALID_CONNECTION_ID; + + return next_conn_id; +} + +uint32 ll_get_next_timer(uint8 current_conn_id) +{ + uint8 next; + uint32 timer; + next = ll_get_next_active_conn(current_conn_id); + + if (next == LL_INVALID_CONNECTION_ID) + return 0; + + timer = (next > current_conn_id) ? + ((next - current_conn_id) * g_ll_conn_ctx.per_slot_time * 625) : + (((g_ll_conn_ctx.connInterval << 1) - (current_conn_id - next) * g_ll_conn_ctx.per_slot_time) * 625); + return timer; +} +//#pragma O0 + + +/******************************************************************************* + @fn ll_scheduler + + @brief schedule next task, if current connection will be free, input + parameter should be LL_INVALID_TIME. The function is invoked + after old connection task end, it will not add new task but may + delete exist task + + input parameters + + @param time - schedule time for current connection + + output parameters + + @param None. + + @return None. +*/ +void ll_scheduler0(uint32 time) +{ + uint32 T1, T2, delta, min, prio_adj; + uint8 i, next, temp; + T1 = read_current_fine_time(); + + // timer1 is running, normally it should not occur + if (isTimer1Running()) + { +// LOG("=== ASSERT FAIL, timer1 running when invoke ll_scheduler ===\n"); + g_pmCounters.ll_evt_shc_err++; + return; + } + + // if timer1 is not running, calculate the time elapse since last timer expiry + delta = g_ll_conn_ctx.current_timer + LL_TIME_DELTA(g_ll_conn_ctx.timerExpiryTick, T1) + pGlobal_config[TIMER_ISR_ENTRY_TIME]; + // update current context + g_ll_conn_ctx.scheduleInfo[g_ll_conn_ctx.currentConn].remainder = time; // if current conn terminal, the parameter "time" shall be LL_INVALID_TIME + min = time; + + if (time == LL_INVALID_TIME) + { + ll_deleteTask(g_ll_conn_ctx.currentConn); + g_ll_conn_ctx.currentConn = LL_INVALID_CONNECTION_ID; + } + + next = g_ll_conn_ctx.currentConn; + + if (next != LL_INVALID_CONNECTION_ID) + { + // if we want master or slave connection has higher schedule priority, set LL_MASTER_PREEMPHASIS/LL_SLAVE_PREEMPHASIS + if (g_ll_conn_ctx.scheduleInfo[next].linkRole == LL_ROLE_MASTER) + min = (time > pGlobal_config[LL_MULTICONN_MASTER_PREEMP]) ? (time - pGlobal_config[LL_MULTICONN_MASTER_PREEMP]) : 0; + + if (g_ll_conn_ctx.scheduleInfo[next].linkRole == LL_ROLE_SLAVE) + min = (time > pGlobal_config[LL_MULTICONN_SLAVE_PREEMP]) ? (time - pGlobal_config[LL_MULTICONN_SLAVE_PREEMP]) : 0; + } + + // update schedule task list and get the earliest task + for (i = 0; i < g_maxConnNum; i++) + { + if ((i != g_ll_conn_ctx.currentConn) && conn_param[i].active) + { + // task conflict process + // if there is no enough time for new task, invoke relate slave/master conn event process function +// if (g_ll_conn_ctx.scheduleInfo[i].remainder < delta + g_ll_conn_ctx.scheduleInfo[i].task_duration) + if (g_ll_conn_ctx.scheduleInfo[i].remainder < delta + 40) // 40 : margin for process delay, unit: us + { + // no enough time to process the event, regard the event as missed and update the conn context and timer + uint8 ret = LL_PROC_LINK_KEEP; + + if (g_ll_conn_ctx.scheduleInfo[i].linkRole == LL_ROLE_MASTER) + { + // temporary update g_ll_conn_ctx.currentConn to current connection ID because + // ll_processMissMasterEvt will invoke function using global variable g_ll_conn_ctx.currentConn + temp = g_ll_conn_ctx.currentConn; + g_ll_conn_ctx.currentConn = i; + ret = ll_processMissMasterEvt(i); + g_ll_conn_ctx.currentConn = temp; + } + else if (g_ll_conn_ctx.scheduleInfo[i].linkRole == LL_ROLE_SLAVE) + { + // TODO: add by Zhangzhufei for Huapu, to check + // temporary update g_ll_conn_ctx.currentConn to current connection ID because + // ll_processMissSlaveEvt will invoke function using global variable g_ll_conn_ctx.currentConn + temp = g_ll_conn_ctx.currentConn; + g_ll_conn_ctx.currentConn = i; + + if( delta > g_ll_conn_ctx.scheduleInfo[i].remainder ) + { + llConnState_t* connPtr = &conn_param[i]; + uint8 missCE = (( delta - g_ll_conn_ctx.scheduleInfo[i].remainder ) / connPtr->curParam.connInterval ) + 1; + + for( uint8 misI = 0; misI < missCE ; misI++) + ll_processMissSlaveEvt(i); + } + else + { + ret = ll_processMissSlaveEvt(i); + } + + g_ll_conn_ctx.currentConn = temp; + } + + if (ret == LL_PROC_LINK_TERMINATE) // the connection is terminated, update shcedule information. + { + ll_deleteTask(i); + continue; // continue next link + } + + // increase the task priority + g_ll_conn_ctx.scheduleInfo[i].priority ++; + + if (g_ll_conn_ctx.scheduleInfo[i].priority == LL_SCH_PRIO_LAST) + g_ll_conn_ctx.scheduleInfo[i].priority = LL_SCH_PRIO_IMMED; + } + + prio_adj =0; + + if (min != LL_INVALID_TIME) + { + // consider the task prioriy + switch (g_ll_conn_ctx.scheduleInfo[i].priority) + { + case LL_SCH_PRIO_LOW: + prio_adj = 0; + break; + + case LL_SCH_PRIO_MED: + prio_adj = MAX(LL_TASK_MASTER_DURATION, LL_TASK_SLAVE_DURATION) + 2000; + break; + + case LL_SCH_PRIO_HIGH: + prio_adj = MAX(LL_TASK_MASTER_DURATION, LL_TASK_SLAVE_DURATION) + 10 + 2000; + break; + + case LL_SCH_PRIO_IMMED: + prio_adj = MAX(LL_TASK_MASTER_DURATION, LL_TASK_SLAVE_DURATION) + 20 + 2000; + break; + + default: + prio_adj = 0; + break; + } + + if (g_ll_conn_ctx.scheduleInfo[i].linkRole == LL_ROLE_MASTER) + prio_adj += pGlobal_config[LL_MULTICONN_MASTER_PREEMP]; + + if (g_ll_conn_ctx.scheduleInfo[i].linkRole == LL_ROLE_SLAVE) + prio_adj += pGlobal_config[LL_MULTICONN_SLAVE_PREEMP]; + } + + // update remainder time + g_ll_conn_ctx.scheduleInfo[i].remainder -= delta; + + if (g_ll_conn_ctx.scheduleInfo[i].remainder < min + prio_adj) + { + next = i; + min = (g_ll_conn_ctx.scheduleInfo[i].remainder > prio_adj) ? (g_ll_conn_ctx.scheduleInfo[i].remainder - prio_adj) : 0; + } + } + } + + if (min == LL_INVALID_TIME) // all task may be delete, not start timer + { +// LOG("=== all task delete ====\n"); + return; + } + + T2 = read_current_fine_time(); + // calculate the time elapse since enter this function. + delta = LL_TIME_DELTA(T1, T2); + + if (g_ll_conn_ctx.scheduleInfo[next].remainder < delta) // TODO: should not go here, if this issue detected, root cause should be invest + { +// LOG("delta = %d\n", delta); + set_timer(AP_TIM1,20); + g_ll_conn_ctx.current_timer = 20; // add 2020-03-30 + } + else + { + set_timer(AP_TIM1,g_ll_conn_ctx.scheduleInfo[next].remainder - delta); + // update connection context & schedule info + g_ll_conn_ctx.current_timer = g_ll_conn_ctx.scheduleInfo[next].remainder - delta; + } + + g_ll_conn_ctx.currentConn = next; + + // set ll state according to current connection LL state + if (g_ll_conn_ctx.scheduleInfo[g_ll_conn_ctx.currentConn].linkRole == LL_ROLE_SLAVE) + llState = LL_STATE_CONN_SLAVE; + else if (g_ll_conn_ctx.scheduleInfo[g_ll_conn_ctx.currentConn].linkRole == LL_ROLE_MASTER) + llState = LL_STATE_CONN_MASTER; + + // the task is scheduled, set the priority as low + g_ll_conn_ctx.scheduleInfo[g_ll_conn_ctx.currentConn].priority = LL_SCH_PRIO_LOW; + + // take into account the time between start timer1 and T1 + for (i = 0; i < g_maxConnNum; i++) + { + if (conn_param[i].active) + g_ll_conn_ctx.scheduleInfo[i].remainder -= delta; + } + +// LOG("<%x, %x> ", g_ll_conn_ctx.scheduleInfo[0].remainder, g_ll_conn_ctx.scheduleInfo[1].remainder); +// LOG("<%x, %x, %x, %x> ", g_ll_conn_ctx.scheduleInfo[0].remainder, g_ll_conn_ctx.scheduleInfo[1].remainder, +// g_ll_conn_ctx.scheduleInfo[2].remainder, g_ll_conn_ctx.scheduleInfo[3].remainder); +} + +//#define LL_ADD_TASK_MARGIN 3000 +/******************************************************************************* + @fn ll_addTask + + @brief when a connection is created, new task will be added to task list. + There are 3 case: + 1. the connection is the 1st connection + 2. new task scheduler time earlier than current, re-schedule task + 3. new task scheduler time later than current, keep current + task and add new task to shceduler list + + input parameters + + @param connId - connection ID + time - schedule time for new task + + output parameters + + @param None. + + @return None. +*/ +void ll_addTask0(uint8 connId, uint32 time) +{ + uint32 T1, T2, delta, remainder, elapse_time; + uint8 i; + T1 = read_current_fine_time(); + // update current context +// g_ll_conn_ctx.scheduleInfo[connId].task_period = time; + g_ll_conn_ctx.scheduleInfo[connId].remainder = time; + g_ll_conn_ctx.scheduleInfo[connId].priority = LL_SCH_PRIO_LOW; + + // case 1: the 1st task. Now only active link use timer1 + if (!isTimer1Running()) + { + T2 = read_current_fine_time(); + delta = LL_TIME_DELTA(T1, T2); + set_timer(AP_TIM1,time - delta); + g_ll_conn_ctx.scheduleInfo[connId].remainder -= delta; + g_ll_conn_ctx.currentConn = connId; + g_ll_conn_ctx.current_timer = g_ll_conn_ctx.scheduleInfo[connId].remainder; +// LOG("[case 1: %d, %d] ", g_ll_conn_ctx.currentConn, time - delta); + return; + } + + remainder = read_LL_remainder_time(); + + // case 2: current awaiting task is earlier than new, not change the current task + if (remainder + pGlobal_config[LL_CONN_TASK_DURATION] < time) // new task has higher priority than old task, so add margin + { + T2 = read_current_fine_time(); + delta = LL_TIME_DELTA(T1, T2); + // when current timer expiry, the timer in the task list will subtract the time elapse, compensate the new task to the same start point + g_ll_conn_ctx.scheduleInfo[connId].remainder = (g_ll_conn_ctx.scheduleInfo[connId].remainder - delta) + (g_ll_conn_ctx.current_timer - remainder); +// LOG("[case 2: %d, %d] ", g_ll_conn_ctx.currentConn, g_ll_conn_ctx.scheduleInfo[connId].remainder); + return; + } + + // case 3: current awaiting task is later than new, change the current task +// elapse_time = ((CP_TIM1->LoadCount - CP_TIM1->CurrentCount) >> 2) + 5; // 5: rough time from read old timer1 to kick new timer1 + elapse_time = g_ll_conn_ctx.current_timer - ((AP_TIM1->CurrentCount) >> 2) + 2; // 2: rough time from read old timer1 to kick new timer1 + T2 = read_current_fine_time(); + // schedule the timer + delta = LL_TIME_DELTA(T1, T2); + set_timer(AP_TIM1,time - delta); + g_ll_conn_ctx.current_timer = time - delta; + + // update task contexts + for (i = 0; i < g_maxConnNum; i++) + { + if (i != connId && conn_param[i].active) + { + g_ll_conn_ctx.scheduleInfo[i].remainder -= elapse_time; + } + } + + g_ll_conn_ctx.scheduleInfo[connId].remainder -= delta; + g_ll_conn_ctx.currentConn = connId; +// LOG("[case 3: %d, %d] ", g_ll_conn_ctx.currentConn, time - delta); + // update other values? +} + + +// delete task: when the link terminate, remove it from schdule task list +/******************************************************************************* + @fn ll_deleteTask + + @brief delete task schedule info in the scheduler list. + Note that connection parameters are reset in other functions. + + input parameters + + @param connId - connection ID + + output parameters + + @param None. + + @return None. +*/ +void ll_deleteTask0(uint8 connId) +{ + g_ll_conn_ctx.scheduleInfo[connId].linkRole = LL_ROLE_INVALID; + g_ll_conn_ctx.scheduleInfo[connId].remainder = LL_INVALID_TIME; + g_ll_conn_ctx.scheduleInfo[connId].priority = LL_SCH_PRIO_LOW; + g_ll_conn_ctx.scheduleInfo[connId].task_duration = 0; +// g_ll_conn_ctx.scheduleInfo[connId].task_period = 0; +// g_ll_conn_ctx.scheduleInfo[connId].rsc_idx = 0xFF +} + +// temp set +#define LL_ADV_TIMING_COMPENSATE 5 // rough compensation for the time not consider in calculation + +#ifdef EXT_ADV_ENABLE +//#pragma O0 +// adv scheduler - conn scheduler interaction functions +void ll_adv_scheduler0(void) +{ + uint32 T2, T3, delta; + uint32 minAuxPduTime, minPriPduTime; + uint8 minIndexAux, minIndexPri; + uint8 done = FALSE; + int i; + llAdvScheduleInfo_t* p_scheduler = NULL; + extAdvInfo_t* pAdvInfo = NULL; + // calculate elapse time since last timer trigger + T2 = read_current_fine_time(); + delta = LL_TIME_DELTA(g_timerExpiryTick, T2); + p_scheduler = &g_pAdvSchInfo[g_currentExtAdv]; + pAdvInfo = p_scheduler->pAdvInfo; + + // the advertisement scheduler will schedule next task according to current adv's next advertise channel + // case 1: not finish primary ADV channel or AUX_XXX_IND chain, continue advertise current adv task + if (pAdvInfo->currentChn > LL_ADV_CHAN_FIRST && // next channel in primary adv channel + pAdvInfo->active == TRUE && // add 04-01, legacy adv may stop when receive conn_req + !ll_isFirstAdvChn(pAdvInfo->parameter.priAdvChnMap, pAdvInfo->currentChn)) // not the 1st primary ADV channel + { + ll_ext_adv_schedule_next_event(pGlobal_config[LL_EXT_ADV_INTER_PRI_CHN_INT] - delta); + done = TRUE; + } + else if (pAdvInfo->currentChn < LL_ADV_CHAN_FIRST // broadcast in aux adv chn + && pAdvInfo->currentAdvOffset > 0) // offset in adv data set greater than 0 means next PDU is AUX_CHAIN_IND PDU + { + // g_interAuxPduDuration is the time between the edge of AUX_ADV_IND & AUX_CHAIN_IND, + // delta consider the time between timer expiry time and new timer trigger point, + // the time from TO to ll_hw_trigger is not consider, this time denote as alpha below. + // If alpha for AUX_ADV_IND and AUX_CHAIN_IND is the same, then no compensation is required + // but if the alpha for AUX_ADV_IND and AUX_CHAIN_IND is different, using pGlobal_config[LL_EXT_ADV_INTER_SEC_COMP] + // to compensate it + ll_ext_adv_schedule_next_event(g_interAuxPduDuration - delta); + done = TRUE; + } + + // update scheduler task list + ll_updateExtAdvRemainderTime(delta); + + if (done) // next task schedule done + return; + + // if current adv is not active, delete it from task list + if (pAdvInfo->active == FALSE) + ll_delete_adv_task(g_currentExtAdv); + + // case 2: finish broadcast in primary adv channel/aux adv channel. Check ext adv scheduler to get the earliest task + // search the nearest expiry task and PDU type + minAuxPduTime = g_pAdvSchInfo[g_currentExtAdv].auxPduRemainder; + minPriPduTime = g_pAdvSchInfo[g_currentExtAdv].nextEventRemainder; + minIndexAux = g_currentExtAdv; + minIndexPri = g_currentExtAdv; + + for (i = 0; i < g_extAdvNumber; i++) + { + if (g_pAdvSchInfo[i].adv_handler != LL_INVALID_ADV_SET_HANDLE) + { + if (g_pAdvSchInfo[i].auxPduRemainder < minAuxPduTime) + { + minIndexAux = i; + minAuxPduTime = g_pAdvSchInfo[i].auxPduRemainder; + } + + if (g_pAdvSchInfo[i].nextEventRemainder < minPriPduTime) + { + minIndexPri = i; + minPriPduTime = g_pAdvSchInfo[i].nextEventRemainder; + } + } + } + + T3 = read_current_fine_time(); + delta = LL_TIME_DELTA(T2, T3); + // compare the minimum AUX channel remainder time & minimum Primary channel PDU remainder time, + // AUX channel PDU could add some pre-emphesis here + uint32 auxPduEmphesis = pGlobal_config[LL_EXT_ADV_INTER_PRI_CHN_INT] * 3; // add 03-31 + + if (minAuxPduTime != LL_INVALID_TIME + && (minAuxPduTime < minPriPduTime + auxPduEmphesis)) // next schedule task is aux PDU + { + ll_ext_adv_schedule_next_event(minAuxPduTime - delta); + g_currentExtAdv = minIndexAux; + } + else // next schedule task is pri PDU + { + ll_ext_adv_schedule_next_event(minPriPduTime - delta); + g_currentExtAdv = minIndexPri; + } + + // update scheduler task list + ll_updateExtAdvRemainderTime(delta); +} + +void ll_add_adv_task0(extAdvInfo_t* pExtAdv) +{ + int i, spare; + llAdvScheduleInfo_t* p_scheduler = NULL, *p_current_scheduler; + uint32 T1 = 0, T2, delta, remainder, elapse_time = 0; + uint8 chanNumber, temp; + uint8 isLegacy = ll_isLegacyAdv(pExtAdv); + temp = pExtAdv->parameter.priAdvChnMap; + chanNumber = (temp & 0x01) + ((temp & 0x02) >> 1) + ((temp & 0x04) >> 2); + // init new Ext adv event context + pExtAdv->currentChn = ((temp & ((~temp) + 1)) >> 1) + 37; // calculate 1st adv channel + pExtAdv->adv_event_counter = 0; + pExtAdv->currentAdvOffset = 0; + pExtAdv->adv_event_duration = 0; + + // ======== case 1: the 1st adv task + if (g_currentExtAdv == LL_INVALID_ADV_SET_HANDLE) // if (!isTimer4Running()) + { + g_schExtAdvNum = 1; + g_currentExtAdv = 0; // scheduler index = 0 + p_current_scheduler = &g_pAdvSchInfo[g_currentExtAdv]; + + // add 03-31 + if (isLegacy) // Legacy Adv PDU has no aux PDU + { + g_pAdvSchInfo[g_currentExtAdv].auxPduRemainder = LL_INVALID_TIME; + } + else + ll_allocAuxAdvTimeSlot(g_currentExtAdv); + +// LOG("[%d] ", g_pAdvSchInfo[i].auxPduRemainder); + + if (llWaitingIrq) + { + g_currentAdvTimer = pGlobal_config[LL_CONN_TASK_DURATION]; + } + else if (isTimer1Running() + && ((remainder = read_LL_remainder_time()) < pGlobal_config[LL_EXT_ADV_TASK_DURATION])) // timer1 for connection or legacy adv + { + g_currentAdvTimer = remainder + pGlobal_config[LL_CONN_TASK_DURATION]; // no enough time for adv case + } + else + { + if (chanNumber > 1) + g_currentAdvTimer = pGlobal_config[LL_EXT_ADV_INTER_PRI_CHN_INT]; + else + g_currentAdvTimer = (p_current_scheduler->auxPduRemainder < p_current_scheduler->pAdvInfo->primary_advertising_interval) ? + p_current_scheduler->auxPduRemainder : p_current_scheduler->pAdvInfo->primary_advertising_interval; + + // invoke set up ext adv function + llSetupExtAdvEvent(pExtAdv); + } + + ll_ext_adv_schedule_next_event(g_currentAdvTimer); + g_timerExpiryTick = read_current_fine_time(); // fake timer expiry tick + p_current_scheduler->pAdvInfo = pExtAdv; + p_current_scheduler->adv_handler = pExtAdv->advHandle; + p_current_scheduler->nextEventRemainder = p_current_scheduler->pAdvInfo->primary_advertising_interval; // add some random delay between 0-10ms? + pExtAdv->active = TRUE; + return; + } + + // ===== case 2: there are ongoing adv + p_current_scheduler = &g_pAdvSchInfo[g_currentExtAdv]; + + // get the 1st spare scheduler slot + for (i = 0; i < g_extAdvNumber; i++) // bug fixed 04-07 + { + if (g_pAdvSchInfo[i].adv_handler == LL_INVALID_ADV_SET_HANDLE) + { + p_scheduler = &g_pAdvSchInfo[i]; + spare = i; + break; + } + } + + // no empty scheduler slot, return + if (p_scheduler == NULL) + return; + + g_schExtAdvNum ++; + pExtAdv->active = TRUE; + + // arrange the timing of AUX_XXX_IND, it is independent to EXT_ADV_IND + // add 03-31 + if (isLegacy) + { + g_pAdvSchInfo[spare].auxPduRemainder = LL_INVALID_TIME; + } + else + ll_allocAuxAdvTimeSlot(spare); + + if (isTimer4Running()) + { + remainder = read_ll_adv_remainder_time(); + T1 = read_current_fine_time(); + // calculate the elapse time since current adv timer trigger + elapse_time = g_currentAdvTimer - remainder; + } + else + remainder = 0; + + if (isTimer1Running()) + { + uint32 temp = read_LL_remainder_time(); + remainder = (temp < remainder) ? temp : remainder; + } + + if (llWaitingIrq) // there is ongoing LL IRQ, not setup adv + remainder = 0; + + // case 2.1: there is enough time for EXT_ADV_IND, setup new adv first + if (remainder > pGlobal_config[LL_EXT_ADV_TASK_DURATION]) + { + g_currentExtAdv = spare; + + if (chanNumber > 1) + g_currentAdvTimer = pGlobal_config[LL_EXT_ADV_INTER_PRI_CHN_INT]; + + ll_ext_adv_schedule_next_event(g_currentAdvTimer); + // setup ext adv event + llSetupExtAdvEvent(pExtAdv); + T2 = read_current_fine_time(); + delta = LL_TIME_DELTA(T1, T2); + p_current_scheduler->nextEventRemainder = p_current_scheduler->pAdvInfo->primary_advertising_interval; // add some random delay between 0-10ms? + + // update the timer in the scheduler info list + for (i = 0; i < g_extAdvNumber; i++) + { + if (g_pAdvSchInfo[i].adv_handler != LL_INVALID_ADV_SET_HANDLE && + i != g_currentExtAdv) + { + if (g_pAdvSchInfo[i].nextEventRemainder < (elapse_time + delta)) + { + g_pAdvSchInfo[i].nextEventRemainder += g_pAdvSchInfo[i].pAdvInfo->primary_advertising_interval; + g_pAdvSchInfo[i].pAdvInfo->adv_event_duration += g_pAdvSchInfo[i].pAdvInfo->primary_advertising_interval; + g_pAdvSchInfo[i].pAdvInfo->adv_event_counter ++; + } + + if (g_pAdvSchInfo[i].auxPduRemainder < (elapse_time + delta)) // normally this case should not occur + g_pAdvSchInfo[i].auxPduRemainder += g_advSlotPeriodic; + + g_pAdvSchInfo[i].nextEventRemainder -= (elapse_time + delta); + + if (g_pAdvSchInfo[i].auxPduRemainder != LL_INVALID_TIME) + g_pAdvSchInfo[i].auxPduRemainder -= (elapse_time + delta); + } + } + } + // case 2.2: no enough time, start new adv after current one + else + { + // add new adv to adv scheduler list, not change current adv task + p_scheduler->nextEventRemainder = p_current_scheduler->nextEventRemainder + + (spare > g_currentExtAdv ? (spare - g_currentExtAdv) : (g_extAdvNumber + spare - g_currentExtAdv)) * pGlobal_config[LL_EXT_ADV_TASK_DURATION]; + } + + p_scheduler->adv_handler = pExtAdv->advHandle; + p_scheduler->pAdvInfo = pExtAdv; + g_schExtAdvNum ++; +} + +// TODO: function split between ll_adv_scheduler() & ll_delete_adv_task +void ll_delete_adv_task0(uint8 index) +{ + uint32 T1, T2, delta, remainder, elapse_time; + uint32 minAuxPduTime, minPriPduTime; + uint8 minIndexAux, minIndexPri; + int i; +// LOG("=== adv task % deleted \r\n", index); + g_pAdvSchInfo[index].adv_handler = LL_INVALID_ADV_SET_HANDLE; + g_pAdvSchInfo[index].pAdvInfo = NULL; + g_pAdvSchInfo[index].auxPduRemainder = LL_INVALID_TIME; + g_pAdvSchInfo[index].nextEventRemainder = LL_INVALID_TIME; + g_schExtAdvNum --; + + // only 1 task case, clear scheduler info and stop timer + if (g_schExtAdvNum == 0) + { + clear_timer(AP_TIM4); + return; + } + + // current awaiting adv is disable, and there are more than 1 task + if (index == g_currentExtAdv) + { + remainder = read_ll_adv_remainder_time(); + T1 = read_current_fine_time(); + elapse_time = g_currentAdvTimer - remainder; + // find the earliest task + minAuxPduTime = g_pAdvSchInfo[g_currentExtAdv].auxPduRemainder; // LL_INVALID_TIME + minPriPduTime = g_pAdvSchInfo[g_currentExtAdv].nextEventRemainder; + minIndexAux = g_currentExtAdv; + minIndexPri = g_currentExtAdv; + + for (i = 0; i < g_extAdvNumber; i++) + { + if (g_pAdvSchInfo[i].adv_handler != LL_INVALID_ADV_SET_HANDLE) + { + if (g_pAdvSchInfo[i].auxPduRemainder < minAuxPduTime) + { + minIndexAux = i; + minAuxPduTime = g_pAdvSchInfo[i].auxPduRemainder; + } + + if (g_pAdvSchInfo[i].nextEventRemainder < minPriPduTime) + { + minIndexPri = i; + minPriPduTime = g_pAdvSchInfo[i].nextEventRemainder; + } + } + } + + // start new timer + T2 = read_current_fine_time(); + delta = LL_TIME_DELTA(T1, T2); + + if (minAuxPduTime < minPriPduTime) // next schedule task is aux PDU + { + ll_ext_adv_schedule_next_event(minAuxPduTime - elapse_time - delta); +// g_currentAdvTimer = minAuxPduTime - elapse_time - delta; + g_currentExtAdv = minIndexAux; + } + else // next schedule task is pri PDU + { + ll_ext_adv_schedule_next_event(minPriPduTime - elapse_time - delta); +// g_currentAdvTimer = minPriPduTime - elapse_time - delta; + g_currentExtAdv = minIndexPri; + } + + // update the scheduler list + ll_updateExtAdvRemainderTime(elapse_time + delta); + } +} +#else +void ll_adv_scheduler0(void) +{ +} + +void ll_add_adv_task0(extAdvInfo_t* pExtAdv) +{ +} + +void ll_delete_adv_task0(uint8 index) +{ +} + +#endif + +// get remainder adv time +uint32 read_ll_adv_remainder_time(void) +{ + uint32 currentCount; + currentCount = AP_TIM4->CurrentCount; + currentCount = currentCount >> 2; // convert to us + return currentCount; +} + + +/******************************************************************************* + @fn llSetupExtAdvEvent + + @brief This function will setup ext adv event + 1. fill ext adv pdu(EXT_ADV_IND or AUX_XXX_IND) + 2. update timer info for next chn EXT_ADV_IND or AUX_XXX_IND + + input parameters + + @param None. + + output== parameters + + @param None. + + @return LL_STATUS_SUCCESS +*/ +uint8 llSetupExtAdvEvent0(extAdvInfo_t* pAdvInfo) +{ + uint8 ch_idx, pktFmt, auxPduIndFlag = FALSE; + int i; + uint32 T2, T1, delta, temp; +// hal_gpio_write(GPIO_P14, 1); + ch_idx = pAdvInfo->currentChn; + T1 = read_current_fine_time(); + //LOG("%d ", pAdvInfo->currentChn); + + if (ch_idx >= LL_ADV_CHAN_FIRST && ch_idx <= LL_ADV_CHAN_LAST ) // advertise at primary channel case + { + llSetupAdvExtIndPDU(pAdvInfo, NULL); + // decide next adv channel + i = ch_idx - LL_ADV_CHAN_FIRST + 1; + + while ((i < 3) && !(pAdvInfo->parameter.priAdvChnMap & (1 << i))) i ++; // search channel map for next adv channel number + + if (i == 3) // finish primary adv channel broadcast + { + if (g_pAdvSchInfo[g_currentExtAdv].auxPduRemainder > g_pAdvSchInfo[g_currentExtAdv].nextEventRemainder) + pAdvInfo->currentChn = ll_getFirstAdvChn(pAdvInfo->parameter.priAdvChnMap); + else + pAdvInfo->currentChn = pAdvInfo->auxChn; + } + else + pAdvInfo->currentChn = LL_ADV_CHAN_FIRST + i; + + // config primary PHY + pktFmt = pAdvInfo->parameter.primaryAdvPHY; + } + else // advertise at primary channel case + { + // Note: if the Ext adv has no aux pdu, llSetupExtAdv should not be invoked + if (pAdvInfo->currentAdvOffset == 0) // 1st AUX PDU. AUX_ADV_IND should include advData + { + llSetupAuxAdvIndPDU(pAdvInfo, NULL); + auxPduIndFlag = TRUE; + } + else + llSetupAuxChainIndPDU(pAdvInfo, NULL); + + // config secondary PHY + if (pAdvInfo->parameter.secondaryAdvPHY == 3) // coded PHY + pktFmt = PKT_FMT_BLR125K; // + else + pktFmt = pAdvInfo->parameter.secondaryAdvPHY; + } + + HAL_ENTER_CRITICAL_SECTION(); + + // if there is ongoing LL HW task, skip this task + if (llWaitingIrq) + { +// g_pmCounters.ll_tbd_cnt1++; + HAL_EXIT_CRITICAL_SECTION(); + return FALSE; + } + + //============== configure and trigger LL HW engine, LL HW work in Single Tx mode ================== + rf_phy_change_cfg(pktFmt); + ll_hw_tx2rx_timing_config(pktFmt); + set_crc_seed(ADV_CRC_INIT_VALUE); // crc seed for adv is same for all channels + set_access_address(ADV_SYNCH_WORD); // access address + set_channel(ch_idx); // channel + set_whiten_seed(ch_idx); // whiten seed + set_max_length(50); // rx PDU max length + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + + // for AUX_ADV_IND, connectable/scannable case, should configure TRX + if ((auxPduIndFlag == TRUE) && // AUX_ADV_IND + ((pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_CONN_BITMASK) || + (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_SCAN_BITMASK))) + { + ll_hw_set_trx_settle(pGlobal_config[LL_HW_BB_DELAY_ADV], + pGlobal_config[LL_HW_AFE_DELAY_ADV], + pGlobal_config[LL_HW_PLL_DELAY_ADV]); //TxBB,RxAFE,PLL + ll_hw_set_trx(); // set LL HW as Tx - Rx mode + } + else + { + ll_hw_set_stx(); // set LL HW as Tx - Rx mode + } + + ll_hw_ign_rfifo(LL_HW_IGN_ALL); //set the rfifo ign control + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(g_tx_ext_adv_buf.txheader), ((g_tx_ext_adv_buf.txheader & 0xff00) >> 8) + 2); + T2 = read_current_fine_time(); + delta = LL_TIME_DELTA(T1, T2); + temp = ( pGlobal_config[LL_EXT_ADV_PROCESS_TARGET] > delta) ? (pGlobal_config[LL_EXT_ADV_PROCESS_TARGET] - delta) : 0; + llWaitUs(temp); // insert delay to make process time equal PROCESS_TARGET + ll_hw_go(); +// hal_gpio_write(GPIO_P14, 1); +// hal_gpio_write(GPIO_P14, 0); + llWaitingIrq = TRUE; + llTaskState = LL_TASK_EXTENDED_ADV; + HAL_EXIT_CRITICAL_SECTION(); + return TRUE; +} + + +// ------------------------------------- +#ifdef PRD_ADV_ENABLE +void ll_adv_scheduler_periodic0(void) +{ + uint32 T2, T3, delta; + uint32 minAuxPduTime, minPriPduTime; + uint8 minIndexAux, minIndexPri; + uint8 done = FALSE; + int i; + llPeriodicAdvScheduleInfo_t* p_scheduler = NULL; + extAdvInfo_t* pAdvInfo = NULL; + periodicAdvInfo_t* pPrdAdv = NULL; + // calculate elapse time since last timer trigger + T2 = read_current_fine_time(); + delta = LL_TIME_DELTA(g_timerExpiryTick, T2); + p_scheduler = &g_pAdvSchInfo_periodic[g_currentExtAdv_periodic]; + pPrdAdv = p_scheduler->pAdvInfo_prd; + pAdvInfo = p_scheduler->pAdvInfo; + + // case 1: not finish primary ADV channel or AUX_XXX_IND chain, continue advertise current adv task + if (pPrdAdv->currentChn > LL_ADV_CHAN_FIRST && // next channel in primary adv channel + !ll_isFirstAdvChn(pAdvInfo->parameter.priAdvChnMap, pPrdAdv->currentChn)) // not the 1st primary ADV channel + { + ll_prd_adv_schedule_next_event(pGlobal_config[LL_EXT_ADV_INTER_PRI_CHN_INT] - delta); +// LOG("<%d> ", pGlobal_config[LL_EXT_ADV_INTER_PRI_CHN_INT] - delta); + done = TRUE; + } + else if (pPrdAdv->currentChn < LL_ADV_CHAN_FIRST && pAdvInfo->sendingAuxAdvInd == TRUE) // extended adv part, sending aux PDU + { + ll_prd_adv_schedule_next_event(g_interAuxPduDuration - delta); + done = TRUE; + } + else if (pPrdAdv->currentChn < LL_ADV_CHAN_FIRST // period adv part + && pPrdAdv->currentAdvOffset > 0) // offset in adv data set greater than 0 means next PDU is AUX_CHAIN_IND PDU + { + ll_prd_adv_schedule_next_event(g_interAuxPduDuration - delta); + done = TRUE; + } + + // update scheduler task list + for (i = 0; i < g_extAdvNumber; i++) + { + if (g_pAdvSchInfo_periodic[i].adv_handler != LL_INVALID_ADV_SET_HANDLE) + { + if (g_pAdvSchInfo_periodic[i].pAdvInfo->active == TRUE) + g_pAdvSchInfo_periodic[i].nextEventRemainder -= delta; + + g_pAdvSchInfo_periodic[i].auxPduRemainder -= delta; + } + } + + if (done) // next task schedule done + return; + + // case 2: finish broadcast in primary adv channel/aux adv channel. Check ext adv scheduler to get the earliest task + // search the nearest expiry task and PDU type + minAuxPduTime = g_pAdvSchInfo_periodic[g_currentExtAdv_periodic].auxPduRemainder; + minPriPduTime = g_pAdvSchInfo_periodic[g_currentExtAdv_periodic].nextEventRemainder; + minIndexAux = g_currentExtAdv_periodic; + minIndexPri = g_currentExtAdv_periodic; + + for (i = 0; i < g_extAdvNumber; i++) + { + if (g_pAdvSchInfo_periodic[i].adv_handler != LL_INVALID_ADV_SET_HANDLE) + { + if (g_pAdvSchInfo_periodic[i].auxPduRemainder < minAuxPduTime) + { + minIndexAux = i; + minAuxPduTime = g_pAdvSchInfo_periodic[i].auxPduRemainder; + } + + if (g_pAdvSchInfo_periodic[i].pAdvInfo->active == TRUE && g_pAdvSchInfo_periodic[i].nextEventRemainder < minPriPduTime) + { + minIndexPri = i; + minPriPduTime = g_pAdvSchInfo_periodic[i].nextEventRemainder; + } + } + } + + T3 = read_current_fine_time(); + delta = LL_TIME_DELTA(T2, T3); + + if (minAuxPduTime < minPriPduTime) // next schedule task is aux PDU + { + ll_prd_adv_schedule_next_event(minAuxPduTime - delta); + g_currentExtAdv_periodic = minIndexAux; + } + else // next schedule task is pri PDU + { + ll_prd_adv_schedule_next_event(minPriPduTime - delta); + g_currentExtAdv_periodic = minIndexPri; + } + + // update scheduler task list + for (i = 0; i < g_extAdvNumber; i++) + { + if (g_pAdvSchInfo_periodic[i].adv_handler != LL_INVALID_ADV_SET_HANDLE) + { + if (g_pAdvSchInfo_periodic[i].pAdvInfo->active == TRUE) + g_pAdvSchInfo_periodic[i].nextEventRemainder -= delta; + + g_pAdvSchInfo_periodic[i].auxPduRemainder -= delta; + } + } +} + + + +void ll_add_adv_task_periodic0(periodicAdvInfo_t* pPrdAdv, extAdvInfo_t* pExtAdv) +{ + int i, spare; + llPeriodicAdvScheduleInfo_t* p_scheduler = NULL, *p_current_scheduler = NULL; + uint32 T1 = 0, T2, delta, remainder, elapse_time = 0; + uint8 chanNumber, temp; + temp = pExtAdv->parameter.priAdvChnMap; + chanNumber = (temp & 0x01) + ((temp & 0x02) >> 1) + ((temp & 0x04) >> 2); + // init new Ext adv event context + pPrdAdv->currentChn = ((temp & ((~temp) + 1)) >> 1) + 37; // calculate 1st adv channel + pPrdAdv->currentAdvOffset = 0; + pPrdAdv->periodic_adv_event_counter = 0; +// pPrdAdv->adv_interval = pPrdAdv->adv_interval_max; // TODO: select property adv interval + // parameters of primary adv channel + pExtAdv->adv_event_duration = 0; + pExtAdv->adv_event_counter = 0; + + // case 1: the 1st task + if (g_currentExtAdv_periodic == LL_INVALID_ADV_SET_HANDLE) + { + g_schExtAdvNum_periodic = 1; + g_currentExtAdv_periodic = 0; // scheduler index = 0 + p_current_scheduler = &g_pAdvSchInfo_periodic[g_currentExtAdv_periodic]; + // allocate auxilary PDU timeslot + ll_allocAuxAdvTimeSlot_prd(g_currentExtAdv_periodic); +// LOG("[%d] ", p_current_scheduler->auxPduRemainder); + p_current_scheduler->pAdvInfo = pExtAdv; + p_current_scheduler->pAdvInfo_prd = pPrdAdv; + p_current_scheduler->adv_handler = pExtAdv->advHandle; + + if (llWaitingIrq) + { + g_currentAdvTimer = pGlobal_config[LL_CONN_TASK_DURATION]; + } + else if (isTimer1Running() + && ((remainder = read_LL_remainder_time()) < pGlobal_config[LL_PRD_ADV_TASK_DURATION])) // timer1 for connection or legacy adv + { + g_currentAdvTimer = remainder + pGlobal_config[LL_CONN_TASK_DURATION]; // no enough time for adv case + } + else + { + if (chanNumber > 1) + g_currentAdvTimer = pGlobal_config[LL_EXT_ADV_INTER_PRI_CHN_INT]; + else // only adv in 1 primary adv channel case + g_currentAdvTimer = pGlobal_config[LL_EXT_ADV_PRI_2_SEC_CHN_INT]; + +// g_currentAdvTimer = (p_current_scheduler->auxPduRemainder < p_current_scheduler->pAdvInfo->primary_advertising_interval) ? +// p_current_scheduler->auxPduRemainder : p_current_scheduler->pAdvInfo->primary_advertising_interval; + // invoke set up ext adv function + llSetupPrdAdvEvent(pPrdAdv, pExtAdv); /// TODO + } + + ll_prd_adv_schedule_next_event(g_currentAdvTimer); + g_timerExpiryTick = read_current_fine_time(); // fake timer expiry tick + p_current_scheduler->nextEventRemainder = p_current_scheduler->pAdvInfo->primary_advertising_interval; // add some random delay between 0-10ms? + pExtAdv->active = TRUE; + return; + } + + // case 2: there are ongoing adv, get the 1st spare scheduler slot + p_current_scheduler = &g_pAdvSchInfo_periodic[g_currentExtAdv_periodic]; + + for (i = 0; i < g_schExtAdvNum_periodic; i++) + { + if (g_pAdvSchInfo_periodic[i].adv_handler == LL_INVALID_ADV_SET_HANDLE) + { + p_scheduler = &g_pAdvSchInfo_periodic[i]; + spare = i; + break; + } + } + + // no empty scheduler slot, return + if (p_scheduler == NULL) + { + // to add error counter here + return; + } + + g_schExtAdvNum_periodic ++; + pExtAdv->active = TRUE; + // arrange the timing of AUX_XXX_IND, it is independent to EXT_ADV_IND + ll_allocAuxAdvTimeSlot_prd(spare); + + if (isTimer4Running()) + { + remainder = read_ll_adv_remainder_time(); + T1 = read_current_fine_time(); + // calculate the elapse time since current adv timer trigger + elapse_time = g_currentAdvTimer - remainder; + } + else + remainder = 0; + + if (isTimer1Running()) + { + uint32 temp = read_LL_remainder_time(); + remainder = (temp < remainder) ? temp : remainder; + } + + if (llWaitingIrq) // there is ongoing LL IRQ, not setup adv + remainder = 0; + + // case 2.1: there is enough time for EXT_ADV_IND, setup new adv first + if (remainder > pGlobal_config[LL_EXT_ADV_TASK_DURATION]) + { + g_currentExtAdv = spare; + + if (chanNumber > 1) + g_currentAdvTimer = pGlobal_config[LL_EXT_ADV_INTER_PRI_CHN_INT]; + + ll_prd_adv_schedule_next_event(g_currentAdvTimer); + // setup ext adv event + llSetupPrdAdvEvent(pPrdAdv, pExtAdv); + T2 = read_current_fine_time(); + delta = LL_TIME_DELTA(T1, T2); + p_current_scheduler->nextEventRemainder = p_current_scheduler->pAdvInfo->primary_advertising_interval; // add some random delay between 0-10ms? + + // update the timer in the scheduler info list + for (i = 0; i < g_extAdvNumber; i++) + { + if (g_pAdvSchInfo_periodic[i].adv_handler != LL_INVALID_ADV_SET_HANDLE && + i != g_currentExtAdv_periodic) + { + if (g_pAdvSchInfo_periodic[i].pAdvInfo->active == TRUE) + g_pAdvSchInfo_periodic[i].nextEventRemainder -= (elapse_time + delta); + + g_pAdvSchInfo_periodic[i].auxPduRemainder -= (elapse_time + delta); + } + } + } + // case 2.2: no enough time, start new adv after current one + else + { + // add new adv to adv scheduler list, not change current adv task + p_scheduler->nextEventRemainder = p_current_scheduler->nextEventRemainder + + (spare > g_currentExtAdv_periodic ? + (spare - g_currentExtAdv_periodic) : + (g_extAdvNumber + spare - g_currentExtAdv_periodic)) * pGlobal_config[LL_PRD_ADV_TASK_DURATION]; + } + + p_current_scheduler->pAdvInfo = pExtAdv; + p_current_scheduler->pAdvInfo_prd = pPrdAdv; + p_current_scheduler->adv_handler = pExtAdv->advHandle; + g_schExtAdvNum_periodic ++; +} + + +void ll_delete_adv_task_periodic0(uint8 index) +{ + uint32 T1, T2, delta, remainder, elapse_time; + uint32 minAuxPduTime, minPriPduTime; + uint8 minIndexAux, minIndexPri; + int i; +// LOG("=== adv task % deleted \r\n", index); + g_pAdvSchInfo_periodic[index].adv_handler = LL_INVALID_ADV_SET_HANDLE; + g_pAdvSchInfo_periodic[index].pAdvInfo = NULL; + g_pAdvSchInfo_periodic[index].auxPduRemainder = LL_INVALID_TIME; + g_pAdvSchInfo_periodic[index].nextEventRemainder = LL_INVALID_TIME; + g_schExtAdvNum_periodic --; + + // only 1 task case, clear scheduler info and stop timer + if (g_schExtAdvNum_periodic == 0) + { + clear_timer(AP_TIM4); + return; + } + + // current awaiting adv is disable, and there are more than 1 task + if (index == g_currentExtAdv_periodic) + { + remainder = read_ll_adv_remainder_time(); + T1 = read_current_fine_time(); + elapse_time = g_currentAdvTimer - remainder; + // find the earliest task + minAuxPduTime = g_pAdvSchInfo_periodic[g_currentExtAdv_periodic].auxPduRemainder; // LL_INVALID_TIME + minPriPduTime = g_pAdvSchInfo_periodic[g_currentExtAdv_periodic].nextEventRemainder; + minIndexAux = g_currentExtAdv_periodic; + minIndexPri = g_currentExtAdv_periodic; + + for (i = 0; i < g_extAdvNumber; i++) + { + if (g_pAdvSchInfo_periodic[i].adv_handler != LL_INVALID_ADV_SET_HANDLE) + { + if (g_pAdvSchInfo_periodic[i].auxPduRemainder < minAuxPduTime) + { + minIndexAux = i; + minAuxPduTime = g_pAdvSchInfo_periodic[i].auxPduRemainder; + } + + if (g_pAdvSchInfo_periodic[i].nextEventRemainder < minPriPduTime) + { + minIndexPri = i; + minPriPduTime = g_pAdvSchInfo_periodic[i].nextEventRemainder; + } + } + } + + // start new timer + T2 = read_current_fine_time(); + delta = LL_TIME_DELTA(T1, T2); + + if (minAuxPduTime < minPriPduTime) // next schedule task is aux PDU + { + ll_prd_adv_schedule_next_event(minAuxPduTime - elapse_time - delta); +// g_currentAdvTimer = minAuxPduTime - elapse_time - delta; + g_currentExtAdv_periodic = minIndexAux; + } + else // next schedule task is pri PDU + { + ll_prd_adv_schedule_next_event(minPriPduTime - elapse_time - delta); +// g_currentAdvTimer = minPriPduTime - elapse_time - delta; + g_currentExtAdv_periodic = minIndexPri; + } + + // update the scheduler list + for (i = 0; i < g_extAdvNumber; i++) + { + if (g_pAdvSchInfo_periodic[i].adv_handler != LL_INVALID_ADV_SET_HANDLE) + { + g_pAdvSchInfo_periodic[i].auxPduRemainder -= (elapse_time + delta); + + if (g_pAdvSchInfo_periodic[i].pAdvInfo->active == TRUE) + g_pAdvSchInfo_periodic[i].nextEventRemainder -= (elapse_time + delta); + } + } + } +} +#else +void ll_adv_scheduler_periodic0(void) +{ +} + +void ll_add_adv_task_periodic0(periodicAdvInfo_t* pPrdAdv, extAdvInfo_t* pExtAdv) +{ +} + +void ll_delete_adv_task_periodic0(uint8 index) +{ +} + +#endif + +/******************************************************************************* + @fn llSetupPrdAdvEvent + + @brief This function will setup ext adv event + 1. fill ext adv pdu(EXT_ADV_IND or AUX_XXX_IND) + 2. update timer info for next chn EXT_ADV_IND or AUX_XXX_IND + + input parameters + + @param None. + + output== parameters + + @param None. + + @return LL_STATUS_SUCCESS +*/ +uint8 llSetupPrdAdvEvent0(periodicAdvInfo_t* pPrdAdv, extAdvInfo_t* pExtAdv) +{ + uint8 ch_idx, pktFmt; + int i; + uint32 crcInit, accessAddress; + uint32 T2, T1, delta, temp; + ch_idx = pPrdAdv->currentChn; + T1 = read_current_fine_time(); + //LOG("%d ", pPrdAdv->currentChn); + crcInit = ADV_CRC_INIT_VALUE; + accessAddress = ADV_SYNCH_WORD; + + if (ch_idx >= LL_ADV_CHAN_FIRST && ch_idx <= LL_ADV_CHAN_LAST ) // primary channel case + { + llSetupAdvExtIndPDU(pExtAdv, pPrdAdv); + // decide next adv channel + i = ch_idx - LL_ADV_CHAN_FIRST + 1; + + while ((i < 3) && !(pExtAdv->parameter.priAdvChnMap & (1 << i))) i ++; // search channel map for next adv channel number + + if (i == 3) // finish primary adv channel broadcast + { + pPrdAdv->currentChn = pExtAdv->auxChn; + pExtAdv->sendingAuxAdvInd = TRUE; + } + else + pPrdAdv->currentChn = LL_ADV_CHAN_FIRST + i; + + // config primary PHY + pktFmt = pExtAdv->parameter.primaryAdvPHY; + } + else // aux channel case + { + // branch 1, send AUX_ADV_IND + if (pExtAdv->sendingAuxAdvInd == TRUE) + { + llSetupAuxAdvIndPDU(pExtAdv, pPrdAdv); + pExtAdv->sendingAuxAdvInd = FALSE; + } + // branch 2, send AUX_SYNC_IND/AUX_CHAIN_IND + else if (pPrdAdv->currentAdvOffset == 0) // 1st AUX PDU. AUX_ADV_IND should include advData + { + // set up AUX_SYNC_IND + llSetupAuxSyncIndPDU(pExtAdv, pPrdAdv); + crcInit = pPrdAdv->crcInit; + accessAddress = pPrdAdv->AA; + pPrdAdv->periodic_adv_event_counter ++; + } + else // set up AUX_CHAIN_IND + { + crcInit = pPrdAdv->crcInit; + accessAddress = pPrdAdv->AA; + llSetupAuxChainIndPDU(pExtAdv, pPrdAdv); + } + + // config secondary PHY + if (pExtAdv->parameter.secondaryAdvPHY == 3) // coded PHY + pktFmt = PKT_FMT_BLR125K; // + else + pktFmt = pExtAdv->parameter.secondaryAdvPHY; + } + + HAL_ENTER_CRITICAL_SECTION(); + + // if there is ongoing LL HW task, skip this task + if (llWaitingIrq) + { +// g_pmCounters.ll_tbd_cnt1++; + HAL_EXIT_CRITICAL_SECTION(); + return FALSE; + } + + //============== configure and trigger LL HW engine, LL HW work in Single Tx mode ================== + rf_phy_change_cfg(pktFmt); + ll_hw_tx2rx_timing_config(pktFmt); + set_crc_seed(crcInit); // crc seed for adv is same for all channels + set_access_address(accessAddress); // access address + set_channel(ch_idx); // channel + set_whiten_seed(ch_idx); // whiten seed +// set_max_length(50); // rx PDU max length + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + ll_hw_set_stx(); // set LL HW as Tx - Rx mode + ll_hw_ign_rfifo(LL_HW_IGN_ALL); //set the rfifo ign control + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(g_tx_ext_adv_buf.txheader), ((g_tx_ext_adv_buf.txheader & 0xff00) >> 8) + 2); + T2 = read_current_fine_time(); + delta = LL_TIME_DELTA(T1, T2); + temp = ( pGlobal_config[LL_PRD_ADV_PROCESS_TARGET] > delta) ? (pGlobal_config[LL_PRD_ADV_PROCESS_TARGET] - delta) : 0; + llWaitUs(temp); // insert delay to make process time equal PROCESS_TARGET + ll_hw_go(); +// hal_gpio_write(GPIO_P14, 1); +// hal_gpio_write(GPIO_P14, 0); + llWaitingIrq = TRUE; + llTaskState = LL_TASK_PERIODIC_ADV; + HAL_EXIT_CRITICAL_SECTION(); + return TRUE; +} + + + +// ------------------------------------- +#ifdef EXT_ADV_ENABLE +uint8 ll_processExtAdvIRQ(uint32_t irq_status) +{ + uint8 mode; + extAdvInfo_t* pAdvInfo; + uint32_t T2, delay; + pAdvInfo = g_pAdvSchInfo[g_currentExtAdv].pAdvInfo; + + if (pAdvInfo == NULL) + return FALSE; + + HAL_ENTER_CRITICAL_SECTION(); + mode = ll_hw_get_tr_mode(); + + if (ll_isLegacyAdv(pAdvInfo)) + { + // process legacy Adv + uint8_t packet_len, pdu_type, txAdd; + uint8_t* peerAddr, *ownAddr; + uint8_t bWlRlCheckOk = TRUE; + uint16_t pktLen; + uint32_t pktFoot0, pktFoot1; + int calibra_time; // this parameter will be provided by global_config + ll_debug_output(DEBUG_LL_HW_TRX); + // read packet + packet_len = ll_hw_read_rfifo((uint8_t*)(&(g_rx_adv_buf.rxheader)), + &pktLen, + &pktFoot0, + &pktFoot1); + + if(ll_hw_get_rfifo_depth()>0) + { + g_pmCounters.ll_rfifo_read_err++; + packet_len=0; + pktLen=0; + } + + // check receive pdu type + pdu_type = g_rx_adv_buf.rxheader & PDU_TYPE_MASK; + txAdd = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + + if (pAdvInfo->parameter.ownAddrType == LL_DEV_ADDR_TYPE_RANDOM && pAdvInfo->parameter.isOwnRandomAddressSet == TRUE) + ownAddr = pAdvInfo->parameter.ownRandomAddress; + else + ownAddr = ownPublicAddr; + + if (packet_len > 0 // any better checking rule for rx anything? + && pdu_type == ADV_SCAN_REQ + && (pAdvInfo->parameter.advEventProperties == LL_EXT_ADV_PROP_ADV_IND + || pAdvInfo->parameter.advEventProperties == LL_EXT_ADV_PROP_ADV_SCAN_IND)) + { + // 1. scan req + g_pmCounters.ll_recv_scan_req_cnt ++; + + // check AdvA + if (g_rx_adv_buf.data[6] != ownAddr[0] + || g_rx_adv_buf.data[7] != ownAddr[1] + || g_rx_adv_buf.data[8] != ownAddr[2] + || g_rx_adv_buf.data[9] != ownAddr[3] + || g_rx_adv_buf.data[10] != ownAddr[4] + || g_rx_adv_buf.data[11] != ownAddr[5]) + { + } + else + { + uint8_t rpaListIndex; + peerAddr = &g_rx_adv_buf.data[0]; // ScanA + + // Resolving list checking + if (g_llRlEnable == TRUE && + txAdd == LL_DEV_ADDR_TYPE_RANDOM && + (g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) + { + rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]); + + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM) + { + peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; + } + else + bWlRlCheckOk = FALSE; + } + + // check white list + if ((pGlobal_config[LL_SWITCH] & LL_WHITELIST_ALLOW) + && (adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_SCAN_REQ + || adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_ALL_REQ) + && (bWlRlCheckOk == TRUE)) + { + // check white list + bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr); + } + + if (bWlRlCheckOk == FALSE) // if not in white list, do nothing + { + g_pmCounters.ll_filter_scan_req_cnt ++; + } + else + { + g_pmCounters.ll_rx_peer_cnt++; + uint8 retScanRspFilter = 1; + + if(LL_PLUS_ScanRequestFilterCBack) + { + retScanRspFilter = 1;//LL_PLUS_ScanRequestFilterCBack(); + } + + if(retScanRspFilter) + { + // send scan rsp + ll_hw_set_stx(); // set LL HW as single Tx mode + g_same_rf_channel_flag = TRUE; + // calculate the delay + T2 = read_current_fine_time(); + delay = (T2 > ISR_entry_time) ? (T2 - ISR_entry_time) : (BASE_TIME_UNITS - ISR_entry_time + T2); + calibra_time = pGlobal_config[SCAN_RSP_DELAY]; // consider rx_done to ISR time, SW delay after read_current_fine_time(), func read_current_fine_time() delay ... + delay = 118 - delay - calibra_time; // IFS = 150us, Tx tail -> Rx done time: about 32us + ll_hw_set_trx_settle(delay, // set BB delay, about 80us in 16MHz HCLK + pGlobal_config[LL_HW_AFE_DELAY], + pGlobal_config[LL_HW_PLL_DELAY]); //RxAFE,PLL + ll_hw_go(); + llWaitingIrq = TRUE; + g_same_rf_channel_flag = FALSE; + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(tx_scanRsp_desc.txheader), + ((tx_scanRsp_desc.txheader & 0xff00) >> 8) + 2); // payload length + header length(2) + ll_debug_output(DEBUG_LL_HW_SET_STX); + g_pmCounters.ll_send_scan_rsp_cnt ++; + } + } + } + } + else if (pdu_type == ADV_CONN_REQ + && (pAdvInfo->parameter.advEventProperties == LL_EXT_ADV_PROP_ADV_IND + || pAdvInfo->parameter.advEventProperties == LL_EXT_ADV_PROP_ADV_LDC_ADV + || pAdvInfo->parameter.advEventProperties == LL_EXT_ADV_PROP_ADV_HDC_ADV)) + { + // 2. connect req + g_pmCounters.ll_recv_conn_req_cnt ++; + + // check AdvA + if (g_rx_adv_buf.data[6] != ownAddr[0] + || g_rx_adv_buf.data[7] != ownAddr[1] + || g_rx_adv_buf.data[8] != ownAddr[2] + || g_rx_adv_buf.data[9] != ownAddr[3] + || g_rx_adv_buf.data[10] != ownAddr[4] + || g_rx_adv_buf.data[11] != ownAddr[5]) + { + // nothing to do + } + else + { + uint8_t rpaListIndex; + peerAddr = &g_rx_adv_buf.data[0]; // initA + + // Resolving list checking + if (g_llRlEnable == TRUE && + txAdd == LL_DEV_ADDR_TYPE_RANDOM && + (g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) + { + rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]); + + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM) + { + peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; + } + else + bWlRlCheckOk = FALSE; + } + + // check white list + if ((pGlobal_config[LL_SWITCH] & LL_WHITELIST_ALLOW) + && (llState == LL_STATE_ADV_UNDIRECTED) + && (adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_CONNECT_REQ + || adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_ALL_REQ) + && (bWlRlCheckOk == TRUE)) + { + // check white list + bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr); + } + + // fixed bug 2018-09-25, LL/CON/ADV/BV-04-C, for direct adv, initA should equal peer Addr + if (llState == LL_STATE_ADV_DIRECTED) + { + if (txAdd != peerInfo.peerAddrType + || peerAddr[0] != peerInfo.peerAddr[0] + || peerAddr[1] != peerInfo.peerAddr[1] + || peerAddr[2] != peerInfo.peerAddr[2] + || peerAddr[3] != peerInfo.peerAddr[3] + || peerAddr[4] != peerInfo.peerAddr[4] + || peerAddr[5] != peerInfo.peerAddr[5]) + { + // not match, check next + bWlRlCheckOk = FALSE; + } + } + + if (bWlRlCheckOk == FALSE) // if not in white list, do nothing + { + g_pmCounters.ll_filter_conn_req_cnt ++; + } + else + { + // increment statistics counter + g_pmCounters.ll_rx_peer_cnt++; + // bug fixed 2018-01-23, peerAddrType should read TxAdd + peerInfo.peerAddrType = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + osal_memcpy( peerInfo.peerAddr, g_rx_adv_buf.data, 6); + move_to_slave_function(); // move to slave role for connection state + // add 04-01, set adv inactive, and it will be remove from the scheduler when invoke ll_adv_scheduler() + pAdvInfo->active = FALSE; + LL_AdvSetTerminatedCback(LL_STATUS_SUCCESS, + pAdvInfo->advHandle, + adv_param.connId, + pAdvInfo->adv_event_counter); + } + } + } + } + else if (mode == LL_HW_MODE_TRX && + (irq_status & LIRQ_COK)) + { + // TRX mode, receives AUX_SCAN_REQ or AUX_CONNECT_REQ + uint8_t packet_len, pdu_type, txAdd; + uint8_t* peerAddr; + uint8_t bWlRlCheckOk = TRUE; + uint16_t pktLen; + uint32_t pktFoot0, pktFoot1; + int calibra_time; // this parameter will be provided by global_config + uint8* ownAddr; + ll_debug_output(DEBUG_LL_HW_TRX); + // read packet + packet_len = ll_hw_read_rfifo((uint8_t*)(&(g_rx_adv_buf.rxheader)), + &pktLen, + &pktFoot0, + &pktFoot1); + + if(ll_hw_get_rfifo_depth() > 0) + { + g_pmCounters.ll_rfifo_read_err++; + packet_len=0; + pktLen=0; + } + + // check receive pdu type + pdu_type = g_rx_adv_buf.rxheader & PDU_TYPE_MASK; + txAdd = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + + if (pAdvInfo->parameter.ownAddrType == LL_DEV_ADDR_TYPE_RANDOM && pAdvInfo->parameter.isOwnRandomAddressSet == TRUE) + ownAddr = pAdvInfo->parameter.ownRandomAddress; + else + ownAddr = ownPublicAddr; + + if (packet_len > 0 + && pdu_type == ADV_AUX_SCAN_REQ + && (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_CONN_BITMASK + || pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_SCAN_BITMASK)) + { + // 1. scan req +// g_pmCounters.ll_recv_scan_req_cnt ++; + + // check AdvA + if (g_rx_adv_buf.data[6] != ownAddr[0] + || g_rx_adv_buf.data[7] != ownAddr[1] + || g_rx_adv_buf.data[8] != ownAddr[2] + || g_rx_adv_buf.data[9] != ownAddr[3] + || g_rx_adv_buf.data[10] != ownAddr[4] + || g_rx_adv_buf.data[11] != ownAddr[5]) + { + } + else + { + uint8_t rpaListIndex; + peerAddr = &g_rx_adv_buf.data[0]; // ScanA + + // Resolving list checking + if (g_llRlEnable == TRUE && + txAdd == LL_DEV_ADDR_TYPE_RANDOM && + (g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) + { + rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]); + + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM) + { + peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; + } + else + bWlRlCheckOk = FALSE; + } + + // check white list + if ((pGlobal_config[LL_SWITCH] & LL_WHITELIST_ALLOW) + && (adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_SCAN_REQ + || adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_ALL_REQ) + && (bWlRlCheckOk == TRUE)) + { + // check white list + bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr); + } + + if (bWlRlCheckOk == FALSE) // if not in white list, do nothing + { + g_pmCounters.ll_filter_scan_req_cnt ++; + } + else + { + g_pmCounters.ll_rx_peer_cnt++; + llSetupAuxScanRspPDU(pAdvInfo); + // send scan rsp + ll_hw_set_stx(); // set LL HW as single Tx mode + g_same_rf_channel_flag = TRUE; + // calculate the delay + T2 = read_current_fine_time(); + delay = (T2 > ISR_entry_time) ? (T2 - ISR_entry_time) : (BASE_TIME_UNITS - ISR_entry_time + T2); + calibra_time = pGlobal_config[SCAN_RSP_DELAY]; // consider rx_done to ISR time, SW delay after read_current_fine_time(), func read_current_fine_time() delay ... + delay = 118 - delay - calibra_time; // IFS = 150us, Tx tail -> Rx done time: about 32us + ll_hw_set_trx_settle(delay, // set BB delay, about 80us in 16MHz HCLK + pGlobal_config[LL_HW_AFE_DELAY], + pGlobal_config[LL_HW_PLL_DELAY]); //RxAFE,PLL + ll_hw_go(); + llWaitingIrq = TRUE; + g_same_rf_channel_flag = FALSE; + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + //write Tx FIFO + // =================== TODO: change the buffer to ext adv set + ll_hw_write_tfifo((uint8*)&(g_tx_ext_adv_buf.txheader), + ((g_tx_ext_adv_buf.txheader & 0xff00) >> 8) + 2); // payload length + header length(2) + ll_debug_output(DEBUG_LL_HW_SET_STX); + g_pmCounters.ll_send_scan_rsp_cnt ++; + } + } + } + else if (pdu_type == ADV_CONN_REQ + && (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_CONN_BITMASK)) + { + // 2. connect req + g_pmCounters.ll_recv_conn_req_cnt ++; + + // check AdvA + if (g_rx_adv_buf.data[6] != ownAddr[0] + || g_rx_adv_buf.data[7] != ownAddr[1] + || g_rx_adv_buf.data[8] != ownAddr[2] + || g_rx_adv_buf.data[9] != ownAddr[3] + || g_rx_adv_buf.data[10] != ownAddr[4] + || g_rx_adv_buf.data[11] != ownAddr[5]) + { + // nothing to do + } + else + { + uint8_t rpaListIndex; + peerAddr = &g_rx_adv_buf.data[0]; // initA + + // Resolving list checking + if (g_llRlEnable == TRUE && + txAdd == LL_DEV_ADDR_TYPE_RANDOM && + (g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) + { + rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]); + + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM) + { + peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; + } + else + bWlRlCheckOk = FALSE; + } + + // check white list + if ((pGlobal_config[LL_SWITCH] & LL_WHITELIST_ALLOW) + && (llState == LL_STATE_ADV_UNDIRECTED) + && (adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_CONNECT_REQ + || adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_ALL_REQ) + && (bWlRlCheckOk == TRUE)) + { + // check white list + bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr); + } + + if (bWlRlCheckOk == FALSE) // if not in white list, do nothing + { + g_pmCounters.ll_filter_conn_req_cnt ++; + } + else + { + // increment statistics counter + g_pmCounters.ll_rx_peer_cnt++; +//============== + llSetupAuxConnectRspPDU(pAdvInfo); + // send scan rsp + ll_hw_set_stx(); // set LL HW as single Tx mode + g_same_rf_channel_flag = TRUE; + // calculate the delay + T2 = read_current_fine_time(); + delay = (T2 > ISR_entry_time) ? (T2 - ISR_entry_time) : (BASE_TIME_UNITS - ISR_entry_time + T2); + calibra_time = pGlobal_config[SCAN_RSP_DELAY]; // consider rx_done to ISR time, SW delay after read_current_fine_time(), func read_current_fine_time() delay ... + delay = 118 - delay - calibra_time; // IFS = 150us, Tx tail -> Rx done time: about 32us + ll_hw_set_trx_settle(delay, // set BB delay, about 80us in 16MHz HCLK + pGlobal_config[LL_HW_AFE_DELAY], + pGlobal_config[LL_HW_PLL_DELAY]); //RxAFE,PLL + ll_hw_go(); + llWaitingIrq = TRUE; + g_same_rf_channel_flag = FALSE; + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(g_tx_adv_buf.txheader), + ((g_tx_adv_buf.txheader & 0xff00) >> 8) + 2); // payload length + header length(2) + ll_debug_output(DEBUG_LL_HW_SET_STX); + g_pmCounters.ll_send_conn_rsp_cnt ++; +//============== + // bug fixed 2018-01-23, peerAddrType should read TxAdd + peerInfo.peerAddrType = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + osal_memcpy( peerInfo.peerAddr, g_rx_adv_buf.data, 6); + move_to_slave_function(); // move to slave role for connection state + // add 04-01, set adv inactive, and it will be remove from the scheduler when invoke ll_adv_scheduler() + pAdvInfo->active = FALSE; + LL_AdvSetTerminatedCback(LL_STATUS_SUCCESS, + pAdvInfo->advHandle, + adv_param.connId, + pAdvInfo->adv_event_counter); + } + } + } + } + else if (mode == LL_HW_MODE_STX ) + { + } + +// // update scheduler list +// ll_adv_scheduler(); + + if (!llWaitingIrq) + { + // update scheduler list // update 04-01, consider sending aux_scan_rsp/aux_conn_rsp case, will invoke scheduler after STX IRQ + ll_adv_scheduler(); + ll_hw_clr_irq(); + llTaskState = LL_TASK_OTHERS; + } + + HAL_EXIT_CRITICAL_SECTION(); + return TRUE; +} +#else +uint8 ll_processExtAdvIRQ(uint32_t irq_status) +{ + return TRUE; +} +#endif + +#ifdef PRD_ADV_ENABLE +uint8 ll_processPrdAdvIRQ(uint32_t irq_status) +{ + uint8 mode; +// extAdvInfo_t *pAdvInfo; +// periodicAdvInfo_t *pAdvInfo_prd; +// uint32_t T2, delay; +// pAdvInfo = g_pAdvSchInfo_periodic[g_currentExtAdv_periodic].pAdvInfo; +// pAdvInfo_prd = g_pAdvSchInfo_periodic[g_currentExtAdv_periodic].pAdvInfo_prd; +// if (pAdvInfo == NULL || pAdvInfo_prd == NULL) +// return FALSE; + HAL_ENTER_CRITICAL_SECTION(); + mode = ll_hw_get_tr_mode(); + + if (mode == LL_HW_MODE_STX ) + { + } + + // update scheduler list + ll_adv_scheduler_periodic(); + + if (!llWaitingIrq) + { + ll_hw_clr_irq(); + llTaskState = LL_TASK_OTHERS; + } + + HAL_EXIT_CRITICAL_SECTION(); + return TRUE; +} +#else +uint8 ll_processPrdAdvIRQ(uint32_t irq_status) +{ + return TRUE; +} +#endif + +#ifdef EXT_SCAN_ENABLE +//#pragma O0 +uint8 ll_processExtScanIRQ(uint32_t irq_status) +{ + uint8 ll_mode, adv_mode, ext_hdr_len; +// extScanInfo_t *pScanInfo; + uint32_t T2, delay; +// pScanInfo = &extScanInfo; + HAL_ENTER_CRITICAL_SECTION(); + ll_mode = ll_hw_get_tr_mode(); + + if (ll_mode == LL_HW_MODE_SRX) // passive scan + { + uint8_t rpaListIndex = LL_RESOLVINGLIST_ENTRY_NUM; + uint8_t bWlRlCheckOk = TRUE; + uint8_t* peerAddr = &ext_adv_hdr.advA[0]; + uint8 peerAddrType; // peer address type + ll_debug_output(DEBUG_LL_HW_SRX); + + // ============= scan case + if (llTaskState == LL_TASK_EXTENDED_SCAN) + { + uint8 bSendingScanReq = FALSE; + memset(&ext_adv_hdr, 0, sizeof(ext_adv_hdr)); + + // check status + if ((irq_status & LIRQ_RD) && (irq_status & LIRQ_COK)) + { + // rx done + uint8_t packet_len, pdu_type; + uint16_t pktLen; + uint32_t pktFoot0, pktFoot1; + // read packet + packet_len = ll_hw_read_rfifo((uint8_t*)(&(g_rx_adv_buf.rxheader)), + &pktLen, + &pktFoot0, + &pktFoot1); + // check receive pdu type + pdu_type = g_rx_adv_buf.rxheader & 0x0f; + + if(ll_hw_get_rfifo_depth() > 0) + { + g_pmCounters.ll_rfifo_read_err++; + packet_len = 0; + pktLen = 0; + } + + if (packet_len != 0 + && (pdu_type == ADV_EXT_TYPE)) + { + uint8_t txAdd = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + uint8 payload_len = (g_rx_adv_buf.rxheader & 0xFF00) >> LENGTH_SHIFT; + uint8 adv_data_len; + peerAddrType = txAdd; + adv_mode = (g_rx_adv_buf.data[0] & 0xc0) >> 6; + ext_hdr_len = g_rx_adv_buf.data[0] & 0x3f; + ll_parseExtHeader(&g_rx_adv_buf.data[1], payload_len - 1); + peerAddr = &ext_adv_hdr.advA[0]; + + // Resolving list checking + if (g_llRlEnable == TRUE + && (adv_mode== LL_EXT_ADV_MODE_CONN || adv_mode == LL_EXT_ADV_MODE_SC ) // BQB test only required checking RL for scanable ADV + && (ext_adv_hdr.header & LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK)) + { + // if ScanA is resolvable private address + if ((ext_adv_hdr.advA[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) + { + bWlRlCheckOk = FALSE; + rpaListIndex = ll_getRPAListEntry(&ext_adv_hdr.advA[0]); + + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM) + { + peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; + bWlRlCheckOk = TRUE; + } + } + else // ScanA is device Identity, if the device ID in the RPA list, check whether RPA should be used + { + bWlRlCheckOk = TRUE; + + for (int i = 0; i < LL_RESOLVINGLIST_ENTRY_NUM; i++) + { + if (ext_adv_hdr.advA[0] == g_llResolvinglist[i].peerAddr[0] + && ext_adv_hdr.advA[1] == g_llResolvinglist[i].peerAddr[1] + && ext_adv_hdr.advA[2] == g_llResolvinglist[i].peerAddr[2] + && ext_adv_hdr.advA[3] == g_llResolvinglist[i].peerAddr[3] + && ext_adv_hdr.advA[4] == g_llResolvinglist[i].peerAddr[4] + && ext_adv_hdr.advA[5] == g_llResolvinglist[i].peerAddr[5]) + { + if (g_llResolvinglist[i].privacyMode == NETWORK_PRIVACY_MODE && + !ll_isIrkAllZero(g_llResolvinglist[i].peerIrk)) + bWlRlCheckOk = FALSE; + + break; + } + } + } + } + + // check white list + if ((pGlobal_config[LL_SWITCH] & LL_WHITELIST_ALLOW) + && (extScanInfo.wlPolicy == LL_SCAN_WL_POLICY_USE_WHITE_LIST) + && (bWlRlCheckOk == TRUE)) + { + // check white list + bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr); + } + + // if valid, trigger osal event to report adv + if (bWlRlCheckOk == TRUE) + { + uint8 advEventType = 0; + int8 rssi; + +// llCurrentScanChn = extScanInfo.nextScanChan; + + // active scan scenario, send scan req + if (extScanInfo.scanType[extScanInfo.current_index] == LL_SCAN_ACTIVE + && adv_mode == LL_EXT_ADV_MODE_SC ) // only scannable adv accept AUX_SCAN_REQ + { + // ========================== active scan path =================== + // fill scanA, using RPA or device ID address + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM && + !ll_isIrkAllZero(g_llResolvinglist[rpaListIndex].localIrk)) + { + // for resolving private address case, calculate the scanA with Local IRK + ll_CalcRandomAddr(g_llResolvinglist[rpaListIndex].localIrk, &g_tx_adv_buf.data[0]); + g_tx_adv_buf.txheader |=(((g_rx_adv_buf.rxheader & TX_ADD_MASK) << 1) + | (LL_DEV_ADDR_TYPE_RANDOM << TX_ADD_SHIFT & TX_ADD_MASK)); + } + else + { + memcpy((uint8*)&g_tx_adv_buf.data[0], &extScanInfo.ownAddr[0], 6); + g_tx_adv_buf.txheader |=(((g_rx_adv_buf.rxheader & TX_ADD_MASK) << 1) + | (extScanInfo.ownAddrType << TX_ADD_SHIFT & TX_ADD_MASK)); + } + + g_tx_adv_buf.txheader = 0xC03; + g_same_rf_channel_flag = TRUE; + ll_hw_set_tx_rx_interval(10); + ll_hw_set_rx_timeout(158); + set_max_length(0xFF); // add 2020-03-10 + T2 = read_current_fine_time(); + delay = (T2 > ISR_entry_time) ? (T2 - ISR_entry_time) : (BASE_TIME_UNITS - ISR_entry_time + T2); + delay = 118 - delay - pGlobal_config[LL_ADV_TO_SCAN_REQ_DELAY]; + ll_hw_set_trx(); // set LL HW as single TRx mode + ll_hw_set_trx_settle(delay, // set BB delay, about 80us in 16MHz HCLK + pGlobal_config[LL_HW_AFE_DELAY], + pGlobal_config[LL_HW_PLL_DELAY]); //RxAFE,PLL + ll_hw_go(); + g_pmCounters.ll_send_scan_req_cnt++; + llWaitingIrq = TRUE; + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + ll_hw_ign_rfifo(LL_HW_IGN_CRC | LL_HW_IGN_EMP); +// //20181012 ZQ: change the txheader according to the adtype +// g_tx_adv_buf.txheader |=(((g_rx_adv_buf.rxheader & TX_ADD_MASK) << 1) +// | (extScanInfo.ownAddrType<< TX_ADD_SHIFT & TX_ADD_MASK)); + // AdvA, for SCAN REQ, it should identical to the ADV_IND/ADV_SCAN_IND + g_tx_adv_buf.data[6] = peerAddr[0]; + g_tx_adv_buf.data[7] = peerAddr[1]; + g_tx_adv_buf.data[8] = peerAddr[2]; + g_tx_adv_buf.data[9] = peerAddr[3]; + g_tx_adv_buf.data[10] = peerAddr[4]; + g_tx_adv_buf.data[11] = peerAddr[5]; + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(g_tx_adv_buf.txheader), + ((g_tx_adv_buf.txheader & 0xff00) >> 8) + 2); // payload length + header length(2) + bSendingScanReq = TRUE; + g_same_rf_channel_flag = FALSE; + // ========================== active scan path end =================== + } + + adv_data_len = payload_len - ext_hdr_len - 1; + rssi = -(pktFoot1 >> 24); + + if (adv_data_len > 0) + { + // copy the adv_data + LL_ExtAdvReportCback( advEventType, // event type + peerAddrType, // Adv address type (TxAdd) + &peerAddr[0], // Adv address (AdvA) + extScanInfo.scanPHYs[extScanInfo.current_index], // primary PHY + extScanInfo.current_scan_PHY, // secondary PHY + (ext_adv_hdr.adi & 0xF000) >> 12, + ext_adv_hdr.txPower, + rssi, + 0, // periodicAdvertisingInterval, reserved + 0, + NULL, // NULL for undirect adv report + pktLen - 8, // length of rest of the payload, 2 - header, 6 - advA + &g_rx_adv_buf.data[6]); // rest of payload + g_pmCounters.ll_recv_adv_pkt_cnt ++; + } + else if (ext_adv_hdr.header & LE_EXT_HDR_SYNC_INFO_PRESENT_BITMASK) + { + LL_ExtAdvReportCback( 0, // event type + peerAddrType, // Adv address type (TxAdd) + &peerAddr[0], // Adv address (AdvA) + extScanInfo.scanPHYs[extScanInfo.current_index], // primary PHY + extScanInfo.current_scan_PHY, // secondary PHY + (ext_adv_hdr.adi & 0xF000) >> 12, + ext_adv_hdr.txPower, + rssi, + syncInfo.interval, // periodicAdvertisingInterval, TO update + 0, + NULL, // NULL for undirect adv report + 0, // for periodic syncInfo, no adv data + &g_rx_adv_buf.data[6]); // rest of payload + } + } + } + else + { + // invalid ADV PDU type +// llSetupScan(); + } + } + + // if not waiting for scan rsp, schedule next scan + if (!bSendingScanReq) + { + uint8 bStartPeriodScan = FALSE; + + // =========== scanning periodic adv case + if ((ext_adv_hdr.header & LE_EXT_HDR_SYNC_INFO_PRESENT_BITMASK) + && (scanSyncInfo.valid == TRUE)) + { + // create sync with periodic advertiser + if (scanSyncInfo.options & LL_PERIODIC_ADV_CREATE_SYNC_USING_ADV_LIST_BITMASK) + { + // using device list case, TO be added in future release + bStartPeriodScan = TRUE; + } + else + { + if (((ext_adv_hdr.adi >> 12) & 0x0F) == scanSyncInfo.advertising_SID + && peerAddrType == scanSyncInfo.advertiser_Address_Type + && memcmp(&peerAddr[0], &scanSyncInfo.advertiser_Address[0], LL_DEVICE_ADDR_LEN) == 0) + { + // find the periodic sync info, sync with the period adv + bStartPeriodScan = TRUE; + } + } + + if (bStartPeriodScan == TRUE) + { + uint16 sync_handler; + uint32 schedule_time; + uint32 accessAddress; + llPeriodicScannerInfo_t* pPrdScanInfo; + sync_handler = llAllocateSyncHandle(); + pPrdScanInfo = &g_llPeriodAdvSyncInfo[sync_handler]; // only 1 period scanner + // get elapse time since the AUX_ADV_IND start point + pPrdScanInfo->syncHandler = sync_handler; + pPrdScanInfo->eventCounter = syncInfo.event_counter; + pPrdScanInfo->advInterval = syncInfo.interval * 1250; + memcpy(&pPrdScanInfo->chnMap[0], &syncInfo.chn_map[0], 4); + pPrdScanInfo->chnMap[4] = syncInfo.chn_map4.chn_map; + pPrdScanInfo->sca = syncInfo.chn_map4.sca; + memcpy(&pPrdScanInfo->accessAddress[0], &syncInfo.AA[0], 4); + memcpy(&pPrdScanInfo->crcInit[0], &syncInfo.crcInit[0], 3); // TO check bit order + accessAddress = (pPrdScanInfo->accessAddress[3] << 24) + | (pPrdScanInfo->accessAddress[2] << 16) + | (pPrdScanInfo->accessAddress[1] << 8) + | pPrdScanInfo->accessAddress[0]; + pPrdScanInfo->advPhy = extScanInfo.current_scan_PHY; + pPrdScanInfo->syncTimeout = scanSyncInfo.sync_Timeout * 1250; + pPrdScanInfo->syncCteType = scanSyncInfo.sync_CTE_Type; + pPrdScanInfo->skip = scanSyncInfo.skip; + // calculate next event timer, need consider the start point of AUX_ADV_IND + pPrdScanInfo->nextEventRemainder = ((syncInfo.offset.offsetUnit == 1) ? 300 : 30) * syncInfo.offset.syncPacketOffset; + pPrdScanInfo->syncEstOk = FALSE; + pPrdScanInfo->event1stFlag = TRUE; // receiving the 1st PDU of a periodic event + // TODO + pPrdScanInfo->channelIdentifier = (( accessAddress & 0xFFFF0000 )>> 16 ) ^ ( accessAddress & 0x0000FFFF); + schedule_time = g_llPeriodAdvSyncInfo[sync_handler].nextEventRemainder - 2500; // 1000: timing advance + + for (int i = 0; i < LL_NUM_BYTES_FOR_CHAN_MAP; i++) + { + // for each channel given by a bit in each of the bytes + // Note: When i is on the last byte, only 5 bits need to be checked, but + // it is easier here to check all 8 with the assumption that the rest + // of the reserved bits are zero. + for (uint8 j = 0; j < 8; j++) + { + // check if the channel is used; only interested in used channels + if ( (pPrdScanInfo->chnMap[i] >> j) & 1 ) + { + // sequence used channels in ascending order + pPrdScanInfo->chanMapTable[pPrdScanInfo->numUsedChans] = (i * 8U) + j; + // count it + pPrdScanInfo->numUsedChans++; + } + } + } + + pPrdScanInfo->currentEventChannel = llGetNextDataChanCSA2(pPrdScanInfo->eventCounter, + pPrdScanInfo->channelIdentifier, + pPrdScanInfo->chnMap, + pPrdScanInfo->chanMapTable, + pPrdScanInfo->numUsedChans); + g_llPeriodAdvSyncInfo[sync_handler].current_channel = pPrdScanInfo->currentEventChannel; + // start timer + ll_prd_scan_schedule_next_event(schedule_time); +// LOG("<%d>", schedule_time); + } + } + + // ============== scanning extended adv case + // case 1: receives auxPtr, update PHY/chn according to AuxPtr, start timer according to aux offset + if (bStartPeriodScan == FALSE) + { + if (ext_adv_hdr.header & LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK) + { + uint32 wait_time; + extScanInfo.current_chn = ext_adv_hdr.auxPtr.chn_idx; + extScanInfo.current_scan_PHY = ext_adv_hdr.auxPtr.aux_phy; + wait_time = ext_adv_hdr.auxPtr.aux_offset * ((ext_adv_hdr.auxPtr.offset_unit == 1) ? 300 : 30); + + if (wait_time < 2000) + wait_time = 10; + else + wait_time -= 1000; // scan advance + + llScanTime = 0; + ll_ext_scan_schedule_next_event(wait_time); + } + // case 2: scanning aux channel, no more aux PDU, continue to scan in primary channel + else if (extScanInfo.current_chn < LL_SCAN_ADV_CHAN_37) + { + extScanInfo.current_chn = LL_SCAN_ADV_CHAN_37; + + if (extScanInfo.numOfScanPHY > 1) + { + extScanInfo.current_index = (extScanInfo.current_index + 1) & 0x01; + } + + extScanInfo.current_scan_PHY = extScanInfo.scanPHYs[extScanInfo.current_index]; + llSetupExtScan(extScanInfo.current_chn); + llScanTime = 0; + } + // case 3: update scan time, only when scan primary channel and not receive AuxPtr + else + { + // not sending SCAN REQ, update scan time + llScanTime += ((ISR_entry_time > llScanT1) ? (ISR_entry_time - llScanT1) : (BASE_TIME_UNITS - llScanT1 + ISR_entry_time)); + + if (llScanTime >= extScanInfo.scanWindow[extScanInfo.current_index] * 625) + { + if (extScanInfo.numOfScanPHY > 1 && extScanInfo.current_chn == LL_SCAN_ADV_CHAN_39) + { + extScanInfo.current_index = (extScanInfo.current_index + 1) & 0x01; + extScanInfo.current_scan_PHY = extScanInfo.scanPHYs[extScanInfo.current_index]; + } + + LL_CALC_NEXT_SCAN_CHN(extScanInfo.current_chn); + + // schedule next scan event + if (extScanInfo.scanWindow[extScanInfo.current_index] == extScanInfo.scanInterval[extScanInfo.current_index]) // scanWindow == scanInterval, trigger immediately + llSetupExtScan(extScanInfo.current_chn); + else + ll_ext_scan_schedule_next_event((extScanInfo.scanInterval[extScanInfo.current_index] + - extScanInfo.scanWindow[extScanInfo.current_index]) * 625); + + // reset scan total time + llScanTime = 0; + } + else + { + llSetupExtScan(extScanInfo.current_chn); + } + } + } + } + } + // =========== initiator case + else if (llTaskState == LL_TASK_EXTENDED_INIT) + { + } + } + else if (ll_mode == LL_HW_MODE_TRX && llTaskState == LL_TASK_EXTENDED_SCAN) // active scan + { + if ((irq_status & LIRQ_RD) && (irq_status & LIRQ_COK)) + { + // rx done + } + } + + if (!llWaitingIrq) + { + ll_hw_clr_irq(); + llTaskState = LL_TASK_OTHERS; + } + + HAL_EXIT_CRITICAL_SECTION(); + return TRUE; +} +//#pragma O2 + +uint8 ll_processExtInitIRQ(uint32_t irq_status) +{ + //uint8 ll_mode, adv_mode, ext_hdr_len; + uint8 ll_mode, adv_mode; + llConnState_t* connPtr; + uint32_t T2, delay; + HAL_ENTER_CRITICAL_SECTION(); + ll_mode = ll_hw_get_tr_mode(); +// hal_gpio_write(GPIO_P14, 1); +// hal_gpio_write(GPIO_P14, 0); + + if (ll_mode == LL_HW_MODE_SRX) + { + uint8_t bWlRlCheckOk = TRUE; + uint8 bConnecting = FALSE; + connPtr = &conn_param[extInitInfo.connId]; // connId is allocated when create conn + memset(&ext_adv_hdr, 0, sizeof(ext_adv_hdr)); + + // check status + if ((irq_status & LIRQ_RD) && (irq_status & LIRQ_COK)) + { + // rx done + uint8_t packet_len, pdu_type; + uint16_t pktLen; + uint32_t pktFoot0, pktFoot1; + // read packet + packet_len = ll_hw_read_rfifo((uint8_t*)(&(g_rx_adv_buf.rxheader)), + &pktLen, + &pktFoot0, + &pktFoot1); + // check receive pdu type + pdu_type = g_rx_adv_buf.rxheader & 0x0f; + + if(ll_hw_get_rfifo_depth() > 0) + { + g_pmCounters.ll_rfifo_read_err++; + packet_len = 0; + pktLen = 0; + } + + if (packet_len != 0 + && (pdu_type == ADV_EXT_TYPE)) + { + // never used (addrType, txAdd) + //uint8 addrType; // peer address type + //uint8_t txAdd = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + uint8 payload_len = (g_rx_adv_buf.rxheader & 0xFF00) >> LENGTH_SHIFT; + //addrType = txAdd; // TO check //never used + adv_mode = (g_rx_adv_buf.data[0] & 0xc0) >> 6; + //ext_hdr_len = g_rx_adv_buf.data[0] & 0x3f; //never used + ll_parseExtHeader(&g_rx_adv_buf.data[1], payload_len - 1); +// ================ RPA for extended init, need investigate more + // Resolving list checking +// if (g_llRlEnable == TRUE && +// txAdd == LL_DEV_ADDR_TYPE_RANDOM && +// (g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) +// +// { +// rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]); +// if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM) +// { +// peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; +// } +// else +// bWlRlCheckOk = FALSE; +// } +// ================ RPA for extended init, end + #if 0 + + // initiator, 2 types of filter process: 1. connect to peer address set by host 2. connect to address in whitelist only + // 1. connect to peer address set by host + if (initInfo.wlPolicy == LL_INIT_WL_POLICY_USE_PEER_ADDR + && bWlRlCheckOk == TRUE) + { + if (txAdd != peerInfo.peerAddrType + || peerAddr[0] != peerInfo.peerAddr[0] + || peerAddr[1] != peerInfo.peerAddr[1] + || peerAddr[2] != peerInfo.peerAddr[2] + || peerAddr[3] != peerInfo.peerAddr[3] + || peerAddr[4] != peerInfo.peerAddr[4] + || peerAddr[5] != peerInfo.peerAddr[5]) + { + // not match, not init connect + bWlRlCheckOk = FALSE; + } + } + // 2. connect to address in whitelist only + else if (initInfo.wlPolicy == LL_INIT_WL_POLICY_USE_WHITE_LIST && + bWlRlCheckOk == TRUE) + { + // if advA in whitelist list, connect + // check white list + bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr); + } + + #endif + + if (bWlRlCheckOk == TRUE + && (adv_mode== LL_EXT_ADV_MODE_CONN) // connectable adv + && !(ext_adv_hdr.header & LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK)) // AUX_ADV_IND + { + g_same_rf_channel_flag = TRUE; + // =============== TODO: construct AUX_CONN_REQ PDU + llSetupAuxConnectReqPDU(); + ll_hw_set_tx_rx_interval(10); + ll_hw_set_rx_timeout(158); + set_max_length(50); + // send conn req + T2 = read_current_fine_time(); + delay = (T2 > ISR_entry_time) ? (T2 - ISR_entry_time) : (BASE_TIME_UNITS - ISR_entry_time + T2); + delay = 118 - delay - pGlobal_config[LL_ADV_TO_CONN_REQ_DELAY]; + ll_hw_set_trx_settle(delay, // set BB delay, about 80us in 16MHz HCLK + pGlobal_config[LL_HW_AFE_DELAY], + pGlobal_config[LL_HW_PLL_DELAY]); //RxAFE,PLL + // send conn req + ll_hw_set_trx(); // set LL HW as single Tx mode + ll_hw_go(); + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + ll_hw_ign_rfifo(LL_HW_IGN_CRC | LL_HW_IGN_EMP); + llWaitingIrq = TRUE; +// hal_gpio_write(GPIO_P15, 1); +// hal_gpio_write(GPIO_P15, 0); + // AdvA, offset 6 + memcpy((uint8*)&g_tx_adv_buf.data[6], &ext_adv_hdr.advA[0], 6); + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(g_tx_adv_buf.txheader), + ((g_tx_adv_buf.txheader & 0xff00) >> 8) + 2); // payload length + header length(2) + move_to_master_function(); + bConnecting = TRUE; + g_same_rf_channel_flag = FALSE; + } + } + else if (packet_len != 0 + && (pdu_type == ADV_DIRECT_IND)) // TODO: add process of direct ADV + { + } + } + + // scan again if not start connect + if (!bConnecting) // if not waiting for scan rsp, schedule next scan + { + if (extInitInfo.scanMode == LL_SCAN_STOP) + { + // scan has been stopped + llState = LL_STATE_IDLE; // for single connection case, set the LL state idle + // release the associated allocated connection + llReleaseConnId(connPtr); // new for multi-connection + g_ll_conn_ctx.numLLMasterConns --; + (void)osal_set_event( LL_TaskID, LL_EVT_MASTER_CONN_CANCELLED ); // inform high layer + } + else + { + // not sending SCAN REQ, update scan time + llScanTime += ((ISR_entry_time > llScanT1) ? (ISR_entry_time - llScanT1) : (BASE_TIME_UNITS - llScanT1 + ISR_entry_time)); + + if (ext_adv_hdr.header & LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK) // receive aux channel information + { + uint32 wait_time; + extInitInfo.current_chn = ext_adv_hdr.auxPtr.chn_idx; + extInitInfo.current_scan_PHY = ext_adv_hdr.auxPtr.aux_phy; + wait_time = ext_adv_hdr.auxPtr.aux_offset * ((ext_adv_hdr.auxPtr.offset_unit == 1) ? 300 : 30); + wait_time -= (ext_adv_hdr.auxPtr.ca == 0) ? 500 : 499; // temporary setting, consider clock accuracy + llScanTime = 0; + ll_ext_init_schedule_next_event(wait_time); + } + else if (llScanTime >= extInitInfo.scanWindow[extInitInfo.current_index] * 625) + { + if (extInitInfo.numOfScanPHY > 1 && extInitInfo.current_chn == LL_SCAN_ADV_CHAN_39) + { + extInitInfo.current_index = (extInitInfo.current_index + 1) & 0x01; + extInitInfo.current_scan_PHY = extInitInfo.initPHYs[extInitInfo.current_index]; + } + + LL_CALC_NEXT_SCAN_CHN(extInitInfo.current_chn); + + // schedule next scan event + if (extInitInfo.scanWindow[extInitInfo.current_index] == extInitInfo.scanInterval[extInitInfo.current_index]) // scanWindow == scanInterval, trigger immediately + llSetupExtInit(); + else + ll_ext_init_schedule_next_event((extInitInfo.scanInterval[extInitInfo.current_index] + - extInitInfo.scanWindow[extInitInfo.current_index]) * 625); + + // reset scan total time + llScanTime = 0; + } + else + { + extInitInfo.current_scan_PHY = extInitInfo.initPHYs[extInitInfo.current_index]; + llSetupExtInit(); + } + } + } + } + else if (ll_mode == LL_HW_MODE_TRX) // init case, waiting for AUX_CONNECT_RSP + { +//============= + uint8_t packet_len, pdu_type;//, txAdd; + uint16_t pktLen; + uint32_t pktFoot0, pktFoot1; + uint8 cancelConnect = FALSE; + ll_debug_output(DEBUG_LL_HW_TRX); + + if ((irq_status & LIRQ_RD) && (irq_status & LIRQ_COK)) + { + // read packet + packet_len = ll_hw_read_rfifo((uint8_t*)(&(g_rx_adv_buf.rxheader)), + &pktLen, + &pktFoot0, + &pktFoot1); + + if(ll_hw_get_rfifo_depth() > 0) + { + g_pmCounters.ll_rfifo_read_err++; + packet_len=0; + pktLen=0; + } + + // check receive pdu type + pdu_type = g_rx_adv_buf.rxheader & PDU_TYPE_MASK; +// txAdd = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + + if (packet_len > 0 // any better checking rule for rx anything? + && pdu_type == ADV_AUX_CONN_RSP) + { +// g_pmCounters.ll_recv_scan_req_cnt ++; + + // check AdvA + if (g_rx_adv_buf.data[8] != ext_adv_hdr.advA[0] + || g_rx_adv_buf.data[9] != ext_adv_hdr.advA[1] + || g_rx_adv_buf.data[10] != ext_adv_hdr.advA[2] + || g_rx_adv_buf.data[11] != ext_adv_hdr.advA[3] + || g_rx_adv_buf.data[12] != ext_adv_hdr.advA[4] + || g_rx_adv_buf.data[13] != ext_adv_hdr.advA[5]) + { + // receive err response, cancel the connection + cancelConnect = TRUE; + } + } + } + else + cancelConnect = TRUE; + + if (cancelConnect == TRUE) + { + // TODO + // receive error connect rsp or timeout, cancel connection + } + +//=========== + } + + if (!llWaitingIrq) + { + ll_hw_clr_irq(); + llTaskState = LL_TASK_OTHERS; + } + + HAL_EXIT_CRITICAL_SECTION(); + return TRUE; +} + +uint8 ll_processPrdScanIRQ(uint32_t irq_status) +{ +// uint8 ll_mode, adv_mode, ext_hdr_len; + uint8 ext_hdr_len; + uint8 temp_event1stFlag; + uint32_t T2, wait_time = 0; + int8 rssi; + llPeriodicScannerInfo_t* pPrdScanInfo; + pPrdScanInfo = &g_llPeriodAdvSyncInfo[0]; + memset(&ext_adv_hdr, 0, sizeof(ext_adv_hdr)); + HAL_ENTER_CRITICAL_SECTION(); + // pPrdScanInfo->event1stFlag indicate we are searching AUX_SYNC_IND PDU + temp_event1stFlag = pPrdScanInfo->event1stFlag; + + if (pPrdScanInfo->event1stFlag == TRUE) + { + pPrdScanInfo->nextEventRemainder = pPrdScanInfo->advInterval; + pPrdScanInfo->eventCounter ++; // increase PA event counter + pPrdScanInfo->currentEventChannel = llGetNextDataChanCSA2(pPrdScanInfo->eventCounter, + pPrdScanInfo->channelIdentifier, + pPrdScanInfo->chnMap, + pPrdScanInfo->chanMapTable, + pPrdScanInfo->numUsedChans); + pPrdScanInfo->event1stFlag = FALSE; + } + + if ((irq_status & LIRQ_RD) && (irq_status & LIRQ_COK)) + { + // rx done + uint8_t packet_len, pdu_type; + uint16_t pktLen; + uint32_t pktFoot0, pktFoot1; + // read packet + packet_len = ll_hw_read_rfifo((uint8_t*)(&(g_rx_adv_buf.rxheader)), + &pktLen, + &pktFoot0, + &pktFoot1); + // check receive pdu type + pdu_type = g_rx_adv_buf.rxheader & 0x0f; + + if(ll_hw_get_rfifo_depth() > 0) + { + g_pmCounters.ll_rfifo_read_err++; + packet_len = 0; + pktLen = 0; + } + + pPrdScanInfo->syncLostTime = 0; + + if (pPrdScanInfo->syncEstOk == FALSE) + { + pPrdScanInfo->syncEstOk = TRUE; + LL_PrdAdvSyncEstablishedCback(0, // status + pPrdScanInfo->syncHandler, // syncHandle, + scanSyncInfo.advertising_SID, // advertisingSID, + scanSyncInfo.advertiser_Address_Type, // advertiserAddressType, + scanSyncInfo.advertiser_Address, // uint8 *advertiserAddress, + pPrdScanInfo->advPhy,// advertiserPHY, + pPrdScanInfo->advInterval,// periodicAdvertisingInterval, + pPrdScanInfo->sca// advertiserClockAccuracy + ); + scanSyncInfo.valid = FALSE; // sync establised, exit sync pending status + } + + if (packet_len != 0 + && (pdu_type == ADV_EXT_TYPE)) + { + //never used(txAdd) + //uint8_t txAdd = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + uint8 payload_len = (g_rx_adv_buf.rxheader & 0xFF00) >> LENGTH_SHIFT; + uint8 adv_data_len; + uint8 dataStatus; +// addrType = txAdd; // TO check + //adv_mode = (g_rx_adv_buf.data[0] & 0xc0) >> 6; //never used + ext_hdr_len = g_rx_adv_buf.data[0] & 0x3f; + ll_parseExtHeader(&g_rx_adv_buf.data[1], payload_len - 1); + pPrdScanInfo->IQSampleInfo.CTE_Type = ext_adv_hdr.cteInfo >> 6; + pPrdScanInfo->IQSampleInfo.CTE_Length = ext_adv_hdr.cteInfo & 0X3F; + adv_data_len = payload_len - ext_hdr_len - 1; + rssi = -(pktFoot1 >> 24); + + if (adv_data_len > 0) + { + // copy the adv_data + //LOG("len=%d\n", adv_data_len); + if (ext_adv_hdr.header & LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK) + dataStatus = 1; + else + dataStatus = 0; + + LL_PrdAdvReportCback(0, // sync handler + 0, //txPower, + rssi, + pPrdScanInfo->IQSampleInfo.CTE_Type, // to update , uint8 cteType, + dataStatus, + pktLen - 8, + &g_rx_adv_buf.data[6] + ); + g_pmCounters.ll_recv_adv_pkt_cnt ++; + } + + // for the 1st PDU of periodic adv & we have sync, fine adjust the anchor point + // loop_time: time elapse between LL trigger and now + // anchor point: time elapse between LL trigger and bb sync + // the time between bb_sync and now is what we should fine adjust + if (temp_event1stFlag == TRUE) + { + uint32 loop_time, anchor_point; + + // read loop timeout counter, system clock may be 16MHz, 32MHz, 64MHz and 48MHz, 96MHz + if (hclk_per_us_shift != 0) + loop_time = ll_hw_get_loop_cycle() >> hclk_per_us_shift; // convert to us + else + loop_time = ll_hw_get_loop_cycle() / hclk_per_us; // convert to us + + // read anchor point + if (hclk_per_us_shift != 0) + anchor_point = ll_hw_get_anchor() >> hclk_per_us_shift; // convert to us + else + anchor_point = ll_hw_get_anchor() / hclk_per_us; // convert to us + + pPrdScanInfo->nextEventRemainder -= loop_time - anchor_point; + } + + // 2020-01-21 add for connectionless IQ Sample Report + if( g_llPeriodAdvSyncInfo[0].IQSampleInfo.enable ) + { + if (ext_adv_hdr.header & LE_EXT_HDR_CTE_INFO_PRESENT_BITMASK) + { + uint8 iqCnt = 0; + +// uint16 iSample[LL_CTE_MAX_SUPP_LEN * LL_CTE_SUPP_LEN_UNIT]; +// uint16 qSample[LL_CTE_MAX_SUPP_LEN * LL_CTE_SUPP_LEN_UNIT]; + if( ( g_pLLcteISample != NULL ) && ( g_pLLcteQSample != NULL) ) + iqCnt = ll_hw_get_iq_RawSample( g_pLLcteISample, g_pLLcteQSample ); + + if(iqCnt>0) + { + LL_ConnectionlessIQReportCback( 0, // SDK only support 1 periodic scanning + ext_adv_hdr.auxPtr.chn_idx, + rssi, + // before CTE Transmit and sampling , no Antenna change , default 0 + 0, + g_llPeriodAdvSyncInfo[0].IQSampleInfo.CTE_Type, + g_llPeriodAdvSyncInfo[0].IQSampleInfo.slot_Duration, + // Packet_Status=0, CRC success,cause only CRC Correctly that can run here + 0, + g_llPeriodAdvSyncInfo[0].eventCounter, + iqCnt, + g_pLLcteISample, + g_pLLcteQSample); + } + } + } + + if (ext_adv_hdr.header & LE_EXT_HDR_AUX_PTR_PRESENT_BITMASK) + { + pPrdScanInfo->current_channel = ext_adv_hdr.auxPtr.chn_idx; + // pPrdScanInfo->advPhy = ext_adv_hdr.auxPtr.aux_phy; // periodic adv could not change PHY + wait_time = ext_adv_hdr.auxPtr.aux_offset * ((ext_adv_hdr.auxPtr.offset_unit == 1) ? 300 : 30); + + // consider the time elapse since last timer expire + if (temp_event1stFlag == FALSE) // if this is not the 1st PDU of periodic adv, update nextEventRemainder + { + uint32 elapse_time; + // calculate elapse time since last timer trigger + T2 = read_current_fine_time(); + elapse_time = LL_TIME_DELTA(g_timerExpiryTick, T2); + pPrdScanInfo->nextEventRemainder -= elapse_time; + } + + // the wait_time calculate from AUX_PTR starts from the frame start, need compensate the frame duration + uint32 loop_time, anchor_point; + + // read loop timeout counter, system clock may be 16MHz, 32MHz, 64MHz and 48MHz, 96MHz + if (hclk_per_us_shift != 0) + loop_time = ll_hw_get_loop_cycle() >> hclk_per_us_shift; // convert to us + else + loop_time = ll_hw_get_loop_cycle() / hclk_per_us; // convert to us + + // read anchor point + if (hclk_per_us_shift != 0) + anchor_point = ll_hw_get_anchor() >> hclk_per_us_shift; // convert to us + else + anchor_point = ll_hw_get_anchor() / hclk_per_us; // convert to us + + wait_time -= loop_time - anchor_point; + +// LOG("<%d>", wait_time); + + if (wait_time < 2000) + wait_time = 10; + else + wait_time -= 2000; // scan advance + } + else + { + // finish receive current periodic adv event + pPrdScanInfo->current_channel = pPrdScanInfo->currentEventChannel; + pPrdScanInfo->event1stFlag = TRUE; + + if (temp_event1stFlag == FALSE) // if this is not the 1st PDU of periodic adv, update nextEventRemainder + { + uint32 elapse_time; + // calculate elapse time since last timer trigger + T2 = read_current_fine_time(); + elapse_time = LL_TIME_DELTA(g_timerExpiryTick, T2); + pPrdScanInfo->nextEventRemainder -= elapse_time; + } + + wait_time = pPrdScanInfo->nextEventRemainder; + wait_time -= 2500; // advance + } + } + } + else + { + // sync lost, should we consider CRC NOK case??? + pPrdScanInfo->syncLostTime += pPrdScanInfo->advInterval; + pPrdScanInfo->current_channel = pPrdScanInfo->currentEventChannel; + pPrdScanInfo->event1stFlag = TRUE; +// if (temp_event1stFlag == FALSE) // if this is not the 1st PDU of periodic adv, update nextEventRemainder +// { + uint32 elapse_time; + // calculate elapse time since last timer trigger + T2 = read_current_fine_time(); + elapse_time = LL_TIME_DELTA(g_timerExpiryTick, T2); + pPrdScanInfo->nextEventRemainder -= elapse_time; +// } + wait_time = pPrdScanInfo->nextEventRemainder; + wait_time -= 2500; // advance + + if (pPrdScanInfo->syncEstOk == TRUE && + pPrdScanInfo->syncLostTime > pPrdScanInfo->syncTimeout) + { + // sync timeout, report HCI event HCI_LE_Periodic_Advertising_Sync_Lost + LL_PrdAdvSyncLostCback(pPrdScanInfo->syncHandler); + llDeleteSyncHandle(pPrdScanInfo->syncHandler); + // TODO: should clear sync info and stop timer + } + else if (pPrdScanInfo->syncEstOk == FALSE && + pPrdScanInfo->syncLostTime >= 6 * pPrdScanInfo->advInterval) + { + // failed to establish sync, report HCI event HCI_LE_Periodic_Advertising_Sync_Lost + LL_PrdAdvSyncEstablishedCback(LL_STATUS_ERROR_SYNC_FAILED_TO_BE_ESTABLISHED, + 0, // syncHandle, + scanSyncInfo.advertising_SID, // advertisingSID, + scanSyncInfo.advertiser_Address_Type, // advertiserAddressType, + scanSyncInfo.advertiser_Address, // advertiserAddress, + 0, // advertiserPHY, + 0, // periodicAdvertisingInterval, + 0 // advertiserClockAccuracy + ); + scanSyncInfo.valid = FALSE; + // TODO: should clear sync info and stop timer + } + } + + if (pPrdScanInfo->valid == FALSE) + { + // llDeleteSyncHandle(pPrdScanInfo->syncHandler); + // pPrdScanInfo->syncHandler = 0xFFFF; + } + else // in future release, below set timer function should change to scheduler + { + ll_prd_scan_schedule_next_event(wait_time); + pPrdScanInfo->nextEventRemainder -= wait_time; + } + +// LOG("<%d>", wait_time); + + if (!llWaitingIrq) + { + ll_hw_clr_irq(); + llTaskState = LL_TASK_OTHERS; + } + + HAL_EXIT_CRITICAL_SECTION(); + return TRUE; +} + +#else +uint8 ll_processExtScanIRQ(uint32_t irq_status) +{ + return TRUE; +} + +uint8 ll_processExtInitIRQ(uint32_t irq_status) +{ + return TRUE; +} + +uint8 ll_processPrdScanIRQ(uint32_t irq_status) +{ + return TRUE; +} +#endif + +#ifdef EXT_ADV_ENABLE +uint8 LL_extAdvTimerExpProcess(void) +{ + extAdvInfo_t* pAdvInfo; + uint8 current_chn; + uint16 current_offset; + // TODO: if the timer IRQ is pending, should advanced expiry tick + g_timerExpiryTick = read_current_fine_time(); + pAdvInfo = g_pAdvSchInfo[g_currentExtAdv].pAdvInfo; + current_chn = pAdvInfo->currentChn; + current_offset = pAdvInfo->currentAdvOffset; + // update scheduler task list + ll_updateExtAdvRemainderTime(g_currentAdvTimer + LL_ADV_TIMING_COMPENSATE); + + // check timer1, if no enough margin, start timer + if (llWaitingIrq || + (isTimer1Running() && read_LL_remainder_time() < pGlobal_config[LL_EXT_ADV_TASK_DURATION])) + { + ll_ext_adv_schedule_next_event(pGlobal_config[LL_EXT_ADV_TASK_DURATION]); + return TRUE; + } + else + { + if (ll_isLegacyAdv(pAdvInfo)) + llSetupExtAdvLegacyEvent(pAdvInfo); // send legacy ADV PDU + else + llSetupExtAdvEvent(pAdvInfo); // send extended advertisement + } + + // for 1st pri adv channel , update remainder time in scheduler + if (ll_isFirstAdvChn(pAdvInfo->parameter.priAdvChnMap, current_chn)) + { + g_pAdvSchInfo[g_currentExtAdv].nextEventRemainder += pAdvInfo->primary_advertising_interval; + g_pAdvSchInfo[g_currentExtAdv].pAdvInfo->adv_event_duration += pAdvInfo->primary_advertising_interval; + g_pAdvSchInfo[g_currentExtAdv].pAdvInfo->adv_event_counter ++; + + // event expiry decision, update 2020-04-07 + if (g_pAdvSchInfo[g_currentExtAdv].pAdvInfo->duration != 0 && + g_pAdvSchInfo[g_currentExtAdv].pAdvInfo->adv_event_duration > g_pAdvSchInfo[g_currentExtAdv].pAdvInfo->duration) + { + g_pAdvSchInfo[g_currentExtAdv].pAdvInfo->active = FALSE; // mark as inactive + LL_AdvSetTerminatedCback(LL_STATUS_ERROR_LIMIT_REACHED, + g_pAdvSchInfo[g_currentExtAdv].pAdvInfo->advHandle, + 0, + g_pAdvSchInfo[g_currentExtAdv].pAdvInfo->adv_event_counter); + } + else if (g_pAdvSchInfo[g_currentExtAdv].pAdvInfo->maxExtAdvEvents != 0 + && g_pAdvSchInfo[g_currentExtAdv].pAdvInfo->adv_event_counter >= g_pAdvSchInfo[g_currentExtAdv].pAdvInfo->maxExtAdvEvents) + { + g_pAdvSchInfo[g_currentExtAdv].pAdvInfo->active = FALSE; // mark as inactive + LL_AdvSetTerminatedCback(LL_STATUS_ERROR_DIRECTED_ADV_TIMEOUT, + g_pAdvSchInfo[g_currentExtAdv].pAdvInfo->advHandle, + 0, + g_pAdvSchInfo[g_currentExtAdv].pAdvInfo->adv_event_counter); + } + } + // for 1st aux adv channel, update remainder time in scheduler + else if (current_chn < LL_ADV_CHAN_FIRST // broadcast in aux adv chn + && current_offset == 0) // offset in adv data set greater than 0 means next PDU is AUX_CHAIN_IND PDU + { + ll_updateAuxAdvTimeSlot(g_currentExtAdv); // update aux PDU + } + + return TRUE; +} +#else +uint8 LL_extAdvTimerExpProcess(void) +{ + return TRUE; +} +#endif + +#ifdef PRD_ADV_ENABLE +uint8 LL_prdAdvTimerExpProcess(void) +{ + int i; + extAdvInfo_t* pAdvInfo; + periodicAdvInfo_t* pPrdAdv; + llPeriodicAdvScheduleInfo_t* p_scheduler = NULL; + // TODO: if the timer IRQ is pending, should advanced expiry tick + g_timerExpiryTick = read_current_fine_time(); + p_scheduler = &g_pAdvSchInfo_periodic[g_currentExtAdv_periodic]; + pAdvInfo = p_scheduler->pAdvInfo; + pPrdAdv = p_scheduler->pAdvInfo_prd; + + // for 1st pri adv channel , update remainder time in scheduler + if (ll_isFirstAdvChn(pAdvInfo->parameter.priAdvChnMap, pPrdAdv->currentChn)) + { + p_scheduler->nextEventRemainder += pAdvInfo->primary_advertising_interval; + pAdvInfo->adv_event_duration += pAdvInfo->primary_advertising_interval; + pAdvInfo->adv_event_counter ++; + + // event expiry decision, update 2020-04-07 + if ((pAdvInfo->duration != 0 && pAdvInfo->adv_event_duration > pAdvInfo->duration) + || (pAdvInfo->maxExtAdvEvents != 0 && pAdvInfo->adv_event_counter >= pAdvInfo->maxExtAdvEvents)) + { + pAdvInfo->active = FALSE; // mark as inactive + p_scheduler->nextEventRemainder = LL_INVALID_TIME; + } + } + // for 1st aux adv channel, update remainder time in scheduler + else if (pPrdAdv->currentChn < LL_ADV_CHAN_FIRST // broadcast in aux adv chn + && pAdvInfo->sendingAuxAdvInd == FALSE // not sending extended aux PDU + && pPrdAdv->currentAdvOffset == 0) // offset in adv data set greater than 0 means next PDU is AUX_CHAIN_IND PDU + { +// ll_updateAuxAdvTimeSlot(g_currentExtAdv); // update aux PDU + p_scheduler->auxPduRemainder += pPrdAdv->adv_interval; + } + + // update scheduler task list + for (i = 0; i < g_extAdvNumber; i++) + { + if (g_pAdvSchInfo_periodic[i].adv_handler != LL_INVALID_ADV_SET_HANDLE) + { + if (g_pAdvSchInfo_periodic[i].pAdvInfo->active == TRUE) + g_pAdvSchInfo_periodic[i].nextEventRemainder -= (g_currentAdvTimer + LL_ADV_TIMING_COMPENSATE); + + g_pAdvSchInfo_periodic[i].auxPduRemainder -= (g_currentAdvTimer + LL_ADV_TIMING_COMPENSATE); + } + } + + // check timer1, if no enough margin, start timer + if (llWaitingIrq || + (isTimer1Running() && read_LL_remainder_time() < pGlobal_config[LL_EXT_ADV_TASK_DURATION])) + { + ll_prd_adv_schedule_next_event(pGlobal_config[LL_EXT_ADV_TASK_DURATION]); + } + else + llSetupPrdAdvEvent(pPrdAdv, pAdvInfo); // send extended advertisement + + return TRUE; +} +#else +uint8 LL_prdAdvTimerExpProcess(void) +{ + return TRUE; +} +#endif + +#ifdef EXT_SCAN_ENABLE +uint8 LL_prdScanTimerExpProcess(void) +{ + // TODO: if the timer IRQ is pending, should advanced expiry tick + g_timerExpiryTick = read_current_fine_time(); + llSetupPrdScan(); + return TRUE; +} + +void LL_extScanTimerExpProcess(void) +{ + llSetupExtScan(extScanInfo.current_chn); +} + +void LL_extInitTimerExpProcess(void) +{ + llSetupExtInit(); +} +#else +uint8 LL_prdScanTimerExpProcess(void) +{ + return TRUE; +} + +void LL_extScanTimerExpProcess(void) +{ +} + +void LL_extInitTimerExpProcess(void) +{ +} + +#endif + +// allocate the aux PDU time slot +uint8 ll_allocAuxAdvTimeSlot(uint8 index) +{ + uint8 ret = TRUE; + llAdvScheduleInfo_t* p_scheduler = NULL, *p_current_scheduler; + uint32 pri_adv_duration; + p_scheduler = &g_pAdvSchInfo[index]; + // consider the adv in primary channel(EXT_ADV_IND) + and IFS and process time(2000) + pri_adv_duration = pGlobal_config[LL_EXT_ADV_INTER_PRI_CHN_INT] * 3 + 2000; + + // allocate time slot for AUX_XXX_IND PDU + // case 1: the 1st task + if (!isTimer4Running()) + { + if (isTimer1Running()) + p_scheduler->auxPduRemainder = read_LL_remainder_time() + pri_adv_duration + pGlobal_config[LL_CONN_TASK_DURATION]; + else + p_scheduler->auxPduRemainder = pri_adv_duration; + + return TRUE; + } + + // case 2: there are ongoing adv, calculate aux pdu timing with the current adv as anchor + p_current_scheduler = &g_pAdvSchInfo[g_currentExtAdv]; + p_scheduler->auxPduRemainder = p_current_scheduler->auxPduRemainder + + (index > g_currentExtAdv ? ((index - g_currentExtAdv) * g_advPerSlotTick) : (g_advSlotPeriodic + (index - g_currentExtAdv) * g_advPerSlotTick)); + return ret; +} + +// allocate the aux PDU time slot +uint8 ll_allocAuxAdvTimeSlot_prd(uint8 index) +{ + uint8 ret = TRUE; + llPeriodicAdvScheduleInfo_t* p_scheduler = NULL, *p_current_scheduler; + uint32 ext_adv_part_duration; + p_scheduler = &g_pAdvSchInfo_periodic[index]; + // consider the adv in primary channel(EXT_ADV_IND) + AUX_ADV_IND + and IFS and process time(2000) + ext_adv_part_duration = pGlobal_config[LL_EXT_ADV_INTER_PRI_CHN_INT] * 3 + + pGlobal_config[LL_EXT_ADV_INTER_SEC_CHN_INT] + + pGlobal_config[LL_EXT_ADV_PRI_2_SEC_CHN_INT] + + 2000; // rough compensation for IFS and process time + + // allocate time slot for AUX_XXX_IND PDU + // case 1: the 1st task + if (!isTimer4Running()) + { + if (isTimer1Running()) + p_scheduler->auxPduRemainder = read_LL_remainder_time() + ext_adv_part_duration + pGlobal_config[LL_CONN_TASK_DURATION]; + else + p_scheduler->auxPduRemainder = ext_adv_part_duration; + + return TRUE; + } + + // case 2: there are ongoing adv, calculate aux pdu timing with the current adv as anchor + p_current_scheduler = &g_pAdvSchInfo_periodic[g_currentExtAdv_periodic]; + p_scheduler->auxPduRemainder = p_current_scheduler->auxPduRemainder + + (index > g_currentExtAdv_periodic ? + ((index - g_currentExtAdv_periodic) * g_advPerSlotTick) : + (g_advSlotPeriodic + (index - g_currentExtAdv_periodic) * g_advPerSlotTick)); + return ret; +} + +// update next aux PDU time slot +void ll_updateAuxAdvTimeSlot(uint8 index) +{ + while (g_pAdvSchInfo[index].auxPduRemainder < g_pAdvSchInfo[index].nextEventRemainder) + g_pAdvSchInfo[index].auxPduRemainder += g_advSlotPeriodic; +} + +//#define INVALID_ADV_RSC_POOL_POS 0xFFFFFFFF +//// get remain time to Aux Adv resource pool position +//uint32 ll_getAuxAdvRscPoolPosition(void) +//{ +// int i; +// uint32 pos, temp; +// +// for (i = 0; i < g_extAdvNumber; i++) +// { +// if (g_pAdvSchInfo[i].adv_handler != LL_INVALID_ADV_SET_HANDLE) +// break; +// } +// +// if (i == g_extAdvNumber) +// return INVALID_ADV_RSC_POOL_POS; +// +// temp = i * g_advPerSlotTick; +// if (g_pAdvSchInfo[i].auxPduRemainder > temp) +// pos = g_pAdvSchInfo[i].auxPduRemainder - temp; +// else +// return INVALID_ADV_RSC_POOL_POS; +// +// return pos; +//} +// +//uint32 ll_getAuxAdvRscPooPeriod(void) +//{ +// return g_advPerSlotTick * g_extAdvNumber; +//} + +void ll_updateExtAdvRemainderTime(uint32 time) +{ + int i; + + for (i = 0; i < g_extAdvNumber; i++) + { + if (g_pAdvSchInfo[i].adv_handler != LL_INVALID_ADV_SET_HANDLE) + { + if (g_pAdvSchInfo[i].nextEventRemainder < time) + { + g_pAdvSchInfo[i].nextEventRemainder += g_pAdvSchInfo[i].pAdvInfo->primary_advertising_interval; + g_pAdvSchInfo[i].pAdvInfo->adv_event_duration += g_pAdvSchInfo[i].pAdvInfo->primary_advertising_interval; + g_pAdvSchInfo[i].pAdvInfo->adv_event_counter ++; + } + + if (g_pAdvSchInfo[i].auxPduRemainder < time) // normally this case should not occur + g_pAdvSchInfo[i].auxPduRemainder += g_advSlotPeriodic; + + if (g_pAdvSchInfo[i].auxPduRemainder != LL_INVALID_TIME) + g_pAdvSchInfo[i].auxPduRemainder -= time; + + g_pAdvSchInfo[i].nextEventRemainder -= time; + } + } +} + +/******************************************************************************* + @fn LL_processBasicIRQ + + @brief Interrupt Request Handler for Link Layer + + input parameters + + @param None. + + output parameters + + @param None. + + @return None +*/ +uint8 ll_processBasicIRQ(uint32_t irq_status) +{ + uint8 mode; + uint32_t T2, delay; + llConnState_t* connPtr; + connPtr = &conn_param[0]; // To update + HAL_ENTER_CRITICAL_SECTION(); + mode = ll_hw_get_tr_mode(); + + // =================== mode TRX process 1 + if (mode == LL_HW_MODE_TRX && + (irq_status & LIRQ_COK) && // bug correct 2018-10-15 + (llState == LL_STATE_ADV_UNDIRECTED || + llState == LL_STATE_ADV_SCAN || + llState == LL_STATE_ADV_DIRECTED) + ) + { + uint8_t packet_len, pdu_type, txAdd; + uint8_t* peerAddr; + uint8_t bWlRlCheckOk = TRUE; + uint16_t pktLen; + uint32_t pktFoot0, pktFoot1; + int calibra_time; // this parameter will be provided by global_config + ll_debug_output(DEBUG_LL_HW_TRX); + // read packet + packet_len = ll_hw_read_rfifo((uint8_t*)(&(g_rx_adv_buf.rxheader)), + &pktLen, + &pktFoot0, + &pktFoot1); + + if(ll_hw_get_rfifo_depth()>0) + { + g_pmCounters.ll_rfifo_read_err++; + packet_len=0; + pktLen=0; + } + + // check receive pdu type + pdu_type = g_rx_adv_buf.rxheader & PDU_TYPE_MASK; + txAdd = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + + if (packet_len > 0 // any better checking rule for rx anything? + && pdu_type == ADV_SCAN_REQ + && (llState == LL_STATE_ADV_UNDIRECTED + || llState == LL_STATE_ADV_SCAN)) + { + // 1. scan req + g_pmCounters.ll_recv_scan_req_cnt ++; + + // check AdvA + if (g_rx_adv_buf.data[6] != adv_param.ownAddr[0] + || g_rx_adv_buf.data[7] != adv_param.ownAddr[1] + || g_rx_adv_buf.data[8] != adv_param.ownAddr[2] + || g_rx_adv_buf.data[9] != adv_param.ownAddr[3] + || g_rx_adv_buf.data[10] != adv_param.ownAddr[4] + || g_rx_adv_buf.data[11] != adv_param.ownAddr[5]) + { + } + else + { + uint8_t rpaListIndex; + peerAddr = &g_rx_adv_buf.data[0]; // ScanA + + // === Resolving list checking + // if ScanA is resolvable private address + if (txAdd == LL_DEV_ADDR_TYPE_RANDOM + && (g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) + { + bWlRlCheckOk = TRUE; + + if (g_llRlEnable == TRUE) + { + bWlRlCheckOk = FALSE; + rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]); + + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM) + { + peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; + bWlRlCheckOk = TRUE; + } + } + } + else // ScanA is device Identity, if the device ID in the RPA list, check whether RPA should be used + { + bWlRlCheckOk = TRUE; + + for (int i = 0; i < LL_RESOLVINGLIST_ENTRY_NUM; i++) + { + if (g_llResolvinglist[i].peerAddr[0] == g_rx_adv_buf.data[0] + && g_llResolvinglist[i].peerAddr[1] == g_rx_adv_buf.data[1] + && g_llResolvinglist[i].peerAddr[2] == g_rx_adv_buf.data[2] + && g_llResolvinglist[i].peerAddr[3] == g_rx_adv_buf.data[3] + && g_llResolvinglist[i].peerAddr[4] == g_rx_adv_buf.data[4] + && g_llResolvinglist[i].peerAddr[5] == g_rx_adv_buf.data[5] + && g_llResolvinglist[i].peerAddrType == txAdd) + { + if (g_llResolvinglist[i].privacyMode == NETWORK_PRIVACY_MODE && + !ll_isIrkAllZero(g_llResolvinglist[i].peerIrk)) + bWlRlCheckOk = FALSE; + else + rpaListIndex = i; + + break; + } + } + } + + // === check white list + if ((pGlobal_config[LL_SWITCH] & LL_WHITELIST_ALLOW) + && (adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_SCAN_REQ + || adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_ALL_REQ) + && (bWlRlCheckOk == TRUE)) + { + // check white list + bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr); + } + + if (bWlRlCheckOk == FALSE) // if not in white list, do nothing + { + g_pmCounters.ll_filter_scan_req_cnt ++; + } + else + { + g_pmCounters.ll_rx_peer_cnt++; + uint8 retScanRspFilter=1; + + if(LL_PLUS_ScanRequestFilterCBack) + { + retScanRspFilter = LL_PLUS_ScanRequestFilterCBack(); + } + + if(retScanRspFilter) + { + // send scan rsp + ll_hw_set_stx(); // set LL HW as single Tx mode + g_same_rf_channel_flag = TRUE; + // calculate the delay + T2 = read_current_fine_time(); + delay = (T2 > ISR_entry_time) ? (T2 - ISR_entry_time) : (BASE_TIME_UNITS - ISR_entry_time + T2); + calibra_time = pGlobal_config[SCAN_RSP_DELAY]; // consider rx_done to ISR time, SW delay after read_current_fine_time(), func read_current_fine_time() delay ... + delay = 118 - delay - calibra_time; // IFS = 150us, Tx tail -> Rx done time: about 32us + ll_hw_set_trx_settle(delay, // set BB delay, about 80us in 16MHz HCLK + pGlobal_config[LL_HW_AFE_DELAY], + pGlobal_config[LL_HW_PLL_DELAY]); //RxAFE,PLL + ll_hw_go(); + llWaitingIrq = TRUE; + g_same_rf_channel_flag = FALSE; + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(tx_scanRsp_desc.txheader), + ((tx_scanRsp_desc.txheader & 0xff00) >> 8) + 2); // payload length + header length(2) + ll_debug_output(DEBUG_LL_HW_SET_STX); + g_pmCounters.ll_send_scan_rsp_cnt ++; + } + } + } + } + else if (pdu_type == ADV_CONN_REQ + && (llState == LL_STATE_ADV_UNDIRECTED + || llState == LL_STATE_ADV_DIRECTED)) + { + // 2. connect req + g_currentPeerAddrType = txAdd; + g_pmCounters.ll_recv_conn_req_cnt ++; + + // check AdvA + if (g_rx_adv_buf.data[6] != adv_param.ownAddr[0] + || g_rx_adv_buf.data[7] != adv_param.ownAddr[1] + || g_rx_adv_buf.data[8] != adv_param.ownAddr[2] + || g_rx_adv_buf.data[9] != adv_param.ownAddr[3] + || g_rx_adv_buf.data[10] != adv_param.ownAddr[4] + || g_rx_adv_buf.data[11] != adv_param.ownAddr[5]) + { + // nothing to do + } + else + { + uint8_t rpaListIndex = LL_RESOLVINGLIST_ENTRY_NUM; + peerAddr = &g_rx_adv_buf.data[0]; // initA + + // ====== check Resolving list + if (txAdd == LL_DEV_ADDR_TYPE_RANDOM && + (g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) + { + bWlRlCheckOk = TRUE; + + if (g_llRlEnable == TRUE) + { + bWlRlCheckOk = FALSE; + rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]); + + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM) + { + // save resolved peer address + peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; + // if resolved address success, map the peer address type to 0x02 or 0x03 + g_currentPeerAddrType = g_llResolvinglist[rpaListIndex].peerAddrType + 2; + osal_memcpy( &g_currentPeerRpa[0], &g_rx_adv_buf.data[0], 6); // save latest peer RPA + bWlRlCheckOk = TRUE; + } + } + } + else // InitA is device Identity, check whether the device Addr in the RPA list, if it is + { + // in the RPA list and network privacy mode is selected and non all-0 IRK, check failed + bWlRlCheckOk = TRUE; + + for (int i = 0; i < LL_RESOLVINGLIST_ENTRY_NUM; i++) + { + if (g_llResolvinglist[i].peerAddr[0] == g_rx_adv_buf.data[0] + && g_llResolvinglist[i].peerAddr[1] == g_rx_adv_buf.data[1] + && g_llResolvinglist[i].peerAddr[2] == g_rx_adv_buf.data[2] + && g_llResolvinglist[i].peerAddr[3] == g_rx_adv_buf.data[3] + && g_llResolvinglist[i].peerAddr[4] == g_rx_adv_buf.data[4] + && g_llResolvinglist[i].peerAddr[5] == g_rx_adv_buf.data[5] + && g_llResolvinglist[i].peerAddrType == txAdd) + { + if (g_llResolvinglist[i].privacyMode == NETWORK_PRIVACY_MODE && + !ll_isIrkAllZero(g_llResolvinglist[i].peerIrk)) + bWlRlCheckOk = FALSE; + else + rpaListIndex = i; + + break; + } + } + } + + // ====== check white list + if ((pGlobal_config[LL_SWITCH] & LL_WHITELIST_ALLOW) + && (llState == LL_STATE_ADV_UNDIRECTED) + && (adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_CONNECT_REQ + || adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_ALL_REQ) + && (bWlRlCheckOk == TRUE)) + { + // check white list + bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr); + } + + // fixed bug 2018-09-25, LL/CON/ADV/BV-04-C, for direct adv, initA should equal peer Addr + if (llState == LL_STATE_ADV_DIRECTED) + { + if (//txAdd != peerInfo.peerAddrType // for (extended) set adv param, peer addr type could only be 0x0 or 0x01 + peerAddr[0] != peerInfo.peerAddr[0] + || peerAddr[1] != peerInfo.peerAddr[1] + || peerAddr[2] != peerInfo.peerAddr[2] + || peerAddr[3] != peerInfo.peerAddr[3] + || peerAddr[4] != peerInfo.peerAddr[4] + || peerAddr[5] != peerInfo.peerAddr[5]) + { + // not match, check next + bWlRlCheckOk = FALSE; + } + } + + if (bWlRlCheckOk == FALSE) // if not in white list, do nothing + { + g_pmCounters.ll_filter_conn_req_cnt ++; + } + else + { + // increment statistics counter + g_pmCounters.ll_rx_peer_cnt++; + // bug fixed 2018-01-23, peerAddrType should read TxAdd + peerInfo.peerAddrType = txAdd; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + osal_memcpy(peerInfo.peerAddr, &peerAddr[0], 6); + move_to_slave_function(); // move to slave role for connection state + } + } + } + //test for fast adv + else if(llState == LL_STATE_ADV_UNDIRECTED) + { + uint8_t firstAdvChan = (adv_param.advChanMap&LL_ADV_CHAN_37) !=0 ? 37 : + (adv_param.advChanMap&LL_ADV_CHAN_38) !=0 ? 38 : 39; + + if(adv_param.advNextChan>firstAdvChan) + { + //llSetupUndirectedAdvEvt1(); + ll_schedule_next_event(50); //20180623 modified by ZQ + // reset the timer1 instead of llSetupUndirectedAdvEvt1 + // reduced the process time in LL_IRQ + // llSetupUndirectedAdvEvt1 will cost about 120us + } + } + } + // =================== mode TRX process 2, for scanner, active scan case + else if (mode == LL_HW_MODE_TRX && + (llState == LL_STATE_SCAN)) + { + // check whether receives SCAN RSP + ll_debug_output(DEBUG_LL_HW_TRX); + llScanTime += ((ISR_entry_time > llScanT1) ? (ISR_entry_time - llScanT1) : (BASE_TIME_UNITS - llScanT1 + ISR_entry_time)); + + // check whether receives SCAN RSP + if (irq_status & LIRQ_COK) // bug correct 2018-10-15 + { + // rx done + uint8_t packet_len, pdu_type; + uint16_t pktLen; + uint32_t pktFoot0, pktFoot1; + // read packet + packet_len = ll_hw_read_rfifo((uint8_t*)(&(g_rx_adv_buf.rxheader)), + &pktLen, + &pktFoot0, + &pktFoot1); + // check receive pdu type + pdu_type = g_rx_adv_buf.rxheader & 0x0f; + + if(ll_hw_get_rfifo_depth()>0) + { + g_pmCounters.ll_rfifo_read_err++; + packet_len=0; + pktLen=0; + } + + if (packet_len > 0 && pdu_type == ADV_SCAN_RSP) + { + // receives SCAN_RSP + uint8 advEventType; + uint8 rpaListIndex; + uint8* peerAddr; + uint8 addrType = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; + uint8 dataLen = pktLen - 8; + int8 rssi = -(pktFoot1 >> 24); + uint8 bCheckOk = TRUE; + peerAddr = &g_rx_adv_buf.data[0]; + + //=== + // AdvA of SCAN_RSP should also be checked here. Refer to 4.4.3.2 Active Scanning + // After sending a scan request PDU the Link Layer listens for a scan response + //PDU from that advertiser. If the scan response PDU was not received from that + //advertiser, it is considered a failure; otherwise it is considered a success. + + // check AdvA in Scan Rsp is identical to Scan Req + if (g_rx_adv_buf.data[0] != g_tx_adv_buf.data[6] || + g_rx_adv_buf.data[1] != g_tx_adv_buf.data[7] || + g_rx_adv_buf.data[2] != g_tx_adv_buf.data[8] || + g_rx_adv_buf.data[3] != g_tx_adv_buf.data[9] || + g_rx_adv_buf.data[4] != g_tx_adv_buf.data[10] || + g_rx_adv_buf.data[5] != g_tx_adv_buf.data[11] + ) + bCheckOk = FALSE; + + // RPA checking. Note that we do not check whether it is the same RPA index + if (addrType == LL_DEV_ADDR_TYPE_RANDOM && + (g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) + { + if (g_llRlEnable == TRUE) + { + rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]); + + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM) + { + peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; + // refer to HCI LE Advertising Report Event, RPA address type should be + // 0x02: Public Identity Address (Corresponds to Resolved Private Address) + // 0x03: Random (static) Identity Address (Corresponds to Resolved Private Address) + addrType = g_llResolvinglist[rpaListIndex].peerAddrType + 2; + bCheckOk = TRUE; + } + else + bCheckOk = FALSE; + } + } + + //=== + + if (bCheckOk == TRUE) + { + advEventType = LL_ADV_RPT_SCAN_RSP; + // below function cost 51us/66us(measure with GPIO) + LL_AdvReportCback( advEventType, // event type + addrType, // Adv address type (TxAdd) + peerAddr, // Adv address (AdvA) + dataLen, // length of rest of the payload + &g_rx_adv_buf.data[6], // rest of payload + rssi ); // RSSI + g_pmCounters.ll_recv_scan_rsp_cnt ++; + llAdjBoffUpperLimitSuccess(); + } + } + else + llAdjBoffUpperLimitFailure(); + } + else + llAdjBoffUpperLimitFailure(); + + // update back off value according to new backoff upperLimit + llGenerateNextBackoffCount(); + + if (llScanTime >= scanInfo.scanWindow * 625) + { + // calculate next scan channel + LL_CALC_NEXT_SCAN_CHN(scanInfo.nextScanChan); + + // schedule next scan event + if (scanInfo.scanWindow == scanInfo.scanInterval) // scanWindow == scanInterval, trigger immediately + LL_evt_schedule(); + else +// set_timer4((scanInfo.scanInterval - scanInfo.scanWindow) * 625); + ll_schedule_next_event((scanInfo.scanInterval - scanInfo.scanWindow) * 625); + + // reset scan total time + llScanTime = 0; + } + else + llSetupScan(scanInfo.nextScanChan); + } + // =================== mode SRX process, for scan/init + else if (mode == LL_HW_MODE_SRX + && (llState == LL_STATE_SCAN || llState == LL_STATE_INIT)) + { + ll_debug_output(DEBUG_LL_HW_SRX); + uint8_t rpaListIndex = LL_RESOLVINGLIST_ENTRY_NUM; + uint8_t bWlRlCheckOk = TRUE; + uint8_t* peerAddr; + + // ============= scan case + if (llState == LL_STATE_SCAN) + { + uint8 bSendingScanReq = FALSE; + + // check status + if ((irq_status & LIRQ_RD) && (irq_status & LIRQ_COK)) // bug correct 2018-10-15 + { + // rx done + uint8_t packet_len, pdu_type; + uint16_t pktLen; + uint32_t pktFoot0, pktFoot1; + // read packet + // cost 21-26us(measure with GPIO), depneds on the length of ADV + packet_len = ll_hw_read_rfifo((uint8_t*)(&(g_rx_adv_buf.rxheader)), + &pktLen, + &pktFoot0, + &pktFoot1); + // check receive pdu type + pdu_type = g_rx_adv_buf.rxheader & 0x0f; + + if(ll_hw_get_rfifo_depth()>0) + { + g_pmCounters.ll_rfifo_read_err++; + packet_len=0; + pktLen=0; + } + + if (packet_len != 0 + && ((pdu_type == ADV_IND) + || (pdu_type == ADV_NONCONN_IND) + || (pdu_type == ADV_SCAN_IND) + || (pdu_type == ADV_DIRECT_IND))) + { + uint8 addrType; // peer address type + uint8_t txAdd = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + peerAddr = &g_rx_adv_buf.data[0]; // AdvA + addrType = txAdd; + + // Resolving list checking + // case 1: receive ScanA using RPA + if (txAdd == LL_DEV_ADDR_TYPE_RANDOM && + (g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) + { + bWlRlCheckOk = FALSE; + + if (g_llRlEnable == TRUE) + { + rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]); + + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM) + { + peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; + // refer to HCI LE Advertising Report Event, RPA address type should be + // 0x02: Public Identity Address (Corresponds to Resolved Private Address) + // 0x03: Random (static) Identity Address (Corresponds to Resolved Private Address) + addrType = g_llResolvinglist[rpaListIndex].peerAddrType + 2; + bWlRlCheckOk = TRUE; + } + } + } + else // case 2: receive ScanA using device ID, or scan device not using RPA + { + bWlRlCheckOk = TRUE; + + for (int i = 0; i < LL_RESOLVINGLIST_ENTRY_NUM; i++) + { + if ( g_llResolvinglist[i].peerAddr[0] == g_rx_adv_buf.data[0] + && g_llResolvinglist[i].peerAddr[1] == g_rx_adv_buf.data[1] + && g_llResolvinglist[i].peerAddr[2] == g_rx_adv_buf.data[2] + && g_llResolvinglist[i].peerAddr[3] == g_rx_adv_buf.data[3] + && g_llResolvinglist[i].peerAddr[4] == g_rx_adv_buf.data[4] + && g_llResolvinglist[i].peerAddr[5] == g_rx_adv_buf.data[5]) + { + // the device ID in the RPA list + if (g_llResolvinglist[i].privacyMode == DEVICE_PRIVACY_MODE || + ll_isIrkAllZero(g_llResolvinglist[i].peerIrk)) + rpaListIndex = i; + else + bWlRlCheckOk = FALSE; // the device in the RPA list but not using RPA, reject it + + break; + } + } + } + + // check white list + if ((pGlobal_config[LL_SWITCH] & LL_WHITELIST_ALLOW) + && (scanInfo.wlPolicy == LL_SCAN_WL_POLICY_USE_WHITE_LIST) + && (bWlRlCheckOk == TRUE)) + { + // check white list + bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr); + } + else if(pdu_type == ADV_DIRECT_IND) // direct adv only report addr & addr type match the whitelist + bWlRlCheckOk = FALSE; + + // if valid, trigger osal event to report adv + if (bWlRlCheckOk == TRUE) + { + uint8 advEventType; + int8 rssi; + llCurrentScanChn = scanInfo.nextScanChan; + + // active scan scenario, send scan req + if (scanInfo.scanType == LL_SCAN_ACTIVE + && (pdu_type== ADV_IND + || pdu_type == ADV_SCAN_IND )) + { + // back off process + scanInfo.currentBackoff = (scanInfo.currentBackoff > 0) ? (scanInfo.currentBackoff - 1) : 0; + + if (scanInfo.currentBackoff == 0) // back off value = 0, send scan req + { + g_tx_adv_buf.txheader = 0xC03; + //ZQ 20181012: add AdvFilterCB + uint8_t retAdvFilter = 1; + + if(LL_PLUS_AdvDataFilterCBack) + { + //!!!CATION!!! + //timing critical + //txbuf will be changed + retAdvFilter = LL_PLUS_AdvDataFilterCBack(); + } + + if(retAdvFilter) + { + g_same_rf_channel_flag = TRUE; + ll_hw_set_tx_rx_interval(10); + ll_hw_set_rx_timeout(158); + set_max_length(0xFF); // add 2020-03-10 + T2 = read_current_fine_time(); + delay = (T2 > ISR_entry_time) ? (T2 - ISR_entry_time) : (BASE_TIME_UNITS - ISR_entry_time + T2); + delay = 118 - delay - pGlobal_config[LL_ADV_TO_SCAN_REQ_DELAY]; + ll_hw_set_trx(); // set LL HW as single TRx mode + ll_hw_set_trx_settle(delay, // set BB delay, about 80us in 16MHz HCLK + pGlobal_config[LL_HW_AFE_DELAY], + pGlobal_config[LL_HW_PLL_DELAY]); //RxAFE,PLL + ll_hw_go(); + g_pmCounters.ll_send_scan_req_cnt++; + llWaitingIrq = TRUE; + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + ll_hw_ign_rfifo(LL_HW_IGN_CRC | LL_HW_IGN_EMP); + // construct SCAN REQ packet + //g_tx_adv_buf.txheader = 0xCC3; + //20181012 ZQ: change the txheader according to the adtype + g_tx_adv_buf.txheader |=(((g_rx_adv_buf.rxheader&0x40)<<1) + | (scanInfo.ownAddrType<< TX_ADD_SHIFT & TX_ADD_MASK)); + + // fill scanA, using RPA or device ID address // TODO: move below code before ll_hw_go? + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM && + !ll_isIrkAllZero(g_llResolvinglist[rpaListIndex].localIrk)) + { + // for resolving private address case, calculate the scanA with Local IRK + ll_CalcRandomAddr(g_llResolvinglist[rpaListIndex].localIrk, &g_tx_adv_buf.data[0]); +// osal_memcpy( &g_currentLocalRpa[0], &g_tx_adv_buf.data[0], 6); + } + else + { + //LL_ReadBDADDR(&g_tx_adv_buf.data[0]); + memcpy((uint8*)&g_tx_adv_buf.data[0], &scanInfo.ownAddr[0], 6); + } + + // AdvA, for SCAN REQ, it should identical to the ADV_IND/ADV_SCAN_IND + g_tx_adv_buf.data[6] = peerAddr[0]; + g_tx_adv_buf.data[7] = peerAddr[1]; + g_tx_adv_buf.data[8] = peerAddr[2]; + g_tx_adv_buf.data[9] = peerAddr[3]; + g_tx_adv_buf.data[10] = peerAddr[4]; + g_tx_adv_buf.data[11] = peerAddr[5]; + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(g_tx_adv_buf.txheader), + ((g_tx_adv_buf.txheader & 0xff00) >> 8) + 2); // payload length + header length(2) + bSendingScanReq = TRUE; + g_same_rf_channel_flag = FALSE; + } + } + } + + // convert pdu type to GAP enum + switch (pdu_type) + { + case ADV_IND: + advEventType = LL_ADV_RPT_ADV_IND; + break; + + case ADV_SCAN_IND: + advEventType = LL_ADV_RPT_ADV_SCANNABLE_IND; + break; + + case ADV_DIRECT_IND: + advEventType = LL_ADV_RPT_ADV_DIRECT_IND; + break; + + case ADV_NONCONN_IND: + advEventType = LL_ADV_RPT_ADV_NONCONN_IND; + break; + + case ADV_SCAN_RSP: + advEventType = LL_ADV_RPT_INVALID; + break; + + default: + advEventType = LL_ADV_RPT_ADV_IND; + break; + } + + rssi = -(pktFoot1 >> 24); + // below function cost 51us/66us(measure with GPIO) + LL_AdvReportCback( advEventType, // event type + addrType, // Adv address type (TxAdd) + &peerAddr[0], // Adv address (AdvA) + pktLen - 8, // length of rest of the payload, 2 - header, 6 - advA + &g_rx_adv_buf.data[6], // rest of payload + rssi ); // RSSI + g_pmCounters.ll_recv_adv_pkt_cnt ++; + } + } + else + { + // invalid ADV PDU type +// llSetupScan(); + } + } + + // if not waiting for scan rsp, schedule next scan + if (!bSendingScanReq) + { + // not sending SCAN REQ, update scan time + llScanTime += ((ISR_entry_time > llScanT1) ? (ISR_entry_time - llScanT1) : (BASE_TIME_UNITS - llScanT1 + ISR_entry_time)); + + if (llScanTime >= scanInfo.scanWindow * 625) + { + // calculate next scan channel + LL_CALC_NEXT_SCAN_CHN(scanInfo.nextScanChan); + + // schedule next scan event + if (scanInfo.scanWindow == scanInfo.scanInterval) // scanWindow == scanInterval, trigger immediately + LL_evt_schedule(); + else +// set_timer4((scanInfo.scanInterval - scanInfo.scanWindow) * 625); + ll_schedule_next_event((scanInfo.scanInterval - scanInfo.scanWindow) * 625); + + // reset scan total time + llScanTime = 0; + } + else + { +// AT_LOG("%03x %x %d %d %d %d\n",irq_status,*(volatile uint32_t *)(0x40031054),ll_hw_get_anchor(), +// g_rfifo_rst_cnt,(uint32_t)ISR_entry_time,read_current_fine_time()); + llSetupScan(scanInfo.nextScanChan); + } + } + } + // =========== initiator case + else if (llState == LL_STATE_INIT) + { + uint8 bConnecting = FALSE; + uint8 bMatchAdv = FALSE; // RPA checking OK in previous adv event, and new adv event identical to the old one + connPtr = &conn_param[initInfo.connId]; // connId is allocated when create conn + + // check status + if ((irq_status & LIRQ_RD) && (irq_status & LIRQ_COK)) // bug correct 2018-10-15 + { + // rx done + uint8_t packet_len, pdu_type; + uint16_t pktLen; + uint32_t pktFoot0, pktFoot1; + // read packet + // cost 21-26us(measure with GPIO), depneds on the length of ADV + packet_len = ll_hw_read_rfifo((uint8_t*)(&(g_rx_adv_buf.rxheader)), + &pktLen, + &pktFoot0, + &pktFoot1); + // check receive pdu type + pdu_type = g_rx_adv_buf.rxheader & 0x0f; + + if(ll_hw_get_rfifo_depth() > 0) + { + g_pmCounters.ll_rfifo_read_err++; + packet_len=0; + pktLen=0; + } + + if (packet_len != 0 + && ((pdu_type == ADV_IND) || pdu_type == ADV_DIRECT_IND)) + { + uint8_t txAdd = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + uint8_t chSel = (g_rx_adv_buf.rxheader & CHSEL_MASK) >> CHSEL_SHIFT; + rpaListIndex = LL_RESOLVINGLIST_ENTRY_NUM; + peerAddr = &g_rx_adv_buf.data[0]; // AdvA + g_currentPeerAddrType = txAdd; + + // ================= Resolving list checking + // case 1: receive InitA using RPA + if (txAdd == LL_DEV_ADDR_TYPE_RANDOM && + ((g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR)) + { + bWlRlCheckOk = FALSE; + + if (g_llRlEnable == TRUE) + { + // if the RPA checking is done in previous scan, compare + if (isPeerRpaStore == TRUE && + currentPeerRpa[0] == g_rx_adv_buf.data[0] + && currentPeerRpa[1] == g_rx_adv_buf.data[1] + && currentPeerRpa[2] == g_rx_adv_buf.data[2] + && currentPeerRpa[3] == g_rx_adv_buf.data[3] + && currentPeerRpa[4] == g_rx_adv_buf.data[4] + && currentPeerRpa[5] == g_rx_adv_buf.data[5]) + { + rpaListIndex = storeRpaListIndex; + peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; + g_currentPeerAddrType = g_llResolvinglist[rpaListIndex].peerAddrType + 2; + bWlRlCheckOk = TRUE; + bMatchAdv = TRUE; + } + else // resolve the address + { + rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]); // spend 30us(48MHz) when the 1st item match + + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM) + { + peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; + g_currentPeerAddrType = g_llResolvinglist[rpaListIndex].peerAddrType + 2; + bWlRlCheckOk = TRUE; + } + } + } + } + // case 2: receive InitA using device ID, or init device not using RPA + else + { + for (int i = 0; i < LL_RESOLVINGLIST_ENTRY_NUM; i++) + { + if ( g_llResolvinglist[i].peerAddr[0] == g_rx_adv_buf.data[0] + && g_llResolvinglist[i].peerAddr[1] == g_rx_adv_buf.data[1] + && g_llResolvinglist[i].peerAddr[2] == g_rx_adv_buf.data[2] + && g_llResolvinglist[i].peerAddr[3] == g_rx_adv_buf.data[3] + && g_llResolvinglist[i].peerAddr[4] == g_rx_adv_buf.data[4] + && g_llResolvinglist[i].peerAddr[5] == g_rx_adv_buf.data[5]) + { + // the device ID in the RPA list + if (g_llResolvinglist[i].privacyMode == NETWORK_PRIVACY_MODE && + !ll_isIrkAllZero(g_llResolvinglist[i].peerIrk)) + bWlRlCheckOk = FALSE; + else + rpaListIndex = i; + } + } + } + + // ====== for direct adv, also check initA == own addr + if (pdu_type == ADV_DIRECT_IND && bWlRlCheckOk == TRUE && bMatchAdv != TRUE) + { + // initA is resolvable address case + if ((g_rx_adv_buf.data[11] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) + { + // should not use RPA case + if (initInfo.ownAddrType != LL_DEV_ADDR_TYPE_RPA_PUBLIC && initInfo.ownAddrType != LL_DEV_ADDR_TYPE_RPA_RANDOM) + bWlRlCheckOk = FALSE; + + if (rpaListIndex >= LL_RESOLVINGLIST_ENTRY_NUM + || (ll_isIrkAllZero(g_llResolvinglist[rpaListIndex].localIrk)) // all-0 local IRK + || (ll_ResolveRandomAddrs(g_llResolvinglist[rpaListIndex].localIrk, &g_rx_adv_buf.data[6]) != SUCCESS)) // resolve failed + bWlRlCheckOk = FALSE; + } + else + { + uint8* localAddr; + uint8_t rxAdd = (g_rx_adv_buf.rxheader & RX_ADD_MASK) >> RX_ADD_SHIFT; + + // should not use device ID case + if ((initInfo.ownAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC || initInfo.ownAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM ) + && (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM + && !ll_isIrkAllZero(g_llResolvinglist[rpaListIndex].localIrk))) + { + bWlRlCheckOk = FALSE; + } + + if (rxAdd == LL_DEV_ADDR_TYPE_RANDOM) + localAddr = ownRandomAddr; + else + localAddr = ownPublicAddr; + + if (g_rx_adv_buf.data[6] != localAddr[0] + || g_rx_adv_buf.data[7] != localAddr[1] + || g_rx_adv_buf.data[8] != localAddr[2] + || g_rx_adv_buf.data[9] != localAddr[3] + || g_rx_adv_buf.data[10] != localAddr[4] + || g_rx_adv_buf.data[11] != localAddr[5]) + { + bWlRlCheckOk = FALSE; + } + } + } + + // initiator, 2 types of filter process: 1. connect to peer address set by host 2. connect to address in whitelist only + // 1. connect to peer address set by host + if (initInfo.wlPolicy == LL_INIT_WL_POLICY_USE_PEER_ADDR + && bWlRlCheckOk == TRUE) + { + if (peerAddr[0] != peerInfo.peerAddr[0] + || peerAddr[1] != peerInfo.peerAddr[1] + || peerAddr[2] != peerInfo.peerAddr[2] + || peerAddr[3] != peerInfo.peerAddr[3] + || peerAddr[4] != peerInfo.peerAddr[4] + || peerAddr[5] != peerInfo.peerAddr[5]) + { + // not match, not init connect + bWlRlCheckOk = FALSE; + } + } + // 2. connect to address in whitelist only + else if (initInfo.wlPolicy == LL_INIT_WL_POLICY_USE_WHITE_LIST && + bWlRlCheckOk == TRUE) + { + // if advA in whitelist list, connect + // check white list + bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr); + } + + if (bWlRlCheckOk == TRUE) + { + g_same_rf_channel_flag = TRUE; + + // channel selection algorithm decision + if ((pGlobal_config[LL_SWITCH] & CONN_CSA2_ALLOW) + && chSel == LL_CHN_SEL_ALGORITHM_2) + { + conn_param[initInfo.connId].channel_selection = LL_CHN_SEL_ALGORITHM_2; + SET_BITS(g_tx_adv_buf.txheader, LL_CHN_SEL_ALGORITHM_2, CHSEL_SHIFT, CHSEL_MASK); + } + else + { + conn_param[initInfo.connId].channel_selection = LL_CHN_SEL_ALGORITHM_1; + SET_BITS(g_tx_adv_buf.txheader, LL_CHN_SEL_ALGORITHM_1, CHSEL_SHIFT, CHSEL_MASK); + } + + // calculate initA if using RPA list, otherwise copy the address stored in initInfo + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM && + !ll_isIrkAllZero(g_llResolvinglist[rpaListIndex].localIrk) && + (initInfo.ownAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC || initInfo.ownAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM)) + { + // for resolving private address case, calculate the scanA with Local IRK + ll_CalcRandomAddr(g_llResolvinglist[rpaListIndex].localIrk, &g_tx_adv_buf.data[0]); + SET_BITS(g_tx_adv_buf.txheader, LL_DEV_ADDR_TYPE_RANDOM, TX_ADD_SHIFT, TX_ADD_MASK); +// osal_memcpy( &g_currentLocalRpa[0], &g_tx_adv_buf.data[0], 6); + g_currentLocalAddrType = LL_DEV_ADDR_TYPE_RPA_RANDOM; // not accute local type, for branch selection in enh conn complete event + } + else + { + if (initInfo.ownAddrType == LL_DEV_ADDR_TYPE_PUBLIC || initInfo.ownAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC) + { + memcpy((uint8*)&g_tx_adv_buf.data[0], &ownPublicAddr[0], 6); + SET_BITS(g_tx_adv_buf.txheader, LL_DEV_ADDR_TYPE_PUBLIC, TX_ADD_SHIFT, TX_ADD_MASK); + } + else + { + memcpy((uint8*)&g_tx_adv_buf.data[0], &ownRandomAddr[0], 6); + SET_BITS(g_tx_adv_buf.txheader, LL_DEV_ADDR_TYPE_RANDOM, TX_ADD_SHIFT, TX_ADD_MASK); + } + + g_currentLocalAddrType = LL_DEV_ADDR_TYPE_RANDOM; // not accute local type, for branch selection in enh conn complete event + } + + // send conn req + T2 = read_current_fine_time(); + delay = (T2 > ISR_entry_time) ? (T2 - ISR_entry_time) : (BASE_TIME_UNITS - ISR_entry_time + T2); + + if (delay > 118 - pGlobal_config[LL_ADV_TO_CONN_REQ_DELAY] - pGlobal_config[LL_HW_PLL_DELAY]) // not enough time + { + // not enough time to send conn req, store the RPA + isPeerRpaStore = TRUE; + storeRpaListIndex = rpaListIndex; + osal_memcpy(¤tPeerRpa[0], &g_rx_adv_buf.data[0], 6); +// LOG("store %d\n", storeRpaListIndex); + g_same_rf_channel_flag = FALSE; + LOG("<%d>", delay); + } + else + { + delay = 118 - delay - pGlobal_config[LL_ADV_TO_CONN_REQ_DELAY]; + ll_hw_set_trx_settle(delay, // set BB delay, about 80us in 16MHz HCLK + pGlobal_config[LL_HW_AFE_DELAY], + pGlobal_config[LL_HW_PLL_DELAY]); //RxAFE,PLL + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + // send conn req + ll_hw_set_stx(); // set LL HW as single Tx mode + ll_hw_go(); + llWaitingIrq = TRUE; + // AdvA, offset 6 + memcpy((uint8*)&g_tx_adv_buf.data[6], &g_rx_adv_buf.data[0], 6); + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(g_tx_adv_buf.txheader), + ((g_tx_adv_buf.txheader & 0xff00) >> 8) + 2); // payload length + header length(2) + + if (g_currentPeerAddrType >= 0x02) + osal_memcpy(&g_currentPeerRpa[0], &g_rx_adv_buf.data[0], 6); + + if (g_currentLocalAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM) + osal_memcpy( &g_currentLocalRpa[0], &g_tx_adv_buf.data[0], 6); + + move_to_master_function(); + isPeerRpaStore = FALSE; + bConnecting = TRUE; + g_same_rf_channel_flag = FALSE; + } + } + } + else if (packet_len != 0 + && (pdu_type == ADV_DIRECT_IND)) // TODO: add process of direct ADV + { + } + } + + // scan again if not start connect + if (!bConnecting) // if not waiting for scan rsp, schedule next scan + { + if (initInfo.scanMode == LL_SCAN_STOP) + { + // scan has been stopped + llState = LL_STATE_IDLE; // for single connection case, set the LL state idle + // release the associated allocated connection + llReleaseConnId(connPtr); // new for multi-connection + g_ll_conn_ctx.numLLMasterConns --; + (void)osal_set_event( LL_TaskID, LL_EVT_MASTER_CONN_CANCELLED ); // inform high layer + } + else + { + // not sending SCAN REQ, update scan time + llScanTime += ((ISR_entry_time > llScanT1) ? (ISR_entry_time - llScanT1) : (BASE_TIME_UNITS - llScanT1 + ISR_entry_time)); + + if (llScanTime >= initInfo.scanWindow * 625) + { + // calculate next scan channel + LL_CALC_NEXT_SCAN_CHN(initInfo.nextScanChan); + + // schedule next scan event + if (initInfo.scanWindow == initInfo.scanInterval) // scanWindow == scanInterval, trigger immediately + LL_evt_schedule(); + else +// set_timer4((initInfo.scanInterval - initInfo.scanWindow) * 625); + ll_schedule_next_event((initInfo.scanInterval - initInfo.scanWindow) * 625); + + // reset scan total time + llScanTime = 0; + } + else + llSetupScan(initInfo.nextScanChan); + } + } + } + } + // =================== mode RTLP process + else if (mode == LL_HW_MODE_RTLP + && llState == LL_STATE_CONN_SLAVE) + { + // slave + uint8_t ack_num, tx_num; + uint32_t anchor_point, loop_time; + uint8 temp_sn_nesn; // 2018-2-28 add, for BQB + connPtr = &conn_param[g_ll_conn_ctx.currentConn]; + ll_debug_output(DEBUG_LL_HW_RTLP); + connPtr->rx_crcok = 0; + connPtr->rx_timeout = 0; + + // read loop timeout counter, system clock may be 16MHz, 32MHz, 64MHz and 48MHz, 96MHz + if (hclk_per_us_shift != 0) + loop_time = ll_hw_get_loop_cycle() >> hclk_per_us_shift; // convert to us + else + loop_time = ll_hw_get_loop_cycle() / hclk_per_us; // convert to us + + // read anchor point + if (irq_status & LIRQ_TD) // sync OK, then anchor point is OK, whether received something or CRC error => something will be Tx and done + { + if (hclk_per_us_shift != 0) + anchor_point = ll_hw_get_anchor() >> hclk_per_us_shift; // convert to us + else + anchor_point = ll_hw_get_anchor() / hclk_per_us; // convert to us + + if (connPtr->firstPacket) // anchor point catched, change state + { + connPtr->firstPacket = 0; + } + + //20180715 by ZQ + //get the rssi form rf_phy register + rf_phy_get_pktFoot(&connPtr->lastRssi, &connPtr->foff, &connPtr->carrSens); + // global_config[SLAVE_CONN_DELAY]: soft parameter could be set after release + slave_conn_event_recv_delay = loop_time - anchor_point + pGlobal_config[SLAVE_CONN_DELAY]; + + if (irq_status & LIRQ_COK) // Rx CRC OK, empty of data packet + { + connPtr->rx_crcok = 1; + } + } + else + { + // timeout case + connPtr->rx_timeout = 1; + connPtr->pmCounter.ll_conn_event_timeout_cnt ++; + // pGlobal_config[SLAVE_CONN_DELAY_BEFORE_SYNC]: soft parameter could be set after release + slave_conn_event_recv_delay = loop_time - 270 + pGlobal_config[SLAVE_CONN_DELAY_BEFORE_SYNC]; // refer to llSlaveEvt_TaskEndOk(), we use the same formula for timeout & sync case + + //20181014 ZQ: perStats + if(p_perStatsByChan!=NULL) + p_perStatsByChan->rxToCnt[connPtr->currentChan]++; + } + + //====== 20180324 modified by ZQ +// ll_adptive_smart_window(irq_status,anchor_point); // comment-out by HZF + ack_num = ll_hw_get_txAck(); + rfCounters.numTxDone = ack_num; + // below 2 counters are update in ll_hw_update() + //rfCounters.numTxAck = ack_num; // not align to TI, ACK for empty packet is not considered + //rfCounters.numRxOk = ll_hw_get_rxPkt_num(); + // TODO: update more Rf counters + rfCounters.numRxNotOk = 0; + rfCounters.numRxIgnored = 0; + rfCounters.numRxEmpty = 0; + rfCounters.numRxFifoFull = 0; + + // A1 ROM metal change add + if ((irq_status & LIRQ_CERR2) + || (irq_status & LIRQ_CERR )) + { + connPtr->pmCounter.ll_recv_crcerr_event_cnt ++; + rfCounters.numRxNotOk = 1; // CRC error, add 2018-6-12 + } + + //rfCounters.numTxRetrans = 0; + //rfCounters.numTx = 0; + //rfCounters.numRxCtrl = 0; + temp_sn_nesn = connPtr->sn_nesn; // 2018-2-28, BQB + // update the LL HW engine mode and save the sn, nesn + connPtr->llMode = ll_hw_update(connPtr->llMode, // Attention: this mode is not real HW mode + &(rfCounters.numTxAck), + &(rfCounters.numRxOk), + &(connPtr->sn_nesn)); + + // add 2018-2-28, for slave latency scenario in BQB test + if (connPtr->firstPacket == 0 // anchor point catched + && (temp_sn_nesn & 0x02) != (connPtr->sn_nesn & 0x02) // local sn has changed + && rfCounters.numTxAck == 0) + { + rfCounters.numTxAck = 1; + } + + // ==== check HW Tx FIFO, read packets which not transmit or transit but not receive ACK + tx_num = (*(volatile uint32_t*)(LL_HW_BASE + 0x04) >> 8) & 0xff; + + if ( connPtr->encEnabled ) + g_pmCounters.ll_tbd_cnt2 += ack_num; + + //20200128 ZQ: perStats + if(p_perStatsByChan!=NULL) + { + p_perStatsByChan->TxNumAck[connPtr->currentChan]+=ack_num; + p_perStatsByChan->txNumRetry[connPtr->currentChan]+=ll_hw_get_nAck(); + uint8_t crcErrNum,rxTotalNum,rxPktNum; + ll_hw_get_rxPkt_stats(&crcErrNum,&rxTotalNum,&rxPktNum); + p_perStatsByChan->rxNumPkts[connPtr->currentChan]+=rxTotalNum; + p_perStatsByChan->rxNumCrcErr[connPtr->currentChan]+=crcErrNum; + } + + if (irq_status & LIRQ_RTO + && ack_num < tx_num) // receive time out, there are bugs in LL HW process TFIFO pointer, recover the pointer by SW + { + ll_hw_process_RTO(ack_num); + } + + ll_hw_read_tfifo_rtlp(); + // update the numTxCtrlAck counter, add on 2017-11-15 + rfCounters.numTxCtrlAck = 0; + + if (connPtr->ctrlDataIsProcess == 1 // control packet in this RTLP event TFIFO + && ack_num > 0 // get ACK in this event + && (connPtr->ll_buf.tx_not_ack_pkt->valid == 0 // no not_ack packet + || (connPtr->ll_buf.tx_not_ack_pkt->header & 0x3) != LL_DATA_PDU_HDR_LLID_CONTROL_PKT)) // not_ack packet is not ctrl packet + { + rfCounters.numTxCtrlAck = 1; + connPtr->ctrlDataIsProcess = 0; + } + + // if receive some packets, read them + if (rfCounters.numRxOk) + { + // read HW Rx FIFO to internal buffer + ll_read_rxfifo(); + } + + // call llSlaveEvt_TaskEndOk + llSlaveEvt_TaskEndOk(); + + // connection event notify + if (g_conn_taskID != 0) + osal_set_event(g_conn_taskID, g_conn_taskEvent); + } + // =================== mode TRLP process + else if (mode == LL_HW_MODE_TRLP + && llState == LL_STATE_CONN_MASTER) + { + // master + ll_debug_output(DEBUG_LL_HW_TRLP); + uint8_t ack_num,tx_num; + connPtr = &conn_param[g_ll_conn_ctx.currentConn]; + connPtr->rx_crcok = 0; + connPtr->rx_timeout = 0; + + // TODO: read anchor point, it seems LIRQ_RD always be set here, to confirm + if (irq_status & LIRQ_RD) // sync OK, then anchor point is OK, whether received something or CRC error => something will be Tx and done + { + //20180715 by ZQ + //get the rssi form rf_phy register + rf_phy_get_pktFoot(&connPtr->lastRssi, &connPtr->foff,&connPtr->carrSens); + + if (irq_status & LIRQ_COK) // Rx CRC OK, empty or data packet + { + connPtr->rx_crcok = 1; + } + else if ((irq_status & LIRQ_CERR2) + || (irq_status & LIRQ_CERR)) + { + g_pmCounters.ll_tbd_cnt4 = 0; + } + else + { + connPtr->pmCounter.ll_conn_event_timeout_cnt ++; + connPtr->rx_timeout = 1; + } + } + else + { + // timeout case + connPtr->rx_timeout = 1; + + //20181014 ZQ: perStats + if(p_perStatsByChan!=NULL) + p_perStatsByChan->rxToCnt[connPtr->currentChan]++; + } + + // CRC error counter + if ((irq_status & LIRQ_CERR2) + || (irq_status & LIRQ_CERR )) + { + connPtr->pmCounter.ll_recv_crcerr_event_cnt ++; + rfCounters.numRxNotOk = 1; // CRC Error + } + + // Tx done OK counter + ack_num = ll_hw_get_txAck(); + rfCounters.numTxDone = ack_num; + uint8_t curr_llMode = connPtr->llMode; + // update the LL HW engine mode and save the sn, nesn + connPtr->llMode = ll_hw_update(connPtr->llMode, // Attention: this mode is not real HW mode + &(rfCounters.numTxAck), + &(rfCounters.numRxOk), + &(connPtr->sn_nesn)); + + //20200128 ZQ: perStats + if(p_perStatsByChan!=NULL) + { + p_perStatsByChan->TxNumAck[connPtr->currentChan]+=ack_num; + p_perStatsByChan->txNumRetry[connPtr->currentChan]+=ll_hw_get_nAck(); + uint8_t crcErrNum,rxTotalNum,rxPktNum; + ll_hw_get_rxPkt_stats(&crcErrNum,&rxTotalNum,&rxPktNum); + p_perStatsByChan->rxNumPkts[connPtr->currentChan]+=rxTotalNum; + p_perStatsByChan->rxNumCrcErr[connPtr->currentChan]+=crcErrNum; + } + + // ==== check HW Tx FIFO, read packets which not transmit or transit but not receive ACK + tx_num = (*(volatile uint32_t*)(LL_HW_BASE + 0x04) >> 8) & 0xff; + + if (!(curr_llMode==LL_HW_TRLP_EMPT && tx_num==1) //when only tx empty pkt in fifo + && (irq_status & LIRQ_RTO) + && (ack_num < tx_num) ) // receive time out, there are bugs in LL HW process TFIFO pointer, recover the pointer by SW + { + ll_hw_process_RTO(ack_num); + } + + ll_hw_read_tfifo_rtlp(); // reused rtlp function + // update the numTxCtrlAck counter, add on 2017-11-15 + rfCounters.numTxCtrlAck = 0; + + if (connPtr->ctrlDataIsProcess == 1 // control packet in this RTLP event TFIFO + && ack_num > 0 // get ACK in this event + && (connPtr->ll_buf.tx_not_ack_pkt->valid == 0 // no not_ack packet + || (connPtr->ll_buf.tx_not_ack_pkt->header & 0x3) != LL_DATA_PDU_HDR_LLID_CONTROL_PKT)) // not_ack packet is not ctrl packet + { + rfCounters.numTxCtrlAck = 1; + connPtr->ctrlDataIsProcess = 0; + } + + // if receive some packets, read them + if (rfCounters.numRxOk) + { + // read HW Rx FIFO to internal buffer + ll_read_rxfifo(); + } + + // call master process task + llMasterEvt_TaskEndOk(); +// hal_gpio_write(GPIO_P18, 0); + + //20181014 ZQ: + // connection event notify + if (g_conn_taskID != 0) + osal_set_event(g_conn_taskID, g_conn_taskEvent); + +//#ifndef MULTI_ROLE +// // switch connection context +// g_ll_conn_ctx.currentConn = ll_get_next_active_conn(g_ll_conn_ctx.currentConn); +//#endif + } + // =================== other mode(STX, RTX), no process(send SCAN RSP done) or no used + // === A2 add for simultaneous connect event & adv event + // conn-adv case 1: STX ISR, continue broadcast left sec adv channels + else if ((llSecondaryState == LL_SEC_STATE_ADV || llSecondaryState == LL_SEC_STATE_IDLE_PENDING) + && (mode == LL_HW_MODE_STX )) + { + // secondary adv state + uint8 i; + #ifdef DEBUG_LL + LOG("Sec Adv\r\n"); + #endif + i = 0; + + while (!(adv_param.advChanMap & (1 << i))) i ++; // get the 1st adv channel + + // adv_param.advNextChan stores the next adv channel, when adv the last adv channel, advNextChan should equal 1st adv channel + if (adv_param.advNextChan != (LL_ADV_CHAN_FIRST + i)) // not finish adv the last channel, continue adv + { + llSetupSecAdvEvt(); + } + else + { + if (llSecondaryState == LL_SEC_STATE_IDLE_PENDING) // advertise last channel and transiting to IDLE + llSecondaryState = LL_SEC_STATE_IDLE; + else // otherwise, schedule next adv + osal_start_timerEx(LL_TaskID, LL_EVT_SECONDARY_ADV, (adv_param.advInterval * 5) >> 3); // * 625 / 1000 + } + + ll_debug_output(DEBUG_LL_HW_STX); + } + // multi-connection, support connectable/scannable adv + else if ((llSecondaryState == LL_SEC_STATE_ADV || llSecondaryState == LL_SEC_STATE_IDLE_PENDING) + && (mode == LL_HW_MODE_TRX ) + && (adv_param.advEvtType == LL_ADV_CONNECTABLE_UNDIRECTED_EVT || adv_param.advEvtType == LL_ADV_SCANNABLE_UNDIRECTED_EVT)) + { + // secondary adv state, connectable adv or scannable adv + uint8_t packet_len, pdu_type, txAdd; + uint16_t pktLen; + uint32_t pktFoot0, pktFoot1; + int calibra_time; // this parameter will be provided by global_config + //int i; +// ll_debug_output(DEBUG_LL_HW_TRX); + // read packet + packet_len = ll_hw_read_rfifo((uint8_t*)(&(g_rx_adv_buf.rxheader)), + &pktLen, + &pktFoot0, + &pktFoot1); + + if(ll_hw_get_rfifo_depth() > 0) + { + g_pmCounters.ll_rfifo_read_err++; + packet_len=0; + pktLen=0; + } + + // check receive pdu type + pdu_type = g_rx_adv_buf.rxheader & PDU_TYPE_MASK; + txAdd = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + + if (packet_len > 0 // any better checking rule for rx anything? + && (irq_status & LIRQ_COK) + && pdu_type == ADV_SCAN_REQ) +// && (llState == LL_STATE_ADV_UNDIRECTED +// || llState == LL_STATE_ADV_SCAN)) + { + // 1. scan req + g_pmCounters.ll_recv_scan_req_cnt ++; + + // check AdvA + if (g_rx_adv_buf.data[6] != adv_param.ownAddr[0] + || g_rx_adv_buf.data[7] != adv_param.ownAddr[1] + || g_rx_adv_buf.data[8] != adv_param.ownAddr[2] + || g_rx_adv_buf.data[9] != adv_param.ownAddr[3] + || g_rx_adv_buf.data[10] != adv_param.ownAddr[4] + || g_rx_adv_buf.data[11] != adv_param.ownAddr[5]) + { + } + else + { +//=== + uint8_t rpaListIndex, bWlRlCheckOk; + uint8_t* peerAddr = &g_rx_adv_buf.data[0]; // ScanA + + // === Resolving list checking + if (txAdd == LL_DEV_ADDR_TYPE_RANDOM + && (g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) + { + bWlRlCheckOk = TRUE; + + // if ScanA is resolvable private address + if (g_llRlEnable == TRUE) + { + bWlRlCheckOk = FALSE; + rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]); + + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM) + { + peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; + bWlRlCheckOk = TRUE; + } + } + } + else // ScanA is device Identity, if the device ID in the RPA list, check whether RPA should be used + { + bWlRlCheckOk = TRUE; + + for (int i = 0; i < LL_RESOLVINGLIST_ENTRY_NUM; i++) + { + if (g_llResolvinglist[i].peerAddr[0] == g_rx_adv_buf.data[0] + && g_llResolvinglist[i].peerAddr[1] == g_rx_adv_buf.data[1] + && g_llResolvinglist[i].peerAddr[2] == g_rx_adv_buf.data[2] + && g_llResolvinglist[i].peerAddr[3] == g_rx_adv_buf.data[3] + && g_llResolvinglist[i].peerAddr[4] == g_rx_adv_buf.data[4] + && g_llResolvinglist[i].peerAddr[5] == g_rx_adv_buf.data[5] + && g_llResolvinglist[i].peerAddrType == txAdd) + { + if (g_llResolvinglist[i].privacyMode == NETWORK_PRIVACY_MODE && + !ll_isIrkAllZero(g_llResolvinglist[i].peerIrk)) + bWlRlCheckOk = FALSE; + + break; + } + } + } + + // === check white list + if ((pGlobal_config[LL_SWITCH] & LL_WHITELIST_ALLOW) + && (adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_SCAN_REQ + || adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_ALL_REQ) + && (bWlRlCheckOk == TRUE)) + { + // check white list + bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr); + } + + if (bWlRlCheckOk == FALSE) // if not in white list, do nothing + { + g_pmCounters.ll_filter_scan_req_cnt ++; + } + else + { + g_pmCounters.ll_rx_peer_cnt++; + uint8 retScanRspFilter=1; + + if(LL_PLUS_ScanRequestFilterCBack) + { + retScanRspFilter = LL_PLUS_ScanRequestFilterCBack(); + } + + if(retScanRspFilter) + { + // send scan rsp + ll_hw_set_stx(); // set LL HW as single Tx mode + g_same_rf_channel_flag = TRUE; + // calculate the delay + T2 = read_current_fine_time(); + delay = (T2 > ISR_entry_time) ? (T2 - ISR_entry_time) : (BASE_TIME_UNITS - ISR_entry_time + T2); + calibra_time = pGlobal_config[SCAN_RSP_DELAY]; // consider rx_done to ISR time, SW delay after read_current_fine_time(), func read_current_fine_time() delay ... + delay = 118 - delay - calibra_time; // IFS = 150us, Tx tail -> Rx done time: about 32us + ll_hw_set_trx_settle(delay, // set BB delay, about 80us in 16MHz HCLK + pGlobal_config[LL_HW_AFE_DELAY], + pGlobal_config[LL_HW_PLL_DELAY]); //RxAFE,PLL + ll_hw_go(); + llWaitingIrq = TRUE; + g_same_rf_channel_flag = FALSE; + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(tx_scanRsp_desc.txheader), + ((tx_scanRsp_desc.txheader & 0xff00) >> 8) + 2); // payload length + header length(2) + ll_debug_output(DEBUG_LL_HW_SET_STX); + g_pmCounters.ll_send_scan_rsp_cnt ++; + } + } + } + } + else if (pdu_type == ADV_CONN_REQ + && (irq_status & LIRQ_COK) ) +// && (llState == LL_STATE_ADV_UNDIRECTED +// || llState == LL_STATE_ADV_DIRECTED)) + { + uint8_t* peerAddr; + uint8_t bWlRlCheckOk = TRUE; + // 2. connect req + g_pmCounters.ll_recv_conn_req_cnt ++; + + // check AdvA + if (g_rx_adv_buf.data[6] != adv_param.ownAddr[0] + || g_rx_adv_buf.data[7] != adv_param.ownAddr[1] + || g_rx_adv_buf.data[8] != adv_param.ownAddr[2] + || g_rx_adv_buf.data[9] != adv_param.ownAddr[3] + || g_rx_adv_buf.data[10] != adv_param.ownAddr[4] + || g_rx_adv_buf.data[11] != adv_param.ownAddr[5]) + { + // nothing to do + } + else + { + uint8_t rpaListIndex = LL_RESOLVINGLIST_ENTRY_NUM; + peerAddr = &g_rx_adv_buf.data[0]; // initA + + // ====== check Resolving list + if (txAdd == LL_DEV_ADDR_TYPE_RANDOM && + (g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) + { + bWlRlCheckOk = TRUE; + + if (g_llRlEnable == TRUE) + { + bWlRlCheckOk = FALSE; + rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]); + + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM) + { + // save resolved peer address + peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; + // if resolved address success, map the peer address type to 0x02 or 0x03 + g_currentPeerAddrType = g_llResolvinglist[rpaListIndex].peerAddrType + 2; + osal_memcpy( &g_currentPeerRpa[0], &g_rx_adv_buf.data[0], 6); // save latest peer RPA + bWlRlCheckOk = TRUE; + } + } + } + else // InitA is device Identity, check whether the device Addr in the RPA list, if it is + { + // in the RPA list and network privacy mode is selected and non all-0 IRK, check failed + bWlRlCheckOk = TRUE; + + for (int i = 0; i < LL_RESOLVINGLIST_ENTRY_NUM; i++) + { + if (g_llResolvinglist[i].peerAddr[0] == g_rx_adv_buf.data[0] + && g_llResolvinglist[i].peerAddr[1] == g_rx_adv_buf.data[1] + && g_llResolvinglist[i].peerAddr[2] == g_rx_adv_buf.data[2] + && g_llResolvinglist[i].peerAddr[3] == g_rx_adv_buf.data[3] + && g_llResolvinglist[i].peerAddr[4] == g_rx_adv_buf.data[4] + && g_llResolvinglist[i].peerAddr[5] == g_rx_adv_buf.data[5] + && g_llResolvinglist[i].peerAddrType == txAdd) + { + if (g_llResolvinglist[i].privacyMode == NETWORK_PRIVACY_MODE && + !ll_isIrkAllZero(g_llResolvinglist[i].peerIrk)) + bWlRlCheckOk = FALSE; + + break; + } + } + } + + // ====== check white list + if ((pGlobal_config[LL_SWITCH] & LL_WHITELIST_ALLOW) + && (llState == LL_STATE_ADV_UNDIRECTED) + && (adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_CONNECT_REQ + || adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_ALL_REQ) + && (bWlRlCheckOk == TRUE)) + { + // check white list + bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr); + } + + // fixed bug 2018-09-25, LL/CON/ADV/BV-04-C, for direct adv, initA should equal peer Addr + if (llState == LL_STATE_ADV_DIRECTED) + { + if (//txAdd != peerInfo.peerAddrType // for (extended) set adv param, peer addr type could only be 0x0 or 0x01 + peerAddr[0] != peerInfo.peerAddr[0] + || peerAddr[1] != peerInfo.peerAddr[1] + || peerAddr[2] != peerInfo.peerAddr[2] + || peerAddr[3] != peerInfo.peerAddr[3] + || peerAddr[4] != peerInfo.peerAddr[4] + || peerAddr[5] != peerInfo.peerAddr[5]) + { + bWlRlCheckOk = FALSE; + } + } + + if (bWlRlCheckOk == FALSE) // if not in white list, do nothing + { + g_pmCounters.ll_filter_conn_req_cnt ++; + } + else + { + // increment statistics counter + g_pmCounters.ll_rx_peer_cnt++; + // bug fixed 2018-01-23, peerAddrType should read TxAdd + peerInfo.peerAddrType = txAdd; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + osal_memcpy(peerInfo.peerAddr, &peerAddr[0], 6); + move_to_slave_function(); // move to slave role for connection state + } + } + } + //test for fast adv + else //if(llState == LL_STATE_ADV_UNDIRECTED) + { + // adv in next channel, or schedule next adv event + uint8 i = 0; + + while (!(adv_param.advChanMap & (1 << i))) i ++; // get the 1st adv channel + + // adv_param.advNextChan stores the next adv channel, when adv the last adv channel, advNextChan should equal 1st adv channel + if (adv_param.advNextChan != (LL_ADV_CHAN_FIRST + i)) // not finish adv the last channel, continue adv + { + llSetupSecAdvEvt(); + } + else + { + if (llSecondaryState == LL_SEC_STATE_IDLE_PENDING) // advertise last channel and transiting to IDLE + llSecondaryState = LL_SEC_STATE_IDLE; + else // otherwise, schedule next adv + osal_start_timerEx(LL_TaskID, LL_EVT_SECONDARY_ADV, (adv_param.advInterval * 5) >> 3); // * 625 / 1000 + } + +// uint8_t firstAdvChan = (adv_param.advChanMap&LL_ADV_CHAN_37) !=0 ? 37 : +// (adv_param.advChanMap&LL_ADV_CHAN_38) !=0 ? 38 : 39; +// +// if(adv_param.advNextChan>firstAdvChan) +// { +// //llSetupUndirectedAdvEvt1(); +// ll_schedule_next_event(50); //20180623 modified by ZQ +// // reset the timer1 instead of llSetupUndirectedAdvEvt1 +// // reduced the process time in LL_IRQ +// // llSetupUndirectedAdvEvt1 will cost about 120us +// } + //llWaitingIrq = TRUE; + } + } + // TODO: add RPA list checking, identical to single role case + else if (mode == LL_HW_MODE_SRX + && llSecondaryState == LL_SEC_STATE_SCAN) + { + // check status + if ((irq_status & LIRQ_RD) && (irq_status & LIRQ_COK)) // bug correct 2018-10-15 + { + // rx done + uint8_t packet_len, pdu_type; + uint16_t pktLen; + uint32_t pktFoot0, pktFoot1; + // read packet + // cost 21-26us(measure with GPIO), depneds on the length of ADV + packet_len = ll_hw_read_rfifo((uint8_t*)(&(g_rx_adv_buf.rxheader)), + &pktLen, + &pktFoot0, + &pktFoot1); + // check receive pdu type + pdu_type = g_rx_adv_buf.rxheader & 0x0f; + + if (packet_len != 0 + && ((pdu_type == ADV_IND) + || (pdu_type == ADV_NONCONN_IND) + || (pdu_type == ADV_SCAN_IND))) + { + int i = 0; + uint8_t txAdd = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + + // check white list + if ((pGlobal_config[LL_SWITCH] & LL_WHITELIST_ALLOW) + && (scanInfo.wlPolicy == LL_SCAN_WL_POLICY_USE_WHITE_LIST)) + { + // check white list + for (i = 0; i < LL_WHITELIST_ENTRY_NUM; i++) + { + if (txAdd != g_llWhitelist[i].peerAddrType + || g_rx_adv_buf.data[0] != g_llWhitelist[i].peerAddr[0] + || g_rx_adv_buf.data[1] != g_llWhitelist[i].peerAddr[1] + || g_rx_adv_buf.data[2] != g_llWhitelist[i].peerAddr[2] + || g_rx_adv_buf.data[3] != g_llWhitelist[i].peerAddr[3] + || g_rx_adv_buf.data[4] != g_llWhitelist[i].peerAddr[4] + || g_rx_adv_buf.data[5] != g_llWhitelist[i].peerAddr[5]) + { + // not match, check next + continue; + } + else + break; + } + } + + // if valid, trigger osal event to report adv + if (i < LL_WHITELIST_ENTRY_NUM) + { + uint8 advEventType; + int8 rssi; + llCurrentScanChn = scanInfo.nextScanChan; + + // no active scan scenario + + // convert pdu type to GAP enum + switch (pdu_type) + { + case ADV_IND: + advEventType = LL_ADV_RPT_ADV_IND; + break; + + case ADV_SCAN_IND: + advEventType = LL_ADV_RPT_ADV_SCANNABLE_IND; + break; + + case ADV_DIRECT_IND: + advEventType = LL_ADV_RPT_ADV_DIRECT_IND; + break; + + case ADV_NONCONN_IND: + advEventType = LL_ADV_RPT_ADV_NONCONN_IND; + break; + + case ADV_SCAN_RSP: + advEventType = LL_ADV_RPT_INVALID; + break; + + default: + advEventType = LL_ADV_RPT_ADV_IND; + break; + } + + rssi = -(pktFoot1 >> 24); + // below function cost 51us/66us(measure with GPIO) + LL_AdvReportCback( advEventType, // event type + txAdd, // Adv address type (TxAdd) + &g_rx_adv_buf.data[0], // Adv address (AdvA) + pktLen - 8, // length of rest of the payload, 2 - header, 6 - advA + &g_rx_adv_buf.data[6], // rest of payload + rssi ); // RSSI + g_pmCounters.ll_recv_adv_pkt_cnt ++; + } + } + } + + // update scan time + llScanTime += ((ISR_entry_time > llScanT1) ? (ISR_entry_time - llScanT1) : (BASE_TIME_UNITS - llScanT1 + ISR_entry_time)); + + if (llScanTime >= scanInfo.scanWindow * 625) + { + // switch scan channel, set event instead of trigger immediately + // calculate next scan channel + LL_CALC_NEXT_SCAN_CHN(scanInfo.nextScanChan); + + // schedule next scan event + if (scanInfo.scanWindow == scanInfo.scanInterval) // scanWindow == scanInterval, trigger immediately + osal_set_event(LL_TaskID, LL_EVT_SECONDARY_SCAN); + else + osal_start_timerEx(LL_TaskID, LL_EVT_SECONDARY_SCAN, ((scanInfo.scanInterval - scanInfo.scanWindow) * 5) >> 3 ); + + // reset scan total time + llScanTime = 0; + } + else if (llSecondaryState == LL_SEC_STATE_SCAN) + llSetupSecScan(scanInfo.nextScanChan); + } + // ======= A2 multi-connection + // TODO: add RPA list checking, identical to single role case + else if (mode == LL_HW_MODE_SRX + && llSecondaryState == LL_SEC_STATE_INIT) // TODO: consider whether could merge to LL_STATE_INIT branch + { + uint8 bConnecting = FALSE; +// hal_gpio_write(GPIO_P18, 0); + connPtr = &conn_param[initInfo.connId]; // connId is allocated when create conn + + // check status + if ((irq_status & LIRQ_RD) && (irq_status & LIRQ_COK)) // bug correct 2018-10-15 + { + // rx done + uint8_t packet_len, pdu_type; + uint16_t pktLen; + uint32_t pktFoot0, pktFoot1; + // read packet + // cost 21-26us(measure with GPIO), depneds on the length of ADV + packet_len = ll_hw_read_rfifo((uint8_t*)(&(g_rx_adv_buf.rxheader)), + &pktLen, + &pktFoot0, + &pktFoot1); + // check receive pdu type + pdu_type = g_rx_adv_buf.rxheader & 0x0f; + + if(ll_hw_get_rfifo_depth()>0) + { + g_pmCounters.ll_rfifo_read_err++; + packet_len=0; + pktLen=0; + } + + if (packet_len != 0 + && ((pdu_type == ADV_IND))) + { + uint8_t txAdd = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + uint8_t chSel = (g_rx_adv_buf.rxheader & CHSEL_MASK) >> CHSEL_SHIFT; + uint8_t bWlRlCheckOk = TRUE; + uint8_t* peerAddr; + uint8_t rpaListIndex = LL_RESOLVINGLIST_ENTRY_NUM; +//-==== + peerAddr = &g_rx_adv_buf.data[0]; // AdvA + g_currentPeerAddrType = txAdd; + + // Resolving list checking + // case 1: receive InitA using RPA + if (txAdd == LL_DEV_ADDR_TYPE_RANDOM && + (g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) + { + bWlRlCheckOk = FALSE; + + if (g_llRlEnable == TRUE) + { + rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]); + + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM) + { + peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; + g_currentPeerAddrType = g_llResolvinglist[rpaListIndex].peerAddrType + 2; + osal_memcpy(&g_currentPeerRpa[0], &g_rx_adv_buf.data[0], 6); + bWlRlCheckOk = TRUE; + } + } + } + else // case 2: receive InitA using device ID, or init device not using RPA + { + bWlRlCheckOk = TRUE; + + for (int i = 0; i < LL_RESOLVINGLIST_ENTRY_NUM; i++) + { + if ( g_llResolvinglist[i].peerAddr[0] == g_rx_adv_buf.data[0] + && g_llResolvinglist[i].peerAddr[1] == g_rx_adv_buf.data[1] + && g_llResolvinglist[i].peerAddr[2] == g_rx_adv_buf.data[2] + && g_llResolvinglist[i].peerAddr[3] == g_rx_adv_buf.data[3] + && g_llResolvinglist[i].peerAddr[4] == g_rx_adv_buf.data[4] + && g_llResolvinglist[i].peerAddr[5] == g_rx_adv_buf.data[5]) + { + // the device ID in the RPA list + if (g_llResolvinglist[i].privacyMode == DEVICE_PRIVACY_MODE || + ll_isIrkAllZero(g_llResolvinglist[i].peerIrk)) + rpaListIndex = i; + else + bWlRlCheckOk = FALSE; // the device in the RPA list but not using RPA, reject it + + break; + } + } + } + + // initiator, 2 types of filter process: 1. connect to peer address set by host 2. connect to address in whitelist only + // 1. connect to peer address set by host + if (initInfo.wlPolicy == LL_INIT_WL_POLICY_USE_PEER_ADDR + && bWlRlCheckOk == TRUE) + { + if (//txAdd != peerInfo.peerAddrType + peerAddr[0] != peerInfo.peerAddr[0] + || peerAddr[1] != peerInfo.peerAddr[1] + || peerAddr[2] != peerInfo.peerAddr[2] + || peerAddr[3] != peerInfo.peerAddr[3] + || peerAddr[4] != peerInfo.peerAddr[4] + || peerAddr[5] != peerInfo.peerAddr[5]) + { + // not match, not init connect + bWlRlCheckOk = FALSE; + } + } + // 2. connect to address in whitelist only + else if (initInfo.wlPolicy == LL_INIT_WL_POLICY_USE_WHITE_LIST && + bWlRlCheckOk == TRUE) + { + // if advA in whitelist list, connect + // check white list + bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr); + } + + if (bWlRlCheckOk == TRUE) + { + g_same_rf_channel_flag = TRUE; + // calculate connPtr->curParam.winOffset and set tx buffer + uint16 win_offset; + uint32 remainder; + + // calculate windows offset in multiconnection case + if (g_ll_conn_ctx.currentConn != LL_INVALID_CONNECTION_ID) + { +//#ifdef MULTI_ROLE + // allocate time slot for new connection + // calculate delta to current connection + // calculate new win_offset + uint32 temp, temp1, temp2; + int i; + + for (i = 0; i < g_maxConnNum; i++ ) + { + if (g_ll_conn_ctx.scheduleInfo[i].linkRole == LL_ROLE_MASTER && conn_param[i].active) + break; + } + + if (i == g_maxConnNum) + { + // case 1: no master connection, schedule new connection after the current slave connection + g_new_master_delta = 12 * 625; // delta time to the current slave event + remainder = read_LL_remainder_time(); + g_new_master_delta += remainder; + remainder = g_new_master_delta - 352; // time of CONN_REQ + remainder = (remainder + (remainder >> 1) + (remainder >> 3) + (remainder >> 7)) >> 10; // rough estimate of (x / 625) = (1/1024 + 1/2048 + 1/8192) + + // winoffset should less then conn interval + if (g_new_master_delta - 2 > (conn_param[initInfo.connId].curParam.connInterval << 1)) // win_offset should less then conn interval + g_new_master_delta -= conn_param[initInfo.connId].curParam.connInterval << 1; + + win_offset = (remainder - 2) >> 1; + } + else + { + // case 2: master connection exist, select the 1st master connection as anchor master connection + + // calculate the delta to the anchor master connection + if (initInfo.connId > i) + g_new_master_delta = (initInfo.connId - i) * g_ll_conn_ctx.per_slot_time; + else + g_new_master_delta = (conn_param[i].curParam.connInterval << 1) - (i - initInfo.connId) * g_ll_conn_ctx.per_slot_time; + + // schedule the new connection after the anchor master connection + g_new_master_delta = g_new_master_delta * 625 + g_ll_conn_ctx.scheduleInfo[i].remainder; + // elapse time since last schedule + temp1 = g_ll_conn_ctx.current_timer - ((AP_TIM1->CurrentCount) >> 2) + 2; + g_new_master_delta -= temp1; + + if (g_new_master_delta - 1250 > (conn_param[initInfo.connId].curParam.connInterval * 1250)) // win_offset should less then conn interval + g_new_master_delta -= conn_param[initInfo.connId].curParam.connInterval * 1250; + + // calculate win_offset + temp = g_new_master_delta - 352; // 352: CONN_REQ time + temp2 = (temp + (temp >> 1) + (temp >> 3) + (temp >> 7)) >> 10; // rough estimate of (x / 625) + win_offset = (temp2 - 2) >> 1; + // calculate remainder time of anchor master connection +// temp1 = (CP_TIM1->LoadCount - CP_TIM1->CurrentCount) >> 2; // get elapse time //read_LL_remainder_time(); +// temp1 = g_ll_conn_ctx.current_timer - ((CP_TIM1->CurrentCount) >> 2) + 2; // 2: rough time from read old timer1 to kick new timer1 +// temp = (g_ll_conn_ctx.scheduleInfo[i].remainder - temp1 - 352);// / 625; +// temp2 = (temp + (temp >> 1) + (temp >> 3) + (temp >> 7)) >> 10; // rough estimate of (x / 625) +// +// // remainder time of new connection = remainder time of anchor master connection + delta +// g_new_master_delta += temp2; +// +// // winoffset should less then conn interval +// if (g_new_master_delta - 2 > (conn_param[initInfo.connId].curParam.connInterval << 1)) // win_offset should less then conn interval +// g_new_master_delta -= conn_param[initInfo.connId].curParam.connInterval << 1; +// +// win_offset = (g_new_master_delta - 2) >> 1; +// g_new_master_delta = win_offset * 1250 + 352; + } + +//#else +// if (initInfo.connId > g_ll_conn_ctx.currentConn) +// g_new_master_delta = (initInfo.connId - g_ll_conn_ctx.currentConn) * g_ll_conn_ctx.per_slot_time; +// else +// g_new_master_delta = (conn_param[initInfo.connId].curParam.connInterval << 1) - (g_ll_conn_ctx.currentConn - initInfo.connId) * g_ll_conn_ctx.per_slot_time; +// +// // there are 2 case for new connection timing : 1. before next current connection slot 2. after next current connection slot. +// // Note: we will send the 1st master packet at time (1.25ms + winoffset) after send CONN REQ msg, +// // the time should align to allocate time slot, i.e. +// // remain time of timer1 + delta tick = 2 + winOffset + CONN REQ msg length(352us) +// remainder = (read_LL_remainder_time() - 352);// / 625; +// remainder = (remainder + (remainder >> 1) + (remainder >> 3) + (remainder >> 7)) >> 10; // rough estimate of (x / 625) = (1/1024 + 1/2048 + 1/8192) +// +// win_offset = (remainder + g_new_master_delta - 2) >> 1; +// if (win_offset > (conn_param[initInfo.connId].curParam.connInterval << 1)) // case 1 +// win_offset -= (conn_param[initInfo.connId].curParam.connInterval << 1); +// +//// g_new_master_delta = win_offset << 1; +// g_new_master_delta = win_offset * 1250 + 352; +//#endif + // WinOffset, Byte 20 ~ 21 + memcpy((uint8*)&g_tx_adv_buf.data[20], (uint8*)&win_offset, 2); + conn_param[initInfo.connId].curParam.winOffset = win_offset; + } + + // channel selection algorithm decision + if ((pGlobal_config[LL_SWITCH] & CONN_CSA2_ALLOW) + && chSel == LL_CHN_SEL_ALGORITHM_2) + { + conn_param[initInfo.connId].channel_selection = LL_CHN_SEL_ALGORITHM_2; + SET_BITS(g_tx_adv_buf.txheader, LL_CHN_SEL_ALGORITHM_2, CHSEL_SHIFT, CHSEL_MASK); + } + else + conn_param[initInfo.connId].channel_selection = LL_CHN_SEL_ALGORITHM_1; + + // send conn req + T2 = read_current_fine_time(); + delay = (T2 > ISR_entry_time) ? (T2 - ISR_entry_time) : (BASE_TIME_UNITS - ISR_entry_time + T2); + delay = 118 - delay - pGlobal_config[LL_ADV_TO_CONN_REQ_DELAY]; + ll_hw_set_trx_settle(delay, // set BB delay, about 80us in 16MHz HCLK + pGlobal_config[LL_HW_AFE_DELAY], + pGlobal_config[LL_HW_PLL_DELAY]); //RxAFE,PLL + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + // send conn req + ll_hw_set_stx(); // set LL HW as single Tx mode + ll_hw_go(); + llWaitingIrq = TRUE; + // AdvA, offset 6 + memcpy((uint8*)&g_tx_adv_buf.data[6], &g_rx_adv_buf.data[0], 6); + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(g_tx_adv_buf.txheader), + ((g_tx_adv_buf.txheader & 0xff00) >> 8) + 2); // payload length + header length(2) + move_to_master_function(); + //LOG("win_off = %d\n", win_offset); + //LOG("remainder = %d\n", remainder); + bConnecting = TRUE; + g_same_rf_channel_flag = FALSE; + } + } + else if (packet_len != 0 + && (pdu_type == ADV_DIRECT_IND)) // TODO: add process of direct ADV + { + } + } + + // scan again if not start connect + if (!bConnecting) // if not start connect, schedule next scan + { + if (initInfo.scanMode == LL_SCAN_STOP) + { + // scan has been stopped + llSecondaryState = LL_SEC_STATE_IDLE; // bug fixed by Zhufei // set the LL state idle + // release the associated allocated connection + llReleaseConnId(connPtr); // new for multi-connection + g_ll_conn_ctx.numLLMasterConns --; + (void)osal_set_event( LL_TaskID, LL_EVT_MASTER_CONN_CANCELLED ); // inform high layer + } + else + { + // not sending SCAN REQ, update scan time + llScanTime += ((ISR_entry_time > llScanT1) ? (ISR_entry_time - llScanT1) : (BASE_TIME_UNITS - llScanT1 + ISR_entry_time)); + + if (llScanTime >= initInfo.scanWindow * 625) + { + // calculate next scan channel + LL_CALC_NEXT_SCAN_CHN(initInfo.nextScanChan); + + // schedule next scan event + if (initInfo.scanWindow == initInfo.scanInterval) // scanWindow == scanInterval, trigger immediately + osal_set_event(LL_TaskID, LL_EVT_SECONDARY_INIT); + else + osal_start_timerEx(LL_TaskID, LL_EVT_SECONDARY_INIT, ((initInfo.scanInterval - initInfo.scanWindow) * 5) >> 3 ); + + // reset scan total time + llScanTime = 0; + } + else + llSetupSecInit(initInfo.nextScanChan); + } + } + } + + // post ISR process + if (!llWaitingIrq) // bug fixed 2018-05-04, only clear IRQ status when no config new one + ll_hw_clr_irq(); + + HAL_EXIT_CRITICAL_SECTION(); + return TRUE; +} + +/******************************************************************************* + @fn llSetupExtAdvLegacyEvent + + @brief This function will setup ext adv event with Legacy PDU + 1. fill ext adv pdu(EXT_ADV_IND or AUX_XXX_IND) + 2. update timer info for next chn EXT_ADV_IND or AUX_XXX_IND + + input parameters + + @param None. + + output== parameters + + @param None. + + @return LL_STATUS_SUCCESS +*/ +uint8 llSetupExtAdvLegacyEvent(extAdvInfo_t* pAdvInfo) +{ + uint8 ch_idx, pktFmt; + int i; + uint8 pduType; + ch_idx = pAdvInfo->currentChn; + LOG("<%d> ", pAdvInfo->currentChn); + + if (ch_idx < LL_ADV_CHAN_FIRST || ch_idx > LL_ADV_CHAN_LAST ) + return FALSE; + + // fill advertisement PDU + g_tx_ext_adv_buf.txheader = 0; + + // AdvA + if (pAdvInfo->parameter.ownAddrType == LL_DEV_ADDR_TYPE_RANDOM && pAdvInfo->parameter.isOwnRandomAddressSet == TRUE) + memcpy(&g_tx_ext_adv_buf.data[0], pAdvInfo->parameter.ownRandomAddress, LL_DEVICE_ADDR_LEN); + else // public address + memcpy(&g_tx_ext_adv_buf.data[0], ownPublicAddr, LL_DEVICE_ADDR_LEN); + + switch (pAdvInfo->parameter.advEventProperties) + { + case LL_EXT_ADV_PROP_ADV_IND: + pduType = ADV_IND; + // Length + SET_BITS(g_tx_ext_adv_buf.txheader, (6 + pAdvInfo->data.advertisingDataLength), LENGTH_SHIFT, LENGTH_MASK); + // AdvData + osal_memcpy((uint8_t*)&(g_tx_ext_adv_buf.data[6]), &pAdvInfo->data.advertisingData[0], pAdvInfo->data.advertisingDataLength); + break; + + case LL_EXT_ADV_PROP_ADV_SCAN_IND: + pduType = ADV_SCAN_IND; + // Length + SET_BITS(g_tx_ext_adv_buf.txheader, (6 + pAdvInfo->data.advertisingDataLength), LENGTH_SHIFT, LENGTH_MASK); + // AdvData + osal_memcpy((uint8_t*)&(g_tx_ext_adv_buf.data[6]), pAdvInfo->data.advertisingData, pAdvInfo->data.advertisingDataLength); + break; + + case LL_EXT_ADV_PROP_ADV_NOCONN_IND: + pduType = ADV_NONCONN_IND; + // Length + SET_BITS(g_tx_ext_adv_buf.txheader, (6 + pAdvInfo->data.advertisingDataLength), LENGTH_SHIFT, LENGTH_MASK); + // AdvData + osal_memcpy((uint8_t*)&(g_tx_ext_adv_buf.data[6]), pAdvInfo->data.advertisingData, pAdvInfo->data.advertisingDataLength); + break; + + case LL_EXT_ADV_PROP_ADV_LDC_ADV: + case LL_EXT_ADV_PROP_ADV_HDC_ADV: + pduType = ADV_DIRECT_IND; + // Length + SET_BITS(g_tx_ext_adv_buf.txheader, 12, LENGTH_SHIFT, LENGTH_MASK); + SET_BITS(g_tx_ext_adv_buf.txheader, pAdvInfo->parameter.peerAddrType, RX_ADD_SHIFT, RX_ADD_MASK); + // initA + osal_memcpy((uint8_t*)&(g_tx_ext_adv_buf.data[6]), &pAdvInfo->parameter.peerAddress[0], 6); + break; + + default: + break; + } + + // PDU type, 4 bits + SET_BITS(g_tx_ext_adv_buf.txheader, pduType, PDU_TYPE_SHIFT, PDU_TYPE_MASK); + // RFU, ChSel, TxAdd, RxAdd + SET_BITS(g_tx_ext_adv_buf.txheader, pAdvInfo->parameter.ownAddrType, TX_ADD_SHIFT, TX_ADD_MASK); + + if ((pduType == ADV_IND + || pduType == ADV_DIRECT_IND) + && pGlobal_config[LL_SWITCH] & CONN_CSA2_ALLOW) + SET_BITS(g_tx_ext_adv_buf.txheader, 1, CHSEL_SHIFT, CHSEL_MASK); + + osal_memcpy( g_tx_ext_adv_buf.data, adv_param.ownAddr, 6); + // decide next adv channel + i = ch_idx - LL_ADV_CHAN_FIRST + 1; + + while ((i < 3) && !(pAdvInfo->parameter.priAdvChnMap & (1 << i))) i ++; // search channel map for next adv channel number + + if (i == 3) // finish primary adv channel broadcast + { + pAdvInfo->currentChn = ll_getFirstAdvChn(pAdvInfo->parameter.priAdvChnMap); + } + else + pAdvInfo->currentChn = LL_ADV_CHAN_FIRST + i; + + // Legacy Adv always in 1M PHY + pktFmt = LE_1M_PHY; + HAL_ENTER_CRITICAL_SECTION(); + + // if there is ongoing LL HW task, skip this task + if (llWaitingIrq) + { + HAL_EXIT_CRITICAL_SECTION(); + return FALSE; + } + + //============== configure and trigger LL HW engine, LL HW work in Single Tx mode ================== + rf_phy_change_cfg(pktFmt); + ll_hw_tx2rx_timing_config(pktFmt); + set_crc_seed(ADV_CRC_INIT_VALUE); // crc seed for adv is same for all channels + set_access_address(ADV_SYNCH_WORD); // access address + set_channel(ch_idx); // channel + set_whiten_seed(ch_idx); // whiten seed + set_max_length(50); // rx PDU max length + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + + // for AUX_ADV_IND, connectable/scannable case, should configure TRX + if ((pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_CONN_BITMASK) || + (pAdvInfo->parameter.advEventProperties & LE_ADV_PROP_SCAN_BITMASK)) + { + ll_hw_set_trx_settle(pGlobal_config[LL_HW_BB_DELAY_ADV], + pGlobal_config[LL_HW_AFE_DELAY_ADV], + pGlobal_config[LL_HW_PLL_DELAY_ADV]); //TxBB,RxAFE,PLL + ll_hw_set_trx(); // set LL HW as Tx - Rx mode + } + else + { + ll_hw_set_stx(); // set LL HW as Tx - Rx mode + } + + ll_hw_ign_rfifo(LL_HW_IGN_ALL); //set the rfifo ign control + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(g_tx_ext_adv_buf.txheader), ((g_tx_ext_adv_buf.txheader & 0xff00) >> 8) + 2); +// T2 = read_current_fine_time(); +// delta = LL_TIME_DELTA(T1, T2); +// +// temp = ( pGlobal_config[LL_EXT_ADV_PROCESS_TARGET] > delta) ? (pGlobal_config[LL_EXT_ADV_PROCESS_TARGET] - delta) : 0; +// llWaitUs(temp); // insert delay to make process time equal PROCESS_TARGET + ll_hw_go(); +// hal_gpio_write(GPIO_P14, 1); + llWaitingIrq = TRUE; + llTaskState = LL_TASK_EXTENDED_ADV; + HAL_EXIT_CRITICAL_SECTION(); +// hal_gpio_write(GPIO_P14, 0); + return TRUE; +} + +//============ + + + diff --git a/src/lib/ble_controller/ll_hw_drv.c b/src/lib/ble_controller/ll_hw_drv.c new file mode 100644 index 0000000..020f823 --- /dev/null +++ b/src/lib/ble_controller/ll_hw_drv.c @@ -0,0 +1,1885 @@ +/********************************************************************** + @file ll_hw_drv.c + @brief Contains all functions support for PHYPLUS LL HW + @version 1.0 + @date 26. Mar. 2017 + @author Zhongqi Yang + + + +***********************************************************************/ + +#include "ll_hw_drv.h" +#include "rf_phy_driver.h" + +extern uint32 hclk_per_us; +uint8_t whiten_seed[40]; + +// ================== A2 metal change add +extern volatile uint8_t g_same_rf_channel_flag; +extern llGlobalStatistics_t g_pmCounters; +extern uint32 llWaitingIrq; +/************************************************************************************** + @fn ll_hw_set_stx + + @brief This function process for HW LL single tx mode setting. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_stx(void) +{ + *(volatile uint32_t*)(LL_HW_BASE+ 0x04) = 0x000100; //[15:8]txNum=1 [23:16]rxNum=0,mode=stx + *(volatile uint32_t*)(LL_HW_BASE+ 0x38) = 0x7; //bypass sn nesn md +} + + + +/************************************************************************************** + @fn ll_hw_set_srx + + @brief This function process for HW LL single rx mode setting. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_srx(void) +{ + *(volatile uint32_t*)(LL_HW_BASE+ 0x04) = 0x010001; //[15:8]txNum=0 [23:16]rxNum=1,mode=srx + *(volatile uint32_t*)(LL_HW_BASE+ 0x38) = 0x7; //bypass sn nesn md +} + + + + +/************************************************************************************** + @fn ll_hw_set_trx + + @brief This function process for HW LL signgle trx mode setting. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_trx(void) +{ + *(volatile uint32_t*)(LL_HW_BASE+ 0x04) = 0x010102; //[15:8]txNum=1 [23:16]rxNum=1,mode=trx + *(volatile uint32_t*)(LL_HW_BASE+ 0x38) = 0x7; //bypass sn nesn md +} + + + +/************************************************************************************** + @fn ll_hw_set_rtx + + @brief This function process for HW LL single rtx mode setting. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_rtx(void) +{ + *(volatile uint32_t*)(LL_HW_BASE+ 0x04) = 0x010103; //[15:8]txNum=1 [23:16]rxNum=1,mode=rtx + *(volatile uint32_t*)(LL_HW_BASE+ 0x38) = 0x7; //bypass sn nesn md +} + + + +/************************************************************************************** + @fn ll_hw_set_trlp + + @brief This function process for HW LL TX-RX Loop mode setting. + + input parameters + + @param snNesn :set for the sn nesn ini value + txPktNum :tx packet number, will impact the md bit + rxPktNum :rx packet number, will trigger mode done + mdRx :md_rx initial value and soft value(when crc error occored) + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_trlp(uint8_t snNesn,uint8_t txPktNum,uint8_t rxPktNum,uint8_t mdRx) +{ + uint8_t mdIni = txPktNum>1 ? 1 : 0; + *(volatile uint32_t*)(LL_HW_BASE+ 0x04) = 0x4 | (txPktNum<<8) | (rxPktNum<<16); + *(volatile uint32_t*)(LL_HW_BASE+ 0x38) = 0x00; //use MdSnNesn Ini + + if(mdRx==0) + { + *(volatile uint32_t*)(LL_HW_BASE+ 0x3c) = LL_HW_MD_RX_SET0 | (mdIni<<2) | (0x03 & snNesn); + } + else + { + *(volatile uint32_t*)(LL_HW_BASE+ 0x3c) = LL_HW_MD_RX_SET1 | (mdIni<<2) | (0x03 & snNesn); + } + + *(volatile uint32_t*)(LL_HW_BASE+ 0x5c) = 0x00; //clr rd_cnt_last and ini +} + + +/************************************************************************************** + @fn ll_hw_set_rtlp + + @brief This function process for HW LL RX-TX Loop mode setting. + + input parameters + + @param snNesn :set for the sn nesn ini value + txPktNum :tx packet number, will impact the md bit + rxPktNum :rx packet number, will trigger mode done + rdCntIni :tx 2nd pkt's addr while rx the 1st pkt is an ACK + mdRx :md_rx initial value and soft value(when crc error occored) + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_rtlp(uint8_t snNesn,uint8_t txPktNum,uint8_t rxPktNum,uint8_t mdRx,uint32_t rdCntIni) +{ + uint8_t mdIni = txPktNum>1 ? 1 : 0; + *(volatile uint32_t*)(LL_HW_BASE+ 0x04) = 0x5 | (txPktNum<<8) | (rxPktNum<<16); + *(volatile uint32_t*)(LL_HW_BASE+ 0x38) = 0x00; //use MdSnNesn Ini + + if(mdRx==0) + { + *(volatile uint32_t*)(LL_HW_BASE+ 0x3c) = LL_HW_MD_RX_SET0 | (mdIni<<2) | (0x03 & snNesn); + } + else + { + *(volatile uint32_t*)(LL_HW_BASE+ 0x3c) = LL_HW_MD_RX_SET1 | (mdIni<<2) | (0x03 & snNesn); + } + + *(volatile uint32_t*)(LL_HW_BASE+ 0x5c) = 0x7ff&rdCntIni; //set rd_cnt_last +} + +/************************************************************************************** + @fn ll_hw_set_rtlp_1st + + @brief This function process for HW LL RX-TX Loop first time mode setting. + + input parameters + + @param snNesn :set for the sn nesn ini value + txPktNum :tx packet number, will impact the md bit + rxPktNum :rx packet number, will trigger mode done + rdCntIni : fix as 0. for the 1st rtloop + mdRx :md_rx initial value and soft value(when crc error occored) + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_rtlp_1st(uint8_t snNesn,uint8_t txPktNum,uint8_t rxPktNum,uint8_t mdRx) +{ + uint8_t mdIni = txPktNum>1 ? 1 : 0; + *(volatile uint32_t*)(LL_HW_BASE+ 0x04) = 0x5 | (txPktNum<<8) | (rxPktNum<<16); + *(volatile uint32_t*)(LL_HW_BASE+ 0x38) = 0x00; //use MdSnNesn Ini + + if(mdRx==0) + { + *(volatile uint32_t*)(LL_HW_BASE+ 0x3c) = LL_HW_MD_RX_SET0 | (mdIni<<2) | (0x03 & snNesn); + } + else + { + *(volatile uint32_t*)(LL_HW_BASE+ 0x3c) = LL_HW_MD_RX_SET1 | (mdIni<<2) | (0x03 & snNesn); + } + + *(volatile uint32_t*)(LL_HW_BASE+ 0x5c) = 0; //set rd_cnt_last +} + +/************************************************************************************** + @fn ll_hw_config + + @brief This function process for LL HW config setting. + + input parameters + + @param llMode : current ll_hw mode + snNesn : set for the sn nesn ini value + txPktNum : tx packet number, will impact the md bit + rxPktNum : rx packet number, will trigger mode done + rdCntIni : fix as 0. for the 1st rtloop + mdRx : md_rx initial value and soft value(when crc error occored) + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_config(uint8_t llMode,uint8_t snNesn,uint8_t txNum,uint8_t rxNum,uint8_t mdRx,uint32_t rdCntIni) +{ + if( llMode==LL_HW_STX ) + { + ll_hw_set_stx(); + } + else if(llMode==LL_HW_SRX ) + { + ll_hw_set_srx(); + } + else if(llMode==LL_HW_TRX ) + { + ll_hw_set_trx(); + } + else if(llMode==LL_HW_RTX ) + { + ll_hw_set_rtx(); + } + else if(llMode==LL_HW_TRLP) + { + ll_hw_set_trlp( snNesn, + txNum, + rxNum, + mdRx); + } + else if(llMode==LL_HW_TRLP_EMPT) + { + ll_hw_set_trlp( snNesn, + txNum+1,/*add one empty pkt*/ + rxNum, + mdRx); + } + else if(llMode==LL_HW_RTLP) + { + ll_hw_set_rtlp( snNesn, + txNum, + rxNum, + mdRx, + rdCntIni); + } + else if(llMode==LL_HW_RTLP_EMPT) + { + ll_hw_set_rtlp( snNesn, + txNum+1,/*add one empty pkt*/ + rxNum, + mdRx, + /*one empty pkt*/1); + } + else if(llMode==LL_HW_RTLP_1ST) + { + ll_hw_set_rtlp_1st( snNesn, + txNum, + rxNum, + mdRx); + } +} + +/************************************************************************************** + @fn ll_hw_go + + @brief This function process for HW LL trigger. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_go0(void) +{ + //20190115 ZQ recorded ll re-trigger + if(llWaitingIrq==TRUE) + { + g_pmCounters.ll_trigger_err++; + } + + *(volatile uint32_t*)(LL_HW_BASE+ 0x14) = LL_HW_IRQ_MASK; //clr irq status + *(volatile uint32_t*)(LL_HW_BASE+ 0x0c) = 0x0001; //mask irq :only use mode done + *(volatile uint32_t*)(LL_HW_BASE+ 0x00) = 0x0001; //trig + //2018-05-23 ZQ + //fix negative rfPhyFreqOff bug, when in scan_rsq case, ll_hw_go will be excuted before set_channel() + //so do not change the tx_rx_foff + //next metal change could modified the set_channel() to deal with the tx_rx_foff + uint8_t rfChnIdx = PHY_REG_RD(0x400300b4)&0xff; + + if(!g_same_rf_channel_flag) + { + if(g_rfPhyFreqOffSet>=0) + PHY_REG_WT(0x400300b4, (g_rfPhyFreqOffSet<<16)+(g_rfPhyFreqOffSet<<8)+rfChnIdx); + else + PHY_REG_WT(0x400300b4, ((255+g_rfPhyFreqOffSet)<<16)+((255+g_rfPhyFreqOffSet)<<8)+(rfChnIdx-1) ); + } + + //2018-02-09 ZQ + //considering the ll_trigger timing, Trigger first, then set the tp_cal cap + + if(rfChnIdx<2) + { + rfChnIdx=2; + } + else if(rfChnIdx>80) + { + rfChnIdx=80; + } + +// if(g_rfPhyPktFmt==PKT_FMT_BLE2M) +// subWriteReg(0x40030094,7,0,g_rfPhyTpCalCapArry_2Mbps[(rfChnIdx-2)>>1]); +// else +// subWriteReg(0x40030094,7,0,g_rfPhyTpCalCapArry[(rfChnIdx-2)>>1]); + + if(g_rfPhyPktFmt==PKT_FMT_BLE2M) + subWriteReg(0x40030094,7,0,RF_PHY_TPCAL_CALC(g_rfPhyTpCal0_2Mbps,g_rfPhyTpCal1_2Mbps,(rfChnIdx-2)>>1)); + else + subWriteReg(0x40030094,7,0,RF_PHY_TPCAL_CALC(g_rfPhyTpCal0,g_rfPhyTpCal1,(rfChnIdx-2)>>1)); +} +/************************************************************************************** + @fn ll_hw_trigger + + @brief This function process for HW LL trigger. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_trigger0(void) +{ + *(volatile uint32_t*)(LL_HW_BASE+ 0x00) = 0x0001; //trig +} +/************************************************************************************** + @fn ll_hw_clr_irq + + @brief This function process for HW LL irq clean. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_clr_irq(void) +{ + *(volatile uint32_t*)(LL_HW_BASE+ 0x14) = LL_HW_IRQ_MASK; +} + +/************************************************************************************** + @fn ll_hw_set_empty_head + + @brief This function process for HW LL set header of empty tx packet. + + input parameters + + @param txHeader: tx empty packet header 2Byte. + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_empty_head(uint16_t txHeader) +{ + *(volatile uint32_t*)(LL_HW_BASE+ 0x2c) = (txHeader & 0xffff)<<16; +} + +/************************************************************************************** + @fn ll_hw_set_irq + + @brief This function process for HW LL irq mask selection. + + input parameters + + @param mask: irq mask. + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_irq(uint32_t mask) +{ + *(volatile uint32_t*)(LL_HW_BASE+ 0x0c)=mask; +} + +/************************************************************************************** + @fn ll_hw_set_rx_timeout_1st + + @brief This function process for HW LL setting 1st rx Time Out in rtloop. + + input parameters + + @param rxTimeOut: (us). + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_rx_timeout_1st(uint32_t rxTimeOut) +{ + *(volatile uint32_t*)(LL_HW_BASE+ 0x24) = rxTimeOut & 0xffff; +} + +/************************************************************************************** + @fn ll_hw_set_rx_timeout + + @brief This function process for HW LL setting rx Time Out in rtloop. + + input parameters + + @param rxTimeOut (us). + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_rx_timeout(uint32_t rxTimeOut) +{ + *(volatile uint32_t*)(LL_HW_BASE+ 0x28) = rxTimeOut & 0xffff; +} + + +/************************************************************************************** + @fn ll_hw_set_tx_rx_release + + @brief This function process for HW LL setting tx rx en release. + + input parameters + + @param txTime (us), rxTime(us) + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_tx_rx_release(uint16_t txTime,uint16_t rxTime) +{ + uint32_t tcycle=txTime * hclk_per_us; + uint32_t rcycle=rxTime * hclk_per_us; + *(volatile uint32_t*)(LL_HW_BASE+ 0x20) = (tcycle<<16) | rcycle; +} + +/************************************************************************************** + @fn ll_hw_set_rx_tx_interval + + @brief This function process for HW LL setting RX to TX interval. + + input parameters + + @param intvTime(us) + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_rx_tx_interval(uint32_t intvTime) +{ + uint32_t cycle=intvTime * hclk_per_us; + *(volatile uint32_t*)(LL_HW_BASE+ 0x1c) = cycle; +} + +/************************************************************************************** + @fn ll_hw_set_tx_rx_interval + + @brief This function process for HW LL setting TX to RX interval. + + input parameters + + @param intvTime(us) + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_tx_rx_interval(uint32_t intvTime) +{ + uint32_t cycle= intvTime * hclk_per_us; + *(volatile uint32_t*)(LL_HW_BASE+ 0x18) = cycle; +} + +/************************************************************************************** + @fn ll_hw_set_trx_settle + + @brief This function process for HW LL setting TRX settle time. + + input parameters + + @param time(us) + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_trx_settle(uint8_t tmBb,uint8_t tmAfe,uint8_t tmPll) +{ + *(volatile uint32_t*)(BB_HW_BASE+ 0xbc) = (tmBb<<16) | (tmAfe<<8) | tmPll; +} + +/************************************************************************************** + @fn ll_hw_set_loop_timeout + + @brief This function process for HW LL setting loop time out in trlp and rtlp. + + input parameters + + @param loopTimeOut(us) + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_loop_timeout(uint32_t loopTimeOut) +{ + *(volatile uint32_t*) (LL_HW_BASE + 0x60) = loopTimeOut* hclk_per_us ; +} + +/************************************************************************************** + @fn ll_hw_set_loop_nack_num + + @brief This function process for HW LL setting loop nAck Number in trlp and rtlp. + + input parameters + + @param nAckNum + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_loop_nack_num(uint8_t nAckNum) +{ + *(volatile uint32_t*) (LL_HW_BASE + 0x64) = nAckNum ; +} + +/************************************************************************************** + @fn ll_hw_set_timing0 + + @brief This function process for HW LL tx-rx swith timing related setting. + In order to keep the T_IFS=150us, the setting will be different for different + pktFmt + input parameters + + @param pktFmt : 0:ZB, 1:BLE1M, 2:BLE2M, 3:BLE500K, 4:BLE125K + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_timing0(uint8 pktFmt) +{ + if( pktFmt==1) + { + ll_hw_set_tx_rx_release (10, 1); + ll_hw_set_rx_tx_interval( 60); //T_IFS=150us for BLE 1M + ll_hw_set_tx_rx_interval( 66); //T_IFS=150us for BLE 1M + ll_hw_set_trx_settle (57, 8, 52); //TxBB,RxAFE,PLL + } + else if(pktFmt==2) + { + ll_hw_set_tx_rx_release (10, 1); + ll_hw_set_rx_tx_interval( 73); //T_IFS=150us for BLE 2M + ll_hw_set_tx_rx_interval( 72); //T_IFS=150us for BLE 2M + ll_hw_set_trx_settle (59, 8, 52); //TxBB,RxAFE,PLL + } + else if(pktFmt==3) + { + ll_hw_set_tx_rx_release (10, 1); + ll_hw_set_rx_tx_interval( 13); //T_IFS=150us for BLE 500K + ll_hw_set_tx_rx_interval( 74); //T_IFS=150us for BLE 500K + ll_hw_set_trx_settle (57, 8, 52); //TxBB,RxAFE,PLL + } + else if(pktFmt==4) + { + ll_hw_set_tx_rx_release (10, 1); + ll_hw_set_rx_tx_interval( 3); //T_IFS=150us for BLE 125K + ll_hw_set_tx_rx_interval( 64); //T_IFS=150us for BLE 125K + ll_hw_set_trx_settle (57, 8, 52); //TxBB,RxAFE,PLL + } + else + { + ll_hw_set_tx_rx_release (10, 1); + ll_hw_set_rx_tx_interval( 62); //T_IFS=150us for ZB + ll_hw_set_tx_rx_interval( 72); //T_IFS=150us for ZB + ll_hw_set_trx_settle (57, 8, 52); //TxBB,RxAFE,PLL + } +} + +/************************************************************************************** + @fn ll_hw_set_tfifo_space + + @brief This function process for HW LL FIFO Space Config + + + input parameters + + @param space : tx fifo depth. RX+TX FIFO Space = 1024 Word. + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_tfifo_space(uint16 space) +{ + *(volatile uint32_t*)(LL_HW_BASE+ 0x74) =((0x400 - (space&0x3ff))<<16) | (space&0x3ff) ; +} + + +/************************************************************************************** + @fn ll_hw_rst_rfifo + + @brief This function process for HW LL rx fifo reset + Only reset the wr/rd ptr to 0 + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_rst_rfifo(void) +{ + int rdPtr, wrPtr, rdDepth; + ll_hw_get_rfifo_info(&rdPtr, &wrPtr, &rdDepth); + + if( rdPtr > 0 && (rdPtr != wrPtr ) ) + { + g_pmCounters.ll_rfifo_read_err++; + } + + *(volatile uint32_t*)(LL_HW_BASE+ 0x58) = 0x0100; + g_pmCounters.ll_rfifo_rst_cnt++; +} +/************************************************************************************** + @fn ll_hw_rst_tfifo + + @brief This function process for HW LL tx fifo reset, + Only reset the wr/rd ptr to 0 + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_rst_tfifo(void) +{ + *(volatile uint32_t*)(LL_HW_BASE+ 0x58) = 0x0001; +} + + +/************************************************************************************** + @fn ll_hw_ign_rfifo + + @brief This function process for HW LL rx fifo control,ignored pkt will not be + writen into rfifo and the rxPkt Num will not be counted + + input parameters + + @param ignCtrl [2]ignSSN : ignore same sn pkt + [1]ignCrc : ignore crc err pkt + [0]ignEmpt: ignore empty pkt + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_ign_rfifo(uint8_t ignCtrl) +{ + *(volatile uint32_t*)(LL_HW_BASE+ 0x68) = ignCtrl; +} + +/************************************************************************************** + @fn ll_hw_get_tfifo_info + + @brief This function process for HW LL getting tx fifo information + + input parameters + + @param + + output parameters + + @param rdPtr : read pointer. + wrPtr : write pointer + wrDepth: fifo depth can be writen + + @return None. +*/ +void ll_hw_get_tfifo_info(int* rdPtr,int* wrPtr,int* wrDepth) +{ + uint32_t tmp = *(volatile uint32_t*)(LL_HW_BASE + 0x50); + *rdPtr = 0x07ff & tmp; + *wrPtr = 0x07ff & (tmp>>16); + *wrDepth = (*wrPtr) - (*rdPtr) ; +} + + +/************************************************************************************** + @fn ll_hw_get_rfifo_info + + @brief This function process for HW LL getting rx fifo information + + input parameters + + @param + + output parameters + + @param rdPtr: read pointer. + wrPtr: write pointer + depth: fifo depth can be readed + + @return None. +*/ +void ll_hw_get_rfifo_info(int* rdPtr,int* wrPtr,int* rdDepth) +{ + uint32_t tmp = *(volatile uint32_t*)(LL_HW_BASE + 0x54); + *rdPtr = 0x07ff & tmp; + *wrPtr = 0x07ff & (tmp>>16); + *rdDepth = (*wrPtr) - (*rdPtr) ; +} + +/************************************************************************************** + @fn ll_hw_get_rxPkt_stats + + @brief This function process for getting rxPkt statistic, crc ok crc error and + total pkt crc err number in trlp or rtlp + + input parameters + + @param None. + + output parameters + + @param crcErrNum + rxTotalNum + rxPktNum. + + @return None. +*/ +void ll_hw_get_rxPkt_stats(uint8_t* crcErrNum,uint8_t* rxTotalNum,uint8_t* rxPktNum) +{ + uint32_t tmp= *(uint32_t*) (LL_HW_BASE + 0x30) ; + *crcErrNum = (0xff0000 & tmp)>>16; + *rxTotalNum = (0x00ff00 & tmp)>> 8; + *rxPktNum = (0x0000ff & tmp); +} + +/************************************************************************************** + @fn ll_hw_read_rfifo + + @brief This function process for HW LL rx fifo pop out each calling will pop one + rx paket as output + + input parameters + + @param + + output parameters + + @param rxPkt : buf for poped rx pkt,only the header+pdu, w/o crc + pktLen : length of rxPkt=pdulen+2 + pktFoot0: foot0 of the rx pkt + pktF00t1: foot1 of the rx pkt + + @return wlen: return rfifo poped cnt, 0: no pkt poped. +*/ +uint8_t ll_hw_read_rfifo(uint8_t* rxPkt, uint16_t* pktLen, uint32_t* pktFoot0, uint32_t* pktFoot1) +{ + int rdPtr, wrPtr, rdDepth, blen, wlen; + uint32_t* p_rxPkt = (uint32_t*)rxPkt; + ll_hw_get_rfifo_info(&rdPtr, &wrPtr, &rdDepth); + + if(rdDepth > 0) + { + *p_rxPkt++ = *(volatile uint32_t*)(LL_HW_RFIFO); + uint8_t sp =BLE_HEAD_WITH_CTE(rxPkt[0]); + blen = rxPkt[1]+sp; //get the byte length for header + wlen = 1+ ( (blen+2+3-1) >>2 ); //+2 for Header, +3 for crc + + //compared the wlen and HW_WTR + //20190115 ZQ + if( (wlen+2) >rdDepth) + { + g_pmCounters.ll_rfifo_read_err++; + rxPkt[0] = 0; + *pktFoot0 = 0; + *pktFoot1 = 0; + *pktLen = 0; + return 0; + } + + while(p_rxPkt < (uint32_t*)rxPkt + wlen) + { + *p_rxPkt++ = *(volatile uint32_t*)(LL_HW_RFIFO); + } + + *pktFoot0 = *(volatile uint32_t*)(LL_HW_RFIFO); + *pktFoot1 = *(volatile uint32_t*)(LL_HW_RFIFO); + *pktLen = blen + 2; + return wlen; + } + else + { + rxPkt[0] = 0; + *pktFoot0 = 0; + *pktFoot1 = 0; + *pktLen = 0; + return 0; + } +} + +/************************************************************************************** + @fn ll_hw_read_rfifo_zb + + @brief This function process for HW LL rx fifo pop out Zigbee, each calling will pop one + rx paket as output + + input parameters + + @param + + output parameters + + @param rxPkt : buf for poped rx pkt,only the header+pdu, w/o crc + pktLen : length of rxPkt=pdulen+1 + pktFoot0: foot0 of the rx pkt + pktF00t1: foot1 of the rx pkt + + @return wlen: return rfifo poped cnt, 0: no pkt poped. +*/ +uint8_t ll_hw_read_rfifo_zb(uint8_t* rxPkt, uint16_t* pktLen, uint32_t* pktFoot0, uint32_t* pktFoot1) +{ + int rdPtr,wrPtr,rdDepth,blen,wlen; + uint32_t* p_rxPkt=(uint32_t*)rxPkt; + ll_hw_get_rfifo_info(&rdPtr,&wrPtr,&rdDepth); + + if(rdDepth>0) + { + *p_rxPkt++ = *(volatile uint32_t*)(LL_HW_RFIFO); + blen = rxPkt[0]; //get the byte length for header + wlen = 1+ ( (blen) >>2 ); //blen included the 2byte crc + + while(p_rxPkt<(uint32_t*)rxPkt+wlen) + { + *p_rxPkt++ = *(volatile uint32_t*)(LL_HW_RFIFO); + } + + *pktFoot0 = *(volatile uint32_t*)(LL_HW_RFIFO); + *pktFoot1 = *(volatile uint32_t*)(LL_HW_RFIFO); + *pktLen = blen+1; + return wlen; + } + else + { + rxPkt[0] = 0; + *pktFoot0 = 0; + *pktFoot1 = 0; + *pktLen = 0; + return 0; + } +} + +/************************************************************************************** + @fn ll_hw_read_rfifo_pplus + + @brief This function process for HW LL rx fifo pop out each calling will pop one + rx paket as output + + input parameters + + @param + + output parameters + + @param rxPkt : buf for poped rx pkt,only the header+pdu, w/o crc + pktLen : length of rxPkt=pdulen+2 + pktFoot0: foot0 of the rx pkt + pktF00t1: foot1 of the rx pkt + + @return wlen: return rfifo poped cnt, 0: no pkt poped. +*/ +uint8_t ll_hw_read_rfifo_pplus(uint8_t* rxPkt, uint16_t* pktLen, uint32_t* pktFoot0, uint32_t* pktFoot1) +{ + int rdPtr,wrPtr,rdDepth,blen,wlen; + uint32_t* p_rxPkt=(uint32_t*)rxPkt; + ll_hw_get_rfifo_info(&rdPtr,&wrPtr,&rdDepth); + + if(rdDepth>0) + { + *p_rxPkt++ = *(volatile uint32_t*)(LL_HW_RFIFO); + blen = (0xff00 & (*(volatile uint32_t*)(BB_HW_BASE+0x40)))>>8; //get the byte length from reg + wlen = 1+ ( (blen+2-1) >>2 ); //+2 for pplus pktfmt_len register define + + while(p_rxPkt<(uint32_t*)rxPkt+wlen) + { + *p_rxPkt++ = *(volatile uint32_t*)(LL_HW_RFIFO); + } + + *pktFoot0 = *(volatile uint32_t*)(LL_HW_RFIFO); + *pktFoot1 = *(volatile uint32_t*)(LL_HW_RFIFO); + *pktLen = blen+2; + return wlen; + } + else + { + rxPkt[0] = 0; + *pktFoot0 = 0; + *pktFoot1 = 0; + *pktLen = 0; + return 0; + } +} + +/************************************************************************************** + @fn ll_hw_write_tfifo + + @brief This function process for HW LL write tfifo once one pkt, heder+pdu + + input parameters + + @param *txPkt : tx packet pointer + pktLen: packet length--> header+pdu, can not be 0 + + output parameters + + @param None. + + @return wlen: tfifo push cnt, 0: no pkt write. +*/ +uint8_t ll_hw_write_tfifo(uint8_t* txPkt, uint16_t pktLen) +{ + int rdPtr,wrPtr,wrDepth,wlen; + uint32_t* p_txPkt=(uint32_t*)txPkt; + ll_hw_get_tfifo_info(&rdPtr,&wrPtr,&wrDepth); + uint16_t tfifoSpace = 0x07ff & (*(uint32_t*) (LL_HW_BASE + 0x74)); + + if((pktLen>0) && (wrDepth+(pktLen>>2) 0 + wlen = 1+((pktLen-1)>>2); // calc the write tfifo count + + //-------------------------------------------------------------- + //write tfifo wlen-1 firstly + while(p_txPkt<((uint32_t*)txPkt+wlen-1)) + { + *(volatile uint32_t*)(LL_HW_TFIFO) = *p_txPkt++; + } + + //-------------------------------------------------------------- + //calc the residue txPkt length + //write tfifo last time + int rduLen = pktLen&0x03;//pktLen%4 + + if( rduLen==3) + { + *(volatile uint32_t*)(LL_HW_TFIFO) = *(uint16_t*)(txPkt+pktLen-3) | (txPkt[pktLen-1]<<16) ; + } + else if( rduLen==2) + { + *(volatile uint32_t*)(LL_HW_TFIFO) = *(uint16_t*)(txPkt+pktLen-2); + } + else if( rduLen==1) + { + *(volatile uint32_t*)(LL_HW_TFIFO) = *(txPkt+pktLen-1); + } + else + { + *(volatile uint32_t*)(LL_HW_TFIFO) = *p_txPkt; + } + + return wlen; + } + else + { + return 0; + } +} +/************************************************************************************** + @fn ll_hw_set_crc_fmt + + @brief This function set crc format + + input parameters + + @param txCrc,rxCrc. + + output parameters + + @param None. + + @return txAckNum. +*/ +void ll_hw_set_crc_fmt(uint8_t txCrc,uint8_t rxCrc) +{ + *(volatile uint32_t*) (BB_HW_BASE+0x124) =(txCrc<<8) | rxCrc; +} + +/************************************************************************************** + @fn ll_hw_set_pplus_pktfmt + + @brief This function set pplus pktfmt and pkt len + + input parameters + + @param pktlen. + + output parameters + + @param None. + + @return txAckNum. +*/ +void ll_hw_set_pplus_pktfmt(uint8_t plen) +{ + uint32_t tmp = 0xffff00e0 & (*(uint32_t*) (BB_HW_BASE + 0x40)); + *(volatile uint32_t*)(BB_HW_BASE+ 0x40) =tmp| ((plen-2)<<8) | 0x1f; + ll_hw_set_crc_fmt(LL_HW_CRC_NULL,LL_HW_CRC_NULL); +} + +/************************************************************************************** + @fn ll_hw_set_ant_switch_mode + + @brief This function set ant switch mode for AOA/AOD + + input parameters + + @param mode: 0 : ant swith manual mode, + 1 : ant switch auto mode(ctrl by PDU Header) + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_ant_switch_mode(uint8_t mode) +{ + uint32_t tmp = 0x0000ffff & (*(uint32_t*) (BB_HW_BASE + 0x110)); + *(volatile uint32_t*)(BB_HW_BASE+ 0x110) = tmp |(mode<<16); +} + +/************************************************************************************** + @fn ll_hw_set_ant_switch_timing + + @brief This function set ant switch for AOA/AOD + + input parameters + + @param antWin: window for each ant arrary + @param antDly: dly for rx ant swith only + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_ant_switch_timing(uint8_t antWin,uint8_t antDly) +{ + uint32_t tmp = 0xffff0000 & (*(uint32_t*) (BB_HW_BASE + 0x110)); + *(volatile uint32_t*)(BB_HW_BASE+ 0x110) = tmp |( antWin<<8) | antDly; +} + +/************************************************************************************** + @fn ll_hw_set_ant_pattern + + @brief This function set ant pattern for AOA/AOD + + input parameters + + @param an0: ant pattern 0 -7. + @param ant1: ant pattern 8-15 + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_ant_pattern(uint32_t ant1, uint32_t ant0) +{ + *(volatile uint32_t*)(BB_HW_BASE+ 0x114) =ant0; + *(volatile uint32_t*)(BB_HW_BASE+ 0x118) =ant1; +} +/************************************************************************************** + @fn ll_hw_set_cte_rxSupp + + @brief This function set cte rx supplement config + + input parameters + + @param rxSupp.[7] check cp, [6] suppLen=CTEInfo, [5:0] suppLen + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_cte_rxSupp(uint8_t rxSupp) +{ + uint32_t tmp = 0xffff00ff & (*(uint32_t*) (BB_HW_BASE + 0x0c)); + *(volatile uint32_t*)(BB_HW_BASE+ 0x0c) = tmp |( rxSupp<<8); +} +/************************************************************************************** + @fn ll_hw_set_cte_txSupp + + @brief This function set cte tx supplement config + + input parameters + + @param txSupp..[7] check cp, [6] suppLen=CTEInfo, [5:0] suppLen + + output parameters + + @param None. + + @return None. +*/ +void ll_hw_set_cte_txSupp(uint8_t txSupp) +{ + uint32_t tmp = 0x00ffffff & (*(uint32_t*) (BB_HW_BASE + 0x40)); + *(volatile uint32_t*)(BB_HW_BASE+ 0x40) = tmp |( txSupp<<24); +} +/************************************************************************************** + @fn ll_hw_get_iq_RawSample + + @brief This function get rx iq sample for AOA/AOD + + input parameters + + @param None + + output parameters + + @param p_i_sample: ptr of i sample [9:0] 2's complement + @param p_q_sample: ptr of q sample [9:0] 2's complement + + @return iq_cnt: iq sample count +*/ +uint8_t ll_hw_get_iq_RawSample(uint16_t* p_iSample, uint16_t* p_qSample) +{ + uint8_t iqCnt = 0xff &( (*(uint32_t*) (BB_HW_BASE + 0xFC))>>20); + uint32_t tmp=0; + uint8_t i= 0; + + for (i=0; i>10) & 0x3ff); + } + + return iqCnt; +} +/************************************************************************************** + @fn ll_hw_get_snNesn + + @brief This function process for getting sn nesn after trlp or rtlp mode done + + input parameters + + @param None. + + output parameters + + @param None. + + @return local_sn | local_nesn. +*/ +uint8_t ll_hw_get_snNesn(void) +{ + return ( (uint8_t) (0x03 & (*(uint32_t*) (LL_HW_BASE + 0x44) ) ) ) ; +} + +/************************************************************************************** + @fn ll_hw_get_txAck + + @brief This function process for getting txPkt Ack number after trlp or rtlp + + input parameters + + @param None. + + output parameters + + @param None. + + @return txAckNum. +*/ +uint8_t ll_hw_get_txAck(void) +{ + return ( (uint8_t)(0xff & (*(uint32_t*) (LL_HW_BASE + 0x34) ) ) ); +} + +/************************************************************************************** + @fn ll_hw_get_nAck + + @brief This function process for getting NACK number after trlp or rtlp + + input parameters + + @param None. + + output parameters + + @param None. + + @return txAckNum. +*/ +uint8_t ll_hw_get_nAck(void) +{ + return ( (uint8_t)(0x0f & ( (*(uint32_t*) (LL_HW_BASE + 0x34) )>>8) ) ); +} + +/************************************************************************************** + @fn ll_hw_get_rxPkt_num + + @brief This function process for getting rxPkt number after trlp or rtlp + + input parameters + + @param None. + + output parameters + + @param None. + + @return rxPktNum. +*/ +uint8_t ll_hw_get_rxPkt_num(void) +{ + return ( (uint8_t)(0xff & (*(uint32_t*) (LL_HW_BASE + 0x30) ) ) ); +} + +/************************************************************************************** + @fn ll_hw_get_rxPkt_Total_num + + @brief This function process for getting rxPkt Total number after trlp or rtlp + + input parameters + + @param None. + + output parameters + + @param None. + + @return rxPktTotalNum. +*/ +uint8_t ll_hw_get_rxPkt_Total_num(void) +{ + return ( (uint8_t)(0xff & ( (*(uint32_t*) (LL_HW_BASE + 0x30) )>>8) ) ); +} + +/************************************************************************************** + @fn ll_hw_get_rxPkt_CrcErr_num + + @brief This function process for getting rxPkt CrcErr number after trlp or rtlp + + input parameters + + @param None. + + output parameters + + @param None. + + @return rxPktTotalNum. +*/ +uint8_t ll_hw_get_rxPkt_CrcErr_num(void) +{ + return ( (uint8_t)(0xff & ( (*(uint32_t*) (LL_HW_BASE + 0x30) )>>16) ) ); +} + + +/************************************************************************************** + @fn ll_hw_get_rxPkt_CrcOk_num + + @brief This function process for getting rxPkt CrcOk number after trlp or rtlp + + input parameters + + @param None. + + output parameters + + @param None. + + @return rxPktTotalNum. +*/ +uint8_t ll_hw_get_rxPkt_CrcOk_num(void) +{ + uint32_t tmp= *(uint32_t*) (LL_HW_BASE + 0x30) ; + return ( ( (0x00ff00 & tmp)>> 8) - ((0xff0000 & tmp)>>16) ) ; +} + + +/************************************************************************************** + @fn ll_hw_get_anchor + + @brief This function process for getting anchor point count after rtlp + + input parameters + + @param None. + + output parameters + + @param None. + + @return anchorPoint[31:0],hclk cycle between ll_trig and bb_sync +*/ +uint32_t ll_hw_get_anchor(void) +{ + return (*(uint32_t*) (LL_HW_BASE + 0x6c)); +} + +/************************************************************************************** + @fn ll_hw_get_irq_status + + @brief This function process for getting HW LL irq status + + input parameters + + @param None. + + output parameters + + @param None. + + @return irq_status. +*/ +uint32_t ll_hw_get_irq_status(void) +{ + return (*(volatile uint32_t*) (LL_HW_BASE+ 0x10) & LL_HW_IRQ_MASK); +} + +/************************************************************************************** + @fn ll_hw_get_fsm_status + + @brief This function process for getting HW LL FSM status + + input parameters + + @param None. + + output parameters + + @param None. + + @return fsm status. +*/ +uint8_t ll_hw_get_fsm_status(void) +{ + return ( (uint8_t)(*(volatile uint32_t*) (LL_HW_BASE + 0x08) & 0x0f ) ); +} + + +/************************************************************************************** + @fn ll_hw_get_last_ack + + @brief This function process for getting HW LL last pkt ack status + + input parameters + + @param None. + + output parameters + + @param None. + + @return lastAck= 1: ack, 0:nack. +*/ +uint8_t ll_hw_get_last_ack(void) +{ + uint16_t snNesnStatus; + uint8_t nesnRx,snLocal,lastAck; + snNesnStatus= (uint16_t)(*(volatile uint32_t*) (LL_HW_BASE + 0x44) & 0xffff ) ; + nesnRx = 0x01 &(snNesnStatus>>8); + snLocal = 0x01 &(snNesnStatus>>1); + lastAck = (nesnRx==snLocal); + return lastAck; +} + +/************************************************************************************** + @fn ll_hw_get_loop_cycle + + @brief This function process for getting HW LL loop cycle from ll_trigger + + input parameters + + @param None. + + output parameters + + @param None. + + @return fsm status. +*/ +uint32_t ll_hw_get_loop_cycle(void) +{ + return (*(volatile uint32_t*) (LL_HW_BASE + 0x70) ); +} + + +/************************************************************************************** + @fn ll_hw_update_rtlp_mode + + @brief This function process for rtlp update next connect event llMode + This fucnction MUST BE called while ll mode_done irq happened!!! + + input parameters + + @param + + output parameters + + @param None. + + @return rtlpMode +*/ +uint8_t ll_hw_update_rtlp_mode(uint8_t llMode) +{ + uint8_t txAckNum; + uint8_t llTxNum; + uint16_t rtlpMode; + uint8_t rtlpNoTx; + llTxNum = ((*(volatile uint32_t*)(LL_HW_BASE+ 0x04))>>8) & 0x00ff; //txNum include fist empty pkt + txAckNum = ll_hw_get_txAck(); //txAck include fist empty pkt + rtlpNoTx = (LIRQ_TD & ll_hw_get_irq_status())==0; //mode_done with tx_done + + //--------------------------------------------------------------------------------- + //when last tx pkt is empty pkt, change the next mode as RTLP_1ST + //OR RX TIME OUT occoured when recevie the 1st pkt(never tx any pkt) + // + if((llTxNum==0) ||( (txAckNum>0) && (txAckNum==llTxNum) /*tx tail empty pkt*/) + ||( (llMode==LL_HW_RTLP_EMPT) && (txAckNum==0) )/*tx first empty pkt*/ ) + { + rtlpMode = LL_HW_RTLP_EMPT; + } + else + { + rtlpMode = LL_HW_RTLP; + } + + rtlpMode = (rtlpNoTx==1) ? llMode : rtlpMode; + return rtlpMode; +} + +/************************************************************************************** + @fn ll_hw_update_trlp_mode + + @brief This function process for trlp update next connect event llMode + This fucnction MUST BE called while ll mode_done irq happened!!! + + input parameters + + @param + + output parameters + + @param None. + + @return trlpMode +*/ +uint8_t ll_hw_update_trlp_mode(uint8_t llMode) +{ + uint8_t txAckNum; + uint8_t llTxNum; + uint8_t trlpMode; + uint16_t lastAck; + uint8_t rxTimeOut; + llTxNum = ((*(volatile uint32_t*)(LL_HW_BASE+ 0x04))>>8) & 0x00ff; //txNum include fist empty pkt + txAckNum = ll_hw_get_txAck(); //txAck include fist empty pkt + lastAck = ll_hw_get_last_ack(); + rxTimeOut = (LIRQ_RTO & ll_hw_get_irq_status())>>2; //mode_done with rx_time_out + + //--------------------------------------------------------------------------------- + //when last tx pkt is empty pkt, change the next mode + //depends on the last rx pkt ack + if((llTxNum==0) ||( (txAckNum>0) && (txAckNum==llTxNum) ) /*tx tail empty pkt*/ + ||( (llMode==LL_HW_TRLP_EMPT) && (txAckNum==0) )/*tx first empty pkt*/ ) + { + if(rxTimeOut==1) + { + trlpMode = LL_HW_TRLP_EMPT; + } + else + { + trlpMode = (lastAck==1) ? LL_HW_TRLP : LL_HW_TRLP_EMPT; + } + } + else + { + trlpMode = LL_HW_TRLP; + } + + return trlpMode; +} + + +/************************************************************************************** + @fn ll_hw_update + + @brief This function process for update next connect event llMode + This fucnction MUST BE called while ll mode_done irq happened!!! + + input parameters + + @param lMode : current ll_hw_mode + txAck : ptr of tx Ack number, when ****_EMPT, txAckNum will excluded the first EMPTY pkt + rxRec : ptr of rx pkt number + snNesn: ptr of snNesn local + + output parameters + + @param None. + + @return llMode +*/ +uint8_t ll_hw_update(uint8_t llMode,uint8_t* txAck,uint8_t* rxRec,uint8_t* snNesn) +{ + uint8_t txAckNum,rxPktNum,snNesnLocal; + uint8_t nextLlMode; + txAckNum = ll_hw_get_txAck(); + rxPktNum = ll_hw_get_rxPkt_num(); + snNesnLocal = ll_hw_get_snNesn(); + + //---------------------------------------------------------------------------------------- + //remove the txAck of first tx empty pkt + if((llMode == LL_HW_TRLP_EMPT) || (llMode == LL_HW_RTLP_EMPT)) + { + txAckNum = (txAckNum==0) ? 0 : txAckNum-1; + } + + //---------------------------------------------------------------------------------------- + //when RTLP last trans empty packet, the txAck number will equal tx_num + //for next turn, we should change to RTLP_EMPT and write back the empty pkt as the fisrt + //pkt in tfifo. + //when TRLP last trans empty packet, we should change the ll_mode + //depends on the last rx pkt status + if( (llMode==LL_HW_RTLP_EMPT) || ( llMode==LL_HW_RTLP) + || ( llMode==LL_HW_RTLP_1ST)) + { + nextLlMode = ll_hw_update_rtlp_mode(llMode); + } + else if( (llMode==LL_HW_TRLP_EMPT) || ( llMode==LL_HW_TRLP)) + { + nextLlMode = ll_hw_update_trlp_mode(llMode); + } + else + nextLlMode = llMode; // should not be here, set default to supress warning + + *txAck = txAckNum; + *rxRec = rxPktNum; + *snNesn= snNesnLocal; + return nextLlMode; +} + +/************************************************************************************** + @fn byte_to_bit + + @brief This function process for byte to bin converter + + input parameters + + @param byte. + + output parameters + + @param bitOut ptr 8bit + + @return None. +*/ +void byte_to_bit(uint8_t byteIn,uint8_t* bitOut) +{ + int i=0; + + for(i=0; i<8; i++) + { + *(bitOut+i) = (byteIn>>i) & 0x01; + } +} + +/************************************************************************************** + @fn bit_to_byte + + @brief This function process for byte to bin converter + + input parameters + + @param bit input ptr. + + output parameters + + @param bitOut ptr + + @return None. +*/ +void bit_to_byte(uint8_t* bitIn,uint8_t* byteOut) +{ + int i=0; + uint8_t tmp=0; + + for(i=0; i<8; i++) + { + tmp = tmp | (bitIn[i]<>i)&0x01; + } + + for(i=0; icurrentEvent = connPtr->nextEvent; + // get the total number of received packets + // Note: Since Auto-Flush is enabled, numRxFifoFull is incremented instead of + // numRxOk when there's no room in the FIFO. When Auto-Flush is + // disabled and there's no room in the FIFO, only numRxFifoFull is + // incremented for any kind of received packet. + numPkts = ( rfCounters.numRxOk + + rfCounters.numRxNotOk + + rfCounters.numRxEmpty + + rfCounters.numRxIgnored + + rfCounters.numRxFifoFull ); + // collect packet error information + connPtr->perInfo.numPkts += numPkts; + connPtr->perInfo.numCrcErr += rfCounters.numRxNotOk; + // + connPtr->perInfo.numEvents++; + +// // check if PER by Channel is enabled +// if ( connPtr->perInfoByChan != NULL ) +// { +// connPtr->perInfoByChan->numPkts[ PHY_GET_DATA_CHAN() ] += numPkts; +// connPtr->perInfoByChan->numCrcErr[ PHY_GET_DATA_CHAN() ] += rfCounters.numRxNotOk; +// } + + // check if any data has been received + // Note: numRxOk includes numRxCtrl + // Note: numRxNotOk removed as 4.5.2 of spec says the timer is reset upon + // receipt of a "valid packet", which is taken to mean no CRC error. + if ( rfCounters.numRxOk || rfCounters.numRxIgnored || + rfCounters.numRxEmpty || rfCounters.numRxFifoFull + || connPtr->rx_crcok != 0) // ever Rx CRC OK packet + { + // yes, so update the supervision expiration count + connPtr->expirationEvent = connPtr->currentEvent + connPtr->expirationValue; + // clear flag that indicates we received first packet + // Note: The first packet only really needs to be signalled when a new + // connection is formed. However, there's no harm in resetting it + // every time in order to simplify the control logic. + // Note: True-Low logic is used here to be consistent with nR's language. + connPtr->firstPacket = 0; + + //20181206 ZQ add phy change nofity + //receiver ack notifty the host + if(connPtr->llPhyModeCtrl.isChanged==TRUE) + { + connPtr->llPhyModeCtrl.isChanged = FALSE; + llPhyModeCtrlUpdateNotify(connPtr,LL_STATUS_SUCCESS); + } + } + else // no data received, or packet received with CRC error + { + // check if we received any packets with a CRC error + if ( rfCounters.numRxNotOk ) + { + // clear flag that indicates we received first packet + // Note: The first packet only really needs to be signalled when a new + // connection is formed. However, there's no harm in resetting it + // every time in order to simplify the control logic. + // Note: True-Low logic is used here to be consistent with nR's language. + connPtr->firstPacket = 0; + } + else // no packet was received + { + // collect packet error information, TI use HCI ext to get this information. No used by PHY+ now + connPtr->perInfo.numMissedEvts++; + } + + // check if we have a Supervision Timeout + if ( connPtr->expirationEvent <= connPtr->currentEvent ) // 2019-7-17, change from '==' to '<=' + { + // check if the connection has already been established + if ( connPtr->firstPacket == 0 ) + { + // yes, so terminate with LSTO + llConnTerminate( connPtr, LL_SUPERVISION_TIMEOUT_TERM ); + } + else // no, so this is a failure to establish the connection + { + // so terminate immediately with failure to establish connection + llConnTerminate( connPtr, LL_CONN_ESTABLISHMENT_FAILED_TERM ); + } + +//#ifdef MULTI_ROLE + ll_scheduler(LL_INVALID_TIME); // link is terminated, update scheduler info +//#endif + return; + } + } + + /* + ** Process RX Data Packets + */ + // check if there is any data in the Rx FIFO + uint8_t buffer_size; + buffer_size = getRxBufferSize(connPtr); + + for ( i = 0; i < buffer_size; i ++) // note: i < getRxBufferSize() will fail the loop + { + // there is, so process it; check if data was processed + if ( llProcessRxData() == FALSE ) + { + // it wasn't, so we're done +// ll_scheduler(LL_INVALID_TIME); + break; + } + } + + // check if this connection was terminated + if ( !connPtr->active ) + { +//#ifdef MULTI_ROLE + ll_scheduler(LL_INVALID_TIME); +//#endif + return; + } + + /* + ** Check Control Procedure Processing + */ + if ( llProcessMasterControlProcedures( connPtr ) == LL_CTRL_PROC_STATUS_TERMINATE ) + { +//#ifdef MULTI_ROLE + ll_scheduler(LL_INVALID_TIME); // link is termainte, update schedle info +//#endif + return; + } + + /* + ** Process TX Data Packets + */ + // copy any pending data to the TX FIFO + llProcessTxData( connPtr, LL_TX_DATA_CONTEXT_POST_PROCESSING ); + // if any fragment l2cap pkt, copy to TX FIFO + l2capPocessFragmentTxData((uint16)connPtr->connId); + + /* + ** Setup Next Slave Event Timing + */ + + // update next event, calculate time to next event, calculate timer drift, + // update anchor points, setup NR T2E1 and T2E2 events + if ( llSetupNextMasterEvent() == LL_SETUP_NEXT_LINK_STATUS_TERMINATE ) // PHY+ always return success here + { + // this connection is terminated, so nothing to schedule +//#ifdef MULTI_ROLE + ll_scheduler(LL_INVALID_TIME); +//#endif + return; + } + + /* + ** Schedule Next Task + */ +//#ifdef MULTI_ROLE +// schedule_time = ll_get_next_timer(g_ll_conn_ctx.currentConn); + schedule_time = (connPtr->curParam.connInterval + connUpdateTimer) * 625; + T2 = read_current_fine_time(); + // TODO: don't know the cause, here need add 32us to gain accurate timing + ll_scheduler(schedule_time - 10 - LL_TIME_DELTA(g_ll_conn_ctx.timerExpiryTick, T2) + 32); // 10us: rough delay from timer expire to timer ISR +//#endif + return; +} + + + + +/******************************************************************************* + @fn llSetupNextMasterEvent + + @brief This function is used to checks if an Update Parameters and/or an + Update Data Channel has occurred, and sets the next data + channel. + + Side Effects: + t2e1 + t2e2 + + input parameters + + @param None. + + output parameters + + @param None. + + @return boolean - Indicates whether a link terminate occurred: + LL_SETUP_NEXT_LINK_STATUS_TERMINATE: Terminate due to a LSTO. + LL_SETUP_NEXT_LINK_STATUS_SUCCESS: Do not terminate. +*/ +uint8 llSetupNextMasterEvent0( void ) +{ + llConnState_t* connPtr; + //uint32 timeToNextEvt; // TODO: use this parameter to update timer1 setting + connUpdateTimer = 0; // for connUpdate case, the value is (winoffset + delta interval) , otherwise, it is zero + // get pointer to connection info + connPtr = &conn_param[g_ll_conn_ctx.currentConn]; + // update the next connection event count + connPtr->nextEvent = (uint16)(connPtr->currentEvent + 1); + + /* + ** Check for a Parameter Update + */ + + // check if there's a connection parameter udpate to the connection, and if + // so, check if the update event is before or equal to the next active event + if ((connPtr->pendingParamUpdate == TRUE) && + (connPtr->nextEvent == connPtr->paramUpdateEvent)) + { + // convert the new LSTO from time to an expiration connection event count + llConvertLstoToEvent( connPtr, &connPtr->paramUpdate ); + // update the LSTO expiration count + // Note: This is needed in case the new connection fails to receive a + // packet and a RXTIMEOUT results. The expiration count must + // already be initialized based on the new event values. + connPtr->expirationEvent = connPtr->nextEvent + connPtr->expirationValue; + #if 0 + // find the number of events between this event and the update parameter + // event, based on the original connection interval + // Note: The old connection interval must be used! + timeToNextEvt = (uint32)connPtr->curParam.connInterval + + (uint32)connPtr->paramUpdate.winOffset; + #endif +//#ifdef MULTI_ROLE + // schedule next timer after processing the connection event, no re-schedule required + // for conn update case, schedule time should be (old interval + offset), in llMasterEvt_TaskEndOk, sheduler using new interval + connUpdateTimer = connPtr->paramUpdate.winOffset + (connPtr->curParam.connInterval - connPtr->paramUpdate.connInterval); +//#endif + // update the current parameters from the new parameters + // Note: The new parameter connTimeout is not needed since once it is + // converted to connection events, its value is maintained by + // expirationValue. The new parameter winSize is only needed in case + // there's a RX timeout. + connPtr->curParam.connInterval = connPtr->paramUpdate.connInterval; + connPtr->curParam.winSize = connPtr->paramUpdate.winSize; + connPtr->curParam.slaveLatency = connPtr->paramUpdate.slaveLatency; + // convert the Control Procedure timeout into connection event count + llConvertCtrlProcTimeoutToEvent( connPtr ); + // clear the pending flag + connPtr->pendingParamUpdate = FALSE; + // notify the Host + // Note: The HCI spec says the LE Connection Update Complete event shall + // be generated after the connection parameters have been applied + // by the Controller. This is different from the Slave, which only + // reports this event if the connection interval, slave latency, + // and/or connection timeout are changed. + // Note: The values are kept in units of 625us, so they must be + // converted back to their what's used at the interface. + LL_ConnParamUpdateCback( (uint16)connPtr->connId, + connPtr->paramUpdate.connInterval >> 1, + connPtr->paramUpdate.slaveLatency, + connPtr->paramUpdate.connTimeout >> 4 ); +//#ifdef MULTI_ROLE +//#else +// // next conn event timer start when trigger current conn event, if conn parameter update is scheduled, update the timer +// uint32 elapse_time, next_time, calibrate; +// +// next_time = timeToNextEvt * 625; +// calibrate = 10; // consider re-schedule timer1 cost +// elapse_time = (CP_TIM1->LoadCount - CP_TIM1->CurrentCount) >> 2; +// +// next_time = next_time - elapse_time - calibrate; +// +// // re-schedule timer1 +// ll_schedule_next_event(next_time); +//#endif + } + else // no parameter update, so... + { + // time to next event continues as usual + // timeToNextEvt = connPtr->curParam.connInterval; // to remove + } + + // check for a Data Channel Update and calculate and set next data channel + // Note: The Data Channel Update must come after the Parameters Update in + // case the latter updates the next event count. + llSetNextDataChan( connPtr ); + llSetNextPhyMode( connPtr ); + return( LL_SETUP_NEXT_LINK_STATUS_SUCCESS ); +} + +/******************************************************************************* + @fn llProcessMasterControlPacket + + @brief This routine is used to process incoming Control packet. + + input parameters + + @param connPtr - Pointer to BLE LL Connection. + @param pBuf - Pointer to Control packet payload. + + output parameters + + @param None. + + @return None. +*/ +void llProcessMasterControlPacket0( llConnState_t* connPtr, + uint8* pBuf ) +{ + uint8 i; + uint8 opcode = *pBuf++; + uint8 iqCnt = 0; + + // check the type of control packet + switch( opcode ) + { + // Encryption Response + case LL_CTRL_ENC_RSP: + // concatenate slave's SKDs with SKDm + // Note: The SKDs MSO is the MSO of the SKD. + //PHY_READ_BYTE( (uint8 *)&connPtr->encInfo.SKD[LL_ENC_SKD_S_OFFSET], LL_ENC_SKD_S_LEN ); + pBuf = llMemCopySrc( (uint8*)&connPtr->encInfo.SKD[LL_ENC_SKD_S_OFFSET], pBuf, LL_ENC_SKD_S_LEN ); + // bytes are received LSO..MSO, but need to be maintained as + // MSO..LSO, per FIPS 197 (AES), so reverse the bytes + LL_ENC_ReverseBytes( &connPtr->encInfo.SKD[LL_ENC_SKD_S_OFFSET], LL_ENC_SKD_S_LEN ); + // concatenate the slave's IVs with IVm + // Note: The IVs MSO is the MSO of the IV. + //PHY_READ_BYTE( (uint8 *)&connPtr->encInfo.IV[LL_ENC_IV_S_OFFSET], LL_ENC_IV_S_LEN ); + pBuf = llMemCopySrc( (uint8*)&connPtr->encInfo.IV[LL_ENC_IV_S_OFFSET], pBuf, LL_ENC_IV_S_LEN ); + // bytes are received LSO..MSO, but need to be maintained as + // MSO..LSO, per FIPS 197 (AES), so reverse the bytes + // ALT: POSSIBLE TO MAINTAIN THE IV IN LSO..MSO ORDER SINCE THE NONCE + // IS FORMED THAT WAY. + LL_ENC_ReverseBytes( &connPtr->encInfo.IV[LL_ENC_IV_S_OFFSET], LL_ENC_IV_S_LEN ); + + // place the IV into the Nonce to be used for this connection + // Note: If a Pause Encryption control procedure is started, the + // old Nonce value will be used until encryption is disabled. + // Note: The IV is sequenced LSO..MSO within the Nonce. + // ALT: POSSIBLE TO MAINTAIN THE IV IN LSO..MSO ORDER SINCE THE NONCE + // IS FORMED THAT WAY. + for (i=0; iencInfo.nonce[ LL_END_NONCE_IV_OFFSET+i ] = + connPtr->encInfo.IV[ (LL_ENC_IV_LEN-i)-1 ]; + } + + // generate the Session Key (i.e. SK = AES128(LTK, SKD)) + LL_ENC_GenerateSK( connPtr->encInfo.LTK, + connPtr->encInfo.SKD, + connPtr->encInfo.SK ); +// LOG("LTK: %x\r\n", connPtr->encInfo.LTK); +// LOG("SKD: %x\r\n", connPtr->encInfo.SKD); +// LOG("SK: %x\r\n", connPtr->encInfo.SK[0], connPtr->encInfo.SK[1], connPtr->encInfo.SK[],connPtr->encInfo.SK[0], +// connPtr->encInfo.SK[0],connPtr->encInfo.SK[0],connPtr->encInfo.SK[0]); + // Note: Done for now; the slave will send LL_CTRL_START_ENC_REQ. +//LOG("ENC_RSP ->"); + break; + + // Start Encryption Request + case LL_CTRL_START_ENC_REQ: + // set a flag to indicate we've received this packet + connPtr->encInfo.startEncReqRcved = TRUE; + break; + + // Start Encryption Response + case LL_CTRL_START_ENC_RSP: + // set flag to allow outgoing data transmissions + connPtr->txDataEnabled = TRUE; + // okay to receive data again + connPtr->rxDataEnabled = TRUE; + // indicate we've received the start encryption response + connPtr->encInfo.startEncRspRcved = TRUE; + + // notify the Host + if ( connPtr->encInfo.encRestart == TRUE ) + { + // a key change was requested + LL_EncKeyRefreshCback( connPtr->connId, + LL_ENC_KEY_REQ_ACCEPTED ); + } + else + { + // a new encryption was requested + LL_EncChangeCback( connPtr->connId, + LL_ENC_KEY_REQ_ACCEPTED, + LL_ENCRYPTION_ON ); + } + + // clear the restart flag in case of another key change request + // Note: But in reality, there isn't a disable encryption in BLE, + // so once encryption is enabled, any call to LL_StartEncrypt + // will result in an encryption key change callback. + connPtr->encInfo.encRestart = FALSE; +//LOG("START_ENC_RSP ->"); + break; + + // Pause Encryption Response + case LL_CTRL_PAUSE_ENC_RSP: + // set a flag to indicate we have received LL_START_ENC_RSP + connPtr->encInfo.pauseEncRspRcved = TRUE; + break; + + // Reject Encryption Indication + case LL_CTRL_REJECT_IND: + // either the slave's Host has failed to provide an LTK, or + // the encryption feature is not supported by the slave, so read + // the rejection indication error code + //connPtr->encInfo.encRejectErrCode = PHY_READ_BYTE_VAL(); + connPtr->encInfo.encRejectErrCode = *pBuf; + // and end the start encryption procedure + connPtr->encInfo.rejectIndRcved = TRUE; + break; + + // Controller Feature Setup --> should be LL_CTRL_SLAVE_FEATURE_REQ +// case LL_CTRL_FEATURE_REQ: // new for BLE4.2, to test + +// for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; +// } + +// // logical-AND with master's feature set to indicate which of the +// // controller features in the master the slave requests to be used +// for (i=0; ifeatureSetInfo.featureSet[i] = +// *pBuf++ & deviceFeatureSet.featureSet[i]; +// } + +// // schedule the output of the control packet +// // Note: Features to be used will be taken on the next connection +// // event after the response is successfully transmitted. +// llEnqueueCtrlPkt( connPtr, LL_CTRL_FEATURE_RSP ); + +// break; + + case LL_CTRL_FEATURE_RSP: + { + uint8 peerFeatureSet[ LL_MAX_FEATURE_SET_SIZE ]; + // get the peer's device Feature Set + //for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + + // logical-AND with slave's feature set to indicate which of the + // controller features in the master the slave requests to be + // used + // Note: For now, there is only one feature that is supported + // controller-to-controller. + // Note: If the peer supports the feature, then our setting is + // the controller-to-controller setting, so no action + // is required. + if ( !(peerFeatureSet[0] & LL_FEATURE_ENCRYPTION) ) + { + // this feature is not supported by the peer, so it doesn't + // matter if we support it or not, it should not be supported + connPtr->featureSetInfo.featureSet[0] &= ~LL_FEATURE_ENCRYPTION; + } + } + + // set flag to indicate the response has been received + connPtr->featureSetInfo.featureRspRcved = TRUE; + break; + + // Version Information Indication + case LL_CTRL_VERSION_IND: + + // check if the peer's version information has already been obtained + if ( connPtr->verExchange.peerInfoValid == TRUE ) + { + // it has, so something is wrong as the spec indicates that + // only one version indication should be sent for a connection + // unknown data PDU control packet received so save the type + connPtr->unknownCtrlType = opcode; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_UNKNOWN_RSP ); + } + else // the peer version info is invalid, so make it valid + { + // get the peer's version information and save it + //PHY_READ_BYTE( (uint8 *)&peerInfo.verInfo.verNum, 1 ); + connPtr->verInfo.verNum = *pBuf++; + //PHY_READ_BYTE( (uint8 *)&peerInfo.verInfo.comId, 2 ); + pBuf = llMemCopySrc( (uint8*)&connPtr->verInfo.comId, pBuf, 2 ); + //PHY_READ_BYTE( (uint8 *)&peerInfo.verInfo.subverNum, 2 ); + pBuf = llMemCopySrc( (uint8*)&connPtr->verInfo.subverNum, pBuf, 2 ); + // set a flag to indicate it is now valid + connPtr->verExchange.peerInfoValid = TRUE; + + // check if a version indication has been sent + if ( connPtr->verExchange.verInfoSent == FALSE ) + { + // no, so this is a peer's request for our version information + llEnqueueCtrlPkt( connPtr, LL_CTRL_VERSION_IND ); + } + } + + break; + + // Terminate Indication + case LL_CTRL_TERMINATE_IND: + // read the reason code + connPtr->termInfo.reason = *pBuf; + // set flag to indicate a termination indication was received + connPtr->termInfo.termIndRcvd = TRUE; + // received a terminate from peer host, so terminate after + // confirming we have sent an ACK + // Note: For the master, we have to ensure that this control + // packet was ACK'ed. For that, the nR has a new flag that + // is set when the control packet is received, and cleared + // when the control packet received is ACK'ed. + // Note: This is not an issue as a slave because the terminate + // packet will re-transmit until the slave ACK's. + // ALT: COULD REPLACE THIS CONTROL PROCEDURE AT THE HEAD OF THE + // QUEUE SO TERMINATE CAN TAKE PLACE ASAP. + //llReplaceCtrlPkt( connPtr, LL_CTRL_TERMINATE_RX_WAIT_FOR_TX_ACK ); + llEnqueueCtrlPkt( connPtr, LL_CTRL_TERMINATE_RX_WAIT_FOR_TX_ACK ); + break; + +// LL PDU Data Length Req + case LL_CTRL_LENGTH_REQ: + + // check if the feature response procedure has already been performed + // on this connection + if ( connPtr->featureSetInfo.featureRspRcved == FALSE ) + { + // it hasn't so re-load this device's local Feature Set to the + // connection as it may have been changed by the Host with HCI + // extenstion Set Local Feature Set command + for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + } + + // check if supported DLE + if ( (connPtr->featureSetInfo.featureSet[0] & LL_FEATURE_DATA_LENGTH_EXTENSION) + != LL_FEATURE_DATA_LENGTH_EXTENSION ) + { + // unknown data PDU control packet received so save the type + connPtr->unknownCtrlType = opcode; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_UNKNOWN_RSP ); + } + else + { + if(connPtr->llPduLen.isProcessingReq==FALSE) + { + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxRxOctets), pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxRxTime), pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxTxOctets), pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxTxTime), pBuf, 2 ); + connPtr->llPduLen.isProcessingReq=TRUE; + llEnqueueCtrlPkt( connPtr, LL_CTRL_LENGTH_RSP ); + } + } + + break; + + // LL PDU Data Length RSP + case LL_CTRL_LENGTH_RSP: + + // check if supported DLE + if ( (connPtr->featureSetInfo.featureSet[0] & LL_FEATURE_DATA_LENGTH_EXTENSION) + != LL_FEATURE_DATA_LENGTH_EXTENSION ) + { + // unknown data PDU control packet received so save the type + connPtr->unknownCtrlType = opcode; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_UNKNOWN_RSP ); + } + else + { + if(connPtr->llPduLen.isWatingRsp==TRUE ) + { + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxRxOctets), pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxRxTime), pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxTxOctets), pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxTxTime), pBuf, 2 ); + llPduLengthUpdate((uint16)connPtr->connId); + connPtr->llPduLen.isWatingRsp=FALSE; + } + } + + break; + + // LL PHY UPDATE REQ + case LL_CTRL_PHY_REQ: + + // check if the feature response procedure has already been performed + // on this connection + if ( connPtr->featureSetInfo.featureRspRcved == FALSE ) + { + // it hasn't so re-load this device's local Feature Set to the + // connection as it may have been changed by the Host with HCI + // extenstion Set Local Feature Set command + for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + } + + // check if supported PHY MODE UPDATE + if ( (connPtr->featureSetInfo.featureSet[1] & LL_FEATURE_2M_PHY) != LL_FEATURE_2M_PHY + && (connPtr->featureSetInfo.featureSet[1] & LL_FEATURE_CODED_PHY) != LL_FEATURE_CODED_PHY) + { + // unknown data PDU control packet received so save the type + connPtr->unknownCtrlType = opcode; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_UNKNOWN_RSP ); + } + else + { + //process for the protocol collision + //2018-11-10 by ZQ + if(connPtr->llPhyModeCtrl.isWatingRsp==TRUE || + connPtr->pendingChanUpdate==TRUE || + connPtr->pendingParamUpdate==TRUE ) + { + connPtr->isCollision=TRUE; + connPtr->rejectOpCode = LL_CTRL_PHY_REQ; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_REJECT_EXT_IND ); + } + else + { + if(connPtr->llPhyModeCtrl.isProcessingReq==FALSE) + { + connPtr->llPhyModeCtrl.req.txPhy=*pBuf++; + connPtr->llPhyModeCtrl.req.rxPhy=*pBuf++; + connPtr->llPhyModeCtrl.req.allPhy=connPtr->llPhyModeCtrl.def.allPhy; + connPtr->llPhyModeCtrl.rsp.txPhy=connPtr->llPhyModeCtrl.def.txPhy; + connPtr->llPhyModeCtrl.rsp.rxPhy=connPtr->llPhyModeCtrl.def.rxPhy; + //rsp and req will be used to determine the next phy mode + LL_PhyUpdate((uint16) connPtr->connId); + connPtr->llPhyModeCtrl.isProcessingReq=TRUE; + } + else + { + //should no be here + } + } + } + + break; + + // LL_CTRL_PHY_RSP + case LL_CTRL_PHY_RSP: + + // check if supported PHY MODE UPDATE + if ( (connPtr->featureSetInfo.featureSet[1] & LL_FEATURE_2M_PHY) != LL_FEATURE_2M_PHY + && (connPtr->featureSetInfo.featureSet[1] & LL_FEATURE_CODED_PHY) != LL_FEATURE_CODED_PHY) + { + // unknown data PDU control packet received so save the type + connPtr->unknownCtrlType = opcode; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_UNKNOWN_RSP ); + } + else + { + if(connPtr->llPhyModeCtrl.isWatingRsp==TRUE) + { + connPtr->llPhyModeCtrl.rsp.txPhy=*pBuf++; + connPtr->llPhyModeCtrl.rsp.rxPhy=*pBuf++; + LL_PhyUpdate((uint16) connPtr->connId); + connPtr->llPhyModeCtrl.isWatingRsp=FALSE; + } + else + { + //should no be here + } + } + + break; + + case LL_CTRL_CTE_REQ: + + // check if the feature response procedure has already been performed + // on this connection + if ( connPtr->featureSetInfo.featureRspRcved == FALSE ) + { + // it hasn't so re-load this device's local Feature Set to the + // connection as it may have been changed by the Host with HCI + // extenstion Set Local Feature Set command + for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + } + + // check if supported CTE Response Feature +// if( connPtr->featureSetInfo.featureSet[LL_CTE_FEATURE_IDX] & LL_CONN_CTE_RSP) + if(( ( connPtr->featureSetInfo.featureSet[LL_CTE_FEATURE_IDX] & LL_CONN_CTE_RSP) != LL_CONN_CTE_RSP) || \ + ( connPtr->llCTE_RspFlag != TRUE )) + { + // unknown data PDU control packet received so save the type + connPtr->unknownCtrlType = opcode; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_UNKNOWN_RSP ); + } + else + { + // process for the protocol collision + // if other ctrl command procedure in processing , then reject + if(connPtr->llCTEModeCtrl.isWatingRsp==TRUE) + { + connPtr->isCollision=TRUE; + connPtr->rejectOpCode = LL_CTRL_CTE_REQ; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_REJECT_EXT_IND ); + } + else + { + if(connPtr->llCTEModeCtrl.isProcessingReq==FALSE) + { + uint8 CTE_tmp; + CTE_tmp = *pBuf++; + connPtr->llConnCTE.CTE_Length = CTE_tmp & 0x1F; + connPtr->llConnCTE.CTE_Type = CTE_tmp & 0xC0; + connPtr->llCTEModeCtrl.isProcessingReq=TRUE; + + if( ( connPtr->llConnCTE.enable ) && ( connPtr->llRfPhyPktFmt < LL_PHY_CODE )) + { + llEnqueueCtrlPkt( connPtr, LL_CTRL_CTE_RSP ); + } + else + { + if( connPtr->llRfPhyPktFmt >= LL_PHY_CODE ) + { + connPtr->llCTEModeCtrl.errorCode = LL_STATUS_ERROR_INVALID_LMP_LL_PARAMETER; + } + else + { + connPtr->llCTEModeCtrl.errorCode = LL_STATUS_ERROR_UNSUPPORT_LMP_LL_PARAMETER; + } + + connPtr->rejectOpCode = LL_CTRL_CTE_REQ; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_REJECT_EXT_IND ); + } + } + } + } + + break; + + case LL_CTRL_CTE_RSP: + if( connPtr->llCTEModeCtrl.isWatingRsp == TRUE ) + { + if( ( g_pLLcteISample != NULL ) && ( g_pLLcteQSample != NULL) ) + iqCnt = ll_hw_get_iq_RawSample( g_pLLcteISample, g_pLLcteQSample ); + + if( iqCnt > 0) + { + LL_ConnectionIQReportCback( connPtr->connId, + connPtr->llRfPhyPktFmt, + connPtr->currentChan, + connPtr->lastRssi, + // before CTE Transmit and sampling , no Antenna change , default 0 + 0, + connPtr->llConnCTE.CTE_Type, + connPtr->llConnCTE.slot_Duration, + // Packet_Status=0, CRC success,cause only CRC Correctly that can run here + 0, + connPtr->currentEvent, + iqCnt, + g_pLLcteISample, + g_pLLcteQSample); + } + else + { + // packet contain LL_CTE_RSP , but did not contain CTE field + // status = 0x0 : LL_CTE_RSP received successful , but without a CTE field + LL_CTE_Report_FailedCback( 0x0,connPtr->connId); + } + + connPtr->llCTEModeCtrl.isWatingRsp = FALSE; + } + + break; + + // Peer Device Received an Unknown Control Type + case LL_CTRL_UNKNOWN_RSP: + + // Note: There doesn't appear to be any action for this message, + // other than to ACK it. + if(connPtr->llPduLen.isWatingRsp) + { + llPduLengthUpdate((uint16)connPtr->connId); + connPtr->llPduLen.isWatingRsp=FALSE;//not support DLE + } + + if(connPtr->llPhyModeCtrl.isWatingRsp) + { + llPhyModeCtrlUpdateNotify(connPtr,LL_STATUS_ERROR_UNSUPPORTED_REMOTE_FEATURE); + connPtr->llPhyModeCtrl.isWatingRsp=FALSE;//not support PHY_UPDATE + } + + // 2020-01-23 add for CTE + if( connPtr->llCTEModeCtrl.isWatingRsp ) + { + connPtr->llCTEModeCtrl.isWatingRsp = FALSE; + } + + break; + + // Our Device Received an Unknown Control Type + default: + // unknown data PDU control packet received so save the type + connPtr->unknownCtrlType = opcode; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_UNKNOWN_RSP ); + break; + } + + return; +} + + + +/******************************************************************************* + @fn llProcessMasterControlProcedures + + @brief This function is used to process any control procedures that + may be active. + + Note: There can only be one active control procedure at a time. + + Note: It is assumed the NR counters have been updated at the + end of the task before calling this routine. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return uint8 - Status of control procedure processing, which can be: + LL_CTRL_PROC_STATUS_SUCCESS: Continue normally. + LL_CTRL_PROC_STATUS_TERMINATE: We have terminated. +*/ +uint8 llProcessMasterControlProcedures0( llConnState_t* connPtr ) +{ + // check if there are any control packets ready for processing + while ( connPtr->ctrlPktInfo.ctrlPktCount > 0 ) + { + // processing based on control packet type at the head of the queue + switch( connPtr->ctrlPktInfo.ctrlPkts[ 0 ] ) + { + case LL_CTRL_TERMINATE_IND: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // we have already place packet on TX FIFO, so check if its been ACK'ed + if ( rfCounters.numTxCtrlAck ) + { + // done with this control packet, so remove from the processing queue + llDequeueCtrlPkt( connPtr ); + // yes, so process the termination + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_HOST_REQUESTED_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else // no done yet + { + // check if a termination control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupTermInd( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + // Note: Unreachable statement generates compiler warning! + //break; + + /* + ** Connection Update Request + */ + case LL_CTRL_CONNECTION_UPDATE_REQ: + +// LOG("CONN UPD"); + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // we have already placed a packet on TX FIFO, so check if its been ACK'ed + if ( rfCounters.numTxCtrlAck ) + { + // yes, so adjust all time values to units of 625us + connPtr->paramUpdate.winSize <<= 1; + connPtr->paramUpdate.winOffset <<= 1; + connPtr->paramUpdate.connInterval <<= 1; + connPtr->paramUpdate.connTimeout <<= 4; + // and activate the update + connPtr->pendingParamUpdate = TRUE; + // done with this control packet, so remove from the processing queue + llDequeueCtrlPkt( connPtr ); + } + else // no done yet + { + // Core Spec V4.0 now indicates there is no control procedure + // timeout. However, it still seems prudent to monitor for the + // instant while waiting for the slave's ACK. + if ( connPtr->nextEvent == connPtr->paramUpdateEvent ) + { + // this event is the instant, and the control procedure still + // has not been ACK'ed, we the instant has passed + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_INSTANT_PASSED_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else // continue waiting for the slave's ACK + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupUpdateParamReq( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + /* + ** Channel Map Update Request + */ + case LL_CTRL_CHANNEL_MAP_REQ: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // we have already placed a packet on TX FIFO, so check if its been ACK'ed + if ( rfCounters.numTxCtrlAck ) + { + // yes, so activate the update + connPtr->pendingChanUpdate = TRUE; + // done with this control packet, so remove from the processing queue + llDequeueCtrlPkt( connPtr ); + } + else // no done yet + { + // Core Spec V4.0 now indicates there is no control procedure + // timeout. However, it still seems prudent to monitor for the + // instant while waiting for the slave's ACK. + if ( connPtr->nextEvent == connPtr->chanMapUpdateEvent ) + { + // this event is the instant, and the control procedure still + // has not been ACK'ed, we the instant has passed + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_INSTANT_PASSED_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else // continue waiting for the slave's ACK + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupUpdateChanReq( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + /* + ** Encryption Request + */ + case LL_CTRL_ENC_REQ: + +// LOG("1 ENC_REQ->"); + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + // set flag to discard all incoming data transmissions + connPtr->rxDataEnabled = FALSE; + } + + // we have already placed a packet on TX FIFO, so wait now until we + // get the slave's LL_START_ENC_REQ + if ( connPtr->encInfo.startEncReqRcved == TRUE ) + { + // clear packet counters + connPtr->encInfo.txPktCount = 0; + connPtr->encInfo.rxPktCount = 0; + // enable encryption + connPtr->encEnabled = TRUE; + // replace control procedure at head of queue to prevent interleaving + llReplaceCtrlPkt( connPtr, LL_CTRL_START_ENC_RSP ); + } + else if ( connPtr->encInfo.rejectIndRcved == TRUE ) + { + // the slave's Host has failed to provide an LTK, so the encryption + // setup has been rejected; end the start encryption procedure + // done with this control packet, so remove from the processing queue + llDequeueCtrlPkt( connPtr ); + // disable encryption + // Note: Not really necessary as no data is supposed to be sent + // or received. + connPtr->encEnabled = FALSE; + // set flag to allow outgoing transmissions again + connPtr->txDataEnabled = TRUE; + // set flag to allow all incoming data transmissions + connPtr->rxDataEnabled = TRUE; + + // check the rejection indication error code + if ( connPtr->encInfo.encRejectErrCode == LL_STATUS_ERROR_PIN_OR_KEY_MISSING ) + { + // notify the Host + LL_EncChangeCback( connPtr->connId, + LL_ENC_KEY_REQ_REJECTED, + LL_ENCRYPTION_OFF ); + } + else // LL_STATUS_ERROR_UNSUPPORTED_REMOTE_FEATURE + { + // notify the Host + LL_EncChangeCback( connPtr->connId, + LL_ENC_KEY_REQ_UNSUPPORTED_FEATURE, + LL_ENCRYPTION_OFF ); + } + } + else if ( connPtr->termInfo.termIndRcvd == TRUE ) + { + // the slave's Host has failed to provide an LTK, so the encryption + // setup has been rejected; end the start encryption procedure + // done with this control packet, so remove from the processing queue + llDequeueCtrlPkt( connPtr ); + } + else // no done yet + { + // check if a update param req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // notify the Host + if ( connPtr->encInfo.encRestart == TRUE ) + { + // a key change was requested + LL_EncKeyRefreshCback( connPtr->connId, + LL_CTRL_PKT_TIMEOUT_TERM ); + } + else + { + // a new encryption was requested + LL_EncChangeCback( connPtr->connId, + LL_CTRL_PKT_TIMEOUT_TERM, + LL_ENCRYPTION_OFF ); + } + + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupEncReq( connPtr ); + // set a flag to indicate we have received LL_START_ENC_REQ + // Note: The LL_ENC_RSP will be received first, which will result in + // the master calculating its IVm and SKDm, concatenating it + // with the slave's IVs and SKDs, and calculating the SK from + // the LTK and SKD. After that, we will receive the + // LL_START_ENC_REQ from the slave. So, it is okay to stay in + // this control procedure until LL_START_ENC_REQ is received. + // Note: It is okay to repeatedly set this flag in the event the + // setup routine hasn't completed yet (e.g. if the TX FIFO + // has not yet become empty). + connPtr->encInfo.startEncReqRcved = FALSE; + connPtr->encInfo.rejectIndRcved = FALSE; + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + /* + ** Encryption Start Response + */ + case LL_CTRL_START_ENC_RSP: + +// LOG("1 START_ENC_RSP->"); + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // we have already placed a packet on TX FIFO, so wait now until we + // get the slave's LL_START_ENC_RSP + if ( connPtr->encInfo.startEncRspRcved == TRUE ) + { + // done with this control packet, so remove from the processing queue + llDequeueCtrlPkt( connPtr ); + // we're done with encryption procedure, so clear flags + connPtr->encInfo.encReqRcved = FALSE; + connPtr->encInfo.pauseEncRspRcved = FALSE; + connPtr->encInfo.startEncReqRcved = FALSE; + connPtr->encInfo.startEncRspRcved = FALSE; + connPtr->encInfo.rejectIndRcved = FALSE; + } + else // no done yet + { + // check if a update param req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // notify the Host + if ( connPtr->encInfo.encRestart == TRUE ) + { + // a key change was requested + LL_EncKeyRefreshCback( connPtr->connId, + LL_CTRL_PKT_TIMEOUT_TERM ); + } + else + { + // a new encryption was requested + LL_EncChangeCback( connPtr->connId, + LL_CTRL_PKT_TIMEOUT_TERM, + LL_ENCRYPTION_OFF ); + } + + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: The llSetupStartEncRsp routine will *not* reset the control + // timeout value since the entire encryption procedure starts + // with the master sending the LL_ENC_REQ, and ends when the + // master receives the LL_START_ENC_RSP from the slave. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupStartEncRsp( connPtr ); + // set a flag to indicate we have received LL_START_ENC_RSP + // Note: It is okay to repeatedly set this flag in the event the + // setup routine hasn't completed yet (e.g. if the TX FIFO + // has not yet become empty). + connPtr->encInfo.startEncRspRcved = FALSE; + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + /* + ** Encryption Pause Request + */ + case LL_CTRL_PAUSE_ENC_REQ: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // we have already placed a packet on TX FIFO, so wait now until we + // get the slave's LL_PAUSE_ENC_RSP + if ( connPtr->encInfo.pauseEncRspRcved == TRUE ) + { + // disable encryption + connPtr->encEnabled = FALSE; + // replace control procedure at head of queue to prevent interleaving + llReplaceCtrlPkt( connPtr, LL_CTRL_PAUSE_ENC_RSP ); + } + else // no done yet + { + // check if a update param req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // notify the Host + if ( connPtr->encInfo.encRestart == TRUE ) + { + // a key change was requested + LL_EncKeyRefreshCback( connPtr->connId, + LL_CTRL_PKT_TIMEOUT_TERM ); + } + else + { + // a new encryption was requested + LL_EncChangeCback( connPtr->connId, + LL_CTRL_PKT_TIMEOUT_TERM, + LL_ENCRYPTION_OFF ); + } + + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: The llSetupStartEncRsp routine will *not* reset the control + // timeout value since the entire encryption procedure starts + // with the master sending the LL_ENC_REQ, and ends when the + // master receives the LL_START_ENC_RSP from the slave. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupPauseEncReq( connPtr ); + // set a flag to indicate we have received LL_START_ENC_RSP + // Note: It is okay to repeatedly set this flag in the event the + // setup routine hasn't completed yet (e.g. if the TX FIFO + // has not yet become empty). + connPtr->encInfo.pauseEncRspRcved = FALSE; + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + /* + ** Encryption Pause Response + */ + case LL_CTRL_PAUSE_ENC_RSP: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This only means the packet has been transmitted, not that it + // has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + // replace control procedure at head of queue to prevent interleaving + llReplaceCtrlPkt( connPtr, LL_CTRL_ENC_REQ ); + } + else // no done yet + { + // check if a update param req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // notify the Host + if ( connPtr->encInfo.encRestart == TRUE ) + { + // a key change was requested + LL_EncKeyRefreshCback( connPtr->connId, + LL_CTRL_PKT_TIMEOUT_TERM ); + } + else + { + // a new encryption was requested + LL_EncChangeCback( connPtr->connId, + LL_CTRL_PKT_TIMEOUT_TERM, + LL_ENCRYPTION_OFF ); + } + + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupPauseEncRsp( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + /* + ** Feature Set Request + */ + case LL_CTRL_FEATURE_REQ: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // we have already placed a packet on TX FIFO, so wait now until we + // get the slave's LL_CTRL_FEATURE_RSP + if ( connPtr->featureSetInfo.featureRspRcved == TRUE ) + { + // notify the Host + LL_ReadRemoteUsedFeaturesCompleteCback( LL_STATUS_SUCCESS, + connPtr->connId, + connPtr->featureSetInfo.featureSet ); + // done with this control packet, so remove from the processing queue + llDequeueCtrlPkt( connPtr ); + } + else // no done yet + { + // check if a update param req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // indicate a control procedure timeout on this request + // Note: The parameters are not valid. + LL_ReadRemoteUsedFeaturesCompleteCback( LL_CTRL_PKT_TIMEOUT_TERM, + connPtr->connId, + connPtr->featureSetInfo.featureSet ); + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // add by HZF, read device feature set + for (int i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupFeatureSetReq( connPtr ); + // set flag while we wait for response + // Note: It is okay to repeatedly set this flag in the event the + // setup routine hasn't completed yet (e.g. if the TX FIFO + // has not yet become empty). + connPtr->featureSetInfo.featureRspRcved = FALSE; + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_FEATURE_RSP: // new for BLE4.2, feature req could be init by slave + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + // packet TX'ed, so use this flag on the Slave to indicate that + // the feature response procedure has already taken place on this + // connection + // Note: This is being done to support the HCI extension command + // LL_EXT_SetLocalSupportedFeatures so that the user can + // update the local supported features even after a connection + // is formed. This update will be used as long as a feature + // response feature has not been performed by the Master. Once + // performed, the connection feature set is fixed! + connPtr->featureSetInfo.featureRspRcved = TRUE; + // ALT: COULD RE-ACTIVATE SL (IF ENABLED) RIGHT HERE. +// connPtr->slaveLatency = connPtr->slaveLatencyValue; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: There is no control procedure timeout associated with this + // control packet. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupFeatureSetRsp( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + /* + ** Vendor Information Exchange (Request or Reply) + */ + case LL_CTRL_VERSION_IND: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if the peer's version information is valid + if ( connPtr->verExchange.peerInfoValid == TRUE ) + { + // yes, so check if the host has requested this information + if ( connPtr->verExchange.hostRequest == TRUE ) + { + // yes, so provide it + LL_ReadRemoteVersionInfoCback( LL_STATUS_SUCCESS, + connPtr->connId, + connPtr->verInfo.verNum, + connPtr->verInfo.comId, + connPtr->verInfo.subverNum ); + } + + // in any case, dequeue this control procedure + llDequeueCtrlPkt( connPtr ); + } + else // no done yet + { + // check if a update param req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so complete the callback with error + LL_ReadRemoteVersionInfoCback( LL_CTRL_PKT_TIMEOUT_TERM, + connPtr->connId, + connPtr->verInfo.verNum, + connPtr->verInfo.comId, + connPtr->verInfo.subverNum ); + // and end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // since we are in the process of sending the version indication, + // it is okay to set this flag here even if it is set repeatedly + // in the of llSetupVersionIndReq failures + connPtr->verExchange.verInfoSent = TRUE; +// // so try to put it there; being active depends on a success +// connPtr->ctrlPktInfo.ctrlPktActive = llSetupPingReq(connPtr);// llSetupVersionIndReq( connPtr ); + connPtr->ctrlPktInfo.ctrlPktActive = llSetupVersionIndReq( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_LENGTH_REQ: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + connPtr->llPduLen.isWatingRsp=TRUE; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: There is no control procedure timeout associated with this + // control packet. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupDataLenghtReq( connPtr ); + connPtr->llPduLen.isWatingRsp=FALSE; + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_LENGTH_RSP: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + connPtr->llPduLen.isProcessingReq=FALSE; + llPduLengthUpdate((uint16)connPtr->connId); + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: There is no control procedure timeout associated with this + // control packet. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupDataLenghtRsp( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + // LL PHY UPDATE REQ + case LL_CTRL_PHY_REQ: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + connPtr->llPhyModeCtrl.isWatingRsp=TRUE; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: There is no control procedure timeout associated with this + // control packet. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupPhyReq( connPtr ); + connPtr->llPhyModeCtrl.isWatingRsp=FALSE; + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_PHY_UPDATE_IND: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // we have already placed a packet on TX FIFO, so check if its been ACK'ed + if ( rfCounters.numTxCtrlAck ) + { + //20181206 ZQ phy update no change case + if( connPtr->phyUpdateInfo.m2sPhy== 0 + && connPtr->phyUpdateInfo.s2mPhy== 0) + { + connPtr->phyUpdateInfo.m2sPhy=connPtr->llPhyModeCtrl.local.txPhy; + connPtr->phyUpdateInfo.s2mPhy=connPtr->llPhyModeCtrl.local.rxPhy; + llPhyModeCtrlUpdateNotify(connPtr,LL_STATUS_SUCCESS); + } + else + { + // yes, so activate the update + connPtr->pendingPhyModeUpdate = TRUE; + } + + connPtr->llPhyModeCtrl.isWatingRsp=FALSE; + connPtr->llPhyModeCtrl.isProcessingReq=FALSE; + // done with this control packet, so remove from the processing queue + llDequeueCtrlPkt( connPtr ); + } + else // no done yet + { + // Core Spec V4.0 now indicates there is no control procedure + // timeout. However, it still seems prudent to monitor for the + // instant while waiting for the slave's ACK. + if ( connPtr->nextEvent == connPtr->phyModeUpdateEvent ) + { + // this event is the instant, and the control procedure still + // has not been ACK'ed, we the instant has passed + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_INSTANT_PASSED_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else // continue waiting for the slave's ACK + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupPhyUpdateInd( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + // REJECT EXT IND --> PHY UPDATE COLLSION + case LL_CTRL_REJECT_EXT_IND: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + connPtr->isCollision=TRUE; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + if(connPtr->llPhyModeCtrl.isWatingRsp==TRUE) + { + connPtr->ctrlPktInfo.ctrlPktActive = llSetupRejectExtInd( connPtr,LL_STATUS_ERROR_LL_PROCEDURE_COLLISION); + } + else if(connPtr->pendingChanUpdate==TRUE || + connPtr->pendingParamUpdate==TRUE ) + { + connPtr->ctrlPktInfo.ctrlPktActive = llSetupRejectExtInd( connPtr,LL_STATUS_ERROR_DIFF_TRANSACTION_COLLISION); + } + else if( connPtr->llCTEModeCtrl.isWatingRsp == TRUE) + { + // 2020-01-23 add for CTE + connPtr->ctrlPktInfo.ctrlPktActive = llSetupRejectExtInd( connPtr,connPtr->llCTEModeCtrl.errorCode ); + connPtr->llCTEModeCtrl.errorCode = LL_STATUS_SUCCESS; + } + else + { + //should not be here + } + + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_CTE_REQ: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + // connPtr->llCTEModeCtrl.isWatingRsp = TRUE; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + osal_memset( &(connPtr->llCTEModeCtrl), 0, sizeof( connPtr->llCTEModeCtrl )); + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + connPtr->ctrlPktInfo.ctrlPktActive = llSetupCTEReq( connPtr ); + connPtr->llCTEModeCtrl.isWatingRsp = TRUE; + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_CTE_RSP: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + connPtr->llCTEModeCtrl.isProcessingReq = FALSE; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + } + else // control packet has not been put on the TX FIFO yet + { + connPtr->ctrlPktInfo.ctrlPktActive = llSetupCTERsp( connPtr ); + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + /* + ** Unknown Control Type Response + */ + case LL_CTRL_UNKNOWN_RSP: + + // try to place control packet in the TX FIFO + // Note: Since there are no dependencies for this control packet, we + // do not have to bother with the active flag. + if ( llSetupUnknownRsp( connPtr ) == TRUE ) + { + // all we have to do is put this control packet on the TX FIFO, so + // remove control packet from the processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + /* + ** Control Internal - Wait for Control ACK + */ + case LL_CTRL_TERMINATE_RX_WAIT_FOR_TX_ACK: + + // check if the control packet has been ACK'ed (i.e. is not pending) + // Note: Normally this routine is used for control procedures where + // control packets are sent by this role. This is a special case + // where a terminate indication was received, but we must as a + // master wait for our ACK to be sent before terminating. + if ( rfCounters.numTxCtrlAck == 1) // ctrl packet has been acked + { + // yes, so terminate + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, connPtr->termInfo.reason ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + + // Note: Unreachable statement generates compiler warning! + //break; + + // Dummy Place Holder + //case LL_CTRL_DUMMY_PLACE_HOLDER: + // // dummy packet stays at head of queue, so exit here + // return( LL_CTRL_PROC_STATUS_SUCCESS ); + // Note: Unreachable statement generates compiler warning! + //break; + default: + #ifdef DEBUG + // fatal error - a unknown control procedure value was used + LL_ASSERT( FALSE ); + #endif // DEBUG + break; + } + } + + return( LL_CTRL_PROC_STATUS_SUCCESS ); +} + +//#pragma O0 +// A2 multi-connection +uint8 ll_processMissMasterEvt(uint8 connId) +{ + llConnState_t* connPtr; +// LOG("-M "); + connPtr = &conn_param[connId]; + connPtr->rx_crcok = 0; + connPtr->rx_timeout = 1; + connPtr->pmCounter.ll_conn_event_cnt ++; + connPtr->pmCounter.ll_conn_event_timeout_cnt ++; + connPtr->pmCounter.ll_miss_master_evt_cnt ++; + + if(p_perStatsByChan!=NULL) + p_perStatsByChan->rxToCnt[connPtr->currentChan]++; + + // Tx done OK counter + rfCounters.numTxDone = 0; + // update the numTxCtrlAck counter, add on 2017-11-15 + rfCounters.numTxCtrlAck = 0; + // this counter is set in function LL_master_conn_event() used in function llProcessMasterControlProcedures() + rfCounters.numTxCtrl = 0; + // advance the connection event count + connPtr->currentEvent = connPtr->nextEvent; + connPtr->perInfo.numEvents++; + connPtr->perInfo.numMissedEvts++; + + // check if we have a Supervision Timeout + if ( connPtr->expirationEvent <= connPtr->currentEvent ) // 2019-7-17, change from '==' to '<=' + { + // check if the connection has already been established + if ( connPtr->firstPacket == 0 ) + { + // yes, so terminate with LSTO + llConnTerminate( connPtr, LL_SUPERVISION_TIMEOUT_TERM ); + } + else // no, so this is a failure to establish the connection + { + // so terminate immediately with failure to establish connection + llConnTerminate( connPtr, LL_CONN_ESTABLISHMENT_FAILED_TERM ); + } + + return LL_PROC_LINK_TERMINATE; + } + + // no Rx packet + + /* + ** Check Control Procedure Processing + */ + if ( llProcessMasterControlProcedures( connPtr ) == LL_CTRL_PROC_STATUS_TERMINATE ) + { + // this connection is terminated, so nothing to schedule + return LL_PROC_LINK_TERMINATE; + } + + /* + ** Process TX Data Packets, no new data for miss event + */ + + /* + ** Setup Next master Event Timing + */ + + // update next event, calculate time to next event, calculate timer drift, + // update anchor points, setup NR T2E1 and T2E2 events + if ( llSetupNextMasterEvent() == LL_SETUP_NEXT_LINK_STATUS_TERMINATE ) // PHY+ always return success here + { + // this connection is terminated, so nothing to schedule + return LL_PROC_LINK_TERMINATE; + } + + // update scheduler information + g_ll_conn_ctx.scheduleInfo[connId].remainder += (connPtr->curParam.connInterval + connUpdateTimer) * 625; + + // connection event notify + if (g_conn_taskID != 0) + osal_set_event(g_conn_taskID, g_conn_taskEvent); + + return LL_PROC_LINK_KEEP; +} + + + + +/******************************************************************************* +*/ diff --git a/src/lib/ble_controller/ll_slaveEndCauses.c b/src/lib/ble_controller/ll_slaveEndCauses.c new file mode 100644 index 0000000..143a643 --- /dev/null +++ b/src/lib/ble_controller/ll_slaveEndCauses.c @@ -0,0 +1,2521 @@ +/******************************************************************************* + Filename: ll_SlaveEndCauses.c + Revised: + Revision: + + Description: This file contains the Link Layer (LL) handlers for the + various slave end causes that result from a PHY task + completion. The file also contains the slave end causes + related to connection termination, as well as common + termination routines used by the slave. + + +*******************************************************************************/ + +/******************************************************************************* + INCLUDES +*/ + + + +#include "ll_def.h" +#include "ll.h" +#include "ll_common.h" +#include "timer.h" + +#include "bus_dev.h" +#include "ll_enc.h" +#include "jump_function.h" +#include "global_config.h" +#include "ll_hw_drv.h" + + +/******************************************************************************* + MACROS +*/ + +/******************************************************************************* + CONSTANTS +*/ + +#define MAX_LSTO_IN_COARSE_TICKS 51200 // 32s in 625us +#define MIN_CI_IN_COARSE_TICKS 12 // 7.5ms in 625us +#define MAX_LSTO_NUM_OF_EVENTS (MAX_LSTO_IN_COARSE_TICKS / MIN_CI_IN_COARSE_TICKS) + +/******************************************************************************* + EXTERNAL VARIABLES +*/ +extern uint32_t ISR_entry_time; +extern int slave_conn_event_recv_delay; + +extern uint32_t g_smartWindowSize; +extern uint8_t g_smartWindowRTOCnt; +extern uint8 g_conn_taskID; +extern uint16 g_conn_taskEvent; +extern perStatsByChan_t* p_perStatsByChan; + +///// EXTERNAL FUNCTION + + +/******************************************************************************* + Prototypes +*/ + + +/******************************************************************************* + Functions +*/ +void ll_adptive_adj_next_time(uint32_t nextTime); + +/******************************************************************************* + @fn llSlaveEvt_TaskEndOk0 + + @brief This function is used to handle the PHY task done end cause + TASK_ENDOK that can result from one of two causes. First, a + normal connection event closure occurred since the Slave + transmitted a packet with MD=0 (i.e. no more Slave data) after + having successfully received a packet from the Master with MD=0 + (i.e. no more Master data). Second, the Slave transmitted a + packet and the BLE_L_CONF.ENDC=1. Since the ENDC bit is + currently not used, only the first case is handled. + + This function needs to read and save the anchor point, which is + used for timing the next connection event. All RX FIFO data + (data and control packets) are to be counted (for encyrtion) + and processed. All data that needs to be sent are placed in the + TX FIFO. The connectin event is counted, and the start of slave + latency is checked. If the connection hasn't been terminated + via a control packet request, the next data channel is selected, + and the timing for the start of the next Slave tasks it + determined based on the connection interval, relative to the + anchor point. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void llSlaveEvt_TaskEndOk0( void ) +{ + llConnState_t* connPtr; + uint32_t next_time; + uint32 sw_delay, T2; + int calibra_time, i; // this parameter will be calibrate provided by global_config + + // check if the connection is still valid + if (FALSE == conn_param[g_ll_conn_ctx.currentConn].active) + { + // connection may have already been ended by a reset + // HZF: if other procedure terminate the link, it should schedule the next event + return; + } + + // get connection information + connPtr = &conn_param[g_ll_conn_ctx.currentConn]; + // advance the connection event count + connPtr->currentEvent = connPtr->nextEvent; + + // check if any data has been received + // Note: numRxOk includes numRxCtrl + // Note: numRxNotOk removed as 4.5.2 of spec says the LSTO is reset upon + // receipt of a "valid packet", which is taken to mean no CRC error. + if ( rfCounters.numRxOk || rfCounters.numRxIgnored || // we have only "numRxOk" + rfCounters.numRxEmpty || rfCounters.numRxFifoFull + || connPtr->rx_crcok != 0) // ever Rx CRC OK packet + { + // yes, so update the supervision expiration count + connPtr->expirationEvent = connPtr->currentEvent + connPtr->expirationValue; + // clear flag that indicates we received first packet + // Note: The first packet only really needs to be signalled when a new + // connection is formed or a connection's parameters are updated. + // However, there's no harm in resetting it every time in order to + // simplify the control logic. + // Note: True-Low logic is used here to be consistent with nR's language. + connPtr->firstPacket = 0; + + // slave latency may have been disabled because a packet from the master + // was not received (see Core spec V4.0, Vol 6, Section 4.5.1), so restore + // the slave latency value; but note that if this is the beginning of a + // connection, you can not allow slave latency until the first NESN change + // has occurred from the master (i.e. until master ACK's slave) + if ( connPtr->slaveLatencyAllowed == TRUE ) + { + // activate slave latency + connPtr->slaveLatency = connPtr->slaveLatencyValue; + } + + //receiver ack notifty the host + if(connPtr->llPhyModeCtrl.isChanged==TRUE) + { + connPtr->llPhyModeCtrl.isChanged = FALSE; + llPhyModeCtrlUpdateNotify(connPtr,LL_STATUS_SUCCESS); + } + } + else // either no packets received, or packets received with CRC error + { + // check if we received any packets with a CRC error + // Note: Spec change (section 4.5.5) indicates any packet received, + // regardless of CRC result, determines the anchor point. + if (connPtr->rx_timeout) // no packet was received from the master + { + // collect packet error information + connPtr->perInfo.numMissedEvts++; + // so listen to every event until a packet is received + connPtr->slaveLatency = 0; + } + else // ( rfCounters.numRxNotOk ) // different to TI sequence + { + // clear flag that indicates we received first packet + // Note: The first packet only really needs to be signalled when a new + // connection is formed or a connection's parameters are updated. + // However, there's no harm in resetting it every time in order to + // simplify the control logic. + // Note: True-Low logic is used here to be consistent with nR's language. + connPtr->firstPacket = 0; + + // slave latency may have been disabled because a packet from the master + // was not received (see Core spec V4.0, Vol 6, Section 4.5.1), so restore + // the slave latency value; but note that if this is the beginning of a + // connection, you can not allow slave latency until the first NESN change + // has occurred from the master (i.e. until master ACK's slave) + if ( connPtr->slaveLatencyAllowed == TRUE ) + { + // activate slave latency + connPtr->slaveLatency = connPtr->slaveLatencyValue; + } + } + + // check if we have a Supervision Timeout + if ( connPtr->expirationEvent == connPtr->currentEvent ) + { + // check if either we already got the first packet in a connection or + // if this isn't the quick LSTO associated with connection establishment + // Note: The Slave reuses firstPacket when a Update Parameter control + // procedure is started, but in that case, the expiration event + // will be well past the event associated with connection + // establishement. + if ( (connPtr->firstPacket == 0) || + (connPtr->currentEvent != LL_LINK_SETUP_TIMEOUT) ) + { + // yes, so terminate with LSTO + llConnTerminate( connPtr, LL_SUPERVISION_TIMEOUT_TERM ); + g_pmCounters.ll_link_lost_cnt ++; + } + else // this is a failure to establish the connection + { + // so terminate immediately with failure to establish connection + llConnTerminate( connPtr, LL_CONN_ESTABLISHMENT_FAILED_TERM ); + g_pmCounters.ll_link_estab_fail_cnt ++; + } + +//#ifdef MULTI_ROLE + ll_scheduler(LL_INVALID_TIME); +//#endif + return; + } + } + + // for a new connection, slave latency isn't enabled until the master's NESN + // bit changes, which is equivalent to receiving a TX ACK; if this is an + // update parameters, slave latency is also disabled until any first packet arrives, + // however, to keep things simple for now, we will use the same ACK constraint + if (rfCounters.numTxAck > 0)//connPtr->firstPacket == 0) /// TODO: test the scenario + { + // set a flag to indicates it is now okay to use slave latency on this + // connection, if specified + // Note: This is now needed due to a change in spec (section 4.5.1) which + // requires that slave latency be disabled when a packet is not + // received from the master. Since this routine is common for END_OK + // and RX_TIMEOUT, there's no way to know if the first Master NESN + // bit change has taken place. This flag will indicate it has, so if + // a master packet is received, the slave latency value can be + // restored. + if (pGlobal_config[LL_SWITCH] & SLAVE_LATENCY_ALLOW) + connPtr->slaveLatencyAllowed = TRUE; + + // only update slave latency if no control procedure is active + // Note: When a control procedure is active, slave latency has to be + // disabled in case it exceeds the control procedure timeout. + // Note: Even when a control procedure is active, but a control transaction + // timeout isn't used, we can still skip setting SL since that kind + // of control procedure wouldn't have disabled slave latency to begin + // with. + // ALT: COULD RESET SL IN llProcessSlaveControlProcedures. + if ( (connPtr->ctrlPktInfo.ctrlPktActive == FALSE) && + (connPtr->pendingParamUpdate == FALSE) && + (connPtr->pendingChanUpdate == FALSE) && + (connPtr->pendingPhyModeUpdate == FALSE) ) + { + // at least one ACK, so Slave Latency is operational + // Note: This really only happens once for the very first connection + // interval, and when an update parameters procedure is taking place. + connPtr->slaveLatency = connPtr->slaveLatencyValue; + } + } + + // check if the nR performed a anchor point capture + // Note: This bit is cleared at the start of a new task. + // Note: The anchor capture will occur even if the RX FIFO was too full to + // accept the packet. +// if (connPtr->connected == 0)//rx_timeout ==1 ) // update by HZF 05-03, if not connected, disable slave latency + if (connPtr->firstPacket) // update by HZF 12-18, if not receive 1st packet(CRC OK or not), disable slave latency + { + connPtr->slaveLatency = 0; + } + + /* + ** Process RX Data Packets + */ + uint8_t buffer_size; + buffer_size = getRxBufferSize(connPtr); + + if (buffer_size > 0) // 2018-10-22, disable slave latency if receives some data/ctrl packet + connPtr->slaveLatencyAllowed = FALSE; + + for ( i = 0; i < buffer_size; i ++) // note: i < getRxBufferSize() will fail the loop + { + // there is, so process it; check if data was processed + if ( llProcessRxData() == FALSE ) + { + // it wasn't, so we're done + break; + } + } + + // check if this connection was terminated + // HZF: when llProcessRxData(), the link may be terminated + if ( !connPtr->active ) + { +//#ifdef MULTI_ROLE + ll_scheduler(LL_INVALID_TIME); +//#endif + return; + } + + /* + ** Check Control Procedure Processing + */ + if ( llProcessSlaveControlProcedures( connPtr ) == LL_CTRL_PROC_STATUS_TERMINATE ) + { +//#ifdef MULTI_ROLE + ll_scheduler(LL_INVALID_TIME); +//#endif + return; + } + + /* + ** Process TX Data Packets + */ + // copy any pending data to the TX FIFO + llProcessTxData( connPtr, LL_TX_DATA_CONTEXT_POST_PROCESSING ); + // if any fragment l2cap pkt, copy to TX FIFO + l2capPocessFragmentTxData((uint16)connPtr->connId); + + if (connPtr->rx_timeout) + connPtr->accuTimerDrift += connPtr->timerDrift; + else + connPtr->accuTimerDrift = 0; + + /* + ** Setup Next Slave Event Timing + */ + + // update next event, calculate time to next event, calculate timer drift, + // update anchor points, setup NR T2E1 and T2E2 events + if ( llSetupNextSlaveEvent() == LL_SETUP_NEXT_LINK_STATUS_TERMINATE ) + { +//#ifdef MULTI_ROLE + ll_scheduler(LL_INVALID_TIME); +//#endif + return; + } + + // schedule next connection event + // calculate the timer drift due to slave latency +// llCalcTimerDrift(conn_param[connId].curParam.connInterval, +// conn_param [connId].slaveLatency, +// conn_param [connId].scaFactor, +// (uint32 *)&conn_param [connId].timerDrift); // + // calibrate time: + // 100 for SW process, 100 for timing advance, 60 for hw engine startup + calibra_time = 100 + 100 + 60 ; + // calculate the delay + T2 = read_current_fine_time(); + sw_delay = (T2 > ISR_entry_time) ? (T2 - ISR_entry_time) : (BASE_TIME_UNITS - ISR_entry_time + T2); + // schedule next connection event time + // ------> -----> (Interrupt trigger) ------> + // note that slaveLatency should be 0,i.e. no latency if there are data to send in slave + // should not use conn_param[connId].curParam.connInterval, lastTimeToNextEvt also cover conn parameter update case + next_time = connPtr->lastTimeToNextEvt * (connPtr->lastSlaveLatency + 1) * 625; + // rx -> anchor: 110us + //next_time = next_time - slave_conn_event_recv_delay - sw_delay - 110 - calibra_time - conn_param[connId].timerDrift ; + //used to adj next time for multi-link + ll_adptive_adj_next_time(next_time); + int32_t adj_time = slave_conn_event_recv_delay + sw_delay + 110 + calibra_time + connPtr->timerDrift; + next_time = (next_time > adj_time || adj_time < 0) ? (next_time - adj_time) : 200; +//#ifdef MULTI_ROLE + ll_scheduler(next_time); +//#else +// ll_schedule_next_event(next_time); +//#endif + return; +} + + + + +/******************************************************************************* + @fn llSetupNextSlaveEvent0 + + @brief This function is used to setup the next Timer 2 Event 1 and + Event 2 times, checks if an Update Parameters and/or an + Update Data Channel has occurred, and sets the next data + channel. + + + input parameters + + @param None. + + output parameters + + @param None. + + @return Indicates whether a link terminate occurred: + LL_SETUP_NEXT_LINK_STATUS_TERMINATE: Terminate due to a LSTO. + LL_SETUP_NEXT_LINK_STATUS_SUCCESS: Do not terminate. +*/ +uint8 llSetupNextSlaveEvent0( void ) +{ + llConnState_t* connPtr; + uint32 timeToNextEvt; + // get pointer to connection info + connPtr = &conn_param[g_ll_conn_ctx.currentConn]; + + // check if there's any TX data pending, and if so, disable slave latency + if ( (getTxBufferSize(connPtr) > 0) // data buffer + || (connPtr->txDataQ.head != NULL) // data queue + || connPtr->ll_buf.tx_not_ack_pkt->valid // not ack buffer + || (connPtr->ll_buf.ntrm_cnt != 0) // not transmit buffer + || (connPtr->rx_timeout) // add 2018-8-21, disable slave latency in Timeout case + || (connPtr->slaveLatencyAllowed == FALSE)) // 2018-10-22, if slave latency not allow, set latency = 0 + { + connPtr->slaveLatency = 0; + } + else // restore slave latency + { + // but only if enabled and no updates or control procedures are pending + // and the first NESN change has occurred from the master (i.e. the Master + // has ACK'ed the Slave) + if ( (connPtr->ctrlPktInfo.ctrlPktActive == FALSE) && + (connPtr->pendingParamUpdate == FALSE) && + (connPtr->pendingChanUpdate == FALSE) && + (connPtr->pendingPhyModeUpdate == FALSE) && + (connPtr->slaveLatencyAllowed == TRUE) ) + { + // activate slave latency + connPtr->slaveLatency = connPtr->slaveLatencyValue; + } + } + + // update the next connection event count, taking slave latency into account + connPtr->nextEvent = connPtr->currentEvent + connPtr->slaveLatency + (uint8)1; + + // check if the supervision timeout is going to occur while we are in slave + // latency, or the user has suspended slave latency + // Note: The check for LSTO during slave latency requires that nextEvent was + // already updated based on slave latency! + if ( (llCheckForLstoDuringSL( connPtr ) == TRUE) ) + { + // yes, so disable slave latency + connPtr->slaveLatency = 0; + // update the next connection event count without slave latency + connPtr->nextEvent = connPtr->currentEvent + (uint8)1; + } + + /* + ** Check for a Parameter Update + ** + ** Note: The Parameters Update must come before the Data Channel Update in + ** case the next event count is changed. + */ + + // check if there's a connection parameter udpate to the connection, and if + // so, check if the update event is before or equal to the next active event + if ( (connPtr->pendingParamUpdate == TRUE) && + (llEventInRange( connPtr->currentEvent, + connPtr->nextEvent, + connPtr->paramUpdateEvent)) ) + { + // override the next active event to be the update event + connPtr->nextEvent = connPtr->paramUpdateEvent; + // convert the new LSTO from time to an expiration connection event count + llConvertLstoToEvent( connPtr, &connPtr->paramUpdate ); + // make the update slave latency the next latency to use + connPtr->slaveLatencyValue = connPtr->paramUpdate.slaveLatency; + // slave latency is not allowed until the first data packet is received + connPtr->slaveLatencyAllowed = FALSE; + // for update parameters, deactivate slave latency until first packet arrives + // Note: The spec isn't clear if slave latency is to be used immediately or + // not, but it seems awkward to allow it before we've even received + // the first packet. + // Note: Assuming we wait for the first packet to re-enable slave latency + // at the possibly new value, the spec places no restrictions on + // requiring an ACK from the Master. However, to keep the TaskDone + // processing generic, the same rules will be applied. This does not + // violate the spec as the Slave is not required to use slave latency. + connPtr->slaveLatency = 0; + // set a flag that indicates when a first data packet was received + // Note: This is used for RX timeouts in llSetupNextSlaveEvent to add the + // window size to the receive window until the first packet is + // received. + connPtr->firstPacket = 1; + // update the LSTO expiration count + // Note: This is needed in case the new connection fails to receive a + // packet and a RXTIMEOUT results. The expiration count must + // already be initialized based on the new event values. + connPtr->expirationEvent = connPtr->nextEvent + connPtr->expirationValue; + // find the number of events between this event and the update parameter + // event, based on the original connection interval + // Note: The old connection interval must be used! + timeToNextEvt = ( (uint32)llEventDelta( connPtr->paramUpdateEvent, + connPtr->currentEvent ) * + (uint32)connPtr->curParam.connInterval ) + + (uint32)connPtr->paramUpdate.winOffset; + + // notify the Host if connInterval, connTimeout, or slaveLatency + // has been changed by the master + if ( (connPtr->paramUpdate.connInterval != connPtr->curParam.connInterval) || + (connPtr->paramUpdate.connTimeout != connPtr->curParam.connTimeout ) || + (connPtr->paramUpdate.slaveLatency != connPtr->curParam.slaveLatency) ) + { + // notify the Host + // Note: The values are kept in units of 625us, so they must be + // converted back to what's used at the interface. + LL_ConnParamUpdateCback( (uint16)connPtr->connId, + connPtr->paramUpdate.connInterval >> 1, + connPtr->paramUpdate.slaveLatency, + connPtr->paramUpdate.connTimeout >> 4 ); + } + + // update the current parameters from the new parameters + // Note: The new parameter connTimeout is not needed since once it is + // converted to connection events, its value is maintained by + // expirationValue. However, in order to compare to the last received + // updates, this value must be copied as well. The new parameter + // winSize is only needed in case there's a RX timeout. + connPtr->curParam.winSize = connPtr->paramUpdate.winSize; + connPtr->curParam.connInterval = connPtr->paramUpdate.connInterval; + connPtr->curParam.slaveLatency = connPtr->paramUpdate.slaveLatency; + connPtr->curParam.connTimeout = connPtr->paramUpdate.connTimeout; + llAdjSlaveLatencyValue(connPtr); + // convert the Control Procedure timeout into connection event count + llConvertCtrlProcTimeoutToEvent( connPtr ); + // clear the pending flag + connPtr->pendingParamUpdate = FALSE; + } + else // no parameter update, so... + { + // time to next event is just the connection interval + // Note: Slave latency will be taken into account below. + timeToNextEvt = connPtr->curParam.connInterval; + // update by HZF: consider slave latency +// timeToNextEvt = connPtr->curParam.connInterval * (connPtr->slaveLatency + 1); + } + + // calculate/recalculate timer drift conditionally + // Note: It is only necessary to recalculate timer drift if the time to next + // event changes. This is based on the connection interval and slave + // latency. This can happen when the connection is formed, from an + // update parameter control procedure, or from anything that affects + // whether slave latency is to be used (assuming it is non-zero). For + // example, whether or not there is data to transmit. + if ( ((connPtr->lastTimeToNextEvt != timeToNextEvt) || + (connPtr->lastSlaveLatency != connPtr->slaveLatency)) ) + { + // calculate timer drift correction, in coarse and fine timer ticks + // Note: This routine needs the time to the next event only. It will use + // the slave latency value to adjust for slave latency. + // Note: If power saving is enabled, this routine will find the timer drift + // by also taking our own device's timer drift into account. + llCalcTimerDrift(timeToNextEvt, + connPtr->slaveLatency, + connPtr->sleepClkAccuracy, + (uint32*)&(connPtr->timerDrift)); + } + + // save time to next event for next connection event + connPtr->lastTimeToNextEvt = timeToNextEvt; + // update last slave latency used + connPtr->lastSlaveLatency = connPtr->slaveLatency; + llSetNextDataChan( connPtr ); + llSetNextPhyMode( connPtr ); + return( LL_SETUP_NEXT_LINK_STATUS_SUCCESS ); +} + + +/******************************************************************************* + @fn llCheckForLstoDuringSL0 + + @brief This function is used to determine if a link supervision timeout + (LSTO) is going to occur during slave latency. Typically, the + expiration event ought to remain ahead of the next event unless + a LSTO is going to occur. This routine is used after the next + event is updated, taking slave latency into account, to find out + if the LSTO will result during the ignored events. This is done + by checking if the next event advances past the expiration + event, taking wrap into consideration. + + Note: Next event can not advance more than the max slave latency + value, and expiration event can not advance more than the + max LSTO. Since the event counter is 64K, rather than + finding the number of events between the two in + consecutive order, the difference between the two will be + found instead. If this difference is larger than max + possible difference, then a wrap has taken place. This + saves the extra calculation otherwise needed. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Indicates whether a supervision timeout is going to occur + during slave latency: + TRUE: Terminate due to a LSTO. + FALSE: Do not terminate. +*/ +uint8 llCheckForLstoDuringSL0( llConnState_t* connPtr ) +{ + // first check if the next event is after the expiration event + if ( connPtr->expirationEvent < connPtr->nextEvent ) + { + // yes, but check if that's only because expiration event wrapped around + // Note: The delta is taken instead of finding the number of events between + // as this calculation is faster. + if ( (connPtr->nextEvent - connPtr->expirationEvent) < MAX_LSTO_NUM_OF_EVENTS ) + { + // expiration event did not wrap and is actually behind next event + return( TRUE ); + } + } + else // expiration event is ahead of or equal to the next event + { + // so check if expiration event is only ahead because next event wrapped + if ( (connPtr->expirationEvent - connPtr->nextEvent) > MAX_LSTO_NUM_OF_EVENTS ) + { + // next event did wrap and is actually ahead of expiration event + return( TRUE ); + } + } + + return( FALSE ); +} + +/******************************************************************************* + @fn llProcessSlaveControlProcedures0 + + @brief This function is used to process any control procedures that + may be active. + + Note: There can only be one active control procedure at a time. + + Note: It is assumed the NR counters have been updated at the + end of the task before calling this routine. + + input parameters + + @param connPtr - Pointer to the current connection. + + output parameters + + @param None. + + @return Status of control procedure processing, which can be: + LL_CTRL_PROC_STATUS_SUCCESS: Continue normally. + LL_CTRL_PROC_STATUS_TERMINATE: We have terminated. +*/ +uint8 llProcessSlaveControlProcedures0( llConnState_t* connPtr ) +{ + // check if there are any control packets ready for processing + while ( connPtr->ctrlPktInfo.ctrlPktCount > 0 ) + { + // processing based on control packet type at the head of the queue + switch( connPtr->ctrlPktInfo.ctrlPkts[ 0 ] ) + { + case LL_CTRL_TERMINATE_IND: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // we have already place packet on TX FIFO, so check if its been ACK'ed + if ( rfCounters.numTxCtrlAck ) + { + // yes, so process the termination + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_HOST_REQUESTED_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else // no done yet + { + // check if a termination control procedure timeout has occurred + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else // no control procedure timeout yet + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupTermInd( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + // Note: Unreachable statement generates compiler warning! + //break; + + case LL_CTRL_ENC_RSP: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + // done with this control packet, so remove from the processing queue + // Note: By dequeueing here, it is possible to get another control + // packet at the head of the queue. This is techincally not + // supposed to happen if the spec is followed. + // ALT: COULD MAKE MORE BULLET PROOF. SINCE THE REPLACE ROUTINE + // CAN'T BE USED UNTIL THE LTK IS RECEIVED BY THE HOST, A + // DUMMY CONTROL PACKET THAT SITS AT THE HEAD UNTIL IT IS + // REPLACE COULD BE USED INSTEAD. + //llReplaceCtrlPkt( connPtr, LL_CTRL_DUMMY_PLACE_HOLDER ); + llDequeueCtrlPkt( connPtr ); + // notify the Host with RAND and EDIV after sending the RSP + // Note: Need to wait for the Host reply to determine if the LTK + // is available or not. + LL_EncLtkReqCback( connPtr->connId, + connPtr->encInfo.RAND, + connPtr->encInfo.EDIV ); + } + else // not done yet + { + // check if a update param req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupEncRsp( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_START_ENC_REQ: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This only means the packet has been transmitted, not that it + // has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + // enable encryption once start encryption request is sent + // Note: We can not receive data once the encryption control + // procedure has begun, so there is no risk of a race + // condition here. + connPtr->encEnabled = TRUE; + // clear packet counters + connPtr->encInfo.txPktCount = 0; + connPtr->encInfo.rxPktCount = 0; + } + + // not done until the LL_CTRL_START_ENC_RSP is received, so check it + // Note: The following code can not be in the previous "if" statement + // since it is possible that numTxCtrl could be true, yet the + // flag startEncRspRcved isn't. Then on the next event, + // numTxCtrl wouldn't be true, and we would never check the + // startEncRspRcved flag again. Since we can't get the + // LL_START_ENC_RSP until we send the LL_CTRL_START_ENC_REQ, + // this isn't an issue. + if ( connPtr->encInfo.startEncRspRcved == TRUE ) + { + // replace control procedure at head of queue to prevent interleaving + llReplaceCtrlPkt( connPtr, LL_CTRL_START_ENC_RSP ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // first, check if the SK has been calculated + if ( connPtr->encInfo.SKValid == TRUE ) + { + // so try to begin the last step of the encryption procedure + if ( llSetupStartEncReq( connPtr ) == TRUE ) + { + // ready the flag that indicates that we've received the response + connPtr->encInfo.startEncRspRcved = FALSE; + // the control packet is now active + connPtr->ctrlPktInfo.ctrlPktActive = TRUE; + } + + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrl. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrl, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + else // SK isn't valid yet, so see if we've received the LTK yet + { + if ( connPtr->encInfo.LTKValid ) + { + // generate the Session Key (i.e. SK = AES128(LTK, SKD)) + LL_ENC_GenerateSK( connPtr->encInfo.LTK, + connPtr->encInfo.SKD, + connPtr->encInfo.SK ); + // indicate the SK is valid, and drop through + connPtr->encInfo.SKValid = TRUE; + } + else // not done yet + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + + break; + + case LL_CTRL_START_ENC_RSP: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This only means the packet has been transmitted, not that it + // has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + // packet TX'ed, so we are done with the encryption procedure + // re-activate slave latency + connPtr->slaveLatency = connPtr->slaveLatencyValue; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + // set flag to allow outgoing data transmissions + connPtr->txDataEnabled = TRUE; + // okay to receive data again + connPtr->rxDataEnabled = TRUE; + + // notify the Host + if ( connPtr->encInfo.encRestart == TRUE ) + { + // a key change was requested + LL_EncKeyRefreshCback( connPtr->connId, + LL_ENC_KEY_REQ_ACCEPTED ); + } + else + { + // a new encryption was requested + LL_EncChangeCback( connPtr->connId, + LL_ENC_KEY_REQ_ACCEPTED, + LL_ENCRYPTION_ON ); + } + + // clear the restart flag in case of another key change request, + // and all other encryption flags + // Note: But in reality, there isn't a disable encryption in BLE, + // so once encryption is enabled, any call to LL_StartEncrypt + // will result in an encryption key change callback. + connPtr->encInfo.encRestart = FALSE; + connPtr->encInfo.encReqRcved = FALSE; + connPtr->encInfo.pauseEncRspRcved = FALSE; + connPtr->encInfo.startEncRspRcved = FALSE; + } + else // not done yet + { + // check if a update param req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupStartEncRsp( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_PAUSE_ENC_RSP: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // not done until the LL_CTRL_PAUSE_ENC_RSP is received, so check it + if ( connPtr->encInfo.pauseEncRspRcved == TRUE ) + { + // done with this control packet, so remove from the processing + // queue and drop through (so the encrypton response can be + // processed) + // ALT: COULD REPLACE HEAD OF QUEUE WITH DUMMY SO NO OTHER CONTROL + // PROCEDURE CAN INTERLEAVE BEFORE THE ENC_REQ IS RECEIVED. + llDequeueCtrlPkt( connPtr ); + } + else // not received yet, so decrement and check control procedure timeout + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there + // Note: All pending transmissions must also be finished before this + // packet is placed in the TX FIFO. + if ( llSetupPauseEncRsp( connPtr ) == TRUE ) + { + // clear the flag that indicates an Encryption Request has been + // received, which is used by this control procedure to restart the + // control procedure timeout + connPtr->encInfo.pauseEncRspRcved = FALSE; + // disable encryption + // Note: Not really necessary as no data is supposed to be sent + // or received. + connPtr->encEnabled = FALSE; + // the control packet is now active; drop through + connPtr->ctrlPktInfo.ctrlPktActive = TRUE; + } + else // not done yet + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + + break; + + case LL_CTRL_REJECT_IND: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This only means the packet has been transmitted, not that it + // has been ACK'ed or NACK'ed. + // Note: The control procedure does not end until the Reject is ACKed. + // However, if the ACK is a data packet, it will be tossed + // unless data is allowed hereafter. So to avoid this, only + // the confirmed transmission of this will be used to qualify + // the related flags, but a new procedure will not be able to + // begin until this procedure completes, per the spec. + if ( rfCounters.numTxCtrl ) + { + // disable encryption + // Note: Never really enabled so this isn't necessary. + connPtr->encEnabled = FALSE; + // set flag to allow outgoing data transmissions + connPtr->txDataEnabled = TRUE; + // okay to receive data again + connPtr->rxDataEnabled = TRUE; + } + + // we have already place packet on TX FIFO, so check if its been ACK'ed + if ( rfCounters.numTxCtrlAck ) + { + // done with this control packet, so remove from the processing + // queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not ack'ed yet + { + // check if a control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupRejectInd( connPtr,connPtr->encInfo.encRejectErrCode); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + // should be LL_CTRL_SLAVE_FEATURE_REQ +// case LL_CTRL_FEATURE_REQ: // for v4.2, slave may send LL_CTRL_FEATURE_REQ msg. to be test later......... HZF +// // check if the control packet procedure is active +// if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) +// { +// // we have already placed a packet on TX FIFO, so wait now until we +// // get the slave's LL_CTRL_FEATURE_RSP +// if ( connPtr->featureSetInfo.featureRspRcved == TRUE ) +// { +// // notify the Host +// LL_ReadRemoteUsedFeaturesCompleteCback( LL_STATUS_SUCCESS, +// connPtr->connId, +// connPtr->featureSetInfo.featureSet ); + +// // done with this control packet, so remove from the processing queue +// llDequeueCtrlPkt( connPtr ); +// } +// else // no done yet +// { +// // check if a update param req control procedure timeout has occurred +// // Note: No need to cleanup control packet info as we are done. +// if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) +// { +// // indicate a control procedure timeout on this request +// // Note: The parameters are not valid. +// LL_ReadRemoteUsedFeaturesCompleteCback( LL_CTRL_PKT_TIMEOUT_TERM, +// connPtr->connId, +// connPtr->featureSetInfo.featureSet ); +// // we're done waiting, so end it all +// // Note: No need to cleanup control packet info as we are done. +// llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_HOST_TERM ); + +// return( LL_CTRL_PROC_STATUS_TERMINATE ); +// } +// else +// { +// // control packet stays at head of queue, so exit here +// return( LL_CTRL_PROC_STATUS_SUCCESS ); +// } +// } +// } +// else // control packet has not been put on the TX FIFO yet +// { +// // so try to put it there; being active depends on a success +// connPtr->ctrlPktInfo.ctrlPktActive = llSetupFeatureSetReq( connPtr ); + +// // set flag while we wait for response +// // Note: It is okay to repeatedly set this flag in the event the +// // setup routine hasn't completed yet (e.g. if the TX FIFO +// // has not yet become empty). +// connPtr->featureSetInfo.featureRspRcved = FALSE; + +// // Note: Two cases are possible: +// // a) We successfully placed the packet in the TX FIFO. +// // b) We did not. +// // +// // In case (a), it may be possible that a previously just +// // completed control packet happened to complete based on +// // rfCounters.numTxCtrlAck. Since the current control +// // procedure is now active, it could falsely detect +// // rfCounters.numTxCtrlAck, when in fact this was from the +// // previous control procedure. Consequently, return. +// // +// // In case (b), the control packet stays at the head of the +// // queue, and there's nothing more to do. Consequently, return. +// // +// // So, in either case, return. +// return( LL_CTRL_PROC_STATUS_SUCCESS ); +// } + +// break; + + case LL_CTRL_FEATURE_RSP: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + // packet TX'ed, so use this flag on the Slave to indicate that + // the feature response procedure has already taken place on this + // connection + // Note: This is being done to support the HCI extension command + // LL_EXT_SetLocalSupportedFeatures so that the user can + // update the local supported features even after a connection + // is formed. This update will be used as long as a feature + // response feature has not been performed by the Master. Once + // performed, the connection feature set is fixed! + connPtr->featureSetInfo.featureRspRcved = TRUE; + // ALT: COULD RE-ACTIVATE SL (IF ENABLED) RIGHT HERE. + connPtr->slaveLatency = connPtr->slaveLatencyValue; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: There is no control procedure timeout associated with this + // control packet. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupFeatureSetRsp( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + // Version Information Indication + case LL_CTRL_VERSION_IND: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if the peer's version information is valid + if ( connPtr->verExchange.peerInfoValid == TRUE ) + { + // yes, so check if the host has requested this information + if ( connPtr->verExchange.hostRequest == TRUE ) + { + // yes, so provide it + LL_ReadRemoteVersionInfoCback( LL_STATUS_SUCCESS, + connPtr->connId, + connPtr->verInfo.verNum, + connPtr->verInfo.comId, + connPtr->verInfo.subverNum ); + } + + // in any case, dequeue this control procedure + llDequeueCtrlPkt( connPtr ); + } + else // no done yet + { + // check if a update param req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so complete the callback with error + LL_ReadRemoteVersionInfoCback( LL_CTRL_PKT_TIMEOUT_TERM, + connPtr->connId, + connPtr->verInfo.verNum, + connPtr->verInfo.comId, + connPtr->verInfo.subverNum ); + // and end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // since we are in the process of sending the version indication, + // it is okay to set this flag here even if it is set repeatedly + // in the of llSetupVersionIndReq failures + connPtr->verExchange.verInfoSent = TRUE; + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupVersionIndReq( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_LENGTH_REQ: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + connPtr->llPduLen.isWatingRsp=TRUE; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: There is no control procedure timeout associated with this + // control packet. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupDataLenghtReq( connPtr ); + connPtr->llPduLen.isWatingRsp=FALSE; + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_LENGTH_RSP: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + connPtr->llPduLen.isProcessingReq=FALSE; + llPduLengthUpdate((uint16)connPtr->connId); + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: There is no control procedure timeout associated with this + // control packet. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupDataLenghtRsp( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_PHY_REQ: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + connPtr->llPhyModeCtrl.isWatingRsp=TRUE; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: There is no control procedure timeout associated with this + // control packet. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupPhyReq( connPtr ); + connPtr->llPhyModeCtrl.isWatingRsp=FALSE; + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_PHY_RSP: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + connPtr->llPhyModeCtrl.isProcessingReq=FALSE; + connPtr->llPhyModeCtrl.isWatingRsp=TRUE; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: There is no control procedure timeout associated with this + // control packet. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupPhyRsp( connPtr ); + connPtr->llPhyModeCtrl.isWatingRsp=FALSE; + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_CTE_REQ: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + // connPtr->llPhyModeCtrl.isWatingRsp=TRUE; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + osal_memset( &(connPtr->llCTEModeCtrl), 0, sizeof( connPtr->llCTEModeCtrl )); + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + connPtr->ctrlPktInfo.ctrlPktActive = llSetupCTEReq( connPtr ); + connPtr->llCTEModeCtrl.isWatingRsp = TRUE; + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_CTE_RSP: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + connPtr->llCTEModeCtrl.isWatingRsp = FALSE; + connPtr->llCTEModeCtrl.isProcessingReq = FALSE; + // remove control packet from processing queue and drop through + // 2020-02-12 comment:after send CONN CTE RSP , then clear txSupp + ll_hw_set_cte_txSupp( CTE_SUPP_NULL); + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + } + } + else // control packet has not been put on the TX FIFO yet + { + connPtr->ctrlPktInfo.ctrlPktActive = llSetupCTERsp( connPtr ); + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_UNKNOWN_RSP: + + // try to place control packet in the TX FIFO + // Note: Since there are no dependencies for this control packet, we + // do not have to bother with the active flag. + if ( llSetupUnknownRsp( connPtr ) == TRUE ) + { + // all we have to do is put this control packet on the TX FIFO, so + // remove control packet from the processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + // Dummy Place Holder + //case LL_CTRL_DUMMY_PLACE_HOLDER: + // // dummy packet stays at head of queue, so exit here + // Note: Unreachable statement generates compiler warning! + //break; + // return( LL_CTRL_PROC_STATUS_SUCCESS ); + + default: + break; + } + } + + return( LL_CTRL_PROC_STATUS_SUCCESS ); +} + +/******************************************************************************* + @fn llProcessSlaveControlPacket0 + + @brief This routine is used to process incoming Control packet. + + input parameters + + @param connPtr - Pointer to BLE LL Connection. + @param pBuf - Pointer to Control packet payload. + + output parameters + + @param None. + + @return None. +*/ +void llProcessSlaveControlPacket0( llConnState_t* connPtr, + uint8* pBuf ) +{ + uint8 i; + uint8 opcode = *pBuf++; + uint8 iqCnt = 0; + +// uint16 iSample[LL_CTE_MAX_SUPP_LEN * LL_CTE_SUPP_LEN_UNIT]; +// uint16 qSample[LL_CTE_MAX_SUPP_LEN * LL_CTE_SUPP_LEN_UNIT]; + // Control Packet + // check the type of control packet + switch( opcode ) + { + // Update Connection Parameters + case LL_CTRL_CONNECTION_UPDATE_REQ: + // Note: It is assumed that we have automatically ACK'ed this + // packet since the only time the nR sends a NACK is when + // the RX FIFO is too full to receive a packet. The fact + // that we received this packet means this wasn't the case. + // Note: What we don't know here is whether or not the Master + // in fact received the ACK. The only way to know that is + // if the Master's next packet is an ACK. For now, we are + // going to assume we only have to verify that we sent an + // ACK to the Master, not that the Master actually received + // it. + // Note: The spec limits the number of control procedures that + // the Slave has to handle to one. It is assumed that the + // Master will ensure this isn't violated, so the Slave + // only need keep track of control procedures it starts. + // Note: Can also check if RX FIFO full counter numRxFifoFull is + // not zero. + // save the connection udpate parameters + connPtr->paramUpdate.winSize = *pBuf++; + pBuf = llMemCopySrc( (uint8*)&connPtr->paramUpdate.winOffset, pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)&connPtr->paramUpdate.connInterval, pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*) &connPtr->paramUpdate.slaveLatency, pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)&connPtr->paramUpdate.connTimeout, pBuf, 2 ); + // convert this data into units of 625us + connPtr->paramUpdate.winSize <<= 1; + connPtr->paramUpdate.winOffset <<= 1; + connPtr->paramUpdate.connInterval <<= 1; + connPtr->paramUpdate.connTimeout <<= 4; + // connection event when update is activated (i.e. Instant) + pBuf = llMemCopySrc( (uint8*)&connPtr->paramUpdateEvent, pBuf, 2 ); + + // check if update event count is still valid + // Note: The spec indicates the connection should be termainted when + // the instant is in the past. + if ( (uint16)(connPtr->paramUpdateEvent - connPtr->currentEvent) >= LL_MAX_UPDATE_COUNT_RANGE ) // bug fixed 2018-09-25 + { + // instant past, so terminate connection immediately + llConnTerminate( connPtr, LL_CTRL_PKT_INSTANT_PASSED_PEER_TERM ); + return; + } + + // check that the LSTO is valid (i.e. meets the requirements) + // Note: LSTO > (1 + Slave Latency) * (Connection Interval * 2) + // Note: The CI * 2 requirement based on ESR05 V1.0, Erratum 3904. + // Note: All times are in 625us. + if ( (uint32)connPtr->paramUpdate.connTimeout <= + ((uint32)(1 + connPtr->paramUpdate.slaveLatency) * + (uint32)(connPtr->paramUpdate.connInterval << 1)) ) + { + // it isn't, so terminate + llConnTerminate( connPtr, LL_UNACCEPTABLE_CONN_INTERVAL_TERM ); + return; + } + + //process for the protocol collision + //2018-11-10 by ZQ + if(connPtr->llPhyModeCtrl.isWatingRsp==TRUE) + { + connPtr->isCollision=TRUE; + connPtr->rejectOpCode = LL_CTRL_CONNECTION_UPDATE_REQ; + } + + // set flag in current connection to indicate an param update is valid + connPtr->pendingParamUpdate = TRUE; + // disable slave latency so slave can listen to every connection + // event, per the spec + // Note: Only required until ACK of this update is confirmed, and the + // connection event of the instant, and the connection event + // before that. + connPtr->slaveLatency = 0; + break; + + // Update Data Channel Map + case LL_CTRL_CHANNEL_MAP_REQ: + // Note: It is assumed that we have automatically ACK'ed this + // packet since the only time the NR sends a NACK is when + // the RX FIFO is too full to receive a packet. The fact + // that we received this packet means this wasn't the case. + // Note: What we don't know here is whether or not the Master + // in fact received the ACK. The only way to know that is + // if the Master's next packet is an ACK. For now, we are + // going to assume we only have to verify that we sent an + // ACK to the Master, not that the Master actually received + // it. + // Note: The spec limits the number of control procedures that + // the Slave has to handle to one. It is assumed that the + // Master will ensure this isn't violated, so the Slave + // only need keep track of control procedures it starts. + // Note: Can also check if RX FIFO full error bit is set. + // save the connection udpate data channel parameters + //ZQ 20200207 + //stored the chanMapUpdate in conn_cxt + //pBuf = llMemCopySrc( chanMapUpdate.chanMap, pBuf, LL_NUM_BYTES_FOR_CHAN_MAP ); + pBuf = llMemCopySrc( (uint8*)&connPtr->chanMapUpdate.chanMap, pBuf, LL_NUM_BYTES_FOR_CHAN_MAP ); + // connection event when update is activated + pBuf = llMemCopySrc( (uint8*)&connPtr->chanMapUpdateEvent, pBuf, 2 ); + + // check if update event count is still valid + // Note: The spec indicates the connection should be termainted when + // the instant is in the past. + if ( (uint16)(connPtr->chanMapUpdateEvent - connPtr->currentEvent) >= LL_MAX_UPDATE_COUNT_RANGE ) // bug fixed 2018-09-25 + { + // instant past, so terminate connection immediately + llConnTerminate( connPtr, LL_CTRL_PKT_INSTANT_PASSED_PEER_TERM ); + return; + } + + //process for the protocol collision + //2018-11-10 by ZQ + if(connPtr->llPhyModeCtrl.isWatingRsp==TRUE) + { + connPtr->isCollision=TRUE; + connPtr->rejectOpCode = LL_CTRL_CHANNEL_MAP_REQ; + } + + // set flag in current connection to indicate an data channel update is valid + connPtr->pendingChanUpdate = TRUE; + // disable slave latency so slave can listen to every connection + // event, per the spec + // Note: Only required until ACK of this update is confirmed, and the + // connection event of the instant, and the connection event + // before that. + connPtr->slaveLatency = 0; + #if ( OSALMEM_METRICS ) + writeLog(TEMP_LOG, 0x333333); + #endif + break; + + // Encryption Request - Slave Only; Sent by the Master + case LL_CTRL_ENC_REQ: + + // check if the feature response procedure has already been performed + // on this connection + if ( connPtr->featureSetInfo.featureRspRcved == FALSE ) + { + // it hasn't so re-load this device's local Feature Set to the + // connection as it may have been changed by the Host with HCI + // extenstion Set Local Feature Set command + for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + } + + // check if encryption is a supported feature set item + if ( (connPtr->featureSetInfo.featureSet[0] & LL_FEATURE_ENCRYPTION) != LL_FEATURE_ENCRYPTION ) + { + // set the encryption rejection error code + connPtr->encInfo.encRejectErrCode = LL_STATUS_ERROR_UNSUPPORTED_REMOTE_FEATURE; + // so reject the encryption request + // ALT: IF THE HEAD OF THE QUEUE HAS A DUMMY TO PREVENT INTERLEAVING + // WHEN THE PAUSE ENC PROCEDURE HAS BEEN STARTED, THEN WE COULD + // USE A REPLACE HERE INSTEAD OF ENQUEUE. BUT NOTE THAT IF THIS + // IS A START ENC (INSTEAD OF RESTART) THEN WE CAN'T REPLACE AT + // THE HEAD AS SOMETHING VALID MAY ALREADY BE THERE. + // WE WOULD HAVE TO ENQUEUE. + llEnqueueCtrlPkt( connPtr, LL_CTRL_REJECT_IND ); + break; + } + + // set flag to stop all outgoing transmissions + connPtr->txDataEnabled = FALSE; + // set flag to discard all incoming data transmissions + connPtr->rxDataEnabled = FALSE; + // indicate an Encryption Request has been received + // Note: This is used in a Pause Encryption procedure to allow + // the control procedure to restart the timer. In a normal + // encryption procedure, this flag is not used. + connPtr->encInfo.encReqRcved = TRUE; + // copy the random vector + // Note: The RAND will be left in LSO..MSO order as this is + // assumed to be the order of the bytes at the Host API + // interface. + pBuf = llMemCopySrc( &connPtr->encInfo.RAND[0], pBuf, LL_ENC_RAND_LEN ); + // copy the encrypted diversifier + // Note: The EDIV will be left in LSO..MSO order as this is + // assumed to be the order of the bytes at the Host API + // interface. + pBuf = llMemCopySrc( &connPtr->encInfo.EDIV[0], pBuf, LL_ENC_EDIV_LEN ); + // copy the master's portion of the session key identifier + // Note: The SKDm LSO is the LSO of the SKD. + pBuf = llMemCopySrc( &connPtr->encInfo.SKD[LL_ENC_SKD_M_OFFSET], pBuf, LL_ENC_SKD_M_LEN ); + // bytes are received LSO..MSO, but need to be maintained as + // MSO..LSO, per FIPS 197 (AES), so reverse the bytes + LL_ENC_ReverseBytes( &connPtr->encInfo.SKD[LL_ENC_SKD_M_OFFSET], LL_ENC_SKD_M_LEN ); + // copy the master's portion of the initialization vector + // Note: The IVm LSO is the LSO of the IV. + pBuf = llMemCopySrc( &connPtr->encInfo.IV[LL_ENC_IV_M_OFFSET], pBuf, LL_ENC_IV_M_LEN ); + // bytes are received LSO..MSO, but need to be maintained as + // MSO..LSO, per FIPS 197 (AES), so reverse the bytes + // ALT: POSSIBLE TO MAINTAIN THE IV IN LSO..MSO ORDER SINCE THE NONCE + // IS FORMED THAT WAY. + LL_ENC_ReverseBytes( &connPtr->encInfo.IV[LL_ENC_IV_M_OFFSET], LL_ENC_IV_M_LEN ); + // generate SKDs + // Note: The SKDs MSO is the MSO of the SKD. + // Note: Placement of result forms concatenation of SKDm and SKDs. + // Note: Leave the SKDs in LSO..MSO order for now since it has to + // be sent OTA in this way. Reservse bytes after that. + LL_ENC_GenDeviceSKD( &connPtr->encInfo.SKD[ LL_ENC_SKD_S_OFFSET ] ); + // generate IVs + // Note: The IVs MSO is the MSO of the IV. + // Note: Placement of result forms concatenation of IVm and IVs. + // Note: Leave the SKDs in LSO..MSO order for now since it has to + // be sent OTA in this way. Reservse bytes after that. + LL_ENC_GenDeviceIV( &connPtr->encInfo.IV[ LL_ENC_IV_S_OFFSET ] ); + // A1 ROM metal change, add update cachedTRNGdata + // a cache update of FIPS TRNG values for next SKD/IV usage + (void)LL_ENC_GenerateTrueRandNum( cachedTRNGdata, LL_ENC_TRUE_RAND_BUF_SIZE ); + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_ENC_RSP ); + break; + + // FIRST MASTER THEN SLAVE SENDS + case LL_CTRL_START_ENC_RSP: + // indicate we've received the start encryption response + connPtr->encInfo.startEncRspRcved = TRUE; + break; + + // ONLY MASTER SENDS, ONLY SLAVE RECEIVES + case LL_CTRL_PAUSE_ENC_REQ: + // set flag to stop all outgoing transmissions + connPtr->txDataEnabled = FALSE; + // set flag to discard all incoming data transmissions + connPtr->rxDataEnabled = FALSE; + // invalidate the existing session key + connPtr->encInfo.SKValid = FALSE; + // set a flag to indicate this is a restart + connPtr->encInfo.encRestart = TRUE; + // indicate the LTK is no longer valid + connPtr->encInfo.LTKValid = FALSE; + // schedule the pause encryption response control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_PAUSE_ENC_RSP ); + break; + + // FIRST MASTER THEN SLAVE + case LL_CTRL_PAUSE_ENC_RSP: + // set a flag to indicate the pause encryption response arrived + connPtr->encInfo.pauseEncRspRcved = TRUE; + break; + + case LL_CTRL_FEATURE_RSP: + // TODO: add the process in Version 4.2 + break; + + // Controller Feature Setup + case LL_CTRL_FEATURE_REQ: + + // read this device's Feature Set + // Note: Must re-read the device feature set as it may have been + // changed by the Host with Set Local Feature Set. + for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + + // logical-AND with master's feature set to indicate which of the + // controller features in the master the slave requests to be used + for (i=0; ifeatureSetInfo.featureSet[i] = + *pBuf++ & deviceFeatureSet.featureSet[i]; + } + + // schedule the output of the control packet + // Note: Features to be used will be taken on the next connection + // event after the response is successfully transmitted. + llEnqueueCtrlPkt( connPtr, LL_CTRL_FEATURE_RSP ); + break; + + // Version Information Indication + case LL_CTRL_VERSION_IND: + + // check if the peer's version information has already been obtained + if ( connPtr->verExchange.peerInfoValid == TRUE ) + { + // it has, so something is wrong as the spec indicates that + // only one version indication should be sent for a connection + // unknown data PDU control packet received so save the type + connPtr->unknownCtrlType = opcode; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_UNKNOWN_RSP ); + } + else // the peer version info is invalid, so make it valid + { + // get the peer's version information and save it + connPtr->verInfo.verNum = *pBuf++; + pBuf = llMemCopySrc( (uint8*)&connPtr->verInfo.comId, pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)&connPtr->verInfo.subverNum, pBuf, 2 ); + // set a flag to indicate it is now valid + connPtr->verExchange.peerInfoValid = TRUE; + + // check if a version indication has been sent + if ( connPtr->verExchange.verInfoSent == FALSE ) + { + // no, so this is a peer's request for our version information + llEnqueueCtrlPkt( connPtr, LL_CTRL_VERSION_IND ); + } + } + + break; + + // LL PDU Data Length Req + case LL_CTRL_LENGTH_REQ: + + // check if the feature response procedure has already been performed + // on this connection + if ( connPtr->featureSetInfo.featureRspRcved == FALSE ) + { + // it hasn't so re-load this device's local Feature Set to the + // connection as it may have been changed by the Host with HCI + // extenstion Set Local Feature Set command + for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + } + + // check if supported DLE + if ( (connPtr->featureSetInfo.featureSet[0] & LL_FEATURE_DATA_LENGTH_EXTENSION) + != LL_FEATURE_DATA_LENGTH_EXTENSION ) + { + // unknown data PDU control packet received so save the type + connPtr->unknownCtrlType = opcode; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_UNKNOWN_RSP ); + } + else + { + if(connPtr->llPduLen.isProcessingReq==FALSE) + { + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxRxOctets), pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxRxTime), pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxTxOctets), pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxTxTime), pBuf, 2 ); + connPtr->llPduLen.isProcessingReq=TRUE; + llEnqueueCtrlPkt( connPtr, LL_CTRL_LENGTH_RSP ); + } + } + + break; + + // LL PDU Data Length RSP + case LL_CTRL_LENGTH_RSP: + + // check if supported DLE + if ( (connPtr->featureSetInfo.featureSet[0] & LL_FEATURE_DATA_LENGTH_EXTENSION) + != LL_FEATURE_DATA_LENGTH_EXTENSION ) + { + // unknown data PDU control packet received so save the type + connPtr->unknownCtrlType = opcode; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_UNKNOWN_RSP ); + } + else + { + if(connPtr->llPduLen.isWatingRsp==TRUE ) + { + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxRxOctets), pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxRxTime), pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxTxOctets), pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxTxTime), pBuf, 2 ); + llPduLengthUpdate((uint16)connPtr->connId); + connPtr->llPduLen.isWatingRsp=FALSE; + } + } + + break; + + // LL PHY UPDATE Req + case LL_CTRL_PHY_REQ: + + // check if the feature response procedure has already been performed + // on this connection + if ( connPtr->featureSetInfo.featureRspRcved == FALSE ) + { + // it hasn't so re-load this device's local Feature Set to the + // connection as it may have been changed by the Host with HCI + // extenstion Set Local Feature Set command + for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + } + + // check if supported PHY MODE UPDATE + if ( (connPtr->featureSetInfo.featureSet[1] & LL_FEATURE_2M_PHY) != LL_FEATURE_2M_PHY + && (connPtr->featureSetInfo.featureSet[1] & LL_FEATURE_CODED_PHY) != LL_FEATURE_CODED_PHY) + { + // unknown data PDU control packet received so save the type + connPtr->unknownCtrlType = opcode; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_UNKNOWN_RSP ); + } + else + { + //process for the protocol collision + //2018-11-10 by ZQ + if(connPtr->llPhyModeCtrl.isWatingRsp==TRUE) + { + connPtr->isCollision=TRUE; + connPtr->rejectOpCode = LL_CTRL_PHY_REQ; + } + + if(connPtr->llPhyModeCtrl.isProcessingReq==FALSE) + { + connPtr->llPhyModeCtrl.req.txPhy=*pBuf++; + connPtr->llPhyModeCtrl.req.rxPhy=*pBuf++; + connPtr->llPhyModeCtrl.req.allPhy=connPtr->llPhyModeCtrl.def.allPhy; + connPtr->llPhyModeCtrl.isProcessingReq=TRUE; + llEnqueueCtrlPkt( connPtr, LL_CTRL_PHY_RSP ); + } + } + + break; + + case LL_CTRL_PHY_UPDATE_IND: + + // check if the feature response procedure has already been performed + // on this connection + if ( connPtr->featureSetInfo.featureRspRcved == FALSE ) + { + // it hasn't so re-load this device's local Feature Set to the + // connection as it may have been changed by the Host with HCI + // extenstion Set Local Feature Set command + for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + } + + // check if supported DLE + if ( (connPtr->featureSetInfo.featureSet[1] & LL_FEATURE_2M_PHY) != LL_FEATURE_2M_PHY + && (connPtr->featureSetInfo.featureSet[1] & LL_FEATURE_CODED_PHY) != LL_FEATURE_CODED_PHY) + { + // unknown data PDU control packet received so save the type + connPtr->unknownCtrlType = opcode; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_UNKNOWN_RSP ); + } + else + { + if(connPtr->llPhyModeCtrl.isWatingRsp==TRUE) + { + connPtr->phyUpdateInfo.m2sPhy = *pBuf++; + connPtr->phyUpdateInfo.s2mPhy = *pBuf++; + + //20181204 ZQ + //process PHY no change case + if(connPtr->phyUpdateInfo.m2sPhy==0 && connPtr->phyUpdateInfo.s2mPhy==0) + { + connPtr->phyUpdateInfo.m2sPhy = connPtr->llPhyModeCtrl.local.rxPhy; + connPtr->phyUpdateInfo.s2mPhy = connPtr->llPhyModeCtrl.local.txPhy; + llPhyModeCtrlUpdateNotify(connPtr,LL_STATUS_SUCCESS); + connPtr->llPhyModeCtrl.isWatingRsp=FALSE; + return; + } + + // connection event when update is activated (i.e. Instant) + pBuf = llMemCopySrc( (uint8*)&connPtr->phyModeUpdateEvent, pBuf, 2 ); + + // check if update event count is still valid + // Note: The spec indicates the connection should be termainted when + // the instant is in the past. + if ( (uint16)(connPtr->phyModeUpdateEvent - connPtr->currentEvent) >= LL_MAX_UPDATE_COUNT_RANGE ) + { + // instant past, so terminate connection immediately + llConnTerminate( connPtr, LL_CTRL_PKT_INSTANT_PASSED_PEER_TERM ); + return; + } + + connPtr->llPhyModeCtrl.isWatingRsp=FALSE; + connPtr->pendingPhyModeUpdate=TRUE; + // disable slave latency so slave can listen to every connection + // event, per the spec + // Note: Only required until ACK of this update is confirmed, and the + // connection event of the instant, and the connection event + // before that. + connPtr->slaveLatency = 0; + } + } + + break; + + // Terminate Indication + case LL_CTRL_TERMINATE_IND: + // read the reason code + connPtr->termInfo.reason = *pBuf++; + // set flag to indicate a termination indication was received + connPtr->termInfo.termIndRcvd = TRUE; + // received a terminate from peer host, so terminate immediately + // Note: It is assumed that we have automatically ACK'ed this + // packet since the terminate indication was correctly received + // (i.e. no NACK from either a CRC error or RX FIFO too full + // to receive error). + // Note: What we don't know here is whether or not the Master + // in fact received the ACK. The only way to know that is + // if the Master's next packet is an ACK. But if the Master + // received the ACK, then it would terminate, so we may not + // ever receive another packet! In any case, the spec has been + // updated such that, when a terminate indication is received, + // we only need confirm we've ACK'ed the packet. + // Note: The spec limits the number of control procedures that + // the Slave has to handle to one. It is assumed that the + // Master will ensure this isn't violated, so the Slave + // only need keep track of control procedures it starts. + // terminate + llConnTerminate( connPtr, connPtr->termInfo.reason ); + return; + + // Process Handling Protocol Collision + case LL_REJECT_IND: + case LL_REJECT_IND_EXT: + if(connPtr->isCollision==TRUE) + { + if(connPtr->rejectOpCode== LL_CTRL_PHY_REQ) + { + llPhyModeCtrlUpdateNotify(connPtr,LL_STATUS_ERROR_DIFF_TRANSACTION_COLLISION); + } + else + { + llPhyModeCtrlUpdateNotify(connPtr,LL_STATUS_ERROR_LL_PROCEDURE_COLLISION); + } + } + else + { + // do nothing + if(opcode==LL_REJECT_IND_EXT) + { + llPhyModeCtrlUpdateNotify(connPtr,*pBuf++); + } + else + { + llPhyModeCtrlUpdateNotify(connPtr,LL_STATUS_ERROR_LL_PROCEDURE_COLLISION); + } + } + + connPtr->llPhyModeCtrl.isWatingRsp=FALSE; + connPtr->isCollision=FALSE; + break; + + // Peer Device Received an Unknown Control Type + case LL_CTRL_UNKNOWN_RSP: + + // Note: There doesn't appear to be any action for this message, + // other than to ACK it. + // if we support BLE 4.2/5.0, need consider the impact to BLE4.2/5.0 new ctrl messages ... HZF + if(connPtr->llPduLen.isWatingRsp) + { + llPduLengthUpdate((uint16)connPtr->connId); + connPtr->llPduLen.isWatingRsp=FALSE;//not support DLE + } + + if(connPtr->llPhyModeCtrl.isWatingRsp) + { + llPhyModeCtrlUpdateNotify(connPtr,LL_STATUS_ERROR_UNSUPPORTED_REMOTE_FEATURE); + connPtr->llPhyModeCtrl.isWatingRsp=FALSE;//not support PHY_UPDATE + } + + break; + + // Our Device Received an Unknown Control Type + case LL_CTRL_CTE_REQ: + + // check if the feature response procedure has already been performed + // on this connection + if ( connPtr->featureSetInfo.featureRspRcved == FALSE ) + { + // it hasn't so re-load this device's local Feature Set to the + // connection as it may have been changed by the Host with HCI + // extenstion Set Local Feature Set command + for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + } + + // check if supported CTE Response Feature and if HCI Command enable rsp + if(( ( connPtr->featureSetInfo.featureSet[LL_CTE_FEATURE_IDX] & LL_CONN_CTE_RSP) != LL_CONN_CTE_RSP) || \ + ( connPtr->llCTE_RspFlag != TRUE )) + { + // unknown data PDU control packet received so save the type + connPtr->unknownCtrlType = opcode; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_UNKNOWN_RSP ); + } + else + { + //process for the protocol collision + if(connPtr->llCTEModeCtrl.isWatingRsp==TRUE) + { + connPtr->isCollision=TRUE; + connPtr->rejectOpCode = LL_CTRL_CTE_REQ; + } + + if(connPtr->llCTEModeCtrl.isProcessingReq==FALSE) + { + uint8 CTE_tmp; + CTE_tmp = *pBuf++; + connPtr->llConnCTE.CTE_Length = CTE_tmp & 0x1F; + connPtr->llConnCTE.CTE_Type = CTE_tmp & 0xC0; + connPtr->llCTEModeCtrl.isProcessingReq=TRUE; + llEnqueueCtrlPkt( connPtr, LL_CTRL_CTE_RSP ); + } + } + + break; + + case LL_CTRL_CTE_RSP: + if( ( g_pLLcteISample != NULL ) && ( g_pLLcteQSample != NULL) ) + iqCnt = ll_hw_get_iq_RawSample( g_pLLcteISample, g_pLLcteQSample ); + + if( iqCnt > 0) + { + LL_ConnectionIQReportCback( connPtr->connId, + connPtr->llRfPhyPktFmt, + connPtr->currentChan, + connPtr->lastRssi, + // before CTE Transmit and sampling , no Antenna change , default 0 + 0, + connPtr->llConnCTE.CTE_Type, + connPtr->llConnCTE.slot_Duration, + // Packet_Status=0, CRC success,cause only CRC Correctly that can run here + 0, + connPtr->currentEvent, + iqCnt, + g_pLLcteISample, + g_pLLcteQSample); + } + else + { + // packet contain LL_CTE_RSP , but did not contain CTE field + // status = 0x0 : LL_CTE_RSP received successful , but without a CTE field + LL_CTE_Report_FailedCback( 0x0,connPtr->connId); + } + + break; + + default: + // unknown data PDU control packet received so save the type + connPtr->unknownCtrlType = opcode; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_UNKNOWN_RSP ); + break; + } + + return; +} + + +/******************************************************************************* + @fn llSlaveEvt_TaskAbort0 + + @brief This function is used to handle the PHY task done end cause + TASK_ABORT that can result from one of two causes. First, a + command was issued to start a new task while the hardware was + already executing a task. Second, a CMD_SHUTDOWN command + was received while executing a task. Since the former is + controlled by the LL software it will never happen. Therefore, + this handler is only for a hardware shutdown initiated by the + LL software. + + Note: Issuing a CMD_SHUTDOWN when the hardware is not running + does not cause this end cause to occur, and in fact, has + no effect. + + Possible reasons for the LL issuing this command are: + - A connection timeout occurred (i.e. a LSTO expiration). + - This device's Host requested termination. + + If the LL was in the process of forming a connection (i.e. was + in a Connection Setup procedure), then the LL connection is + immediately terminated (i.e. everything in the RX and TX FIFO + are forfeited, and the Host is notified). If the LL is in a + connection, then a Connection Termination procedure is started + in that the peer device is sent a TERMINATE_IND control packet. + Then the connection is terminated. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void llSlaveEvt_TaskAbort0( void ) +{ + return; +} + + +/******************************************************************************* + @fn ll_adptive_adj_next_time + + @brief will adptive modified following var to adjust the rx window in RTLP + 1.slave_conn_event_recv_delay + 2.pGlobal_config[LL_HW_RTLP_1ST_TIMEOUT + + input parameters + @param none + + output parameters + + @param None + + @return None. +*/ +void ll_adptive_adj_next_time0(uint32 nextTime) +{ + //================================================== + //DO NOT ADD LOG PRINTF In this FUNCTION + //================================================== + (void)(nextTime); + llConnState_t* connPtr; + // get connection information + connPtr = &conn_param[g_ll_conn_ctx.currentConn]; + + //no anche point + if(connPtr->rx_timeout) + connPtr->pmCounter.ll_tbd_cnt1++; + else + connPtr->pmCounter.ll_tbd_cnt1=0; + + //only adj for the 1st rxtimeout + if(1==connPtr->pmCounter.ll_tbd_cnt1) + slave_conn_event_recv_delay+=500; + + //adj for ntrm pkt, each pkt cost 50us in wt tfifo + //if(connPtr->rx_timeout) + slave_conn_event_recv_delay+=((connPtr->ll_buf.ntrm_cnt)*50); +} + + +// process missing slave event +uint8 ll_processMissSlaveEvt(uint8 connId) +{ + llConnState_t* connPtr; +// LOG("-S "); + uint32_t sche_time; + // get connection information + connPtr = &conn_param[connId]; + connPtr->rx_crcok = 0; + connPtr->rx_timeout = 1; + connPtr->pmCounter.ll_conn_event_cnt ++; + connPtr->pmCounter.ll_conn_event_timeout_cnt ++; + connPtr->pmCounter.ll_miss_slave_evt_cnt ++; + + if(p_perStatsByChan!=NULL) + p_perStatsByChan->rxToCnt[connPtr->currentChan]++; + + rfCounters.numTxDone = 0; + rfCounters.numRxNotOk = 0; + rfCounters.numRxIgnored = 0; + rfCounters.numRxEmpty = 0; + rfCounters.numRxFifoFull = 0; + rfCounters.numTxAck = 0; + // update the numTxCtrlAck counter, add on 2017-11-15 + rfCounters.numTxCtrlAck = 0; + // advance the connection event count + connPtr->currentEvent = connPtr->nextEvent; + // collect packet error information + connPtr->perInfo.numMissedEvts++; + // so listen to every event until a packet is received + connPtr->slaveLatency = 0; + + // check if we have a Supervision Timeout + if ( connPtr->expirationEvent == connPtr->currentEvent ) + { + // check if either we already got the first packet in a connection or + // if this isn't the quick LSTO associated with connection establishment + // Note: The Slave reuses firstPacket when a Update Parameter control + // procedure is started, but in that case, the expiration event + // will be well past the event associated with connection + // establishement. + if ( (connPtr->firstPacket == 0) || + (connPtr->currentEvent != LL_LINK_SETUP_TIMEOUT) ) + { + // yes, so terminate with LSTO + llConnTerminate( connPtr, LL_SUPERVISION_TIMEOUT_TERM ); + g_pmCounters.ll_link_lost_cnt ++; + return LL_PROC_LINK_TERMINATE; + } + else // this is a failure to establish the connection + { + // so terminate immediately with failure to establish connection + llConnTerminate( connPtr, LL_CONN_ESTABLISHMENT_FAILED_TERM ); + g_pmCounters.ll_link_estab_fail_cnt ++; + return LL_PROC_LINK_TERMINATE; + } + } + + connPtr->slaveLatency = 0; + + /* + ** Process RX Data Packets, no Rx data for missing event + */ + + /* + ** Check Control Procedure Processing + */ + if ( llProcessSlaveControlProcedures( connPtr ) == LL_CTRL_PROC_STATUS_TERMINATE ) + { + // this connection is terminated, so nothing to schedule + return LL_PROC_LINK_TERMINATE; + } + + /* + ** Process TX Data Packets, no Tx data for missing event + */ + connPtr->accuTimerDrift += connPtr->timerDrift; + + /* + ** Setup Next Slave Event Timing + */ + + // update next event, calculate time to next event, calculate timer drift, + // update anchor points, setup NR T2E1 and T2E2 events + if ( llSetupNextSlaveEvent() == LL_SETUP_NEXT_LINK_STATUS_TERMINATE ) + { + // this connection is terminated, so nothing to schedule + return LL_PROC_LINK_TERMINATE; + } + + // schedule next connection event time + // not really timeout case so not widen the receive windows + sche_time = conn_param[connId].lastTimeToNextEvt * 625 - conn_param[connId].timerDrift; + // update scheduler information + g_ll_conn_ctx.scheduleInfo[connId].remainder += sche_time; + +// ========= + // connection event notify + if (g_conn_taskID != 0) + osal_set_event(g_conn_taskID, g_conn_taskEvent); + + return LL_PROC_LINK_KEEP; +} + + +/******************************************************************************* +*/ diff --git a/src/lib/ble_controller/ll_sleep.c b/src/lib/ble_controller/ll_sleep.c new file mode 100644 index 0000000..a9810cc --- /dev/null +++ b/src/lib/ble_controller/ll_sleep.c @@ -0,0 +1,556 @@ + + +/******************************************************************************* + INCLUDES +*/ +#include "bus_dev.h" +#include "OSAL_PwrMgr.h" +#include "OSAL_Clock.h" +#include "ll_sleep.h" + +#include "ll_def.h" +#include "timer.h" +#include "ll_common.h" +#include "jump_function.h" +#include "global_config.h" +#include "ll_sleep.h" +#include "ll_debug.h" +#include "ll_hw_drv.h" +#include "rf_phy_driver.h" + +/******************************************************************************* + MACROS +*/ +#define SRAM0_ADDRESS 0x1fff0f00 +#define SRAM1_ADDRESS 0x1fff9000 + +/******************************************************************************* + CONSTANTS +*/ + +/******************************************************************************* + Prototypes +*/ + + +/******************************************************************************* + GLOBAL VARIABLES +*/ +uint32 sleep_flag = 0; // when sleep, set this value to SLEEP_MAGIC. when wakeup, set this value to 0 +uint32_t g_wakeup_rtc_tick = 0; +uint32_t g_counter_traking_avg = 3906; + +//used for sleep timer sync +uint32_t g_TIM2_IRQ_TIM3_CurrCount = 0; +uint32_t g_TIM2_IRQ_to_Sleep_DeltTick=0; +uint32_t g_TIM2_IRQ_PendingTick=0; +uint32_t g_osal_tick_trim=0; +uint32_t g_osalTickTrim_mod=0; +uint32_t g_TIM2_wakeup_delay=0; +uint32_t rtc_mod_value = 0; +uint32_t g_counter_traking_cnt = 0; +uint32_t sleep_tick; +uint32_t counter_tracking; // 24bit tracking counter, read from 0x4000f064 +/******************************************************************************* + LOCAL VARIABLES +*/ +static Sleep_Mode sleepMode = SYSTEM_SLEEP_MODE;// MCU_SLEEP_MODE; +static uint8 bSleepAllow = TRUE; + + +volatile uint32_t forever_write; + + +/********************************************************************* + EXTERNAL VARIABLES +*/ +extern uint32 ll_remain_time; +extern uint32 osal_sys_tick; +extern uint8 llState; + +/******************************************************************************* + Functions +*/ + +extern void wakeup_init(void); +extern void set_flash_deep_sleep(void); + +extern void ll_hw_tx2rx_timing_config(uint8 pkt); +extern void ll_hw_trx_settle_config(uint8 pkt); + +// =========================== sleep mode configuration functions +// is sleep allow +uint8 isSleepAllow(void) +{ + return bSleepAllow; +} + +// enable sleep +void enableSleep(void) +{ + bSleepAllow = TRUE; +} + +// disable sleep +void disableSleep(void) +{ + bSleepAllow = FALSE; +} + +// set sleep mode +void setSleepMode(Sleep_Mode mode) +{ + sleepMode = mode; +} + +// get sleep mode configuration +Sleep_Mode getSleepMode(void) +{ + return sleepMode; +} + +//////////////////////////// +// process of enter system sleep mode + +/******************************************************************************* + @fn enterSleepProcess0 + + @brief enter system sleep process function. + + + input parameters + + @param time - sleep RTC ticks + + output parameters + + @param None. + + @return None. +*/ +void enterSleepProcess0(uint32 time) +{ + uint32 delta, total, step, temp; + + // if allow RC 32KHz tracking, adjust the time according to the bias + if (pGlobal_config[LL_SWITCH] & RC32_TRACKINK_ALLOW) + { + // 1. read RC 32KHz tracking counter, calculate 16MHz ticks number per RC32KHz cycle + temp = *(volatile uint32_t*)0x4000f064 & 0x1ffff; +// //====== assume the error cnt is (n+1/2) cycle,for this case, it should be 9 or 10 +// //LOG("c %d\n",temp); +// error_delt = (temp>STD_CRY32_8_CYCLE_16MHZ_CYCLE) +// ? (temp- STD_CRY32_8_CYCLE_16MHZ_CYCLE) : (STD_CRY32_8_CYCLE_16MHZ_CYCLE-temp); +// if(error_delt>3)+ERR_THD_RC32_CYCLE)) +// { +// //temp = ((temp<<3)*455+2048)>>12;//*455/4096~=1/9 +// temp = temp<<3; +// temp = ((temp<<9)-(temp<<6)+(temp<<3)-temp+2048)>>12; +// } +// else +// { +// //temp = ((temp<<3)*410+2048)>>12;//*410/4096~=1/10 +// temp = temp<<3; +// temp = ((temp<<9)-(temp<<6)-(temp<<5)-(temp<<3)+(temp<<1)+2048)>>12; +// } + //check for the abnormal temp value + counter_tracking = (temp>CRY32_16_CYCLE_16MHZ_CYCLE_MAX) ? counter_tracking : temp; + //20181204 filter the counter_tracking spur, due to the N+1 issue + + if(g_counter_traking_cnt<1000) + { + //before traking converage use hard limitation + counter_tracking = (counter_tracking>CRY32_16_CYCLE_16MHZ_CYCLE_MAX || counter_tracking g_counter_traking_avg+(g_counter_traking_avg>>8) + || counter_tracking < g_counter_traking_avg-(g_counter_traking_avg>>8) ) + ? g_counter_traking_avg : counter_tracking; + } + + //one order filer to tracking the average counter_tracking + g_counter_traking_avg = (7*g_counter_traking_avg+counter_tracking)>>3 ; + // 2. adjust the time according to the bias + step = (counter_tracking) >> 3; // accurate step = 500 for 32768Hz timer + + if (counter_tracking > STD_CRY32_16_CYCLE_16MHZ_CYCLE) // RTC is slower, should sleep less RTC tick + { + delta = counter_tracking - STD_CRY32_16_CYCLE_16MHZ_CYCLE; // delta 16MHz tick in 8 32KHz ticks + total = (time * delta) >> 3; // total timer bias in 16MHz tick + + while (total > step) + { + total -= step; + time --; + } + } + else // RTC is faster, should sleep more RTC tick + { + delta = STD_CRY32_16_CYCLE_16MHZ_CYCLE - counter_tracking; // delta 16MHz tick in 8 32KHz ticks + total = (time * delta) >> 3; // total timer bias in 16MHz tick + + while (total > step) + { + total -= step; + time ++; + } + } + } + + // backup registers ------ none now + // backup timers ------ none now + //#warning "need check -- byZQ" + //===20180417 added by ZQ + // for P16,P17 + subWriteReg(&(AP_AON->PMCTL2_0),6,6,0x00); //disable software control + // 3. config wakeup timer + config_RTC(time); + // 4. app could add operation before sleep + app_sleep_process(); + //====== set sram retention + // hal_pwrmgr_RAM_retention_set(); // IMPORTANT: application should set retention in app_sleep_process + ll_debug_output(DEBUG_ENTER_SYSTEM_SLEEP); + // 5. set sleep flag(AON reg & retention SRAM variable) + set_sleep_flag(1); + // 6. trigger system sleep + enter_sleep_off_mode(SYSTEM_SLEEP_MODE); +} + + +/******************************************************************************* + @fn config_RTC API + + @brief This function will configure SRAM retention & comparator + Regs: + 0x4000f024 : RTCCTL + 0x4000f028 : current RTC counter + + input parameters + @param time - sleep time in RC32K ticks, may be adjust + + + output parameters + + @param None. + + @return None + +*/ +void config_RTC0(uint32 time) +{ +// *((volatile uint32_t *)(0xe000e100)) |= INT_BIT_RTC; // remove, we don't use RTC interrupt + // comparator configuration + sleep_tick = *(volatile uint32_t*) 0x4000f028; // read current RTC counter + //align to rtc clock edge + WaitRTCCount(1); + g_TIM2_IRQ_to_Sleep_DeltTick = (g_TIM2_IRQ_TIM3_CurrCount>(AP_TIM3->CurrentCount)) + ? (g_TIM2_IRQ_TIM3_CurrCount-(AP_TIM3->CurrentCount)): 0; + AP_AON->RTCCC0 = sleep_tick + time; //set RTC comparatr0 value +// *(volatile uint32_t *) 0x4000f024 |= 1 << 20; //enable comparator0 envent +// *(volatile uint32_t *) 0x4000f024 |= 1 << 18; //counter overflow interrupt +// *(volatile uint32_t *) 0x4000f024 |= 1 << 15; //enable comparator0 inerrupt + //*(volatile uint32_t *) 0x4000f024 |= 0x148000; // combine above 3 statement to save MCU time + AP_AON->RTCCTL |= BIT(15)|BIT(18)|BIT(20); +} + +/******************************************************************************* + @fn wakeupProcess0 + + @brief wakeup from system sleep process function. + + + input parameters + + @param None + + output parameters + + @param None. + + @return None. +*/ +void wakeupProcess0(void) +{ + uint32 current_RTC_tick; + uint32 wakeup_time, wakeup_time0, next_time; + uint32 sleep_total; + uint32 dlt_tick; + //restore initial_sp according to the app_initial_sp : 20180706 ZQ + __set_MSP(pGlobal_config[INITIAL_STACK_PTR]); + HAL_CRITICAL_SECTION_INIT(); + + //==== 20180416 commented by ZQ + // to enable flash access after wakeup + // current consumption has been checked. No big different + //rom_set_flash_deep_sleep(); + + //=======fix sram_rent issue 20180323 + //hal_pwrmgr_RAM_retention_clr(); + //subWriteReg(0x4000f01c,21,17,0); + + if (sleep_flag != SLEEP_MAGIC) + { + // enter this branch not in sleep/wakeup scenario + set_sleep_flag(0); + // software reset + *(volatile uint32*)0x40000010 &= ~0x2; // bit 1: M0 cpu reset pulse, bit 0: M0 system reset pulse. + } + + // restore HW registers + wakeup_init(); + //===20180417 added by ZQ + // could be move into wakeup_init + // add the patch entry for tx2rx/rx2tx interval config + //2018-11-10 by ZQ + //config the tx2rx timing according to the g_rfPhyPktFmt + ll_hw_tx2rx_timing_config(g_rfPhyPktFmt); + + if (pGlobal_config[LL_SWITCH] & LL_RC32K_SEL) + { + subWriteReg(0x4000f01c,16,7,0x3fb); //software control 32k_clk + subWriteReg(0x4000f01c,6,6,0x01); //enable software control + } + else + { + subWriteReg(0x4000f01c,9,8,0x03); //software control 32k_clk + subWriteReg(0x4000f01c,6,6,0x00); //disable software control + } + + //20181201 by ZQ + //restart the TIM2 to align the RTC + //---------------------------------------------------------- + //stop the 625 timer + AP_TIM2->ControlReg=0x0; + AP_TIM2->ControlReg=0x2; + AP_TIM2->LoadCount = 2500; + //---------------------------------------------------------- + //wait rtc cnt change + WaitRTCCount(1); + //---------------------------------------------------------- + //restart the 625 timer + AP_TIM2->ControlReg=0x3; + current_RTC_tick = rtc_get_counter(); + //g_TIM2_wakeup_delay= (AP_TIM2->CurrentCount)+12; //12 is used to align the rtc_tick + wakeup_time0 = read_current_fine_time(); + g_wakeup_rtc_tick = rtc_get_counter(); + // rf initial entry, will be set in app + rf_init(); + + if(current_RTC_tick>sleep_tick) + { + dlt_tick = current_RTC_tick - sleep_tick; + } + else + { + //dlt_tick = current_RTC_tick+0x00ffffff - sleep_tick; + dlt_tick = (0xffffffff - sleep_tick)+current_RTC_tick; + } + + //dlt_tick should not over 24bit + //otherwise, sleep_total will overflow !!! + if(dlt_tick>0x3fffff) + dlt_tick &=0x3fffff; + + if (pGlobal_config[LL_SWITCH] & RC32_TRACKINK_ALLOW) + { + //sleep_total = ((current_RTC_tick - sleep_tick) * counter_tracking) >> 7; // shift 4 for 16MHz -> 1MHz, shift 3 for we count 8 RTC tick + // sleep_total = ((((dlt_tick &0xffff0000)>>16)*counter_tracking)<<9) + // + (((dlt_tick &0xffff)*counter_tracking)>>7); + //counter_tracking default 16 cycle + sleep_total = ((((dlt_tick &0xffff0000)>>16)*counter_tracking)<<8) + + (((dlt_tick &0xffff)*counter_tracking)>>8); + } + else + { + // time = tick * 1000 0000 / f (us). f = 32000Hz for RC, f = 32768Hz for crystal. We also calibrate 32KHz RC to 32768Hz + //sleep_total = ((current_RTC_tick - sleep_tick) * TIMER_TO_32K_CRYSTAL) >> 2; + //fix sleep timing error + sleep_total = ( ( (dlt_tick<<7)-(dlt_tick<<2)-(dlt_tick<<1) +2) >>2 ) /* dlt_tick * (128-4-2)/4 */ + +( ( (dlt_tick<<3)+ dlt_tick +128) >>9 ) ; /* dlt_tick *9/512 */ + //+2,+128 for zero-mean quanization noise + } + + // restore systick + g_osal_tick_trim = (pGlobal_config[OSAL_SYS_TICK_WAKEUP_TRIM]+g_TIM2_IRQ_to_Sleep_DeltTick+2500-g_TIM2_IRQ_PendingTick)>>2; //16 is used to compensate the cal delay + g_osalTickTrim_mod+=(pGlobal_config[OSAL_SYS_TICK_WAKEUP_TRIM]+g_TIM2_IRQ_to_Sleep_DeltTick+2500-g_TIM2_IRQ_PendingTick)&0x03; //16 is used to compensate the cal delay + + if(g_osalTickTrim_mod>4) + { + g_osal_tick_trim+=1; + g_osalTickTrim_mod = g_osalTickTrim_mod%4; + } + + // restore systick + osal_sys_tick += (sleep_total+g_osal_tick_trim) / 625; // convert to 625us systick + rtc_mod_value += ((sleep_total+g_osal_tick_trim)%625); + + if(rtc_mod_value > 625) + { + osal_sys_tick += 1; + rtc_mod_value = rtc_mod_value%625; + } + + osalTimeUpdate(); + + // osal time update, not required. It will be updated when osal_run_system() is called after wakeup + + // TODO: should we consider widen the time drift window ???? + + //20190117 ZQ + if(llState != LL_STATE_IDLE) + { + // SW delay + wakeup_time = read_current_fine_time() - wakeup_time0; + next_time = 0; + + if (ll_remain_time > sleep_total + wakeup_time) + { + next_time = ll_remain_time - sleep_total - wakeup_time; + // restore LL timer + set_timer(AP_TIM1, next_time); + } + else + { + // should not be here + set_timer(AP_TIM1, 1000); + } + } + + if (g_llSleepContext.isTimer4RecoverRequired) + { + // SW delay + wakeup_time = read_current_fine_time() - wakeup_time0; + next_time = 0; + + if (g_llSleepContext.timer4Remainder > sleep_total + wakeup_time) + { + next_time = g_llSleepContext.timer4Remainder - sleep_total - wakeup_time; + // restore LL timer + set_timer(AP_TIM4, next_time); + } + else + { + // should not be here + set_timer(AP_TIM4, 1500); + // next_time = 0xffff; + } + + g_llSleepContext.isTimer4RecoverRequired = FALSE; + } + + // app could add operation after wakeup + app_wakeup_process(); +// uart_tx0(" 111 "); + ll_debug_output(DEBUG_WAKEUP); + set_sleep_flag(0); + // ==== measure value, from RTC counter meet comparator 0 -> here : 260us ~ 270us + // start task loop + osal_start_system(); +} + +/************************************************************************************** + @fn set_sleep_flag + + @brief This function set/clear sleep flag in 2 ways: 1. AON reg 0x4000f0a8 + 2. global variable "sleep_flag" + + input parameters + + @param flag - 0 clear the sleep flag, 1 set the sleep flag. + + output parameters + + @param None. + + @return None. +*/ +void set_sleep_flag(int flag) +{ + if(flag) + { + *(volatile uint32_t*) 0x4000f0a8 |= 1 ; + sleep_flag = SLEEP_MAGIC ; + } + else + { + *(volatile uint32_t*) 0x4000f0a8 &= ~1; + sleep_flag = 0 ; + } +} + +/************************************************************************************** + @fn get_sleep_flag + + @brief This function read the AON reg 0x4000f0a8 + + + input parameters + + @param None. + + output parameters + + @param None. + + @return value of AON reg 0x4000f0a8. +*/ +unsigned int get_sleep_flag(void) +{ + return (*(volatile uint32_t*) 0x4000f0a8); +} + +/************************************************************************************** + @fn enter_sleep_off_mode + + @brief This function will trigger + + + input parameters + + @param mode - sleep mode, could be SYSTEM_SLEEP_MODE and SYSTEM_OFF_MODE. + + output parameters + + @param None. + + @return None +*/ +void enter_sleep_off_mode0(Sleep_Mode mode) +{ + //uint32 sram0, sram1; + + // read data from sram0 - sram4 + //sram0 = *(uint32 *)(SRAM0_ADDRESS); + //sram1 = *(uint32 *)(SRAM1_ADDRESS); + if(mode == SYSTEM_SLEEP_MODE) + { + *(volatile uint32_t*) 0x4000f004 = 0xa5a55a5a; //enter system sleep mode + } + else if(mode == SYSTEM_OFF_MODE) + { + *(volatile uint32_t*) 0x4000f000 = 0x5a5aa5a5; //enter system off mode + } + + // write back sram0 - sram4, HW need read sram clock so that the sram could enter retention mode, + // otherwise it will enter standby mode which will consume more power + //*(volatile uint32 *)(SRAM0_ADDRESS) = sram0; + //*(volatile uint32 *)(SRAM1_ADDRESS) = sram1; + + //same as Prime + while (1) // from config reg to sleep cost about 10us, halt the process + { + forever_write = 0x12345678; + } +} + + + + diff --git a/src/lib/ble_controller/rf_phy_driver.c b/src/lib/ble_controller/rf_phy_driver.c new file mode 100644 index 0000000..cd4047f --- /dev/null +++ b/src/lib/ble_controller/rf_phy_driver.c @@ -0,0 +1,2416 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/******************************************************************************* + @file rf_phy_driver.c + @brief Contains all functions support for PHYPLUS RF_PHY_DRIVER + @version 1.0 + @date 24. Aug. 2017 + @author Zhongqi Yang + + + +*******************************************************************************/ + + +/******************************************************************************* + INCLUDES +*/ + +#include "rf_phy_driver.h" +#include "mcu.h" +#include "clock.h" +#include "timer.h" +#include "ll_hw_drv.h" + +/******************************************************************************* + BUILD CONFIG +*/ + +#define RF_PHY_DTM_CTRL_NONE 0x00 +#define RF_PHY_DTM_CTRL_UART 0x01 +#define RF_PHY_DTM_CTRL_HCI 0x02 + +#define RF_PHY_DTM_BB_SUPPORT_BLE1M 0x01 +#define RF_PHY_DTM_BB_SUPPORT_BLE2M 0x02 +#define RF_PHY_DTM_BB_SUPPORT_BLR500K 0x04 +#define RF_PHY_DTM_BB_SUPPORT_BLR125K 0x08 +#define RF_PHY_DTM_BB_SUPPORT_ZIGBEE 0x10 + +#define RF_PHY_DTM_BB_SUPPORT_BLR_CODED (RF_PHY_DTM_BB_SUPPORT_BLR500K|RF_PHY_DTM_BB_SUPPORT_BLR125K) +#define RF_PHY_DTM_BB_SUPPORT_BLE_5 (RF_PHY_DTM_BB_SUPPORT_BLE1M|RF_PHY_DTM_BB_SUPPORT_BLE2M|RF_PHY_DTM_BB_SUPPORT_BLR_CODED) +#define RF_PHY_DTM_BB_SUPPORT_FULL (RF_PHY_DTM_BB_SUPPORT_ZIGBEE|RF_PHY_DTM_BB_SUPPORT_BLE_5) + + +// TODO: move to phypuls_build_cfg.h +#define RF_PHY_DTM_CTRL_MOD RF_PHY_DTM_CTRL_UART +#define RF_PHY_DTM_BB_SUPPORT_MOD RF_PHY_DTM_BB_SUPPORT_BLE_5 + + +#define RF_PHY_CT_MONITER 0 // VCO corase tuning moniter counter +// 0 : disable moniter +// other: enable +#define RF_PHY_TIME_BASE TIME_BASE +#define RF_PHY_TIME_DELTA(x,y) TIME_DELTA(x,y) + +/******************************************************************************* + Global Var +*/ +//volatile uint8_t g_rfPhyTpCal0 = 0x2d; +//volatile uint8_t g_rfPhyTpCal1 = 0x23; +//volatile uint8_t g_rfPhyTpCal0_2Mbps = 0x47; +//volatile uint8_t g_rfPhyTpCal1_2Mbps = 0x45; +//volatile uint8_t g_rfPhyTxPower = 0x0f; +//volatile uint8_t g_rfPhyPktFmt = PKT_FMT_BLE1M; +//volatile uint32 g_rfPhyRxDcIQ = 0x20200000; +//volatile int8_t g_rfPhyFreqOffSet = RF_PHY_FREQ_FOFF_00KHZ; +//volatile sysclk_t g_system_clk = SYS_CLK_XTAL_16M; +//volatile rfphy_clk_t g_rfPhyClkSel = RF_PHY_CLK_SEL_16M_XTAL; +//volatile rxadc_clk_t g_rxAdcClkSel = RX_ADC_CLK_SEL_32M_DBL; +// volatile uint8_t g_rfPhyDtmCmd[2] = {0}; +// volatile uint8_t g_rfPhyDtmEvt[2] = {0}; + +// volatile uint8_t g_dtmModeType = 0; + +// volatile uint8_t g_dtmCmd = 0; +// volatile uint8_t g_dtmFreq = 0; +// volatile uint8_t g_dtmLength = 0; +// volatile uint8_t g_dtmExtLen = 0; + +// volatile uint16_t g_dtmPktIntv = 0; + + +// volatile uint8_t g_dtmPKT = 0; +// volatile uint8_t g_dtmCtrl = 0; +// volatile uint8_t g_dtmPara = 0; +// volatile uint8_t g_dtmEvt = 0; +// volatile uint8_t g_dtmStatus = 0; +// volatile uint16_t g_dtmPktCount = 0; +// volatile uint16_t g_dtmRxCrcNum = 0; +// volatile uint16_t g_dtmRxTONum = 0; +// volatile uint16_t g_dtmRsp = 0; + +// volatile uint8_t g_dtmTxPower = RF_PHY_TX_POWER_0DBM;//RF_PHY_TX_POWER_EXTRA_MAX;//according to the rfdrv +// volatile uint16_t g_dtmFoff = 0; +// volatile uint8_t g_dtmRssi = 0; +// volatile uint8_t g_dtmCarrSens = 0; +// volatile uint8_t g_dtmTpCalEnable = 1; //default enable tpcal + +// volatile uint32_t g_dtmTick = 0; +// volatile uint32_t g_dtmPerAutoIntv = 0; + +// volatile uint32_t g_dtmAccessCode = RF_PHY_DTM_SYNC_WORD; +volatile uint8_t g_dtmManualConfig = RF_PHY_DTM_MANUL_ALL; +//volatile uint8_t g_rc32kCalRes = 0xff; +// extern volatile int uart_rx_wIdx; // +// extern volatile char *urx_buf; + +#if(RF_PHY_DTM_CTRL_MOD == RF_PHY_DTM_CTRL_UART) + #include "log.h" + #define MAX_UART_BUF_SIZE 32 + #define MAX_UART_BUF_ID (MAX_UART_BUF_SIZE-1) + #define _DTM_UART_ UART0 + #define DTM_OUT(x) hal_uart_send_byte(_DTM_UART_,x) + #define DTM_LOG_INIT(...) dbg_printf_init() + #define DTM_LOG(s) dbg_printf(s) + #define CLR_UART_WIDX {uart_rx_wIdx=0;} + #define GET_UART_WIDX (uart_rx_wIdx) + #define DTM_ADD_IDX(a,b) {(a==b)? a=0:a++;} + static unsigned char urx_buf[MAX_UART_BUF_SIZE]; + static volatile uint32_t uart_rx_wIdx=0,uart_rx_rIdx=0; +#endif + +#if(RF_PHY_CT_MONITER) +#define CT_MONT_BUFF_SIZE 128 +volatile uint32_t g_rfPhy_ct_moniter_word_cnt = 0; +volatile uint32_t g_rfPhy_ct_moniter_word_target = 0; +volatile uint16_t g_rfPhy_ct_moniter_word_arry[CT_MONT_BUFF_SIZE] = {0}; +#endif + + +void rf_tpCal_cfg_avg(uint8 rfChn,uint8 cnt); +/************************************************************************************** + @fn rf_phy_ini + + @brief This function process for rf phy ini call api + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void rf_phy_ini(void) +{ + g_rfPhyClkSel = RF_PHY_CLK_SEL_16M_XTAL; + g_rxAdcClkSel = RX_ADC_CLK_SEL_32M_DBL; + rf_phy_ana_cfg(); + rf_phy_set_txPower(g_rfPhyTxPower);//set to max power + rf_phy_bb_cfg(g_rfPhyPktFmt); + extern void ll_hw_tx2rx_timing_config(uint8 pkt); + ll_hw_tx2rx_timing_config(g_rfPhyPktFmt); +} + +/************************************************************************************** + @fn rf_tpCal_cfg + + @brief This function process for rf tpCal config + + input parameters + + @param rfChn: two point calibration rf channel setting(0-80)->2400-2480MHz. + + output parameters + + @param None. + + @return None. +*/ +void rf_tpCal_cfg(uint8 rfChn) +{ + if( g_rfPhyPktFmt==PKT_FMT_BLE1M + || g_rfPhyPktFmt==PKT_FMT_BLR500K + || g_rfPhyPktFmt==PKT_FMT_BLR125K) + { + //g_rfPhyTpCal0=rf_tp_cal(rfChn,0)+5; + //ZQ:debug 20180427 + g_rfPhyTpCal0=rf_tp_cal(rfChn,0)+8; + } + else if( g_rfPhyPktFmt==PKT_FMT_BLE2M ) + { + g_rfPhyTpCal0=rf_tp_cal(rfChn,1)+4; + } + else + { + //for ZIGBEE + g_rfPhyTpCal0=rf_tp_cal(rfChn,1)+4; + } +} + + +/************************************************************************************** + @fn rf_tpCal_cfg_avg + + @brief This function process for rf tpCal config + + input parameters + + @param rfChn: two point calibration rf channel setting(0-80)->2400-2480MHz. + + output parameters + + @param None. + + @return None. +*/ +void rf_tpCal_cfg_avg(uint8 rfChn,uint8 avgNum) +{ + volatile uint8_t i = 0; + volatile uint16_t tmp=0; + + if( g_rfPhyPktFmt==PKT_FMT_BLE1M + || g_rfPhyPktFmt==PKT_FMT_BLR500K + || g_rfPhyPktFmt==PKT_FMT_BLR125K) + { + //g_rfPhyTpCal0=rf_tp_cal(rfChn,0)+5; + //ZQ:debug 20180427 + for ( i=0; i<(1<>avgNum)+8; + } + else if( g_rfPhyPktFmt==PKT_FMT_BLE2M ) + { + for ( i=0; i<(1<>avgNum)+4; + } + else + { + //for ZIGBEE + for ( i=0; i<(1<>avgNum)+4; + } +} + + +/************************************************************************************** + @fn rf_tpCal_gen_cap_arrary + + @brief This function process for tx tp calibration,genearte the tpCal cap arrary. + + input parameters + + @param + + output parameters + + @param none + + @return kCal : cal result for rfChn. +*/ + +void rf_tpCal_gen_cap_arrary(void) +{ + g_rfPhyTpCal0=rf_tp_cal(/*/rfChn*/2,0)+2; + g_rfPhyTpCal1=rf_tp_cal(/*/rfChn*/66,0)+2; + g_rfPhyTpCal0_2Mbps=rf_tp_cal(/*/rfChn*/2,1)+2; + g_rfPhyTpCal1_2Mbps=rf_tp_cal(/*/rfChn*/66,1)+2; +} + +/************************************************************************************** + @fn rf_phy_ana_cfg + + @brief This function process for rf phy analog block config, + include PLL, RX_FRONT_END,PA Power. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void rf_phy_ana_cfg(void) +{ + //------------------------------------------------------------------- + // RF_PHY RX ADC CLOCK Config + subWriteReg(0x4000f040,18,18, 0x01); // xtal output to digital enable : ALWAYS Set 1 + subWriteReg(0x4000f044,25,24, g_rxAdcClkSel); + subWriteReg(0x4000f044,23,22, g_rfPhyClkSel); + subWriteReg(0x4000f044, 6, 5, 0x03); // trim dll/dbl ldo vout + + if( (g_rxAdcClkSel == RX_ADC_CLK_SEL_32M_DBL) + || (g_rxAdcClkSel == RX_ADC_CLK_SEL_32M_DBL_B) + || (g_rfPhyClkSel == RF_PHY_CLK_SEL_32M_DBL) + || (g_rfPhyClkSel == RF_PHY_CLK_SEL_32M_DBL_B) ) + { + // enable dbl for rf + subWriteReg(0x4000f044, 8, 8, 0x01); // DBL EN,DLL EN,DLL LDO EN + } + + if( (g_rxAdcClkSel == RX_ADC_CLK_SEL_32M_DLL) + || (g_rfPhyClkSel == RF_PHY_CLK_SEL_32M_DLL) + ) + { + // enable dll for rf + subWriteReg(0x4000f044, 7, 7, 0x01); // DLL ensable + } + + subWriteReg(0x4000f044, 19, 18, 0x03); // Rx adc clk en, rf phy clk en + #if 0 + + //Reserved????? + //20190111 ZQ + // for 48M case should set dbl clk polarity + //config sel_rxadc_dbl_clk_32M_polarity; + if((g_system_clk==SYS_CLK_DLL_48M) ) + { + subWriteReg(0x4000f044,26,25, 0x03); + } + else + { + subWriteReg(0x4000f044,26,25, 0x00); + } + + #endif + + if(g_rfPhyClkSel==RF_PHY_CLK_SEL_16M_XTAL && g_system_clk == SYS_CLK_DLL_48M) + subWriteReg( 0x4003008c,23,23,0x01); + else + subWriteReg( 0x4003008c,23,23,0x00); + + //------------------------------------------------------------------- + // PLL + PHY_REG_WT(0x400300cc,0x20000bc0); // i_pll_ctrl0 : + //PHY_REG_WT(0x400300cc,0x20000fc0); // i_pll_ctrl0 : + //------------------------------------------------------------------- + //TX PLL BW + PHY_REG_WT(0x400300d0,0x00000180); // i_pll_ctrl1 + PHY_REG_WT(0x400300d4,0x076a3e7a); // i_pll_ctrl2 pll lpf, boost vco current[7:4] + PHY_REG_WT(0x400300d8,0x04890000); // i_pll_ctrl3 vco/tp varactor + //------------------------------------------------------------------- + //RX PLL BW active when rx_en + PHY_REG_WT(0x40030104,0x00000180); // i_pll_ctrl5 + PHY_REG_WT(0x40030108,0x076a3e7a); // i_pll_ctrl6 pll lpf, boost vco current[7:4] + PHY_REG_WT(0x4003010c,0x04898000); // i_pll_ctrl7 vco/tp varactor + //------------------------------------------------------------------- + //VCO Coarse Tuning Setting + PHY_REG_WT(0x40030080,0x000024cc); //[11:10] vco coarse tune slot time + //[9:7] delay from pll reset ends to start vco coarse tune + + //------------------------------------------------------------------- + //PLL config for rfPhyClk=16M + if(g_rfPhyClkSel==RF_PHY_CLK_SEL_16M_XTAL) + { + subWriteReg(0x40030080, 0, 0, 1);//indicate 16M reference clk to rfpll + //PHY_REG_WT(0x400300d0,0x00000140); // i_pll_ctrl1 //double cp current to compensate for clock; + //PHY_REG_WT(0x40030104,0x00000140); // i_pll_ctrl5 //double cp current to compensate for clock; + } + + //------------------------------------------------------------------- + // Tx PA + //PHY_REG_WT(0x400300b8,0x0000f825); // pa ramp reg, txPower for 0dBm + PHY_REG_WT(0x400300b8,0x0825|(((g_rfPhyTxPower)&0x1f)<<12)); // pa ramp reg, txPower for g_rfPhyTxPower + //------------------------------------------------------------------- + // TP Modulation + //PHY_REG_WT(0x40030090,0x00020000); // reg dc 40000 for 2M + //PHY_REG_WT(0x40030094,0x00001025); // tp_cal val + //PHY_REG_WT(0x400300b0,0x01000003); // dac dly + //------------------------------------------------------------------- + // Rx FrontEnd + //PHY_REG_WT(0x400300dc,0x01be7f2f); // + PHY_REG_WT(0x400300dc,0x01a6fc2f); // boost TIA current + //------------------------------------------------------------------- + //PA override + //subWriteReg(0x400300a0,0,0,1); //pa override + //subWriteReg(0x400300a4,0,0,1); //pa on + //subWriteReg(0x400300a4,8,8,0); //pa set b +} + + + + +/************************************************************************************** + @fn rf_phy_bb_cfg + + @brief This function process for rf phy baseband tx and rx config. + + input parameters + + @param pktMod:0 for Zigbee, 1 for BLE1M, 2 for BLE2M, 3or4 for BLELR. + + output parameters + + @param None. + + @return None. +*/ +void rf_phy_bb_cfg(uint8_t pktFmt) +{ + //BW Sel and Gauss sel + if(pktFmt==0 || pktFmt==2) + { + PHY_REG_WT( 0x400300e0,0x00000080); // set pga bw use small bw for zigbee and BLE2M + subWriteReg( 0x400300d8,20,18,0x02); // tpm dac var + + if(g_rfPhyClkSel == RF_PHY_CLK_SEL_16M_XTAL) + PHY_REG_WT( 0x40030090,0x00080000); // set reg_dc + else + PHY_REG_WT( 0x40030090,0x00040000); // set reg_dc + + //PHY_REG_WT( 0x40030094,0x00001048); // tp_cal val + } + else if(pktFmt<5) + { + PHY_REG_WT( 0x400300e0,0x00000100); // set pga bw + subWriteReg( 0x400300d8,20,18,0x01); // tpm dac var + + //subWriteReg( 0x400300d8,20,18,0x02); // tpm dac var + if(g_rfPhyClkSel == RF_PHY_CLK_SEL_16M_XTAL) + PHY_REG_WT( 0x40030090,0x00040000); // set reg_dc + else + PHY_REG_WT( 0x40030090,0x00020000); // set reg_dc + + //PHY_REG_WT( 0x40030094,0x00001025); // tp_cal val + } + else + { + PHY_REG_WT( 0x400300e0,0x00000100); // set pga bw + subWriteReg( 0x400300d8,20,18,0x01); // tpm dac var + + if(g_rfPhyClkSel == RF_PHY_CLK_SEL_16M_XTAL) + PHY_REG_WT( 0x40030090,0x00040000); // set reg_dc + else + PHY_REG_WT( 0x40030090,0x00020000); // set reg_dc + } + + PHY_REG_WT( 0x400300b0,0x01000003); // dac dly + PHY_REG_WT( 0x40030094,0x00001000+g_rfPhyTpCal0); // tp_cal val + + //pktFmt Setting and syncThd + if(pktFmt==0) + { + PHY_REG_WT( 0x40030000,0x78068000); + PHY_REG_WT( 0x40030048,0x00000000); //clr crc and wtSeed + PHY_REG_WT( 0x40030040,0x000b2800); // disable gauss + PHY_REG_WT( 0x4003004c,0x3675ee07); + ll_hw_set_crc_fmt (LL_HW_CRC_ZB_FMT, LL_HW_CRC_ZB_FMT); + } + else if(pktFmt==1) + { + PHY_REG_WT( 0x40030000,0x3d068001); + PHY_REG_WT( 0x40030048,0x37555555); + PHY_REG_WT( 0x40030040,0x00032800); // enable gauss + PHY_REG_WT( 0x4003004c,0x8e89bed6); + ll_hw_set_crc_fmt (LL_HW_CRC_BLE_FMT, LL_HW_CRC_BLE_FMT); + } + else if(pktFmt==2) + { + PHY_REG_WT( 0x40030000,0x3d068002); + PHY_REG_WT( 0x40030048,0x37555555); + PHY_REG_WT( 0x40030040,0x00032800); // enable gauss + PHY_REG_WT( 0x4003004c,0x8e89bed6); + ll_hw_set_crc_fmt (LL_HW_CRC_BLE_FMT, LL_HW_CRC_BLE_FMT); + } + else if(pktFmt==3 || pktFmt==4) + { + //pktFmt=3 or pktFmt=4 + PHY_REG_WT( 0x40030000,0x98068000|pktFmt); //for tx set differnt phy + PHY_REG_WT( 0x40030004,0x50985a54); //for RSSI >-90 set higher syncThd=0x98 + PHY_REG_WT( 0x40030040,0x00032800); // enable gauss + PHY_REG_WT( 0x40030048,0x37555555); + PHY_REG_WT( 0x4003004c,0x8e89bed6); + ll_hw_set_crc_fmt (LL_HW_CRC_BLE_FMT, LL_HW_CRC_BLE_FMT); + } + else + { + PHY_REG_WT( 0x40030000,0x42068000|pktFmt); + PHY_REG_WT( 0x40030048,0x00555555); + PHY_REG_WT( 0x40030040,0x000b2800); // enable gauss + PHY_REG_WT( 0x4003004c,0x8e89bed6); + ll_hw_set_crc_fmt (LL_HW_CRC_BLE_FMT, LL_HW_CRC_BLE_FMT); + } + + //Agc Control Setting + if(pktFmt==0) + { + PHY_REG_WT( 0x40030050,0x22086680); + } + else if(pktFmt==2) + { + PHY_REG_WT( 0x40030050,0x22084580); + } + else + { + PHY_REG_WT( 0x40030050,0x22085580); + } + + // add by ZQ 20181030 for DLE feature + // set to 255 + // need considering the ADV PDU in BLE 5.0 + subWriteReg(0x4003000c,7,0, 0xff); + //AGC TAB with LNA two gain step,no bypass lna mode + //20200721 for tsop 6252 + PHY_REG_WT(0x40030054, 0x545c9ca4); + PHY_REG_WT(0x40030058, 0x4243444c); + PHY_REG_WT(0x4003005c, 0x464c5241); + PHY_REG_WT(0x40030060, 0x2e343a40); + PHY_REG_WT(0x40030064, 0x557f0028); + PHY_REG_WT(0x40030068, 0x3d43494f); + PHY_REG_WT(0x4003006c, 0x4c2b3137); + PHY_REG_WT(0x40030070, 0x343a4046); + PHY_REG_WT(0x40030074, 0x1c22282e); + #if 0 + PHY_REG_WT( 0x40030054,0x545c9ca4 ); + PHY_REG_WT( 0x40030058,0x03040c4c ); + PHY_REG_WT( 0x4003005c,0x464c5202 ); + PHY_REG_WT( 0x40030060,0x262e3a40 ); + PHY_REG_WT( 0x40030064,0x557f0020 ); + PHY_REG_WT( 0x40030068,0x3b43494f ); + PHY_REG_WT( 0x4003006c,0x4c23292f ); + PHY_REG_WT( 0x40030070,0x343a4046 ); + PHY_REG_WT( 0x40030074,0x191f252b ); + #endif + #if(RF_PHY_EXT_PREAMBLE_US) + + //ext preamble for BLE 1M/2M, nByte + if(pktFmt==PKT_FMT_BLE1M) + { + subWriteReg(0x40030040, 7, 5, (RF_PHY_EXT_PREAMBLE_US>>3) ); // 1byte -> 8us + } + else if(pktFmt == PKT_FMT_BLE2M) + { + subWriteReg(0x40030040, 7, 5, (RF_PHY_EXT_PREAMBLE_US>>2) );//2 byte -> 8us + } + else + { + subWriteReg(0x40030040, 7, 5, (0) ); + } + + #endif +} + + +void rf_phy_change_cfg0(uint8_t pktFmt) +{ + //BW Sel and Gauss sel + if(pktFmt==PKT_FMT_BLE2M) + { + PHY_REG_WT( 0x400300e0,0x00000080); // set pga bw use small bw for zigbee and BLE2M + subWriteReg( 0x400300d8,20,18,0x02); // tpm dac var + + if(g_rfPhyClkSel == RF_PHY_CLK_SEL_16M_XTAL) + PHY_REG_WT( 0x40030090,0x00080000); // set reg_dc + else + PHY_REG_WT( 0x40030090,0x00040000); // set reg_dc + + //PHY_REG_WT( 0x40030094,0x00001048); // tp_cal val + } + else + { + PHY_REG_WT( 0x400300e0,0x00000080); // set pga bw + subWriteReg( 0x400300d8,20,18,0x01); // tpm dac var + + if(g_rfPhyClkSel == RF_PHY_CLK_SEL_16M_XTAL) + PHY_REG_WT( 0x40030090,0x00040000); // set reg_dc + else + PHY_REG_WT( 0x40030090,0x00020000); // set reg_dc + + //PHY_REG_WT( 0x40030094,0x00001025); // tp_cal val + } + + //pktFmt Setting and syncThd + if(pktFmt==PKT_FMT_BLE1M) + { + PHY_REG_WT( 0x40030000,0x3d068001); + } + else if(pktFmt==PKT_FMT_BLE2M) + { + PHY_REG_WT( 0x40030000,0x3d068002); + } + else + { + //pktFmt=3 or pktFmt=4 + PHY_REG_WT( 0x40030000,0x98068000|pktFmt); //for tx set differnt phy + } + + //Agc Control Setting + if(pktFmt==PKT_FMT_BLE1M) + { + PHY_REG_WT( 0x40030050,0x22086680); + } + else if(pktFmt==PKT_FMT_BLE2M) + { + PHY_REG_WT( 0x40030050,0x22084580); + } + else + { + PHY_REG_WT( 0x40030050,0x22085580); + } + + #if(RF_PHY_EXT_PREAMBLE_US) + + //ext preamble for BLE 1M/2M, nByte + if(pktFmt==PKT_FMT_BLE1M) + { + subWriteReg(0x40030040, 7, 5, (RF_PHY_EXT_PREAMBLE_US>>3) ); // 1byte -> 8us + } + else if(pktFmt == PKT_FMT_BLE2M) + { + subWriteReg(0x40030040, 7, 5, (RF_PHY_EXT_PREAMBLE_US>>2) );//2 byte -> 8us + } + else + { + subWriteReg(0x40030040, 7, 5, (0) ); + } + + #endif +} +/************************************************************************************** + @fn rf_tp_cal + + @brief This function process for tx tp calibration. + + input parameters + + @param rfChn : rfFreq=2400+rfChn + fDev : used to config the tpCal fDelt, 0 for 0.5M, 1 for 1M + + + output parameters + + @param none + + @return kCal : cal result for rfChn. +*/ +uint8_t rf_tp_cal(uint8_t rfChn, uint8_t fDev) +{ + PHY_REG_WT( 0x40030040,0x00030010); // enable test mode not to generate txdone + + if(fDev==1) + { + subWriteReg( 0x400300d8,20,18,0x02); // tpm dac var + PHY_REG_WT( 0x4003008c,0x0053407f); + } + else + { + subWriteReg( 0x400300d8,20,18,0x01); // tpm dac var + PHY_REG_WT( 0x4003008c,0x0073407f); + } + + if(g_rfPhyClkSel==RF_PHY_CLK_SEL_16M_XTAL && g_system_clk == SYS_CLK_DLL_48M) + subWriteReg( 0x4003008c,23,23,0x01); + else + subWriteReg( 0x4003008c,23,23,0x00); + + PHY_REG_WT( 0x400300b4,0xff&rfChn); // set rfFreq=2400+rfChn + PHY_REG_WT( 0x400300a0,0x0000000e); // set pll_auto override + //------------------------------------------------------------------------- + // Cal Trig + // + PHY_REG_WT( 0x400300a4,0x00000000); // clr tx_auto + PHY_REG_WT( 0x400300a4,0x00000114); // set tx_auto + //------------------------------------------------------------------------- + // Wait to Read Reslut + // When HCLK 16M --> 10000*3/16 around 2ms + volatile int timeOut = 10000; + + switch (g_system_clk) + { + case SYS_CLK_XTAL_16M: + timeOut=timeOut; + break; + + case SYS_CLK_RC_32M: + case SYS_CLK_DBL_32M: + timeOut=timeOut*2; + break; + #if (PHY_MCU_TYPE == MCU_BUMBEE_M0 || PHY_MCU_TYPE == MCU_BUMBEE_CK802) + + case SYS_CLK_4M: + break; + + case SYS_CLK_8M: + break; + #elif ((PHY_MCU_TYPE == MCU_PRIME_A1) ||(PHY_MCU_TYPE == MCU_PRIME_A2)) + + case SYS_CLK_DBL_32M: + timeOut=timeOut*2; + break; + #endif + + case SYS_CLK_DLL_48M: + timeOut=timeOut*3; + break; + + case SYS_CLK_DLL_64M: + timeOut=timeOut*4; + break; + + default: + timeOut=timeOut; + break; + } + + while(timeOut--) {}; + + uint8_t kCal = (0xff0000 & PHY_REG_RD(0x400300f4))>>16; + + PHY_REG_WT( 0x400300a4,0x00000000); // clr tx_auto + + PHY_REG_WT( 0x400300a0,0x00000000); // clr pll_auto override + + PHY_REG_WT( 0x4003008c,0x00104040); // clr tp_cal_en + + PHY_REG_WT( 0x400300a4,0x00000140); // clr tx_auto + + PHY_REG_WT( 0x40030040,0x00032800); + + #if(RF_PHY_EXT_PREAMBLE_US) + + //ext preamble for BLE 1M/2M, nByte + if(g_rfPhyPktFmt==PKT_FMT_BLE1M) + { + subWriteReg(0x40030040, 7, 5, (RF_PHY_EXT_PREAMBLE_US>>3) ); // 1byte -> 8us + } + else if(g_rfPhyPktFmt == PKT_FMT_BLE2M) + { + subWriteReg(0x40030040, 7, 5, (RF_PHY_EXT_PREAMBLE_US>>2) );//2 byte -> 8us + } + else + { + subWriteReg(0x40030040, 7, 5, (0) ); + } + + #endif + + if(g_rfPhyClkSel==RF_PHY_CLK_SEL_16M_XTAL && g_system_clk == SYS_CLK_DLL_48M) + subWriteReg( 0x4003008c,23,23,0x01); + else + subWriteReg( 0x4003008c,23,23,0x00); + + return kCal; +} + + + + +/************************************************************************************** + @fn rf_rxDcoc_cfg + + @brief This function process for rx dc offset calibration and canncellation config. + + input parameters + + @param rfChn : rfFreq=2400+rfChn + bwSet : used to config rx complex filter bandwitdh. 1 for 1MHz, other for 2MHz + + + output parameters + + @param dcCal : cal result for rxdc, dcQ[13:8],dcI[5:0] + + @return none +*/ +void rf_rxDcoc_cfg(uint8_t rfChn, uint8_t bwSet, volatile uint32* dcCal) +{ + //-------------------------------------------------------------- + //rf_ana_cfg should be called before doing dcoc calibration + //-------------------------------------------------------------- + // restore the rxTimeOut setting, and set rxto to zero, not to generate rx_done + // + // + int rxTimeOut1st = PHY_REG_RD(0x40031024); + int rxTimeOut = PHY_REG_RD(0x40031028); + PHY_REG_WT(0x40031024,0x00000000); + PHY_REG_WT(0x40031028,0x00000000); + //-------------------------------------------------------------- + //rx close + // + PHY_REG_WT( 0x400300b4,0xff&rfChn); // set rfFreq=2400+rfChn + PHY_REG_WT( 0x400300a0,0x0000000e); // set pll_auto override + PHY_REG_WT( 0x400300a4,0x00000100); // clr trx_auto + PHY_REG_WT( 0x400300a8,0x00000040); // set lo override + PHY_REG_WT( 0x400300ac,0x00000050); // set rx lo and pll buff + PHY_REG_WT( 0x400300a4,0x0000012a); // rx close + //-------------------------------------------------------------- + //set filter bw and rx gain,dcoc cal control + // + uint16 fltPhy = 0; + + if(bwSet==1) + { + PHY_REG_WT( 0x400300e0,0x00000100); // set pga bw(0100:1M,1100:2M) + fltPhy = 0x034d; + } + else + { + PHY_REG_WT( 0x400300e0,0x00000080); // set pga bw(0100:1M,1100:2M) + fltPhy = 0x02ca; + } + + PHY_REG_WT( 0x400300c8,0x000001a4); // set to rx max gain + PHY_REG_WT( 0x400300c4,0x00002020); // dcoc dac controled by mix_sig_top for cal + PHY_REG_WT( 0x40030050,0x200c5680); // enlarge dcoc cal average time + // enlarge pga settle time + //-------------------------------------------------------------- + //wait for rf settle + // + volatile int cnt=1000; + + while(cnt--) {}; + + PHY_REG_WT( 0x40030078,(fltPhy<<22)|0x216564); // clr dcoc_en[0] , set to phase search mode[1] + + PHY_REG_WT( 0x40030078,(fltPhy<<22)|0x216565); // set dcoc_en[0], dcoc start + + //-------------------------------------------------------------- + //wait to read the cal result + // + cnt=10000; + + switch (g_system_clk) + { + case SYS_CLK_XTAL_16M: + cnt=cnt; + break; + + case SYS_CLK_RC_32M: + case SYS_CLK_DBL_32M: + cnt=cnt*2; + break; + #if (PHY_MCU_TYPE == MCU_BUMBEE_M0 || PHY_MCU_TYPE == MCU_BUMBEE_CK802) + + case SYS_CLK_4M: + break; + + case SYS_CLK_8M: + break; + #elif ((PHY_MCU_TYPE == MCU_PRIME_A1) ||(PHY_MCU_TYPE == MCU_PRIME_A2)) + + case SYS_CLK_DBL_32M: + cnt=cnt*2; + break; + #endif + + case SYS_CLK_DLL_48M: + cnt=cnt*3; + break; + + case SYS_CLK_DLL_64M: + cnt=cnt*4; + break; + + default: + cnt=cnt; + break; + } + + *dcCal = 0x20200000; // set the dc cal to default val + + while(cnt--) + { + if(3==(0x03 & (PHY_REG_RD(0x400300ec)>>30))) + { + *dcCal = PHY_REG_RD(0x400300ec)&0x3f3fffff; // get the dc cal result + PHY_REG_WT( 0x400300c4,0x00010000 | ((*dcCal)>>16)); // set to dcoc dac code + break; + } + } + + //-------------------------------------------------------------- + //end of cfg + // + PHY_REG_WT( 0x40030078,(fltPhy<<22)|0x216564); // clr dcoc_en[0] , set to phase search mode[1] + PHY_REG_WT( 0x400300a8,0x00000000); // clr lo override + PHY_REG_WT( 0x400300ac,0x00000000); // clr rx lo and pll buff + PHY_REG_WT( 0x400300c8,0x00000000); // set to rx max gain + PHY_REG_WT( 0x400300a4,0x00000100); // clr tx_auto + PHY_REG_WT( 0x400300a0,0x00000000); // clr pll_auto override + PHY_REG_WT( 0x400300a4,0x00000140); // clr tx_auto + PHY_REG_WT(0x40031024,rxTimeOut1st); + PHY_REG_WT(0x40031028,rxTimeOut); +} + +#if(RF_PHY_DTM_CTRL_MOD == RF_PHY_DTM_CTRL_UART) +/************************************************************************************** + @fn rf_phy_dtm_uart_irq + + @brief This function process for rf phy direct test uart irq. + + input parameters + + @param none + + output parameters + + @param none + + @return none +*/ +void DTM_UART_IRQHandler(void) +{ + uint8_t IRQ_ID= (AP_UART0->IIR & 0x0f); + + switch (IRQ_ID) + { + case RDA_IRQ: + case TIMEOUT_IRQ: + while(AP_UART0 ->LSR & 0x1) + { + urx_buf[uart_rx_wIdx]=(AP_UART0->RBR & 0xff); + DTM_ADD_IDX(uart_rx_wIdx, MAX_UART_BUF_ID); + } + + break; + + case BUSY_IRQ: + AP_UART0 -> USR; + break; + } +} +// static uint32_t dtm_read_current_time(void) +// { +// // return ((4000000-get_timer3_count())/4+2); +// return (RF_PHY_TIME_BASE - ((AP_TIM3->CurrentCount) >> 2) ) ; +// } + +#endif + +#if(RF_PHY_DTM_CTRL_MOD == RF_PHY_DTM_CTRL_UART) +/************************************************************************************** + @fn rf_phy_direct_test + + @brief This function process for rf phy direct test. + + input parameters + + @param none + + output parameters + + @param none + + @return none +*/ +void rf_phy_direct_test(void) +{ + int dtmState = 0; + uint32_t deltTick = 0; + uint32_t currTick = 0; + //enable received data available interrupt + DTM_LOG_INIT(); + DTM_LOG("\n===RF_PHY_DTM V1.1.2===\n"); + //clr UART IRQ, switch to ROM_UART_IRQ + JUMP_FUNCTION(UART0_IRQ_HANDLER) = (uint32_t)&DTM_UART_IRQHandler; + + if(RF_PHY_DTM_BB_SUPPORT_MOD&RF_PHY_DTM_BB_SUPPORT_BLE1M) + DTM_LOG("=== SUPPORT BLE 1M ===\n"); + + if(RF_PHY_DTM_BB_SUPPORT_MOD&RF_PHY_DTM_BB_SUPPORT_BLE2M) + DTM_LOG("=== SUPPORT BLE 2M ===\n"); + + if(RF_PHY_DTM_BB_SUPPORT_MOD&RF_PHY_DTM_BB_SUPPORT_BLR500K) + DTM_LOG("=== SUPPORT BLR 500K===\n"); + + if(RF_PHY_DTM_BB_SUPPORT_MOD&RF_PHY_DTM_BB_SUPPORT_BLR125K) + DTM_LOG("=== SUPPORT BLR 125K===\n"); + + if(RF_PHY_DTM_BB_SUPPORT_MOD&RF_PHY_DTM_BB_SUPPORT_ZIGBEE) + DTM_LOG("=== SUPPORT ZIGBEE ===\n"); + + //*(volatile int *) 0xe000e100 |= 0x800; + *(volatile int*) 0xe000e100 = 0x800; //only use uart irq + *(volatile unsigned int*) 0x40004004 |= 0x01; //ENABLE_ERBFI; + //set timer3 free run + //AP_TIM3->ControlReg = 0x05; + //24bit count down mode no IRQ + set_timer(AP_TIM3,RF_PHY_TIME_BASE); + NVIC_DisableIRQ(TIM3_IRQn); + //clear widx + CLR_UART_WIDX; + + while(1) + { + if( dtmState == RF_PHY_DTM_IDL) + { + if(GET_UART_WIDX>=2) + { + g_rfPhyDtmCmd[0]=urx_buf[0]; + g_rfPhyDtmCmd[1]=urx_buf[1]; + dtmState = RF_PHY_DTM_CMD; + CLR_UART_WIDX; + } + + //=================== cmd parsing ===================== + } + else if(dtmState == RF_PHY_DTM_CMD) + { + rf_phy_dtm_cmd_parse(); + dtmState = RF_PHY_DTM_EVT; + //=================== send event ===================== + } + else if(dtmState == RF_PHY_DTM_EVT) + { + rf_phy_dtm_evt_send(g_dtmModeType); + dtmState = RF_PHY_DTM_TEST; + //=================== TEST Start ===================== + } + else if(dtmState == RF_PHY_DTM_TEST) + { + rf_phy_dtm_trigged(); + g_dtmPktCount = 0; + uint8_t rssi; + uint8_t carrSens; + uint16_t foff; + uint8_t zgb_pkt_flg=0; + + //when new cmd arrived, state change + while(GET_UART_WIDX<2) + { + //TX BURST re-trigger + if(g_dtmModeType == RF_PHY_DTM_MODE_TX_BURST) + { + //============================================================ + //20180424-ZQ + //option 1 + ll_hw_set_trx_settle (100, 8, 80); //TxBB,RxAFE,PLL + //============================================================ + currTick = read_current_fine_time(); + deltTick = RF_PHY_TIME_DELTA(currTick,g_dtmTick); + + if( (ll_hw_get_irq_status() & LIRQ_MD) + && g_rfPhyPktFmt == PKT_FMT_ZIGBEE + && zgb_pkt_flg==0) + { + //ll_hw_rst_tfifo(); + //rf_phy_dtm_zigbee_pkt_gen(); + ll_hw_clr_irq(); + zgb_pkt_flg=1; + PHY_REG_WT( 0x4003105c,0x00000000); // clr rd_ini and rd_last + } + + if(deltTick>=g_dtmPktIntv) + { + if(!(g_rfPhyPktFmt==PKT_FMT_ZIGBEE)) + { + ll_hw_rst_tfifo(); + ll_hw_trigger(); +// if(g_rfPhyPktFmt==PKT_FMT_BLE2M) +// { +// //set tx_auto_ctrl0 first +// PHY_REG_WT( 0x400300a4,0x00000140); // clr tx_auto +// PHY_REG_WT( 0x400300a4,0x00000150); // clr tx_auto +// //wait a while then set tx_bb_en +// int delay=100;while(delay--){}; +// PHY_REG_WT( 0x400300a4,0x00000154); // clr tx_auto +// } +// else +// { +// ll_hw_trigger(); +// //PHY_REG_WT( 0x400300a0,0x0000000e); // clr pll_auto override +// //PHY_REG_WT( 0x400300a4,0x00000140); // clr tx_auto +// //PHY_REG_WT( 0x400300a4,0x00000154); // clr tx_auto +// +// } + } + else + { + ll_hw_trigger(); + //PHY_REG_WT( 0x400300a4,0x00000140); // clr tx_auto + //PHY_REG_WT( 0x400300a4,0x00000154); // clr tx_auto + zgb_pkt_flg=0; + } + + #if(RF_PHY_CT_MONITER) + WaitUs(350); + int32_t ct_word= (PHY_REG_RD(0x400300f4)&0x3ff); + + if(ct_word>0) + { + if(g_rfPhy_ct_moniter_word_cnt==0) + g_rfPhy_ct_moniter_word_target = ct_word; + + int32_t idx= (ct_word)-g_rfPhy_ct_moniter_word_target+(CT_MONT_BUFF_SIZE>>1); + g_rfPhy_ct_moniter_word_cnt++; + + if(idx<0) + { + LOG("e %d %d\n",ct_word,PHY_REG_RD(0x400300f8)&0xfffff); + g_rfPhy_ct_moniter_word_arry[0]++; + } + else if(idx>CT_MONT_BUFF_SIZE-1) + { + g_rfPhy_ct_moniter_word_arry[CT_MONT_BUFF_SIZE-1]++; + } + else + { + g_rfPhy_ct_moniter_word_arry[idx]++; + } + + if(g_rfPhy_ct_moniter_word_cnt>RF_PHY_CT_MONITER) + { + for (int i=0; i0) + LOG("%d %d\n",g_rfPhy_ct_moniter_word_target-(CT_MONT_BUFF_SIZE>>1)+i,g_rfPhy_ct_moniter_word_arry[i]); + + g_rfPhy_ct_moniter_word_arry[i]=0; + } + + g_rfPhy_ct_moniter_word_cnt=0; + } + } + + #endif + //g_dtmTick = read_current_time(); + g_dtmTick = g_dtmTick+g_dtmPktIntv; + + if(g_dtmTick>RF_PHY_TIME_BASE) + g_dtmTick = g_dtmTick-RF_PHY_TIME_BASE; + } + } + else if( g_dtmModeType == RF_PHY_DTM_MODE_RX_PER + || g_dtmModeType == RF_PHY_DTM_MODE_GET_PER_AUTO) + { + //fix max gain can imporve 2480 sensitivity + if(g_dtmManualConfig&RF_PHY_DTM_MANUL_MAX_GAIN) + { + subWriteReg(0x40030050, 4,0,0x10); //fix max gain + } + + subWriteReg(0x4000f018,14,9,0x3f);//rc32M clk slow + + if(ll_hw_get_irq_status()&LIRQ_MD) + { + if(ll_hw_get_irq_status()&LIRQ_COK) + { + g_dtmPktCount++; + rf_phy_get_pktFoot(&rssi,&foff,&carrSens); + } + else if(ll_hw_get_irq_status()&LIRQ_CERR) + { + g_dtmRxCrcNum++; + } + else if(ll_hw_get_irq_status()&LIRQ_RTO) + { + g_dtmRxTONum++; + } + else + { + //wrap the pktCount + g_dtmPktCount= (g_dtmPktCount==65535) ? 0 : g_dtmPktCount; + } + + if( g_dtmModeType == RF_PHY_DTM_MODE_GET_PER_AUTO) + { + currTick = read_current_fine_time(); + deltTick = RF_PHY_TIME_DELTA(currTick,g_dtmTick); + + if(deltTick>g_dtmPerAutoIntv) + { + rf_phy_dtm_evt_send(RF_PHY_DTM_MODE_TEST_END);//send pktCount + WaitUs(500); + rf_phy_dtm_evt_send(RF_PHY_DTM_MODE_GET_FOFF);//send FOFF + WaitUs(500); + rf_phy_dtm_evt_send(RF_PHY_DTM_MODE_GET_RSSI);//send RSSI + WaitUs(500); + rf_phy_dtm_evt_send(RF_PHY_DTM_MODE_GET_CARR_SENS);//send CARR_SENS + WaitUs(500); + g_dtmPktCount = 0; + g_dtmRxCrcNum = 0; + g_dtmRxTONum = 0; + g_dtmTick = read_current_fine_time(); + } + }//EndOfIF PER_AUTO + + ll_hw_clr_irq(); + ll_hw_trigger(); + + if(g_dtmPktCount>0) + { + g_dtmRssi = (g_dtmPktCount==1) ? rssi :((g_dtmRssi+rssi) >>1); + g_dtmFoff = (g_dtmPktCount==1) ? foff :((g_dtmFoff+foff) >>1); + g_dtmCarrSens = (g_dtmPktCount==1) ? carrSens :((g_dtmCarrSens+carrSens) >>1); + } + } + }//end of RX_PER + }//end of GET_UART_WIDX + + dtmState = RF_PHY_DTM_IDL; + } + }//end of while(1) +} + + +#endif + +#if(RF_PHY_DTM_CTRL_MOD == RF_PHY_DTM_CTRL_UART) +/************************************************************************************** + @fn rf_phy_dtm_cmd_parse + + @brief This function process for rf phy direct test,cmd parse + + input parameters + + @param none + + output parameters + + @param none + + @return none +*/ +void rf_phy_dtm_cmd_parse(void) +{ + g_dtmCmd = ((g_rfPhyDtmCmd[0] & 0xc0)>>6); // bit 15 14 + + //test setup and test end + if(g_dtmCmd == 0 || g_dtmCmd==3 ) + { + g_dtmCtrl = ((g_rfPhyDtmCmd[0] & 0x3f) ); // bit 13 8 + g_dtmPara = ((g_rfPhyDtmCmd[1] & 0xfc)>>2); // bit 7 2 + + //TEST SETUP + if(g_dtmCmd==0) + { + if(g_dtmCtrl==0 && g_dtmPara==0) + { + g_dtmModeType = RF_PHY_DTM_MODE_RESET; + } + else if(g_dtmCtrl==1) + { + g_dtmModeType = RF_PHY_DTM_MODE_SET_LENGTH_UP2BIT; + g_dtmExtLen = (g_dtmPara&0x3); + } + else if(g_dtmCtrl==2 && g_dtmPara ==0x01) + { + g_dtmModeType = RF_PHY_DTM_MODE_SET_PHY_1M; + g_rfPhyPktFmt = PKT_FMT_BLE1M; + } + else if(g_dtmCtrl==2 && g_dtmPara ==0x02) + { + g_dtmModeType = RF_PHY_DTM_MODE_SET_PHY_2M; + g_rfPhyPktFmt = (RF_PHY_DTM_BB_SUPPORT_BLE2M & RF_PHY_DTM_BB_SUPPORT_MOD) + ?PKT_FMT_BLE2M:PKT_FMT_BLE1M; + } + else if(g_dtmCtrl==2 && g_dtmPara ==0x03) + { + g_dtmModeType = RF_PHY_DTM_MODE_SET_PHY_125K; + g_rfPhyPktFmt = (RF_PHY_DTM_BB_SUPPORT_BLR125K & RF_PHY_DTM_BB_SUPPORT_MOD) + ?PKT_FMT_BLR125K:PKT_FMT_BLE1M; + } + else if(g_dtmCtrl==2 && g_dtmPara ==0x04) + { + g_dtmModeType = RF_PHY_DTM_MODE_SET_PHY_500K; + g_rfPhyPktFmt = (RF_PHY_DTM_BB_SUPPORT_BLR500K & RF_PHY_DTM_BB_SUPPORT_MOD) + ?PKT_FMT_BLR500K:PKT_FMT_BLE1M; + } + else if(g_dtmCtrl==2 && g_dtmPara ==0x20) + { + g_dtmModeType = RF_PHY_DTM_MODE_SET_PHY_ZB; + g_rfPhyPktFmt = (RF_PHY_DTM_BB_SUPPORT_ZIGBEE & RF_PHY_DTM_BB_SUPPORT_MOD) + ?PKT_FMT_ZIGBEE:PKT_FMT_BLE1M; + } + else if(g_dtmCtrl==3 && g_dtmPara ==0x00) + { + g_dtmModeType = RF_PHY_DTM_MODE_ASSUME_TX_MOD_INDX_STANDARD; + } + else if(g_dtmCtrl==3 && g_dtmPara ==0x01) + { + g_dtmModeType = RF_PHY_DTM_MODE_ASSUME_TX_MOD_INDX_STABLE; + } + else if(g_dtmCtrl==4 && g_dtmPara ==0x00) + { + g_dtmModeType = RF_PHY_DTM_MODE_READ_SUPPORTED_TEST_CASE; + } + else if(g_dtmCtrl==5 && g_dtmPara ==0x00) + { + g_dtmModeType = RF_PHY_DTM_MODE_READ_MAX_TX_OCTETS; + } + else if(g_dtmCtrl==5 && g_dtmPara ==0x01) + { + g_dtmModeType = RF_PHY_DTM_MODE_READ_MAX_TX_TIME; + } + else if(g_dtmCtrl==5 && g_dtmPara ==0x02) + { + g_dtmModeType = RF_PHY_DTM_MODE_READ_MAX_RX_OCTETS; + } + else if(g_dtmCtrl==5 && g_dtmPara ==0x03) + { + g_dtmModeType = RF_PHY_DTM_MODE_READ_MAX_RX_TIME; + } + else if(g_dtmCtrl==0x34) + { + uint8_t ret=g_dtmPara & 0x01; + + for(uint8_t pin=0; pin<23; pin++) + { + if((pin == P2) || (pin == P3)) + { + hal_gpio_pin2pin3_control((gpio_pin_e)pin,ret); + gpio_write((gpio_pin_e)pin,ret); + } + else if((pin == P9) || (pin == P10) || (pin == P16) || (pin == P17)) + { + continue; + } + else + gpio_write((gpio_pin_e)pin,ret); + } + } + else if(g_dtmCtrl==0x35) + { + uint8_t ret=g_dtmPara>>5; + uint8_t pin=g_dtmPara & 0x1f; + + if((pin == P2) || (pin == P3)) + hal_gpio_pin2pin3_control((gpio_pin_e)pin,ret); + + gpio_write((gpio_pin_e)pin,ret); + // PHYPLUSE DEFINED: RF_PHY_DTM_MODE_SET_ACCCODE_0 + } + else if(g_dtmCtrl==0x36) + { + g_dtmModeType = RF_PHY_DTM_MODE_SET_ACCCODE_0; + g_dtmAccessCode = (g_dtmAccessCode&(0xffffff00))|g_rfPhyDtmCmd[1]; + // PHYPLUSE DEFINED: RF_PHY_DTM_MODE_SET_ACCCODE_1 + } + else if(g_dtmCtrl==0x37) + { + g_dtmModeType = RF_PHY_DTM_MODE_SET_ACCCODE_1; + g_dtmAccessCode = (g_dtmAccessCode&(0xffff00ff))|(g_rfPhyDtmCmd[1]<<8); + // PHYPLUSE DEFINED: RF_PHY_DTM_MODE_SET_ACCCODE_2 + } + else if(g_dtmCtrl==0x38) + { + g_dtmModeType = RF_PHY_DTM_MODE_SET_ACCCODE_2; + g_dtmAccessCode = (g_dtmAccessCode&(0xff00ffff))|(g_rfPhyDtmCmd[1]<<16); + // PHYPLUSE DEFINED: RF_PHY_DTM_MODE_SET_ACCCODE_3 + } + else if(g_dtmCtrl==0x39) + { + g_dtmModeType = RF_PHY_DTM_MODE_SET_ACCCODE_3; + g_dtmAccessCode = (g_dtmAccessCode&(0x00ffffff))|(g_rfPhyDtmCmd[1]<<24); + // PHYPLUSE DEFINED: TX TEST MODE Set FREQ FOFF + } + else if(g_dtmCtrl==0x3a) + { + g_dtmModeType = RF_PHY_DTM_MODE_SET_FREQ_FOFF; + + if(g_dtmManualConfig & RF_PHY_DTM_MANUL_FOFF) + { + g_rfPhyFreqOffSet = (g_dtmPara-10)*5;//[0:1:20]-->[-50:5:50]-->[-200:20:200]KHz + } + + // PHYPLUSE DEFINED: TX TEST MODE Set TP_CAL MANUAL + } + else if(g_dtmCtrl==0x3b) + { + g_dtmModeType = RF_PHY_DTM_MODE_SET_TPCAL_MANUAL; + + if(g_dtmPara==0) + { + g_dtmTpCalEnable = 1; + } + else + { + g_dtmTpCalEnable = 0; + g_rfPhyTpCal0 = (g_dtmPara)<<1; + PHY_REG_WT( 0x40030094,0x00001000+g_rfPhyTpCal0); // tp_cal val + } + + // PHYPLUSE DEFINED: TX TEST MODE Set XTAL CAP + } + else if(g_dtmCtrl==0x3c) + { + g_dtmModeType = RF_PHY_DTM_MODE_SET_XTAL_CAP; + + if(g_dtmManualConfig & RF_PHY_DTM_MANUL_XTAL_CAP) + { + XTAL16M_CAP_SETTING(g_dtmPara); + } + + // PHYPLUSE DEFINED: TX TEST MODE Set TX POWER + } + else if(g_dtmCtrl==0x3d) + { + g_dtmModeType = RF_PHY_DTM_MODE_SET_TX_POWER; + + if(g_dtmManualConfig & RF_PHY_DTM_MANUL_TXPOWER) + { + g_dtmTxPower = g_dtmPara; + } + + // PHYPLUSE DEFINED: TX TEST MODE Continous Modulation + } + else if(g_dtmCtrl==0x3e) + { + g_dtmModeType = RF_PHY_DTM_MODE_TX_CTMOD; + g_dtmFreq = g_dtmPara; + // PHYPLUSE DEFINED: TX TEST MODE Single Tone + } + else if(g_dtmCtrl==0x3f) + { + g_dtmModeType = RF_PHY_DTM_MODE_TX_SINGLE; + g_dtmFreq = g_dtmPara; + } + else + { + g_dtmModeType = RF_PHY_DTM_MODE_ERROR; + } + + //TEST END + } + else + { + if(g_dtmCtrl==0 && g_dtmPara==0) + { + g_dtmModeType = RF_PHY_DTM_MODE_TEST_END; + // PHYPLUSE DEFINED: get foff + } + else if(g_dtmCtrl==0x3f && g_dtmPara==0) + { + g_dtmModeType = RF_PHY_DTM_MODE_GET_FOFF; + // PHYPLUSE DEFINED: get tpCal + } + else if(g_dtmCtrl==0x3f && g_dtmPara==1) + { + g_dtmModeType = RF_PHY_DTM_MODE_GET_TPCAL; + // PHYPLUSE DEFINED: get RSSI + } + else if(g_dtmCtrl==0x3f && g_dtmPara==2) + { + g_dtmModeType = RF_PHY_DTM_MODE_GET_RSSI; + // PHYPLUSE DEFINED: get CARR_SENS + } + else if(g_dtmCtrl==0x3f && g_dtmPara==3) + { + g_dtmModeType = RF_PHY_DTM_MODE_GET_CARR_SENS; + // PHYPLUSE DEFINED: get PER report Auto + } + else if(g_dtmCtrl==0x3f && g_dtmPara==4) + { + g_dtmModeType = RF_PHY_DTM_MODE_GET_PER_AUTO; + } + else + { + g_dtmModeType = RF_PHY_DTM_MODE_ERROR; + } + } + + //tx-rx test + } + else if( g_dtmCmd == 1 || g_dtmCmd == 2) + { + g_dtmFreq = ((g_rfPhyDtmCmd[0] & 0x3f) ); // bit 13 8 + g_dtmLength = ((g_rfPhyDtmCmd[1] & 0xfc)>>2); // bit 7 2 + g_dtmPKT = ((g_rfPhyDtmCmd[1] & 0x03) ); // bit 1 0 + + if(g_dtmPktCount==3 && (g_rfPhyPktFmt==PKT_FMT_BLR125K || g_rfPhyPktFmt==PKT_FMT_BLR500K )) + { + g_dtmPKT = 4;//all ones 'b 11111111 + } + + g_dtmModeType = (g_dtmCmd ==1 )? RF_PHY_DTM_MODE_RX_PER : RF_PHY_DTM_MODE_TX_BURST; + } +} + +#endif +//------------------------------------------------------------------------------------- + + +#if(RF_PHY_DTM_CTRL_MOD == RF_PHY_DTM_CTRL_UART) +/************************************************************************************** + @fn rf_phy_dtm_evt_send + + @brief This function process for rf phy direct test, test mode trigged + + input parameters + + @param none + + output parameters + + @param none + + @return none +*/ +void rf_phy_dtm_evt_send(uint8_t dtmType ) +{ + //clear Event Buf + g_rfPhyDtmEvt[0] = 0; + g_rfPhyDtmEvt[1] = 0; + + if(dtmType==RF_PHY_DTM_MODE_ERROR) + { + g_dtmEvt = 0; //status + g_dtmStatus = 1; //Error + } + else + { + if(dtmType == RF_PHY_DTM_MODE_TEST_END) + { + g_dtmEvt = 0x80; //report + g_dtmStatus = 0; + g_dtmRsp = g_dtmPktCount; + } + else if(dtmType == RF_PHY_DTM_MODE_GET_FOFF) + { + g_dtmEvt = 0x80; //report + g_dtmStatus = 0; + g_dtmRsp = g_dtmFoff; + } + else if(dtmType == RF_PHY_DTM_MODE_GET_TPCAL) + { + g_dtmEvt = 0x80; //report + g_dtmStatus = 0; + g_dtmRsp = g_rfPhyTpCal0; + } + else if(dtmType == RF_PHY_DTM_MODE_GET_RSSI ) + { + g_dtmEvt = 0x80; //report + g_dtmStatus = 0; + g_dtmRsp = g_dtmRssi; + } + else if(dtmType == RF_PHY_DTM_MODE_GET_CARR_SENS) + { + g_dtmEvt = 0x80; //report + g_dtmStatus = 0; + g_dtmRsp = g_dtmCarrSens; + } + else if(dtmType == RF_PHY_DTM_MODE_READ_SUPPORTED_TEST_CASE) + { + g_dtmEvt = 0x00; //status + g_dtmStatus = 0; + g_dtmRsp = 0x0c; //bit3,support stable modulation index + //bit2, support LE 2M PHY + //bit1, support LE PACKET LENGTH EXTENTION + } + else if(dtmType == RF_PHY_DTM_MODE_READ_MAX_TX_OCTETS) + { + g_dtmEvt = 0x00; //status + g_dtmStatus = 0; + g_dtmRsp = 27<<1; + } + else if(dtmType == RF_PHY_DTM_MODE_READ_MAX_TX_TIME) + { + g_dtmEvt = 0x00; //status + g_dtmStatus = 0; + g_dtmRsp = 1352<<1; + } + else if(dtmType == RF_PHY_DTM_MODE_READ_MAX_RX_OCTETS) + { + g_dtmEvt = 0x00; //status + g_dtmStatus = 0; + g_dtmRsp = 27<<1; + } + else if(dtmType == RF_PHY_DTM_MODE_READ_MAX_RX_TIME) + { + g_dtmEvt = 0x00; //status + g_dtmStatus = 0; + g_dtmRsp = 1352<<1; + } + else + { + g_dtmEvt = 0; //status + g_dtmStatus = 0; //Sucess + g_dtmRsp = g_dtmModeType; + } + } + + g_rfPhyDtmEvt[0] = g_rfPhyDtmEvt[0] | g_dtmEvt | (g_dtmRsp >> 8); + g_rfPhyDtmEvt[1] = g_rfPhyDtmEvt[1] | g_dtmStatus | (g_dtmRsp & 0xff); + DTM_OUT(g_rfPhyDtmEvt[0]); + DTM_OUT(g_rfPhyDtmEvt[1]); +} + + +#endif +//------------------------------------------------------------------------------------- + + +#if(RF_PHY_DTM_CTRL_MOD == RF_PHY_DTM_CTRL_UART) +/************************************************************************************** + @fn rf_phy_dtm_trigged + + @brief This function process for rf phy direct test, test mode trigged + + input parameters + + @param none + + output parameters + + @param none + + @return none +*/ +void rf_phy_dtm_trigged(void) +{ + //cal the pkt length and pkt interval + g_dtmLength = ((0x03&g_dtmExtLen)<<6)|(0x3f&g_dtmLength); + int pktLenUs =0; //(g_dtmLength+10)<<3; + uint8_t rfChn = 2+(g_dtmFreq<<1); + uint8_t preambleLen = 1; + +// if( pktLenUs <= 376 ) { g_dtmPktIntv = 625; +// }else if( pktLenUs <= 1000 ) { g_dtmPktIntv = 1250; +// }else if( pktLenUs <= 1624 ) { g_dtmPktIntv = 1875; +// }else if( pktLenUs <= 2120 ) { g_dtmPktIntv = 2500; +// }else { g_dtmPktIntv = 2500; +// } +// + if( g_rfPhyPktFmt==PKT_FMT_BLE1M) + { + pktLenUs = (g_dtmLength+1+4+2+3)<<3; + } + else if( g_rfPhyPktFmt==PKT_FMT_BLE2M) + { + pktLenUs = (g_dtmLength+2+4+2+3)<<2; + } + else if( g_rfPhyPktFmt==PKT_FMT_BLR500K) + { + pktLenUs = 80+296+((g_dtmLength+2+3)<<4)+6; + } + else if( g_rfPhyPktFmt==PKT_FMT_BLR125K) + { + pktLenUs = 80+296+((g_dtmLength+2+3)<<6)+24; + } + else + { + pktLenUs = (g_dtmLength+4+1+1)<<5;//per byte -> 2symbol ->32us + rfChn = 5+g_dtmFreq*5;//for zigbee + } + + g_dtmPktIntv = (((pktLenUs+249)+624)/625)*625;// ceil((L+249)/625) * 625 + + if(g_dtmModeType == RF_PHY_DTM_MODE_GET_PER_AUTO) + { + g_dtmPerAutoIntv = g_dtmPktIntv*1000; + g_dtmTick = read_current_fine_time(); + } + + PHY_REG_WT( 0x40030040,0x00030000); // close tx_bb test mode + PHY_REG_WT( 0x400300a0,0x0000000e); // clr pll_auto override + PHY_REG_WT( 0x400300a4,0x00000100); // clr tx_auto + PHY_REG_WT( 0x400300a0,0x00000000); // clr pll_auto override + PHY_REG_WT( 0x4003008c,0x00104040); // clr tp_cal_en + + if(g_dtmModeType == RF_PHY_DTM_MODE_RESET) + { + g_dtmPktCount = 0; + g_dtmRsp = 0; + g_dtmExtLen = 0; + g_dtmLength = 0; + g_dtmPktIntv = 0; + g_dtmTxPower = g_rfPhyTxPower; + g_dtmFoff = 0; + g_dtmRssi = 0; + g_dtmCarrSens = 0; + g_rfPhyPktFmt = PKT_FMT_BLE1M; + g_dtmPKT = 0; + DCDC_CONFIG_SETTING(0x0a); + } + else if( g_dtmModeType == RF_PHY_DTM_MODE_TX_BURST + || g_dtmModeType == RF_PHY_DTM_MODE_TX_CTMOD + || g_dtmModeType == RF_PHY_DTM_MODE_TX_SINGLE ) + { + //====== tp cal + if(g_dtmTpCalEnable) + { + rf_phy_ana_cfg(); + //rf_tpCal_cfg(rfChn); + rf_tpCal_cfg_avg(rfChn,4); + } + + //====== rf initial + rf_phy_ini(); + rf_phy_set_txPower(g_dtmTxPower); + ll_hw_set_timing(g_rfPhyPktFmt); + + //add some tx_foff + if(g_rfPhyFreqOffSet>=0) + PHY_REG_WT(0x400300b4,rfChn+(g_rfPhyFreqOffSet<<8)); + else + PHY_REG_WT(0x400300b4,rfChn-1+((255+g_rfPhyFreqOffSet)<<8)); + + if(!(g_rfPhyPktFmt==PKT_FMT_ZIGBEE)) + { + PHY_REG_WT(0x40030048,RF_PHY_DTM_CRC_WT ); + PHY_REG_WT(0x4003004c,g_dtmAccessCode ); + PHY_REG_WT(0x40030040,0x00030010); + } + + //---------------------------------- + //PRBS SEED should be configed before tx_mod en + PHY_REG_WT(0x40030044,RF_PHY_DTM_PRBS9_SEED ); + + if(g_dtmModeType == RF_PHY_DTM_MODE_TX_SINGLE) + { + PHY_REG_WT(0x400300a4,0x00000100); //tp_mod en and pa_ramp_en + } + else + { + PHY_REG_WT(0x400300a4,0x00000140); //tp_mod en and pa_ramp_en + } + + //PHY_REG_WT(0x40030040,0x000300f0);//need to extend the preamble length + + if(g_dtmModeType == RF_PHY_DTM_MODE_TX_BURST) + { + //DCDC_CONFIG_SETTING(0x08); + if(!(g_rfPhyPktFmt==PKT_FMT_ZIGBEE)) + { + #if 0 + + //[15:8] payload Len [7:5] preamble len, [4] tx mode, [3:0] payload type + //PHY_REG_WT(0x40030040,(0x00030010|(g_dtmLength<<8)|(preambleLen<<5)|(0x0f & g_dtmPKT)) ); + if((g_rfPhyPktFmt == PKT_FMT_BLR125K || g_rfPhyPktFmt == PKT_FMT_BLR500K) + && g_dtmPKT == 0x03 ) + { + //for PKT_FMT all ones 11111111 + //PHY_REG_WT(0x40030040,(0x00030010|((g_dtmLength+2)<<8)|(preambleLen<<5)|0x04) ); + PHY_REG_WT(0x40030040,(0x00030010|((g_dtmLength)<<8)|(preambleLen<<5)|0x04) ); + } + else + { + //PHY_REG_WT(0x40030040,(0x00030010|((g_dtmLength+2)<<8)|(preambleLen<<5)|(0x0f & g_dtmPKT)) ); + PHY_REG_WT(0x40030040,(0x00030010|((g_dtmLength)<<8)|(preambleLen<<5)|(0x0f & g_dtmPKT)) ); + } + + #else + ll_hw_rst_tfifo(); + extern void rf_phy_dtm_ble_pkt_gen(void); + rf_phy_dtm_ble_pkt_gen(); + #endif + } + else + { + ll_hw_rst_tfifo(); + rf_phy_dtm_zigbee_pkt_gen(); + } + } + else + { + if(!(g_rfPhyPktFmt==PKT_FMT_ZIGBEE)) + { + //[15:8] payload Len [7:5] preamble len, [4] tx mode, [3:0] payload type + PHY_REG_WT(0x40030040,0x00030010|(preambleLen<<5)); + } + else + { + //[15:8] payload Len [7:5] preamble len, [4] tx mode, [3:0] payload type + PHY_REG_WT(0x40030040,0x000b0013|(preambleLen<<5)); + PHY_REG_WT(0x40030000,0x78068002); + } + } + + //close ll hw irg + ll_hw_set_irq(0); + ll_hw_set_stx(); + ll_hw_clr_irq(); + + if(g_dtmModeType == RF_PHY_DTM_MODE_TX_BURST) + { + if(!(g_rfPhyPktFmt==PKT_FMT_ZIGBEE)) + { + //PHY_REG_WT( 0x400300a0,0x0000000e); // clr pll_auto override + //PHY_REG_WT( 0x400300a4,0x00000154); // clr tx_auto + ll_hw_trigger(); + } + else + { + ll_hw_trigger(); + //PHY_REG_WT( 0x400300a0,0x0000000e); // clr pll_auto override + //PHY_REG_WT( 0x400300a4,0x00000154); // clr tx_auto + } + + g_dtmTick = read_current_fine_time(); + } + else + { + ll_hw_trigger(); + } + } + else if( g_dtmModeType == RF_PHY_DTM_MODE_RX_PER + || g_dtmModeType == RF_PHY_DTM_MODE_GET_PER_AUTO ) + { + rf_phy_ana_cfg(); + rf_rxDcoc_cfg(/*rfChn*/2,/*bwSet*/1,&g_rfPhyRxDcIQ); //set the rfChn as 2402 for BW=1MHz + //====== rf initial + rf_phy_ini(); + ll_hw_set_timing(g_rfPhyPktFmt); + PHY_REG_WT(0x40031024,g_dtmPktIntv-100);//timeout set + PHY_REG_WT(0x40031028,g_dtmPktIntv-100);//timeout set + + if((rfChn&0x0f)==0) + { + PHY_REG_WT(0x400300b4,rfChn);//freqOffset = 0 + subWriteReg(0x4003011c,11,8,3);//enable spur notch filter setting + } + else + { + subWriteReg(0x4003011c,11,8,0);//disable spur notch filter setting + + if(g_rfPhyFreqOffSet>=0) + PHY_REG_WT(0x400300b4,rfChn+(g_rfPhyFreqOffSet<<16)); + else + PHY_REG_WT(0x400300b4,rfChn-1+((255+g_rfPhyFreqOffSet)<<16)); + } + + if(!(g_rfPhyPktFmt==PKT_FMT_ZIGBEE)) + { + PHY_REG_WT(0x40030044,RF_PHY_DTM_PRBS9_SEED ); + PHY_REG_WT(0x40030048,RF_PHY_DTM_CRC_WT ); + PHY_REG_WT(0x4003004c,g_dtmAccessCode ); + } + + //set rx no timeout[31:16] + max packet len + //PHY_REG_WT(0x4003000c,(g_dtmLength+3)>255 ? 255: g_dtmLength+3 ); + PHY_REG_WT(0x4003000c,(g_dtmLength+3)>255 ? 255:( g_dtmLength<40 ? 40 : g_dtmLength+3) ); + //close ll hw irg + ll_hw_set_irq(0); + ll_hw_set_srx(); + ll_hw_clr_irq(); + ll_hw_trigger(); + } +} +void gen_pn_prbs9(uint16_t seed, int length,uint8_t* pnOut) +{ + uint8_t bitOut[8] = {0}; + uint8_t reg[9]; + uint8_t i = 0; + uint8_t j = 0; + uint8_t feedback = 0; + + for (i = 0; i < 9; i++) + { + reg[i] = (seed >> i) & 0x01; + } + + for (i = 0; i < length; i++) + { + for (j = 0; j < 8; j++) + { + feedback = reg[5] ^ reg[0]; + bitOut[j] = reg[0]; + reg[0] = reg[1]; + reg[1] = reg[2]; + reg[2] = reg[3]; + reg[3] = reg[4]; + reg[4] = reg[5]; + reg[5] = reg[6]; + reg[6] = reg[7]; + reg[7] = reg[8]; + reg[8] = feedback; + } + + bit_to_byte(bitOut, pnOut + i); + } +} +void rf_phy_dtm_ble_pkt_gen(void) +{ + uint8_t tmp[256]; + tmp[1] = g_dtmLength; + tmp[0] = g_dtmPKT; + uint8_t pld=0x00; + + if(g_dtmPKT==1) + { + pld = 0x0f; + } + else if(g_dtmPKT==2) + { + pld=0x55; + } + else if(g_dtmPKT==3) + { + pld=0xff; + tmp[0]=4; + } + + if(g_dtmPKT==0) + { + gen_pn_prbs9(0x01ff,g_dtmLength,&(tmp[2])); + } + else + { + for(uint8_t i=0; i>1) ) ^ 0x61); + } + + zigbee_crc16_gen(tmp+1,g_dtmLength-2,seed,crcCode); + tmp[g_dtmLength-1] = crcCode[0]; + tmp[g_dtmLength ] = crcCode[1]; + ll_hw_write_tfifo(tmp,g_dtmLength+1);//include the crc16 +} +#endif +//------------------------------------------------------------------------------------- + + + +/************************************************************************************** + @fn rf_phy_get_pktFoot + + @brief This function process to get pkt foot + + input parameters + + @param none + + output parameters + + @param rssi : recv signal strength indicator(-dBm) + foff : estimated freq offset by rx BB ,foff-512-->[-512 511]KHz + carrSens: sync qualitiy indicator, estimated by rx BB. + + @return none +*/ +void rf_phy_get_pktFoot(uint8* rssi, uint16* foff,uint8* carrSens) +{ + uint32_t pktFoot0; + uint32_t pktFoot1; + uint16_t tmpFoff; + pktFoot0 = (*(volatile uint32_t*) 0x400300e4); + pktFoot1 = (*(volatile uint32_t*) 0x400300e8); + tmpFoff = pktFoot0 & 0x3ff; + *foff = (tmpFoff>512) ? tmpFoff-512 : tmpFoff+512; + *rssi = (pktFoot1>>24) ; + *carrSens = (pktFoot0>>24) ; +} +void rf_phy_get_pktFoot_fromPkt(uint32 pktFoot0, uint32 pktFoot1, + uint8* rssi, uint16* foff,uint8* carrSens) +{ + uint16_t tmpFoff; +// pktFoot0 = (*(volatile uint32_t *) 0x400300e4); +// pktFoot1 = (*(volatile uint32_t *) 0x400300e8); + tmpFoff = pktFoot0 & 0x3ff; + *foff = (tmpFoff>512) ? tmpFoff-512 : tmpFoff+512; + *rssi = (pktFoot1>>24) ; + *carrSens = (pktFoot0>>24) ; +} +/************************************************************************************** + @fn rf_phy_set_txPower + + @brief This function process for rf phy tx power config + + input parameters + + @param txPower : tx pa power setting (0~0x1f) + + output parameters + + @param none + + @return none +*/ +void rf_phy_set_txPower (uint8 txPower) +{ + if(RF_PHY_TX_POWER_EXTRA_MAX==txPower) + { + DCDC_CONFIG_SETTING(0x08);//set dcdc to highest + RF_PHY_LO_LDO_SETTING(0); + RF_PHY_LNA_LDO_SETTING(0); + RF_PHY_PA_VTRIM_SETTING(1); + } + else + { + DCDC_CONFIG_SETTING(0x0a); + RF_PHY_LO_LDO_SETTING(2); + RF_PHY_LNA_LDO_SETTING(1); + RF_PHY_PA_VTRIM_SETTING(0); + } + + PHY_REG_WT(0x400300b8,(PHY_REG_RD(0x400300b8)&0x0fff) | ((txPower&0x1f)<<12)); +} + + + +/******************************************************************************* + @fn rc32k calibration + + @brief RF calibration function + + + + input parameters + @param None. + + + output parameters + + @param None. + + @return rcCalCode + +*/ +uint8 rc32k_calibration(void) +{ + if(AON_LOAD_RC32K_CALIB_FLG) + { + return 0; + } + else + { + AON_SAVE_RC32K_CALIB_FLG(1); + } + + uint8 delay = 10; + uint32_t temp=0; + *(volatile uint32_t*) 0x4000f05c &= 0xfffffffe; // disable RC32K calibration + WaitRTCCount(6); + // calibrate RC32K clock + *(volatile uint32_t*) 0x4000f018 |= 0x80; // set capbank controlled by calibration + *(volatile uint32_t*) 0x4000f05c |= 0x01; // enable RC32K calibration + + while (!(*(volatile uint32_t*) 0x4000f068 & 0x200) // check RC32K calibration OK flag, normally need >200us + && delay -- > 0) + { + WaitRTCCount(8);//30.125*8 us each loop + } + + if (delay > 0) + { + temp = (*(volatile uint32_t*) 0x4000f060 & 0x3f0000) >> 15; // read 6bit calibration result + *(volatile uint32_t*)0x4000f018 = (*(volatile uint32_t*) 0x4000f018 & 0xffffff81) | temp; // write the result + } + + *(volatile uint32_t*) 0x4000f018 &= 0xffffff7f; // set capbank controlled by AON + return (uint8)(0x7f&(temp>>1)); +} +/******************************************************************************* + @fn rf_calibrate API + + @brief RF calibration function + + + + input parameters + @param None. + + + output parameters + + @param None. + + @return None + +*/ +void rf_calibrate1(void) +{ + /* rf_phy_ana_cfg will overwrite txpower setting configed in rf_phy_ini. + in ble_main, rf_calibration is called after rf_phy_ini,so comment the rf_phy_ana_cfg + */ + //rf_phy_ana_cfg(); + //========== do rf tp cal for tx and rx dcoffset cal + rf_tpCal_gen_cap_arrary(); //generate the tpCal cap arrary + //rf_tpCal_cfg(/*rfChn*/2); + rf_rxDcoc_cfg(/*rfChn*/88,/*bwSet*/1,&g_rfPhyRxDcIQ); //set the rfChn as 2488 for BW=1MHz + rc32k_calibration(); +} + + +static void rf_phy_dtm_init(void) +{ + //*(volatile int *) 0xe000e100 |= 0x800; + *(volatile int*) 0xe000e100 = 0x800; //only use uart irq + *(volatile unsigned int*) 0x40004004 |= 0x01; //ENABLE_ERBFI; + //set timer3 free run + //AP_TIM3->ControlReg = 0x05; + //24bit count down mode no IRQ + set_timer(AP_TIM3, RF_PHY_TIME_BASE); + NVIC_DisableIRQ(TIM3_IRQn); +} + + +static void rf_phy_dtm_stop(void) +{ + //====================================================================== + //stop RF_PHY_DTM_MODE + //PHY_REG_WT( 0x400300a4,0x00000100); // clr tx_auto + //PHY_REG_WT( 0x400300a0,0x0000000e); // pll_auto override + subWriteReg(AP_PCR_BASE+0x0c,10,10,0);//reset bbll + PHY_REG_WT( 0x400300a4,0x00000140); // clr tx_auto + PHY_REG_WT( 0x400300a0,0x0000000e); // clr pll_auto override + PHY_REG_WT( 0x400300a0,0x00000000); // clr pll_auto override + subWriteReg(AP_PCR_BASE+0x0c,10,10,1);//release bbll reset +} + +/************************************************************************************** + @fn rf_phy_dtm_ext_tx_singleTone + + @brief This function process for rf phy direct test, test mode interup + + input parameters + + @param txPower : rf tx power + rfChnIdx : rf channel = 2402+(rfChnIdx<<1) + rfFoff : rf freq offset = rfFoff*4KHz + testTimeUs : test loop active time(ms) + + output parameters + + @param none + + @return none +*/ +void rf_phy_dtm_ext_tx_singleTone(uint8_t txPower, uint8_t rfChnIdx,uint8_t xtal_cap,int8_t rfFoff,uint32 testTimeUs) +{ + rf_phy_dtm_init(); + //====================================================================== + //rest RF_PHY_DTM_MODE + g_dtmModeType = RF_PHY_DTM_MODE_RESET; + rf_phy_dtm_trigged(); + //====================================================================== + //config dtm mode + g_dtmModeType = RF_PHY_DTM_MODE_TX_SINGLE; + g_dtmTxPower = txPower; + g_dtmFreq = rfChnIdx; + g_rfPhyPktFmt = PKT_FMT_BLE1M; + g_rfPhyFreqOffSet = rfFoff; + XTAL16M_CAP_SETTING(xtal_cap); + rf_phy_dtm_trigged(); + WaitUs(testTimeUs); + //====================================================================== + //stop RF_PHY_DTM_MODE + rf_phy_dtm_stop(); +} + + +/************************************************************************************** + @fn rf_phy_dtm_ext_tx_modulation + + @brief This function process for rf phy direct test, test mode interup + + input parameters + + @param txPower : rf tx power + rfChnIdx : rf channel = 2402+(rfChnIdx<<1) + rfFoff : rf freq offset = rfFoff*4KHz + pktType : modulaiton data type, 0: prbs9, 1: 1111000: 2 10101010 + testTimeUs : test loop active time(ms) + + output parameters + + @param none + + @return none +*/ +void rf_phy_dtm_ext_tx_modulation(uint8_t txPower, uint8_t rfChnIdx,uint8_t xtal_cap,int8_t rfFoff,uint8_t pktType,uint32 testTimeUs) +{ + rf_phy_dtm_init(); + //====================================================================== + //rest RF_PHY_DTM_MODE + g_dtmModeType = RF_PHY_DTM_MODE_RESET; + rf_phy_dtm_trigged(); + //====================================================================== + //config dtm mode + g_dtmModeType = RF_PHY_DTM_MODE_TX_CTMOD; + g_dtmTxPower = txPower; + g_dtmFreq = rfChnIdx; + g_rfPhyPktFmt = PKT_FMT_BLE1M; + g_dtmPKT = pktType; + g_rfPhyFreqOffSet = rfFoff; + XTAL16M_CAP_SETTING(xtal_cap); + rf_phy_dtm_trigged(); + WaitUs(testTimeUs); + //====================================================================== + //stop RF_PHY_DTM_MODE + rf_phy_dtm_stop(); +} + +/************************************************************************************** + @fn rf_phy_dtm_ext_tx_mt_burst + + @brief This function process for rf phy direct test, test mode interup + + input parameters + + @param txPower : rf tx power + rfChnIdx : rf channel = 2402+(rfChnIdx<<1) + rfFoff : rf freq offset = rfFoff*4KHz + pktType : modulaiton data type, 0: prbs9, 1: 1111000: 2 10101010 + pktLength : pkt length(Byte) + + txPktNum : burst pkt tx number + txPktIntv : txPkt intv,0 txPkt intv is pkt interval = ceil((L+249)/625) * 625 + + output parameters + + @param none + + @return none +*/ +void rf_phy_dtm_ext_tx_mod_burst(uint8_t txPower, uint8_t rfChnIdx,uint8_t xtal_cap,int8_t rfFoff, + uint8_t pktType, uint8_t pktLength,uint32 txPktNum,uint32 txPktIntv) +{ + rf_phy_dtm_init(); + //====================================================================== + //rest RF_PHY_DTM_MODE + g_dtmModeType = RF_PHY_DTM_MODE_RESET; + rf_phy_dtm_trigged(); + //====================================================================== + //config dtm mode + g_dtmModeType = RF_PHY_DTM_MODE_TX_BURST; + g_dtmTxPower = txPower; + g_dtmFreq = rfChnIdx; + g_rfPhyPktFmt = PKT_FMT_BLE1M; + g_dtmPKT = pktType; + g_dtmLength = pktLength; + g_rfPhyFreqOffSet = rfFoff; + XTAL16M_CAP_SETTING(xtal_cap); + rf_phy_dtm_trigged(); + uint32_t currTick=0; + uint32_t deltTick=0; + uint32_t tIntv = 0; + + if(txPktIntv==0) + tIntv = g_dtmPktIntv; + else + tIntv = txPktIntv; + + while(txPktNum>0) + { + ll_hw_set_trx_settle (100, 8, 90); //TxBB,RxAFE,PLL + //subWriteReg(0x400300d4,7,4,0x0f); //boost vco current[7:4] to 0xf to reduce dcdc spur + currTick = read_current_fine_time(); + deltTick = RF_PHY_TIME_DELTA(currTick,g_dtmTick); + + if(deltTick>=tIntv) + { + ll_hw_rst_tfifo(); + ll_hw_trigger(); + txPktNum--; + g_dtmTick = g_dtmTick+tIntv; + + if(g_dtmTick>RF_PHY_TIME_BASE) + g_dtmTick = g_dtmTick-RF_PHY_TIME_BASE; + } + } + + //====================================================================== + //stop RF_PHY_DTM_MODE + rf_phy_dtm_stop(); +} + + +/************************************************************************************** + @fn rf_phy_dtm_ext_rx_demod_burst + + @brief This function process for rf phy direct test, test mode interup + + input parameters + + @param rfChnIdx : rf channel = 2402+(rfChnIdx<<1) + rfFoff : rf freq offset = rfFoff*4KHz + pktLength : pkt length(Byte) + rxWindow : rx demod window length(us) + rxTimeOut : rx on time (ms) + + output parameters + + @param rxEstFoff : rx demod estimated frequency offset + rxEstRssi : rx demod estimated rssi + rxEstCarrSens : rx demod estimated carrier sense + rxPktNum : rx demod received pkt number + + @return none +*/ +void rf_phy_dtm_ext_rx_demod_burst(uint8_t rfChnIdx,int8_t rfFoff,uint8_t xtal_cap,uint8_t pktLength,uint32 rxTimeOut,uint32 rxWindow, + uint16_t* rxEstFoff,uint8_t* rxEstRssi,uint8_t* rxEstCarrSens,uint16_t* rxPktNum) +{ + rf_phy_dtm_init(); + //====================================================================== + //rest RF_PHY_DTM_MODE + g_dtmModeType = RF_PHY_DTM_MODE_RESET; + rf_phy_dtm_trigged(); + //====================================================================== + //config dtm mode + g_dtmModeType = RF_PHY_DTM_MODE_RX_PER; + g_dtmFreq = rfChnIdx; + g_rfPhyPktFmt = PKT_FMT_BLE1M; + g_dtmLength = pktLength; + g_rfPhyFreqOffSet = rfFoff; + rf_phy_dtm_trigged(); + g_dtmPktCount = 0; + uint8_t rssi; + uint16_t foff; + uint8_t carrSens; + uint32 t0 = hal_systick(); + XTAL16M_CAP_SETTING(xtal_cap); + + while(hal_ms_intv(t0)0) + { + PHY_REG_WT(0x40031024,0xffff&rxWindow); + PHY_REG_WT(0x40031028,0xffff&rxWindow); + } + + if(ll_hw_get_irq_status()&LIRQ_MD) + { + if(ll_hw_get_irq_status()&LIRQ_COK) + { + g_dtmPktCount++; + rf_phy_get_pktFoot(&rssi,&foff,&carrSens); + } + else if(ll_hw_get_irq_status()&LIRQ_CERR) + { + g_dtmRxCrcNum++; + } + else if(ll_hw_get_irq_status()&LIRQ_RTO) + { + g_dtmRxTONum++; + } + else + { + //wrap the pktCount + g_dtmPktCount= (g_dtmPktCount==65535) ? 0 : g_dtmPktCount; + } + + ll_hw_clr_irq(); + ll_hw_trigger(); + + if(g_dtmPktCount>0) + { + g_dtmRssi = (g_dtmPktCount==1) ? rssi :((g_dtmRssi+rssi) >>1); + g_dtmFoff = (g_dtmPktCount==1) ? foff :((g_dtmFoff+foff) >>1); + g_dtmCarrSens = (g_dtmPktCount==1) ? carrSens :((g_dtmCarrSens+carrSens) >>1); + } + } + } + + *rxEstFoff = g_dtmFoff; + *rxEstRssi = g_dtmRssi; + *rxPktNum = g_dtmPktCount; + *rxEstCarrSens = g_dtmCarrSens; + //====================================================================== + //stop RF_PHY_DTM_MODE + rf_phy_dtm_stop(); +} + +/************************************************************************************** + @fn rf_phy_dtm_ext_acc_code_set + + @brief config the acc_code in rf phy dtm + + input parameters + + @param acc_code : sync word + + output parameters + @return none +*/ +void rf_phy_dtm_ext_acc_code_set(uint32 accCode) +{ + g_dtmAccessCode = accCode; +} + + + + + + diff --git a/src/lib/ble_host.lib b/src/lib/ble_host.lib new file mode 100644 index 0000000000000000000000000000000000000000..83c683d7aefc9cb1391299a84b3de7a20be69665 GIT binary patch literal 335968 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%0Dh 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

D30_axs^uz+#?r%^m6lA0pCFX!miwG#nM?O3P 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 literal 0 HcmV?d00001 diff --git a/src/lib/ble_host/att_client.c b/src/lib/ble_host/att_client.c new file mode 100644 index 0000000..88fd835 --- /dev/null +++ b/src/lib/ble_host/att_client.c @@ -0,0 +1,369 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: att_client.c + Revised: + Revision: + + Description: This file contains the Attribute Protocol Client. + + +**************************************************************************************************/ + + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" + +#include "att_internal.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +/********************************************************************* + LOCAL FUNCTIONS +*/ + +/********************************************************************* + API FUNCTIONS +*/ + +/********************************************************************* + @fn ATT_ExchangeMTUReq + + @brief Send Exchange MTU Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_ExchangeMTUReq( uint16 connHandle, attExchangeMTUReq_t* pReq ) +{ + // Validate Type field + if ( pReq->clientRxMTU >= ATT_MTU_SIZE_MIN && + pReq->clientRxMTU <= ATT_MTU_SIZE) // add 2020-0319 + { + return ( attSendMsg( connHandle, ATT_BuildExchangeMTUReq, ATT_EXCHANGE_MTU_REQ, (uint8*)pReq ) ); + } + + return ( INVALIDPARAMETER ); +} + +/********************************************************************* + @fn ATT_FindInfoReq + + @brief Send Find Information Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_FindInfoReq( uint16 connHandle, attFindInfoReq_t* pReq ) +{ + return ( attSendMsg( connHandle, ATT_BuildFindInfoReq, ATT_FIND_INFO_REQ, (uint8*)pReq ) ); +} + +/********************************************************************* + @fn ATT_FindByTypeValueReq + + @brief Send Find By Type Value Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_FindByTypeValueReq( uint16 connHandle, attFindByTypeValueReq_t* pReq ) +{ + // Validate the UUID field + if ( pReq->type.len == ATT_BT_UUID_SIZE ) + { + return ( attSendMsg( connHandle, ATT_BuildFindByTypeValueReq, + ATT_FIND_BY_TYPE_VALUE_REQ, (uint8*)pReq ) ); + } + + return ( INVALIDPARAMETER ); +} + +/********************************************************************* + @fn ATT_ReadByTypeReq + + @brief Send Read By Type Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_ReadByTypeReq( uint16 connHandle, attReadByTypeReq_t* pReq ) +{ + // Validate Type field + if ( ( pReq->type.len == ATT_UUID_SIZE ) || ( pReq->type.len == ATT_BT_UUID_SIZE ) ) + { + return ( attSendMsg( connHandle, ATT_BuildReadByTypeReq, ATT_READ_BY_TYPE_REQ, (uint8*)pReq ) ); + } + + return ( INVALIDPARAMETER ); +} + +/********************************************************************* + @fn ATT_ReadReq + + @brief Send Read Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_ReadReq( uint16 connHandle, attReadReq_t* pReq ) +{ + return ( attSendMsg( connHandle, ATT_BuildReadReq, ATT_READ_REQ, (uint8*)pReq ) ); +} + +/********************************************************************* + @fn ATT_ReadBlobReq + + @brief Send Read Blob Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_ReadBlobReq( uint16 connHandle, attReadBlobReq_t* pReq ) +{ + return ( attSendMsg( connHandle, ATT_BuildReadBlobReq, ATT_READ_BLOB_REQ, (uint8*)pReq ) ); +} + +/********************************************************************* + @fn ATT_ReadMultiReq + + @brief Send Read Multiple Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_ReadMultiReq( uint16 connHandle, attReadMultiReq_t* pReq ) +{ + // Validate number of attributes + if ( pReq->numHandles >= ATT_MIN_NUM_HANDLES ) + { + return ( attSendMsg( connHandle, ATT_BuildReadMultiReq, ATT_READ_MULTI_REQ, (uint8*)pReq ) ); + } + + return ( INVALIDPARAMETER ); +} + +/********************************************************************* + @fn ATT_ReadByGrpTypeReq + + @brief Send Read By Group Type Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_ReadByGrpTypeReq( uint16 connHandle, attReadByGrpTypeReq_t* pReq ) +{ + // Validate Type field + if ( ( pReq->type.len == ATT_UUID_SIZE ) || ( pReq->type.len == ATT_BT_UUID_SIZE ) ) + { + return ( attSendMsg( connHandle, ATT_BuildReadByTypeReq, ATT_READ_BY_GRP_TYPE_REQ, (uint8*)pReq ) ); + } + + return ( INVALIDPARAMETER ); +} + +/********************************************************************* + @fn ATT_WriteReq + + @brief Send Write Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. + bleLinkEncrypted: Connection is already encrypted. +*/ +bStatus_t ATT_WriteReq( uint16 connHandle, attWriteReq_t* pReq ) +{ + uint8 opcode = ATT_WRITE_REQ; + + if ( pReq->sig == TRUE ) + { + // Authentication Signature requested to be included + if ( pReq->len > ( gAttMtuSize[connHandle] - 15 ) ) + { + return ( INVALIDPARAMETER ); + } + + // Set the Authentication Signature Flag + opcode |= ATT_AUTHEN_SIG_FLAG_BIT; + } + + if ( pReq->cmd == TRUE ) + { + // Set the Command Flag + opcode |= ATT_CMD_FLAG_BIT; + } + + return ( attSendMsg( connHandle, ATT_BuildWriteReq, opcode, (uint8*)pReq ) ); +} + +/********************************************************************* + @fn ATT_PrepareWriteReq + + @brief Send Prepare Write Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_PrepareWriteReq( uint16 connHandle, attPrepareWriteReq_t* pReq ) +{ + return ( attSendMsg( connHandle, ATT_BuildPrepareWriteReq, ATT_PREPARE_WRITE_REQ, (uint8*)pReq ) ); +} + +/********************************************************************* + @fn ATT_ExecuteWriteReq + + @brief Send Execute Write Request. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_ExecuteWriteReq( uint16 connHandle, attExecuteWriteReq_t* pReq ) +{ + return ( attSendMsg( connHandle, ATT_BuildExecuteWriteReq, ATT_EXECUTE_WRITE_REQ, (uint8*)pReq ) ); +} + +/********************************************************************* + @fn ATT_HandleValueCfm + + @brief Send Handle Value Confirmation. + + @param connHandle - connection to use + + @return SUCCESS: Confirmation was sent successfully. + INVALIDPARAMETER: Invalid confirmation field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_HandleValueCfm( uint16 connHandle ) +{ + return ( attSendMsg( connHandle, NULL, ATT_HANDLE_VALUE_CFM, NULL ) ); +} + + +/**************************************************************************** +****************************************************************************/ diff --git a/src/lib/ble_host/att_server.c b/src/lib/ble_host/att_server.c new file mode 100644 index 0000000..2d084c9 --- /dev/null +++ b/src/lib/ble_host/att_server.c @@ -0,0 +1,394 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: att_server.c + Revised: + Revision: + + Description: This file contains the Attribute Protocol Server. + + +**************************************************************************************************/ + + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" + +#include "att_internal.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +/********************************************************************* + LOCAL FUNCTIONS +*/ + +/********************************************************************* + API FUNCTIONS +*/ + +/********************************************************************* + @fn ATT_ErrorRsp + + @brief Send Error Response. + + @param connHandle - connection to use + @param pRsp - pointer to error response to be sent + + @return SUCCESS: Response was sent successfully. + INVALIDPARAMETER: Invalid response field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_ErrorRsp( uint16 connHandle, attErrorRsp_t* pRsp ) +{ + return ( attSendMsg( connHandle, ATT_BuildErrorRsp, ATT_ERROR_RSP, (uint8*)pRsp ) ); +} + +/********************************************************************* + @fn ATT_ExchangeMTURsp + + @brief Send Exchange MTU Response. + + @param connHandle - connection to use + @param pRsp - pointer to request to be sent + + @return SUCCESS: Response was sent successfully. + INVALIDPARAMETER: Invalid response field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_ExchangeMTURsp( uint16 connHandle, attExchangeMTURsp_t* pRsp ) +{ + // Validate Type field + if ( pRsp->serverRxMTU >= ATT_MTU_SIZE_MIN ) + { + bStatus_t ret = attSendMsg( connHandle, ATT_BuildExchangeMTURsp, ATT_EXCHANGE_MTU_RSP, (uint8*)pRsp ) ; + #if 1 + + if(ret==SUCCESS) + { +// ATT_MTU_SIZE_UPDATE(MIN(pRsp->serverRxMTU,g_attMtuClientServer.clientMTU)); + ATT_UpdateMtuSize(connHandle, MIN(pRsp->serverRxMTU,g_attMtuClientServer.clientMTU)); + } + + #endif + return (ret ); + } + + return ( INVALIDPARAMETER ); +} + +/********************************************************************* + @fn ATT_FindInfoRsp + + @brief Send Find Information Response. + + @param connHandle - connection to use + @param pRsp - pointer to response to be sent + + @return SUCCESS: Response was sent successfully. + INVALIDPARAMETER: Invalid response field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_FindInfoRsp( uint16 connHandle, attFindInfoRsp_t* pRsp ) +{ + // Validate Type field + if ( ( ( pRsp->format == ATT_HANDLE_BT_UUID_TYPE ) || + ( pRsp->format == ATT_HANDLE_UUID_TYPE ) ) && + ( pRsp->numInfo > 0 ) ) + { + return ( attSendMsg( connHandle, ATT_BuildFindInfoRsp, ATT_FIND_INFO_RSP, (uint8*)pRsp ) ); + } + + return ( INVALIDPARAMETER ); +} + +/********************************************************************* + @fn ATT_FindByTypeValueRsp + + @brief Send Find By Tyep Value Response. + + @param connHandle - connection to use + @param pRsp - pointer to response to be sent + + @return SUCCESS: Response was sent successfully. + INVALIDPARAMETER: Invalid response field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_FindByTypeValueRsp( uint16 connHandle, attFindByTypeValueRsp_t* pRsp ) +{ + // Validate number of handle range field + if ( pRsp->numInfo > 0 ) + { + return ( attSendMsg( connHandle, ATT_BuildFindByTypeValueRsp, + ATT_FIND_BY_TYPE_VALUE_RSP, (uint8*)pRsp ) ); + } + + return ( INVALIDPARAMETER ); +} + +/********************************************************************* + @fn ATT_ReadByTypeRsp + + @brief Send Read By Type Respond. + + @param connHandle - connection to use + @param pRsp - pointer to response to be sent + + @return SUCCESS: Response was sent successfully. + INVALIDPARAMETER: Invalid response field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_ReadByTypeRsp( uint16 connHandle, attReadByTypeRsp_t* pRsp ) +{ + if ( pRsp->numPairs > 0 ) + { + return ( attSendMsg( connHandle, ATT_BuildReadByTypeRsp, ATT_READ_BY_TYPE_RSP, (uint8*)pRsp ) ); + } + + return ( INVALIDPARAMETER ); +} + +/********************************************************************* + @fn ATT_ReadRsp + + @brief Send Read Response. + + @param connHandle - connection to use + @param pRsp - pointer to response to be sent + + @return SUCCESS: Response was sent successfully. + INVALIDPARAMETER: Invalid response field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_ReadRsp( uint16 connHandle, attReadRsp_t* pRsp ) +{ + return ( attSendMsg( connHandle, ATT_BuildReadRsp, ATT_READ_RSP, (uint8*)pRsp ) ); +} + +/********************************************************************* + @fn ATT_ReadBlobRsp + + @brief Send Read Blob Response. + + @param connHandle - connection to use + @param pRsp - pointer to response to be sent + + @return SUCCESS: Response was sent successfully. + INVALIDPARAMETER: Invalid response field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_ReadBlobRsp( uint16 connHandle, attReadBlobRsp_t* pRsp ) +{ + return ( attSendMsg( connHandle, ATT_BuildReadBlobRsp, ATT_READ_BLOB_RSP, (uint8*)pRsp ) ); +} + +/********************************************************************* + @fn ATT_ReadMultiRsp + + @brief Send Read Multiple Response. + + @param connHandle - connection to use + @param pRsp - pointer to response to be sent + + @return SUCCESS: Response was sent successfully. + INVALIDPARAMETER: Invalid response field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_ReadMultiRsp( uint16 connHandle, attReadMultiRsp_t* pRsp ) +{ + return ( attSendMsg( connHandle, ATT_BuildReadMultiRsp, ATT_READ_MULTI_RSP, (uint8*)pRsp ) ); +} + +/********************************************************************* + @fn ATT_ReadByGrpTypeRsp + + @brief Send Read By Group Type Respond. + + @param connHandle - connection to use + @param pRsp - pointer to response to be sent + + @return SUCCESS: Response was sent successfully. + INVALIDPARAMETER: Invalid response field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_ReadByGrpTypeRsp( uint16 connHandle, attReadByGrpTypeRsp_t* pRsp ) +{ + if ( pRsp->numGrps > 0 ) + { + return ( attSendMsg( connHandle, ATT_BuildReadByGrpTypeRsp, ATT_READ_BY_GRP_TYPE_RSP, (uint8*)pRsp ) ); + } + + return ( INVALIDPARAMETER ); +} + +/********************************************************************* + @fn ATT_WriteRsp + + @brief Send Write Response. + + @param connHandle - connection to use + + @return SUCCESS: Response was sent successfully. + INVALIDPARAMETER: Invalid response field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_WriteRsp( uint16 connHandle ) +{ + return ( attSendMsg( connHandle, NULL, ATT_WRITE_RSP, NULL ) ); +} + +/********************************************************************* + @fn ATT_PrepareWriteRsp + + @brief Send Prepare Write Response. + + @param connHandle - connection to use + @param pRsp - pointer to response to be sent + + @return SUCCESS: Response was sent successfully. + INVALIDPARAMETER: Invalid response field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_PrepareWriteRsp( uint16 connHandle, attPrepareWriteRsp_t* pRsp ) +{ + return ( attSendMsg( connHandle, ATT_BuildPrepareWriteRsp, ATT_PREPARE_WRITE_RSP, (uint8*)pRsp ) ); +} + +/********************************************************************* + @fn ATT_ExecuteWriteRsp + + @brief Send Execute Write Response. + + @param connHandle - connection to use + + @return SUCCESS: Response was sent successfully. + INVALIDPARAMETER: Invalid response field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_ExecuteWriteRsp( uint16 connHandle ) +{ + return ( attSendMsg( connHandle, NULL, ATT_EXECUTE_WRITE_RSP, NULL ) ); +} + +/********************************************************************* + @fn ATT_HandleValueNoti + + @brief Send Handle Value Notification. + + @param connHandle - connection to use + @param pNoti - pointer to notification to be sent + + @return SUCCESS: Notification was sent successfully. + INVALIDPARAMETER: Invalid notification field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_HandleValueNoti( uint16 connHandle, attHandleValueNoti_t* pNoti ) +{ + return ( attSendMsg( connHandle, ATT_BuildHandleValueInd, ATT_HANDLE_VALUE_NOTI, (uint8*)pNoti ) ); +} + +/********************************************************************* + @fn ATT_HandleValueInd + + @brief Send Handle Value Indication. + + @param connHandle - connection to use + @param pInd - pointer to indication to be sent + + @return SUCCESS: Indication was sent successfully. + INVALIDPARAMETER: Invalid indication field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t ATT_HandleValueInd( uint16 connHandle, attHandleValueInd_t* pInd ) +{ + return ( attSendMsg( connHandle, ATT_BuildHandleValueInd, ATT_HANDLE_VALUE_IND, (uint8*)pInd ) ); +} + + +/**************************************************************************** +****************************************************************************/ diff --git a/src/lib/ble_host/att_util.c b/src/lib/ble_host/att_util.c new file mode 100644 index 0000000..1e01429 --- /dev/null +++ b/src/lib/ble_host/att_util.c @@ -0,0 +1,1819 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: att_util.c + Revised: + Revision: + + Description: This file contains the the utility functions used by + the Attribute Protocol Client and Server. + + +**************************************************************************************************/ + + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "osal_bufmgr.h" +#include "linkdb.h" +#include "sm.h" + +#include "att_internal.h" + +/********************************************************************* + MACROS +*/ +// Attribute opcode fields +#define attMethod( opcode ) ( (opcode) & ATT_METHOD_BITS ) +#define attCmdFlag( opcode ) ( (opcode) & ATT_CMD_FLAG_BIT ) +#define attAuthenSigFlag( opcode ) ( (opcode) & ATT_AUTHEN_SIG_FLAG_BIT ) + +/********************************************************************* + CONSTANTS +*/ +// Length of Exchange MTU Request: client receive MTU size (2) +#define EXCHANGE_MTU_REQ_SIZE 2 + +// Length of Exchange MTU Response: server receive MTU size (2) +#define EXCHANGE_MTU_RSP_SIZE 2 + +// Length of Error Response: Command opcode in error (1) + Attribute handle in error (2) + Status code (1) +#define ERROR_RSP_SIZE 4 + +// Length of Find Information Request's fixed fields: First handle number (2) + Last handle number (2) +#define FIND_INFO_REQ_FIXED_SIZE 4 + +// Length of Find Information Response's fixed field: Format (1) +#define FIND_INFO_RSP_FIXED_SIZE 1 + +// Length of Find By Type Value Request's fixed fields: First handle number (2) + Last handle number (2) +#define FIND_BY_TYPE_VALUE_REQ_FIXED_SIZE 4 + +// Length of Read By Type Response's fixed fields: Length (1) + Attribute handle number (2) +#define READ_BY_TYPE_RSP_FIXED_SIZE 3 + +// Length of Read Request: Attribute Handle (2) +#define READ_REQ_SIZE 2 + +// Length of Write Request's fixed field: Attribute Handle (2) +#define WRITE_REQ_FIXED_SIZE 2 + +// Length of Read Blob Request: Attribute Handle (2) + Value Offset (2) +#define READ_BLOB_REQ_SIZE 4 + +// Length of Prepare Write Response's fixed size: Attribute Handle (2) + Value Offset (2) +#define PREPARE_WRITE_RSP_FIXED_SIZE 4 + +// Length of Execute Write Request: Flags (1) +#define EXECUTE_WRITE_REQ_SIZE 1 + +// Length of Handle Value Indication's fixed size: Attribute Handle (2) +#define HANDLE_VALUE_IND_FIXED_SIZE 2 + +// Length of Authentication Signature field +#define AUTHEN_SIG_LEN 12 + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +// Bluetooth base UUID for Attribute Protocol: 00000000-0000-1000-8000-00805F9B34FB +CONST uint8 btBaseUUID[ATT_UUID_SIZE] = +{ + 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +//add for MTU size exchange +uint16 g_ATT_MTU_SIZE_MAX = ATT_MTU_SIZE; + +uint16 g_ATT_MAX_NUM_HANDLES_INFO =( ( ATT_MTU_SIZE_MIN - 1 ) / 4 ); +uint16 g_ATT_MAX_NUM_HANDLES =( ( ATT_MTU_SIZE_MIN - 1 ) / 2 ); +attMTU_t g_attMtuClientServer; + +// multi-role MTU size variables +uint16 gAttMtuSize[MAX_NUM_LL_CONN]; + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ +#if defined ( TESTMODES ) + static uint16 paramValue = 0; +#endif + +/********************************************************************* + LOCAL FUNCTIONS +*/ + +/********************************************************************* + API FUNCTIONS +*/ + +/********************************************************************* + @fn ATT_ParsePacket + + @brief Parse an attribute protocol message received over the ATT + fixed channel. + + @param pL2capMsg �C pointer to received L2CAP message + @param pPkt �C pointer to parsed packet + + @return SUCCESS or FAILURE +*/ +uint8 ATT_ParsePacket( l2capDataEvent_t* pL2capMsg, attPacket_t* pPkt ) +{ + uint16 len = pL2capMsg->pkt.len; + + // PDU should contain at least the Opcode + if ( len > 0 ) + { + // Attribute Opcode + uint8 opcode = pL2capMsg->pkt.pPayload[0]; + + // First check for authenticated data + if ( attAuthenSigFlag( opcode ) != 0 ) + { + uint8 authenSig; // Whether or not to authenticate incoming signature + + // PDU should contain at least the Opcode and Authentication Signature + if ( len <= AUTHEN_SIG_LEN ) + { + return ( FAILURE ); + } + + #if defined ( TESTMODES ) + + if ( paramValue == ATT_TESTMODE_UNAUTHEN_SIG ) + { + authenSig = FALSE; // Don't authenticate incoming signature + } + else + #endif + authenSig = TRUE; // Authenticate incoming signature + + len -= AUTHEN_SIG_LEN; // Subtract length of Authentication Signature + + // Verify the Athentication Signature + if ( SM_VerifyAuthenSig( pL2capMsg->connHandle, authenSig, pL2capMsg->pkt.pPayload, + len, &(pL2capMsg->pkt.pPayload[len]) ) == SUCCESS ) + { + pPkt->sig = ATT_SIG_VALID; + } + else + { + pPkt->sig = ATT_SIG_INVALID; + } + } + else + { + // No Athentication Signature is included with this PDU + pPkt->sig = ATT_SIG_NOT_INCLUDED; + } + + // Command Flag + pPkt->cmd = attCmdFlag( opcode ) == 0 ? FALSE : TRUE; + // Method + pPkt->method = attMethod( opcode ); + // Length of the attribute PDU paramters + pPkt->len = len - 1; + + if ( pPkt->len > 0 ) + { + // Attribute PDU parameters + pPkt->pParams = &(pL2capMsg->pkt.pPayload[1]); + } + else + { + // No attribute PDU parameter + pPkt->pParams = NULL; + } + + return ( SUCCESS ); + } + + return ( FAILURE ); +} + +/********************************************************************* + @fn ATT_BuildErrorRsp + + @brief Build Error Response. + + @param pBuf - pointer to buffer to be build + @param pMsg - pointer to message structure + + @return length of the command data +*/ +uint16 ATT_BuildErrorRsp( uint8* pBuf, uint8* pMsg ) +{ + attErrorRsp_t* pRsp = (attErrorRsp_t*)pMsg; + // Command opcode in error + *pBuf++ = pRsp->reqOpcode; + // Attribute handle in error + *pBuf++ = LO_UINT16( pRsp->handle ); + *pBuf++ = HI_UINT16( pRsp->handle ); + // Error code + *pBuf = pRsp->errCode; + return ( ERROR_RSP_SIZE ); +} + +/********************************************************************* + @fn ATT_ParseErrorRsp + + @brief Parse Error Response message. + + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseErrorRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + if ( len == ERROR_RSP_SIZE ) + { + attErrorRsp_t* pRsp = &pMsg->errorRsp; + // Command opcode in error + pRsp->reqOpcode = pParams[0]; + // Attribute handle in error + pRsp->handle = BUILD_UINT16( pParams[1], pParams[2] ); + // Error code + pRsp->errCode = pParams[3]; + return ( SUCCESS ); + } + + return ( ATT_ERR_INVALID_PDU ); +} + +/********************************************************************* + @fn ATT_BuildExchangeMTUReq + + @brief Build Exchange MTU Request. + + @param pBuf - pointer to buffer to be built + @param pMsg - pointer to message structure + + @return length of the request data +*/ +uint16 ATT_BuildExchangeMTUReq( uint8* pBuf, uint8* pMsg ) +{ + attExchangeMTUReq_t* pReq = (attExchangeMTUReq_t*)pMsg; + // Client receive MTU size + *pBuf++ = LO_UINT16( pReq->clientRxMTU ); + *pBuf = HI_UINT16( pReq->clientRxMTU ); + return ( READ_REQ_SIZE ); +} + +/********************************************************************* + @fn ATT_ParseExchangeMTUReq + + @brief Parse Exchange MTU message. + + @param sig - authentication signature status + @param cmd - command flag + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseExchangeMTUReq( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + VOID sig; // Not applicable to this message + VOID cmd; // Not applicable to this message + + if ( len == EXCHANGE_MTU_REQ_SIZE ) + { + attExchangeMTUReq_t* pReq = &pMsg->exchangeMTUReq; + // Client receive MTU size + pReq->clientRxMTU = BUILD_UINT16( pParams[0], pParams[1] ); + return ( SUCCESS); + } + + return ( ATT_ERR_INVALID_PDU ); +} + +/********************************************************************* + @fn ATT_BuildExchangeMTURsp + + @brief Build Exchange MTU Response. + + @param pBuf - pointer to buffer to be built + @param pMsg - pointer to message structure + + @return length of the command data +*/ +uint16 ATT_BuildExchangeMTURsp( uint8* pBuf, uint8* pMsg ) +{ + attExchangeMTURsp_t* pRsp = (attExchangeMTURsp_t*)pMsg; + // Server receive MTU size + *pBuf++ = LO_UINT16( pRsp->serverRxMTU ); + *pBuf = HI_UINT16( pRsp->serverRxMTU ); + return ( EXCHANGE_MTU_RSP_SIZE ); +} + +/********************************************************************* + @fn ATT_ParseExchangeMTURsp + + @brief Parse Exchange MTU Response message. + + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseExchangeMTURsp( uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + if ( len == EXCHANGE_MTU_RSP_SIZE ) + { + attExchangeMTURsp_t* pRsp = &pMsg->exchangeMTURsp; + // Server receive MTU size + pRsp->serverRxMTU = BUILD_UINT16( pParams[0], pParams[1] ); + return ( SUCCESS); + } + + return ( ATT_ERR_INVALID_PDU ); +} + +/********************************************************************* + @fn ATT_BuildFindInfoReq + + @brief Build Find Information Request. + + @param pBuf - pointer to buffer to be built + @param pMsg - pointer to message structure + + @return length of the command data +*/ +uint16 ATT_BuildFindInfoReq( uint8* pBuf, uint8* pMsg ) +{ + attFindInfoReq_t* pReq = (attFindInfoReq_t*)pMsg; + // First requested handle number + *pBuf++ = LO_UINT16( pReq->startHandle ); + *pBuf++ = HI_UINT16( pReq->startHandle ); + // Last requested handle number + *pBuf++ = LO_UINT16( pReq->endHandle ); + *pBuf = HI_UINT16( pReq->endHandle ); + return ( FIND_INFO_REQ_FIXED_SIZE ); +} + +/********************************************************************* + @fn ATT_ParseFindInfoReq + + @brief Parse FInd Information Request message. + + @param sig - authentication signature status + @param cmd - command flag + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseFindInfoReq( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + VOID sig; // Not applicable to this message + VOID cmd; // Not applicable to this message + + // Requested UUID + if ( len == FIND_INFO_REQ_FIXED_SIZE ) + { + attFindInfoReq_t* pReq = &pMsg->findInfoReq; + // First requested handle number + pReq->startHandle = BUILD_UINT16( pParams[0], pParams[1] ); + // Last requested handle number + pReq->endHandle = BUILD_UINT16( pParams[2], pParams[3] ); + return ( SUCCESS ); + } + + return ( ATT_ERR_INVALID_PDU ); +} + +/********************************************************************* + @fn ATT_BuildFindInfoRsp + + @brief Build Find Information Response. + + @param pBuf - pointer to buffer to be built + @param pMsg - pointer to message structure + + @return length of the command data +*/ +uint16 ATT_BuildFindInfoRsp( uint8* pBuf, uint8* pMsg ) +{ + uint16 len = FIND_INFO_RSP_FIXED_SIZE; + attFindInfoRsp_t* pRsp = (attFindInfoRsp_t*)pMsg; + // Format + *pBuf++ = pRsp->format; + + // Information data (handle-UUID pairs) + for ( uint8 i = 0; i < pRsp->numInfo; i++ ) + { + if ( pRsp->format == ATT_HANDLE_BT_UUID_TYPE ) + { + // Handle + *pBuf++ = LO_UINT16( pRsp->info.btPair[i].handle ); + *pBuf++ = HI_UINT16( pRsp->info.btPair[i].handle ); + len += 2; + // 2-octet Bluetooth UUID + VOID osal_memcpy( pBuf, pRsp->info.btPair[i].uuid, ATT_BT_UUID_SIZE ); + pBuf += ATT_BT_UUID_SIZE; + len += ATT_BT_UUID_SIZE; + } + else // ATT_HANDLE_UUID_TYPE + { + // Handle + *pBuf++ = LO_UINT16( pRsp->info.pair[i].handle ); + *pBuf++ = HI_UINT16( pRsp->info.pair[i].handle ); + len += 2; + // 16-octet UUID + VOID osal_memcpy( pBuf, pRsp->info.pair[i].uuid, ATT_UUID_SIZE ); + pBuf += ATT_UUID_SIZE; + len += ATT_UUID_SIZE; + } + } // for + + return ( len ); +} + +/********************************************************************* + @fn ATT_ParseFindInfoRsp + + @brief Parse Find Information Response message. + + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseFindInfoRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + uint8 stat = ATT_ERR_INVALID_PDU; + + if ( len >= FIND_INFO_RSP_FIXED_SIZE ) + { + uint8 numInfo = 0; + uint8 dataLen = len - FIND_INFO_RSP_FIXED_SIZE; // Length of information data field + + // Find out the number of handle-UUID pairs + if ( ( pParams[0] == ATT_HANDLE_BT_UUID_TYPE ) && ( dataLen % ( 2 + ATT_BT_UUID_SIZE ) == 0 ) ) + { + numInfo = dataLen / ( 2 + ATT_BT_UUID_SIZE ); + + // Validate the number of Handle and 2-octet UUID pairs + if ( ( numInfo > 0 ) && ( numInfo <= ATT_MAX_NUM_HANDLE_BT_UUID ) ) + { + stat = SUCCESS; + } + } + else if ( ( pParams[0] == ATT_HANDLE_UUID_TYPE ) && ( dataLen % ( 2 + ATT_UUID_SIZE ) == 0 ) ) + { + numInfo = dataLen / ( 2 + ATT_UUID_SIZE ); + + // Validate the number of handle and 16-octet UUID pairs + if ( ( numInfo > 0 ) && ( numInfo <= ATT_MAX_NUM_HANDLE_UUID ) ) + { + stat = SUCCESS; + } + } + + // See if we need to parse the rest of the PDU + if ( stat == SUCCESS ) + { + attFindInfoRsp_t* pRsp = &pMsg->findInfoRsp; + // Format + pRsp->format = *pParams++; + // Number of handle-UUID pairs + pRsp->numInfo = numInfo; + + // Parse information data (handle-UUID pairs) + for ( uint8 i = 0; i < numInfo; i++ ) + { + if ( pRsp->format == ATT_HANDLE_BT_UUID_TYPE ) + { + // Handle + pRsp->info.btPair[i].handle = BUILD_UINT16( pParams[0], pParams[1] ); + pParams += 2; + // 2-octet Bluetooth UUID + VOID osal_memcpy( pRsp->info.btPair[i].uuid, pParams, ATT_BT_UUID_SIZE ); + pParams += ATT_BT_UUID_SIZE; + } + else // ATT_HANDLE_UUID_TYPE + { + // Handle + pRsp->info.pair[i].handle = BUILD_UINT16( pParams[0], pParams[1] ); + pParams += 2; + // 16-octet Bluetooth UUID + VOID osal_memcpy( pRsp->info.pair[i].uuid, pParams, ATT_UUID_SIZE ); + pParams += ATT_UUID_SIZE; + } + } // for + } + } + + return ( stat ); +} + +/********************************************************************* + @fn ATT_BuildFindByTypeValueReq + + @brief Build Find By Type Value Request. + + @param pBuf - pointer to buffer to be built + @param pMsg - pointer to message structure + + @return length of the command data +*/ +uint16 ATT_BuildFindByTypeValueReq( uint8* pBuf, uint8* pMsg ) +{ + attFindByTypeValueReq_t* pReq = (attFindByTypeValueReq_t*)pMsg; + // First requested handle number + *pBuf++ = LO_UINT16( pReq->startHandle ); + *pBuf++ = HI_UINT16( pReq->startHandle ); + // Last requested handle number + *pBuf++ = LO_UINT16( pReq->endHandle ); + *pBuf++ = HI_UINT16( pReq->endHandle ); + // Requested 2 octet UUID + VOID osal_memcpy( pBuf, pReq->type.uuid, pReq->type.len ); + pBuf += pReq->type.len; + // Attribute value + VOID osal_memcpy( pBuf, pReq->value, pReq->len ); + return ( FIND_BY_TYPE_VALUE_REQ_FIXED_SIZE + pReq->type.len + pReq->len ); +} + +/********************************************************************* + @fn ATT_ParseFindByTypeValueReq + + @brief Parse Find By Type Value Request message. + + @param sig - authentication signature status + @param cmd - command flag + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseFindByTypeValueReq( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + VOID sig; // Not applicable to this message + VOID cmd; // Not applicable to this message + + if ( len >= FIND_BY_TYPE_VALUE_REQ_FIXED_SIZE + ATT_BT_UUID_SIZE ) + { + attFindByTypeValueReq_t* pReq = &pMsg->findByTypeValueReq; + // First requested handle number + pReq->startHandle = BUILD_UINT16( pParams[0], pParams[1] ); + // Last requested handle number + pReq->endHandle = BUILD_UINT16( pParams[2], pParams[3] ); + // 2 octet UUID + pReq->type.len = ATT_BT_UUID_SIZE; + // Requested 2 octet UUID + VOID osal_memcpy( pReq->type.uuid, &pParams[4], pReq->type.len ); + // length of attribute value + pReq->len = len - ( FIND_BY_TYPE_VALUE_REQ_FIXED_SIZE + ATT_BT_UUID_SIZE ); + + // Requested attribute value + if ( pReq->len <= ATT_MTU_SIZE - 7 ) + { + VOID osal_memcpy( pReq->value, &pParams[6], pReq->len ); + return ( SUCCESS); + } + } + + return ( ATT_ERR_INVALID_PDU ); +} + +/********************************************************************* + @fn ATT_BuildFindByTypeValueRsp + + @brief Build Find By Type Value Response. + + @param pBuf - pointer to buffer to be built + @param pMsg - pointer to message structure + + @return length of the command data +*/ +uint16 ATT_BuildFindByTypeValueRsp( uint8* pBuf, uint8* pMsg ) +{ + attFindByTypeValueRsp_t* pRsp = (attFindByTypeValueRsp_t*)pMsg; + + for ( uint8 i = 0; i < pRsp->numInfo; i++ ) + { + // Attribute handle + *pBuf++ = LO_UINT16( pRsp->handlesInfo[i].handle ); + *pBuf++ = HI_UINT16( pRsp->handlesInfo[i].handle ); + // End handle + *pBuf++ = LO_UINT16( pRsp->handlesInfo[i].grpEndHandle ); + *pBuf++ = HI_UINT16( pRsp->handlesInfo[i].grpEndHandle ); + } // for + + return ( pRsp->numInfo * 4 ); +} + +/********************************************************************* + @fn ATT_ParseFindByTypeValueRsp + + @brief Parse Find By Type Value Response message. + + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseFindByTypeValueRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + // Make sure there's at least one handle range in the response + if ( len % 4 == 0 ) + { + uint8 numInfo = len / 4; // Number of handle ranges + + if ( ( numInfo > 0 ) && ( numInfo <= g_ATT_MAX_NUM_HANDLES_INFO ) ) + { + attFindByTypeValueRsp_t* pRsp = &pMsg->findByTypeValueRsp; + pRsp->numInfo = numInfo; + + for ( uint8 i = 0; i < numInfo; i++ ) + { + // First requested handle number + pRsp->handlesInfo[i].handle = BUILD_UINT16( pParams[0], pParams[1] ); + // Last requested handle number + pRsp->handlesInfo[i].grpEndHandle = BUILD_UINT16( pParams[2], pParams[3] ); + // Next handle range + pParams += 4; + } + + return ( SUCCESS ); + } + } + + return ( ATT_ERR_INVALID_PDU); +} + +/********************************************************************* + @fn ATT_BuildReadByTypeReq + + @brief Build Read By Type Request. + + @param pBuf - pointer to buffer to be built + @param pMsg - pointer to message structure + + @return length of the command data +*/ +uint16 ATT_BuildReadByTypeReq( uint8* pBuf, uint8* pMsg ) +{ + uint16 len = READ_BY_TYPE_REQ_FIXED_SIZE; + attReadByTypeReq_t* pReq = (attReadByTypeReq_t*)pMsg; + // First requested handle number + *pBuf++ = LO_UINT16( pReq->startHandle ); + *pBuf++ = HI_UINT16( pReq->startHandle ); + // Last requested handle number + *pBuf++ = LO_UINT16( pReq->endHandle ); + *pBuf++ = HI_UINT16( pReq->endHandle ); + // Requested UUID (2 or 16 octect) + VOID osal_memcpy( pBuf, pReq->type.uuid, pReq->type.len ); + len += pReq->type.len; + return ( len ); +} + +/********************************************************************* + @fn ATT_ParseReadByTypeReq + + @brief Parse Read By Type Request message. + + @param sig - authentication signature status + @param cmd - command flag + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseReadByTypeReq( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + attReadByTypeReq_t* pReq = &pMsg->readByTypeReq; + VOID sig; // Not applicable to this message + VOID cmd; // Not applicable to this message + + if ( len == READ_BY_TYPE_REQ_FIXED_SIZE + ATT_BT_UUID_SIZE ) + { + // 2-octet UUID + pReq->type.len = ATT_BT_UUID_SIZE; + } + else if ( len == READ_BY_TYPE_REQ_FIXED_SIZE + ATT_UUID_SIZE ) + { + // 16-octet UUID + pReq->type.len = ATT_UUID_SIZE; + } + else + { + return ( ATT_ERR_INVALID_PDU ); + } + + // First requested handle number + pReq->startHandle = BUILD_UINT16( pParams[0], pParams[1] ); + // Last requested handle number + pReq->endHandle = BUILD_UINT16( pParams[2], pParams[3] ); + // Requested UUID + VOID osal_memcpy( pReq->type.uuid, &pParams[4], pReq->type.len ); + return ( SUCCESS); +} + +/********************************************************************* + @fn ATT_BuildReadByTypeRsp + + @brief Build Read By Type Response. + + @param pBuf - pointer to buffer to be built + @param pMsg - pointer to message structure + + @return length of the command data +*/ +uint16 ATT_BuildReadByTypeRsp( uint8* pBuf, uint8* pMsg ) +{ + attReadByTypeRsp_t* pRsp = (attReadByTypeRsp_t*)pMsg; + uint8 dataLen = pRsp->numPairs * pRsp->len; + // Length of each attribute handle-value pair + *pBuf++ = pRsp->len; + // List of 1 or more attribute handle-value pairs + VOID osal_memcpy( pBuf, pRsp->dataList, dataLen ); + return ( dataLen + 1 ); +} + +/********************************************************************* + @fn ATT_ParseReadByTypeRsp + + @brief Parse Read By Type Response message. + + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseReadByTypeRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + attReadByTypeRsp_t* pRsp = &pMsg->readByTypeRsp; + + if ( len >= READ_BY_TYPE_RSP_FIXED_SIZE ) + { + uint8 dataLen = len - 1; + // Length of each attribute handle-value pair + pRsp->len = pParams[0]; + + if ( ( dataLen <= ATT_MTU_SIZE - 2 ) && + ( pRsp->len > 0 ) && + ( ( dataLen % pRsp->len ) == 0 ) ) + { + // Total length of attribute handle-value pairs + pRsp->numPairs = dataLen / pRsp->len; + // List of 1 or more attribute handle-value pairs + VOID osal_memcpy( pRsp->dataList, &pParams[1], dataLen ); + return ( SUCCESS); + } + } + + return ( ATT_ERR_INVALID_PDU ); +} + +/********************************************************************* + @fn ATT_BuildReadReq + + @brief Build Read Request. + + @param pBuf - pointer to buffer to be built + @param pMsg - pointer to message structure + + @return length of the request data +*/ +uint16 ATT_BuildReadReq( uint8* pBuf, uint8* pMsg ) +{ + attReadReq_t* pReq = (attReadReq_t*)pMsg; + // Attribute handle + *pBuf++ = LO_UINT16( pReq->handle ); + *pBuf = HI_UINT16( pReq->handle ); + return ( READ_REQ_SIZE ); +} + +/********************************************************************* + @fn ATT_ParseReadReq + + @brief Parse Read Request message. + + @param sig - authentication signature status + @param cmd - command flag + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseReadReq( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + VOID sig; // Not applicable to this message + VOID cmd; // Not applicable to this message + + if ( len == READ_REQ_SIZE ) + { + attReadReq_t* pReq = &pMsg->readReq; + // Attribute handle + pReq->handle = BUILD_UINT16( pParams[0], pParams[1] ); + return ( SUCCESS); + } + + return ( ATT_ERR_INVALID_PDU ); +} + +/********************************************************************* + @fn ATT_BuildReadRsp + + @brief Build Read Response. + + @param pBuf - pointer to buffer to be built + @param pMsg - pointer to message structure + + @return length of the command data +*/ +uint16 ATT_BuildReadRsp( uint8* pBuf, uint8* pMsg ) +{ + attReadRsp_t* pRsp = (attReadRsp_t*)pMsg; + // Attribute value + VOID osal_memcpy( pBuf, pRsp->value, pRsp->len ); + return ( pRsp->len ); +} + +/********************************************************************* + @fn ATT_ParseReadRsp + + @brief Parse Read Response message. + + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseReadRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + attReadRsp_t* pRsp = &pMsg->readRsp; + + // Attribute value + if ( len <= ATT_MTU_SIZE - 1 ) + { + pRsp->len = len; + VOID osal_memcpy( pRsp->value, pParams, len ); + return ( SUCCESS); + } + + return ( ATT_ERR_INVALID_PDU ); +} + +/********************************************************************* + @fn ATT_ParseWriteReq + + @brief Parse Write Command message. + + @param sig - authentication signature status + @param cmd - command flag + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseWriteReq( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + if ( len >= WRITE_REQ_FIXED_SIZE ) + { + attWriteReq_t* pReq = &pMsg->writeReq; + uint16 maxLen; + // Attribute handle + pReq->handle = BUILD_UINT16( pParams[0], pParams[1] ); + // Authentication signature + pReq->sig = sig; + // Command flag + pReq->cmd = cmd; + + if ( sig == ATT_SIG_NOT_INCLUDED ) + { + maxLen = ATT_MTU_SIZE - 3; + } + else + { + maxLen = ATT_MTU_SIZE - (AUTHEN_SIG_LEN + 3); + } + + // Attribute value length + pReq->len = len - WRITE_REQ_FIXED_SIZE; + + // Attribute value + if ( pReq->len <= maxLen ) + { + VOID osal_memcpy( pReq->value, &pParams[2], pReq->len ); + return ( SUCCESS); + } + } + + return ( ATT_ERR_INVALID_PDU ); +} + +/********************************************************************* + @fn ATT_BuildWriteReq + + @brief Build Write Request/Command. + + @param pBuf - pointer to buffer to be built + @param pMsg - pointer to message structure + + @return length of the request data +*/ +uint16 ATT_BuildWriteReq( uint8* pBuf, uint8* pMsg ) +{ + attWriteReq_t* pReq = (attWriteReq_t*)pMsg; + // Attribute handle + *pBuf++ = LO_UINT16( pReq->handle ); + *pBuf++ = HI_UINT16( pReq->handle ); + // Attribute value + VOID osal_memcpy( pBuf, pReq->value, pReq->len ); + return ( WRITE_REQ_FIXED_SIZE + pReq->len ); +} + +/********************************************************************* + @fn ATT_ParseWriteRsp + + @brief Parse Write Response message. + + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseWriteRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + VOID pParams; // Not applicable to this message + VOID pMsg; // Not applicable to this message + return ( len == 0 ? SUCCESS : ATT_ERR_INVALID_PDU ); +} + +/********************************************************************* + @fn ATT_BuildReadBlobReq + + @brief Build Read Blob Request. + + @param pBuf - pointer to buffer to be built + @param pMsg - pointer to message structure + + @return length of the request data +*/ +uint16 ATT_BuildReadBlobReq( uint8* pBuf, uint8* pMsg ) +{ + attReadBlobReq_t* pReq = (attReadBlobReq_t*)pMsg; + // Attribute handle + *pBuf++ = LO_UINT16( pReq->handle ); + *pBuf++ = HI_UINT16( pReq->handle ); + // Value Offset + *pBuf++ = LO_UINT16( pReq->offset ); + *pBuf = HI_UINT16( pReq->offset ); + return ( READ_BLOB_REQ_SIZE ); +} + +/********************************************************************* + @fn ATT_ParseReadBlobReq + + @brief Parse Read Blob Request message. + + @param sig - authentication signature status + @param cmd - command flag + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseReadBlobReq( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + VOID sig; // Not applicable to this message + VOID cmd; // Not applicable to this message + + if ( len == READ_BLOB_REQ_SIZE ) + { + attReadBlobReq_t* pReq = &pMsg->readBlobReq; + // Attribute handle + pReq->handle = BUILD_UINT16( pParams[0], pParams[1] ); + // Value Offset + pReq->offset = BUILD_UINT16( pParams[2], pParams[3] ); + return ( SUCCESS); + } + + return ( ATT_ERR_INVALID_PDU ); +} + +/********************************************************************* + @fn ATT_BuildReadBlobRsp + + @brief Build Read Blob Response. + + @param pBuf - pointer to buffer to be built + @param pMsg - pointer to message structure + + @return length of the command data +*/ +uint16 ATT_BuildReadBlobRsp( uint8* pBuf, uint8* pMsg ) +{ + attReadBlobRsp_t* pRsp = (attReadBlobRsp_t*)pMsg; + // Part of attribute value + VOID osal_memcpy( pBuf, pRsp->value, pRsp->len ); + return ( pRsp->len ); +} + +/********************************************************************* + @fn ATT_ParseReadBlobRsp + + @brief Parse Read Blob Response message. + + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseReadBlobRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + attReadBlobRsp_t* pRsp = &pMsg->readBlobRsp; + // Part Attribute value + pRsp->len = len; + + if ( pRsp->len <= ATT_MTU_SIZE - 1 ) + { + VOID osal_memcpy( pRsp->value, pParams, pRsp->len ); + return ( SUCCESS); + } + + return ( ATT_ERR_INVALID_PDU ); +} + +/********************************************************************* + @fn ATT_BuildReadMultiReq + + @brief Build Read Multiple Request. + + @param pBuf - pointer to buffer to be built + @param pMsg - pointer to message structure + + @return length of the request data +*/ +uint16 ATT_BuildReadMultiReq( uint8* pBuf, uint8* pMsg ) +{ + attReadMultiReq_t* pReq = (attReadMultiReq_t*)pMsg; + + for ( uint8 i = 0; i < pReq->numHandles; i++ ) + { + // Attribute handle + *pBuf++ = LO_UINT16( pReq->handle[i] ); + *pBuf++ = HI_UINT16( pReq->handle[i] ); + } + + return ( pReq->numHandles * 2 ); +} + +/********************************************************************* + @fn ATT_ParseReadMultiReq + + @brief Parse Read Multiple Request message. + + @param sig - authentication signature status + @param cmd - command flag + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseReadMultiReq( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + VOID sig; // Not applicable to this message + VOID cmd; // Not applicable to this message + + // Make sure the length of attribute handles is even + if ( len % 2 == 0 ) + { + uint8 numHandles = len / 2; // Number of attribute handles + + // Make sure there're at least two attribute handles in the request + if ( ( numHandles >= ATT_MIN_NUM_HANDLES ) && ( numHandles <= g_ATT_MAX_NUM_HANDLES ) ) + { + attReadMultiReq_t* pReq = &pMsg->readMultiReq; + pReq->numHandles = numHandles; + + for ( uint8 i = 0; i < numHandles; i++ ) + { + // Attribute handle + pReq->handle[i] = BUILD_UINT16( pParams[0], pParams[1] ); + // Next handle + pParams += 2; + } + + return ( SUCCESS); + } + } + + return ( ATT_ERR_INVALID_PDU ); +} + +/********************************************************************* + @fn ATT_BuildReadMultiRsp + + @brief Build Read Multiple Response. + + @param pBuf - pointer to buffer to be built + @param pMsg - pointer to message structure + + @return length of the command data +*/ +uint16 ATT_BuildReadMultiRsp( uint8* pBuf, uint8* pMsg ) +{ + attReadMultiRsp_t* pRsp = (attReadMultiRsp_t*)pMsg; + // A set of two or more values + VOID osal_memcpy( pBuf, pRsp->values, pRsp->len ); + return ( pRsp->len ); +} + +/********************************************************************* + @fn ATT_ParseReadMultiRsp + + @brief Parse Read Multiple Response message. + + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseReadMultiRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + attReadMultiRsp_t* pRsp = &pMsg->readMultiRsp; + pRsp->len = len; + + // A set of two or more values + if ( pRsp->len <= ATT_MTU_SIZE - 1 ) + { + VOID osal_memcpy( pRsp->values, &pParams[0], pRsp->len ); + return ( SUCCESS ); + } + + return ( ATT_ERR_INVALID_PDU ); +} + +/********************************************************************* + @fn ATT_BuildReadByGrpTypeRsp + + @brief Build Read By Group Type Response. + + @param pBuf - pointer to buffer to be built + @param pMsg - pointer to message structure + + @return length of the command data +*/ +uint16 ATT_BuildReadByGrpTypeRsp( uint8* pBuf, uint8* pMsg ) +{ + attReadByGrpTypeRsp_t* pRsp = (attReadByGrpTypeRsp_t*)pMsg; + uint8 dataLen = pRsp->numGrps * pRsp->len; + // Length of each attribute handle, group end handle and value set + *pBuf++ = pRsp->len; + // List of 1 or more attribute handle, group end handle and value + VOID osal_memcpy( pBuf, pRsp->dataList, dataLen ); + return ( dataLen + 1 ); +} + +/********************************************************************* + @fn ATT_ParseReadByGrpTypeRsp + + @brief Parse Read By Group Type Response message. + + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseReadByGrpTypeRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + attReadByGrpTypeRsp_t* pRsp = &pMsg->readByGrpTypeRsp; + + if ( len >= READ_BY_TYPE_RSP_FIXED_SIZE ) + { + uint8 dataLen = len - 1; + // Length of each attribute handle, group end handle and value set + pRsp->len = pParams[0]; + + if ( ( dataLen <= ATT_MTU_SIZE - 2 ) && + ( pRsp->len > 0 ) && + ( ( dataLen % pRsp->len ) == 0 ) ) + { + // Number of all attribute handle, group end handle and value sets found + pRsp->numGrps = dataLen / pRsp->len; + // List of 1 or more attribute handle, end group handle and value set + VOID osal_memcpy( pRsp->dataList, &pParams[1], dataLen ); + return ( SUCCESS); + } + } + + return ( ATT_ERR_INVALID_PDU ); +} + +/********************************************************************* + @fn ATT_BuildPrepareWriteReq + + @brief Build Prepare Write Request. + + @param pBuf - pointer to buffer to be built + @param pMsg - pointer to message structure + + @return length of the request data +*/ +uint16 ATT_BuildPrepareWriteReq( uint8* pBuf, uint8* pMsg ) +{ + attPrepareWriteReq_t* pReq = (attPrepareWriteReq_t*)pMsg; + // Attribute handle + *pBuf++ = LO_UINT16( pReq->handle ); + *pBuf++ = HI_UINT16( pReq->handle ); + // Value Offset + *pBuf++ = LO_UINT16( pReq->offset ); + *pBuf++ = HI_UINT16( pReq->offset ); + // Part Attribute value + VOID osal_memcpy( pBuf, pReq->value, pReq->len ); + return ( PREPARE_WRITE_REQ_FIXED_SIZE + pReq->len ); +} + +/********************************************************************* + @fn ATT_ParsePrepareWriteReq + + @brief Parse Write Prepare Request message. + + @param sig - authentication signature status + @param cmd - command flag + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParsePrepareWriteReq( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + VOID sig; // Not applicable to this message + VOID cmd; // Not applicable to this message + + if ( len >= PREPARE_WRITE_REQ_FIXED_SIZE ) + { + attPrepareWriteReq_t* pReq = &pMsg->prepareWriteReq; + // Attribute handle + pReq->handle = BUILD_UINT16( pParams[0], pParams[1] ); + // Value Offset + pReq->offset = BUILD_UINT16( pParams[2], pParams[3] ); + // Part Attribute value + pReq->len = len - PREPARE_WRITE_REQ_FIXED_SIZE; + + if ( pReq->len <= ATT_MTU_SIZE - 5 ) + { + VOID osal_memcpy( pReq->value, &pParams[4], pReq->len ); + return ( SUCCESS); + } + } + + return ( ATT_ERR_INVALID_PDU ); +} + +/********************************************************************* + @fn ATT_BuildPrepareWriteRsp + + @brief Build Prepare Write Response. + + @param pBuf - pointer to buffer to be built + @param pMsg - pointer to message structure + + @return length of the command data +*/ +uint16 ATT_BuildPrepareWriteRsp( uint8* pBuf, uint8* pMsg ) +{ + attPrepareWriteRsp_t* pReq = (attPrepareWriteRsp_t*)pMsg; + // Attribute handle + *pBuf++ = LO_UINT16( pReq->handle ); + *pBuf++ = HI_UINT16( pReq->handle ); + // Value Offset + *pBuf++ = LO_UINT16( pReq->offset ); + *pBuf++ = HI_UINT16( pReq->offset ); + // Part Attribute value + VOID osal_memcpy( pBuf, pReq->value, pReq->len ); + return ( PREPARE_WRITE_RSP_FIXED_SIZE + pReq->len ); +} + +/********************************************************************* + @fn ATT_ParsePrepareWriteRsp + + @brief Parse Prepare Write Response message. + + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParsePrepareWriteRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + if ( len >= PREPARE_WRITE_RSP_FIXED_SIZE ) + { + attPrepareWriteRsp_t* pRsp = &pMsg->prepareWriteRsp; + // Attribute handle + pRsp->handle = BUILD_UINT16( pParams[0], pParams[1] ); + // Value Offset + pRsp->offset = BUILD_UINT16( pParams[2], pParams[3] ); + // Part Attribute value + pRsp->len = len - PREPARE_WRITE_RSP_FIXED_SIZE; + + if ( pRsp->len <= ATT_MTU_SIZE - 5 ) + { + VOID osal_memcpy( pRsp->value, &pParams[4], pRsp->len ); + return ( SUCCESS); + } + } + + return ( ATT_ERR_INVALID_PDU ); +} + +/********************************************************************* + @fn ATT_BuildExecuteWriteReq + + @brief Build Execute Write Request. + + @param pBuf - pointer to buffer to be built + @param pMsg - pointer to message structure + + @return length of the request data +*/ +uint16 ATT_BuildExecuteWriteReq( uint8* pBuf, uint8* pMsg ) +{ + attExecuteWriteReq_t* pReq = (attExecuteWriteReq_t*)pMsg; + // Flags + *pBuf = pReq->flags; + return ( EXECUTE_WRITE_REQ_SIZE ); +} + +/********************************************************************* + @fn ATT_ParseExecuteWriteReq + + @brief Parse Execute Write Request message. + + @param sig - authentication signature status + @param cmd - command flag + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseExecuteWriteReq( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + VOID sig; // Not applicable to this message + VOID cmd; // Not applicable to this message + + if ( len == EXECUTE_WRITE_REQ_SIZE ) + { + attExecuteWriteReq_t* pReq = &pMsg->executeWriteReq; + // Attribute handle + pReq->flags = pParams[0]; + return ( SUCCESS); + } + + return ( ATT_ERR_INVALID_PDU ); +} + +/********************************************************************* + @fn ATT_ParseExecuteWriteRsp + + @brief Parse Execute Write Response message. + + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseExecuteWriteRsp( uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + VOID pParams; // Not applicable to this message + VOID pMsg; // Not applicable to this message + return ( len == 0 ? SUCCESS : ATT_ERR_INVALID_PDU ); +} + +/********************************************************************* + @fn ATT_BuildHandleValueInd + + @brief Build Handle Value Indication. + + @param pBuf - pointer to buffer to be built + @param pMsg - pointer to message structure + + @return length of the command data +*/ +uint16 ATT_BuildHandleValueInd( uint8* pBuf, uint8* pMsg ) +{ + attHandleValueInd_t* pReq = (attHandleValueInd_t*)pMsg; + // Attribute handle + *pBuf++ = LO_UINT16( pReq->handle ); + *pBuf++ = HI_UINT16( pReq->handle ); + // Attribute value + VOID osal_memcpy( pBuf, pReq->value, pReq->len ); + return ( HANDLE_VALUE_IND_FIXED_SIZE + pReq->len ); +} + +/********************************************************************* + @fn ATT_ParseHandleValueInd + + @brief Parse Handle Value Indication message. + + @param sig - authentication signature status + @param cmd - command flag + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseHandleValueInd( uint8 sig, uint8 cmd, uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + VOID sig; // Not applicable to this message + VOID cmd; // Not applicable to this message + + if ( len >= HANDLE_VALUE_IND_FIXED_SIZE ) + { + attHandleValueInd_t* pInd = &pMsg->handleValueInd; + // Attribute handle + pInd->handle = BUILD_UINT16( pParams[0], pParams[1] ); + // Attribute value length + pInd->len = len - HANDLE_VALUE_IND_FIXED_SIZE; + + if ( pInd->len <= ATT_MTU_SIZE - 3 ) + { + VOID osal_memcpy( pInd->value, &pParams[2], pInd->len ); + return ( SUCCESS); + } + } + + return ( ATT_ERR_INVALID_PDU ); +} + +/********************************************************************* + @fn ATT_ParseHandleValueCfm + + @brief Parse Handle Value Confirmation message. + + @param pParams - pointer to received parameters + @param len - length of parameters + @param pMsg - pointer to message structure to be built + + @return SUCCESS or ATT_ERR_INVALID_PDU +*/ +bStatus_t ATT_ParseHandleValueCfm( uint8* pParams, uint16 len, attMsg_t* pMsg ) +{ + VOID pParams; // Not applicable to this message + VOID pMsg; // Not applicable to this message + return ( len == 0 ? SUCCESS : ATT_ERR_INVALID_PDU ); +} + +/********************************************************************* + @fn attSendMsg + + @brief Send an attribute protocol message over the ATT fixed channel. + + @param connHandle �C connection to use + @param pfnBuildMsg �C build function for message + @param opcode �C operation code + @param pMsg �C pointer to message to be sent + + @return SUCCESS: Request was sent successfully. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. + bleLinkEncrypted: Connection is already encrypted. +*/ +bStatus_t attSendMsg( uint16 connHandle, attBuildMsg_t pfnBuildMsg, uint8 opcode, uint8* pMsg ) +{ + uint8* buf; + uint8 status; + // Allocate space for the message + buf = (uint8*)L2CAP_bm_alloc( gAttMtuSize[connHandle] ); + + if ( buf != NULL ) + { + uint8* pBuf = buf; + uint16 len = 1; // opcode + // operation code + *pBuf++ = opcode; + + // Build the command specific data + if ( pfnBuildMsg != NULL ) + { + len += (*pfnBuildMsg)( pBuf, pMsg ); + } + + // Do we need to include an Authentication Signature? + if ( attAuthenSigFlag( opcode ) != 0 ) + { + // Make sure the link is not encrypted + if ( !linkDB_Encrypted( connHandle ) ) + { + // Calcuate the Authentication Signature field, which will provide + // an Authentication Signature for the following values in this + // order: Opcode, Attribute Handle, and Attribute Value. + // Append the Authentication Signature after the Attribute Value + status = SM_GenerateAuthenSig( buf, len, &(buf[len]) ); + + if ( status == SUCCESS ) + { + len += AUTHEN_SIG_LEN; // Add length of Authentication Signature + } + } + else + { + // An Attribute PDU that includes an Authentication Signature should + // not be sent on an encrypted link. Note: an encrypted link already + // includes authentication data on every packet and therefore adding + // more authentication data is not required. + status = bleLinkEncrypted; + } + } + else + { + status = SUCCESS; + } + + // Send the message + if ( status == SUCCESS ) + { + l2capPacket_t pkt; + // Create an L2CAP packet + pkt.CID = L2CAP_CID_ATT; + pkt.pPayload = buf; + pkt.len = len; + // Send the packet over the ATT fixed channel + status = L2CAP_SendData( connHandle, &pkt ); + } + + if ( status != SUCCESS ) + { + // free the buffer + osal_bm_free( buf ); + } + } + else + { + status = bleMemAllocError; + } + + return ( status ); +} + +/********************************************************************* + @fn ATT_CompareUUID + + @brief Compare two UUIDs. The UUIDs are converted if necessary. + Valid lengths are 2 or 16 octets. + + @param pUUID1 - pointer to first UUID + @param len1 - length of first UUID + @param pUUID2 - pointer to second UUID + @param len2 - length of second UUID + + @return TRUE if equal. FALSE, otherwise. +*/ +uint8 ATT_CompareUUID( const uint8* pUUID1, uint16 len1, + const uint8* pUUID2, uint16 len2 ) +{ + uint8 longUUID[ATT_UUID_SIZE]; + + // Make sure both of them have the right length + if ( ( len1 != ATT_BT_UUID_SIZE ) && ( len1 != ATT_UUID_SIZE ) ) + { + return ( FALSE ); + } + + if ( ( len2 != ATT_BT_UUID_SIZE ) && ( len2 != ATT_UUID_SIZE ) ) + { + return ( FALSE ); + } + + // See if both are the same length + if ( len1 == len2 ) + { + // Both are the same length; just compare them + return ( osal_memcmp( pUUID1, pUUID2, len1 ) ); + } + + // One of them is 16 octets and other is not + if ( len1 == ATT_UUID_SIZE ) + { + // The first UUID is 16 octets; convert the second one to 16 octets + VOID ATT_ConvertUUIDto128( pUUID2, longUUID ); + // Compare them now + return ( osal_memcmp( pUUID1, longUUID, ATT_UUID_SIZE ) ); + } + + // The second UUID is 16 octets; convert the first one to 16 octets + VOID ATT_ConvertUUIDto128( pUUID1, longUUID ); + // Compare them now + return ( osal_memcmp( pUUID2, longUUID, ATT_UUID_SIZE ) ); +} + +/********************************************************************* + @fn ATT_ConvertUUIDto128 + + @brief Convert a 16-bit UUID to 128-bit UUID. Simply, the 2 byte + Attribute UUID replaces the x's in the following: + 0000xxxx-0000-1000-8000-00805F9B34FB + + @param pUUID16 - pointer to 16-bit UUID + @param pUUID128 - pointer to 128-bit UUID to be built + + @return TRUE if converted. FALSE, otherwise. +*/ +uint8 ATT_ConvertUUIDto128( const uint8* pUUID16, uint8* pUUID128 ) +{ + if ( ( pUUID16 != NULL ) && ( pUUID128 != NULL ) ) + { + // Start off with the Bluetooth base UUID + VOID osal_memcpy( pUUID128, btBaseUUID, ATT_UUID_SIZE ); + // Copy the 2 byte UUID over + pUUID128[12] = pUUID16[0]; + pUUID128[13] = pUUID16[1]; + return ( TRUE ); + } + + return ( FALSE ); +} + +/********************************************************************* + @fn ATT_ConvertUUIDto16 + + @brief Convert a 128-bit UUID to 16-bit UUID. Simply, the 2 byte + Attribute UUID represents the x's in the following: + 0000xxxx-0000-1000-8000-00805F9B34FB + + @param pUUID128 - pointer to 128-bit UUID + @param pUUID16 - pointer to 16-bit UUID to be built + + @return TRUE if converted. FALSE, otherwise. +*/ +uint8 ATT_ConvertUUIDto16( const uint8* pUUID128, uint8* pUUID16 ) +{ + if ( ( pUUID16 != NULL ) && ( pUUID128 != NULL ) ) + { + uint8 uuid[ATT_UUID_SIZE]; + // First make sure the 128-bit UUID is a valid Bluetooth UUID + VOID osal_memcpy( uuid, pUUID128, ATT_UUID_SIZE ); + uuid[12] = 0x00; + uuid[13] = 0x00; + + // Compare it to the Bluetooth base UUID + if ( osal_memcmp( uuid, btBaseUUID, ATT_UUID_SIZE ) == TRUE ) + { + // Extract the 2 byte UUID + pUUID16[0] = pUUID128[12]; + pUUID16[1] = pUUID128[13]; + return ( TRUE ); + } + } + + return ( FALSE ); +} + +/********************************************************************* + @fn ATT_SetParamValue + + @brief Set a ATT Parameter value. Use this function to change + the default ATT parameter values. + + @param value - new param value + + @return void +*/ +void ATT_SetParamValue( uint16 value ) +{ + #if defined ( TESTMODES ) + paramValue = value; + #else + VOID value; + #endif +} + +/********************************************************************* + @fn ATT_GetParamValue + + @brief Get a ATT Parameter value. + + @param none + + @return ATT Parameter value +*/ +uint16 ATT_GetParamValue( void ) +{ + #if defined ( TESTMODES ) + return ( paramValue ); + #else + return ( 0 ); + #endif +} + +void ATT_SetMTUSizeMax(uint16 mtuSize) +{ + g_ATT_MTU_SIZE_MAX = mtuSize > ATT_MTU_SIZE ? ATT_MTU_SIZE : mtuSize; + g_ATT_MAX_NUM_HANDLES_INFO = ( ( g_ATT_MTU_SIZE_MAX - 1 ) / 4 ); + g_ATT_MAX_NUM_HANDLES = ( ( g_ATT_MTU_SIZE_MAX - 1 ) / 2 ); + return ; +} + +void ATT_UpdateMtuSize(uint16 connHandle, uint16 mtuSize) +{ + if (mtuSize > g_ATT_MTU_SIZE_MAX) + return; + + gAttMtuSize[connHandle] = mtuSize; + LOG("[ATT_MTU] %d \n", gAttMtuSize[connHandle]); +} + +uint16 ATT_GetCurrentMTUSize(uint16 connHandle) +{ + return gAttMtuSize[connHandle]; +} + +void ATT_InitMtuSize(void) +{ + for (int i = 0; i < MAX_NUM_LL_CONN; i ++) + { + gAttMtuSize[i] = ATT_MTU_SIZE_MIN; + } +} + +#if 0 +uint16 ATT_GetCurrentMTUSize(void) +{ + return g_ATT_MTU_SIZE; +} + +void ATT_MTU_SIZE_UPDATE(uint8 mtuSize) +{ + g_ATT_MTU_SIZE = mtuSize; + LOG("[ATT_MTU] %d \n",g_ATT_MTU_SIZE); +// g_ATT_MAX_NUM_HANDLE_BT_UUID = ( ( g_ATT_MTU_SIZE - 2 ) / ( 2 + ATT_BT_UUID_SIZE ) ); +// g_ATT_MAX_NUM_HANDLE_UUID = ( ( g_ATT_MTU_SIZE - 2 ) / ( 2 + ATT_UUID_SIZE ) ); +} +#endif +/**************************************************************************** +****************************************************************************/ diff --git a/src/lib/ble_host/gap_centdevmgr.c b/src/lib/ble_host/gap_centdevmgr.c new file mode 100644 index 0000000..46f3813 --- /dev/null +++ b/src/lib/ble_host/gap_centdevmgr.c @@ -0,0 +1,973 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: gap_centdevmgr.c + Revised: + Revision: + + Description: This file contains the GAP Central Device Manager. + + +**************************************************************************************************/ + + +/******************************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "hci_tl.h" +#include "l2cap.h" +#include "gap.h" +#include "gap_internal.h" +#include "global_config.h" + +#include "log.h" +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +// GAP Advertisement Report types - same as HCI values except EMPTY +// others are defined in gap.h (ie. GAP_ADVERTISEMENT_REPORT_TYPE_DEFINES) +#define GAP_ADRPT_EMPTY 0xFF // Used only internally + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +// Scan records: advertisements and scan responses +static gapAdvertRec_t* pGapScanRecs = NULL; + +// Number of scan responses to accept +static uint8 gapMaxScanResponses = 0; + +/********************************************************************* + LOCAL FUNCTIONS +*/ + +static uint8 gapCentProcessHCICmdEvt( uint16 cmdOpcode, hciEvt_CmdComplete_t* pMsg ); +static void gapProcessScanningEvt( hciEvt_BLEAdvPktReport_t* pPkt ); +static uint8 gapProcessConnEvt( uint16 cmdOpcode, hciEvt_CommandStatus_t* pMsg ); + +static void gapProcessScanDurationTimeout( void ); +static gapAdvertRec_t* gapFindEmptyScanRec( void ); +static gapAdvertRec_t* gapFindScanRec( uint8 addrType, uint8* pAddr ); +static void gapFreeScanRecs( uint8 numScanRecs, uint8 freeRecs ); +static bStatus_t gapAllocScanRecs( void ); +static uint8 gapProcessAdvertDevInfo( hciEvt_DevInfo_t* pDevInfo ); +static void gapSendDevDiscEvent( bStatus_t status ); +static void gapSendDeviceInfoEvent( hciEvt_DevInfo_t* pDevInfo ); +static bStatus_t gapSendScanEnable( uint8 enable ); + +static void gapProcessAdvertisementReport( hciEvt_BLEAdvPktReport_t* pPkt ); + +/********************************************************************* + CENTRAL CALLBACKS +*/ + +// GAP Central Callbacks +static gapCentralCBs_t gapCentralCBs = +{ + gapCentProcessHCICmdEvt, // Process HCI Command Event Callback + gapProcessScanningEvt, // Process Scanning Event Callback +}; + +// GAP Central Connection-Related Callbacks +static gapCentralConnCBs_t gapCentralConnCBs = +{ + gapCancelLinkReq, // Process Cancel Connection Initiation Callback + gapProcessConnEvt, // Process Connection-Related Event Callback +}; + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/********************************************************************* + Start a device discovery scan. + + Public function defined in gap.h. +*/ +bStatus_t GAP_DeviceDiscoveryRequest( gapDevDiscReq_t* pParams ) +{ + if ( pGapDiscReq ) + { + // We only support one scan at a time + return ( bleAlreadyInRequestedMode ); + } + + if ( (gapProfileRole & (GAP_PROFILE_CENTRAL | GAP_PROFILE_OBSERVER)) == 0 ) + { + // This is only allowed for Central or Observer profile roles + return ( bleIncorrectMode ); + } + + // Save off the parameters + pGapDiscReq = (gapDevDiscReq_t*)osal_mem_alloc( (uint16)sizeof ( gapDevDiscReq_t ) ); + + if ( pGapDiscReq ) + { + uint16 scanInterval; // Selected scan interval + uint16 scanWindow; // Selected scan window + // Copy parameters + VOID osal_memcpy( pGapDiscReq, pParams, (unsigned int)(sizeof ( gapDevDiscReq_t )) ); + + // Select the LL parameters + if ( GAP_NumActiveConnections() ) + { + // We are already in a connection + scanInterval = GAP_GetParamValue( TGAP_CONN_SCAN_INT ); + scanWindow = GAP_GetParamValue( TGAP_CONN_SCAN_WIND ); + } + else if ( pParams->mode == DEVDISC_MODE_LIMITED ) + { + scanInterval = GAP_GetParamValue( TGAP_LIM_DISC_SCAN_INT ); + scanWindow = GAP_GetParamValue( TGAP_LIM_DISC_SCAN_WIND ); + } + else // Assume General Discovery Mode + { + scanInterval = GAP_GetParamValue( TGAP_GEN_DISC_SCAN_INT ); + scanWindow = GAP_GetParamValue( TGAP_GEN_DISC_SCAN_WIND ); + } + + return ( HCI_LE_SetScanParamCmd( pParams->activeScan, scanInterval, scanWindow, + ((gapDeviceAddrMode == ADDRTYPE_PUBLIC) ? ADDRTYPE_PUBLIC : ADDRTYPE_RANDOM), + ((pParams->whiteList) ? TRUE : FALSE) ) ); + } + else + { + return ( bleMemAllocError ); + } +} + +/********************************************************************* + Cancel an existing device discovery request. + + Public function defined in gap.h. +*/ +bStatus_t GAP_DeviceDiscoveryCancel( uint8 taskID ) +{ + // Make sure we are discovering. + if ( pGapDiscReq == NULL ) + { + return ( bleIncorrectMode ); + } + + // Is this the same task that started the scan? + if ( pGapDiscReq->taskID != taskID ) + { + return ( bleInvalidTaskID ); + } + + // Turn off the scan timer + VOID osal_stop_timerEx( gapTaskID, GAP_OSAL_TIMER_SCAN_DURATION_EVT ); + // Send the user the Device Discovery Event message + gapSendDevDiscEvent( bleGAPUserCanceled ); + // Cancel LL Scan + return ( gapSendScanEnable( FALSE ) ); +} + +/********************************************************************* + PUBLIC INTERNAL GAP FUNCTIONS +*/ + +/********************************************************************* + @fn GAP_CentDevMgrInit + + @brief Initialize the GAP Central Dev Manager. + + @param profileRole - GAP Profile Roles + @param maxScanResponses - maximum number to scan responses + can receive during a device discovery + + @return SUCCESS or bleMemAllocError +*/ +bStatus_t GAP_CentDevMgrInit( uint8 maxScanResponses ) +{ + // Free the space first + gapFreeScanRecs( gapMaxScanResponses, TRUE ); + + if ( gapProfileRole & (GAP_PROFILE_CENTRAL | GAP_PROFILE_OBSERVER) ) + { + // Set up Central's processing functions + gapMaxScanResponses = maxScanResponses; + gapRegisterCentral( &gapCentralCBs ); + return ( gapAllocScanRecs() ); + } + + gapMaxScanResponses = 0; + gapRegisterCentral( NULL ); + return ( SUCCESS ); +} + +/********************************************************************* + @fn GAP_CentConnRegister + + @brief Register the GAP Central Connection processing functions. + + @param none + + @return none +*/ +void GAP_CentConnRegister( void ) +{ + if ( gapProfileRole & GAP_PROFILE_CENTRAL ) + { + // Set up Central's Connection processing functions + gapRegisterCentralConn( &gapCentralConnCBs ); + } + else + { + gapRegisterCentralConn( NULL ); + } +} + +/********************************************************************* + @fn gapCentProcessHCICmdEvt + + @brief Process an incoming GAP Central Event. + + @param pMsg - message to process + + @return TRUE if processed and safe to deallocate, FALSE if passed + off to another task. +*/ +static uint8 gapCentProcessHCICmdEvt( uint16 cmdOpcode, hciEvt_CmdComplete_t* pMsg ) +{ + uint8 safeToDealloc = TRUE; + + switch ( cmdOpcode ) + { + case HCI_LE_SET_SCAN_ENABLE: + if ( *(pMsg->pReturnParam) == SUCCESS ) + { + break; + } + + /*lint --fallthrough */ + case HCI_LE_SET_SCAN_PARAM: + safeToDealloc = gapSetScanParamStatus( *(pMsg->pReturnParam) ); + break; + + default: + safeToDealloc = FALSE; // send this message to the app + break; + } + + return ( safeToDealloc ); +} + +/********************************************************************* + @fn gapProcessConnEvt + + @brief Process an incoming GAP Central Connection Event. + + @param pMsg - message to process + + @return TRUE if processed and safe to deallocate, FALSE if passed + off to another task. +*/ +static uint8 gapProcessConnEvt( uint16 cmdOpcode, hciEvt_CommandStatus_t* pMsg ) +{ + uint8 safeToDealloc = TRUE; + + switch ( cmdOpcode ) + { + case HCI_LE_CREATE_CONNECTION_CANCEL: + // this is a command complete event (hciEvt_CmdComplete_t) + gapTerminateConnComplete(); + break; + + case HCI_LE_CREATE_CONNECTION: + gapProcessCreateLLConnCmdStatus( pMsg->cmdStatus ); + break; + + case HCI_LE_CONNECTION_UPDATE: + gapProcessConnUpdateCmdStatus( pMsg->cmdStatus ); + break; + + case L2CAP_PARAM_UPDATE: + gapProcessL2CAPSignalEvt( (l2capSignalEvent_t*)pMsg ); + break; + + default: + safeToDealloc = FALSE; // send this message to the app + break; + } + + return ( safeToDealloc ); +} + +/********************************************************************* + @fn gapSetScanParamStatus + + @brief Process HCI Command Complete Event status for + the call to HCI_BLESetScanParamCmd(). + + @param status - HCI Set Scan Parameters status + + @return TRUE if expected, FALSE if not. +*/ +uint8 gapSetScanParamStatus( uint8 status ) +{ + if ( pGapDiscReq ) + { + if ( status == SUCCESS ) + { + uint32 timeout; + + // Set the Scan duration + if ( pGapDiscReq->mode == DEVDISC_MODE_LIMITED ) + { + timeout = GAP_GetParamValue( TGAP_LIM_DISC_SCAN ); + } + else + { + timeout = GAP_GetParamValue( TGAP_GEN_DISC_SCAN ); + } + + VOID osal_start_timerEx( gapTaskID, + GAP_OSAL_TIMER_SCAN_DURATION_EVT, timeout ); + // Enable the LL Scan Mode + status = gapSendScanEnable( TRUE ); + } + + if ( status != SUCCESS ) + { + // Turn off the timer + VOID osal_stop_timerEx( gapTaskID, GAP_OSAL_TIMER_SCAN_DURATION_EVT ); + // Send back Device Discovery Event + gapSendDevDiscEvent( status ); + } + + return ( TRUE ); + } + else + { + return ( FALSE ); + } +} + +/********************************************************************* + @fn gapProcessScanningEvt + + @brief Process Scanning event. + + @param pPkt - Advertisement packet, NULL if Device Discovery timeout + + @return none +*/ +static void gapProcessScanningEvt( hciEvt_BLEAdvPktReport_t* pPkt ) +{ + if ( pPkt == NULL ) + { + gapProcessScanDurationTimeout(); + } + else + { + gapProcessAdvertisementReport( pPkt ); + } +} + +/********************************************************************* + @fn gapProcessScanDurationTimeout + + @brief Scan Duration timer expired. Terminate the scan. + + @param none + + @return none +*/ +static void gapProcessScanDurationTimeout( void ) +{ + // Are we doing a scan? + if ( pGapDiscReq ) + { + // Send the user the Device Discovery Event message + gapSendDevDiscEvent( SUCCESS ); + // Turn off the scan + VOID gapSendScanEnable( FALSE ); + } +} + +/********************************************************************* + @fn gapProcessAdvertisementReport + + @brief Process HCI BLE Advertisement Report Event. + + @param pkt - Advertisement packet + + @return none +*/ +static void gapProcessAdvertisementReport( hciEvt_BLEAdvPktReport_t* pPkt ) +{ + // Parameter check + if ( pPkt->numDevices && pPkt->devInfo ) + { + hciEvt_DevInfo_t* pDevInfo = pPkt->devInfo; + int8 minRssi = (int8)GAP_GetParamValue( TGAP_SCAN_RSP_RSSI_MIN ); + + // Loop through the device advertisements + for ( uint8 x = 0; x < pPkt->numDevices; x++ ) + { + if ( ( pDevInfo->rssi >= minRssi ) && gapProcessAdvertDevInfo( pDevInfo ) ) + { + // Send a report to the app + gapSendDeviceInfoEvent( pDevInfo ); + } + + pDevInfo++; // Move to next device + } + } +} + +/********************************************************************* + LOCAL FUNCTIONS +*/ + +/********************************************************************* + @fn gapFreeScanRecs + + @brief Free the scan records. + + @param numScanRecs - number of scan records + @param freeRecs - TRUE to deallocate, + FALSE to just clear the memory. + + @return none +*/ +static void gapFreeScanRecs( uint8 numScanRecs, uint8 freeRecs ) +{ + if ( pGapScanRecs ) + { + uint8 x; + + for ( x = 0; x < numScanRecs; x++ ) + { + if ( pGapScanRecs[x].pAdData ) + { + osal_mem_free( pGapScanRecs[x].pAdData ); + pGapScanRecs[x].pAdData = NULL; + } + + if ( pGapScanRecs[x].pScanData ) + { + osal_mem_free( pGapScanRecs[x].pScanData ); + pGapScanRecs[x].pScanData = NULL; + } + } + + if ( freeRecs ) + { + osal_mem_free( pGapScanRecs ); + pGapScanRecs = NULL; + } + else + { + // Clear the memory + uint16 blockSize = (uint16)(sizeof ( gapAdvertRec_t ) * numScanRecs); + + if ( pGapScanRecs ) + { + VOID osal_memset( pGapScanRecs, 0, blockSize ); + + for ( x = 0; x < numScanRecs; x++ ) + { + pGapScanRecs[x].eventType = GAP_ADRPT_EMPTY; + } + } + } + } +} + +/********************************************************************* + @fn gapAllocScanRecs + + @brief Allocate and initialize the scan records. + + @param none + + @return SUCCESS or bleMemAllocError +*/ +static bStatus_t gapAllocScanRecs( void ) +{ + if ( pGapScanRecs != NULL ) + { + return ( bleMemAllocError ); + } + + // Check scan responses are needed + if ( gapMaxScanResponses ) + { + // Calculate the block size (bytes) + uint16 blockSize = (uint16)(sizeof ( gapAdvertRec_t ) * gapMaxScanResponses); + // Allocate one block for all the scan records + pGapScanRecs = (gapAdvertRec_t*)osal_mem_alloc( blockSize ); + + if ( pGapScanRecs ) + { + uint8 x; // loop counter + // Initialize the entire space + VOID osal_memset( pGapScanRecs, 0, (int)blockSize ); + + // Loop through all records and mark them empty + for ( x = 0; x < gapMaxScanResponses; x++ ) + { + pGapScanRecs[x].eventType = GAP_ADRPT_EMPTY; + } + } + else + { + return ( bleMemAllocError ); + } + } + + return ( SUCCESS ); +} + +/********************************************************************* + @fn gapFindEmptyScanRec + + @brief Find an empty scan record slot. + + @param none + + @return empty record pointer or NULL if no empty slots +*/ +static gapAdvertRec_t* gapFindEmptyScanRec( void ) +{ + if ( pGapScanRecs ) + { + for ( uint8 x = 0; x < gapMaxScanResponses; x++ ) + { + // Look for empty slot + if ( pGapScanRecs[x].eventType == GAP_ADRPT_EMPTY ) + { + // Empty slot found + return ( &(pGapScanRecs[x]) ); + } + } + } + + // No empty slots + return ( (gapAdvertRec_t*)NULL ); +} + +/********************************************************************* + @fn gapFindScanRec + + @brief Find an existing scan record. + + @param addrType - ADDRTYPE_PUBLIC, ADDRTYPE_STATIC, + ADDRTYPE_PRIVATE_NONRESOLVE + or ADDRTYPE_PRIVATE_RESOLVE + @param pAddr - pointer to address + + @return pointer to record or NULL if not found +*/ +static gapAdvertRec_t* gapFindScanRec( uint8 addrType, uint8* pAddr ) +{ + if ( pGapScanRecs ) + { + // Look for a record that matches the address + for ( uint8 x = 0; x < gapMaxScanResponses; x++ ) + { + if ( pGapScanRecs[x].eventType != GAP_ADRPT_EMPTY ) + { + if ( (pGapScanRecs[x].addrType == addrType) + && (osal_memcmp( pGapScanRecs[x].addr, pAddr, B_ADDR_LEN )) ) + { + // Record found + return ( &(pGapScanRecs[x]) ); + } + } + } + } + + // Address not found + return ( (gapAdvertRec_t*)NULL ); +} + +/********************************************************************* + @fn gapProcessAdvertDevInfo + + @brief Process a Device Information structure of a + HCI BLE Advertisement Report Event. + + @param pDevInfo - Device Information Structure + + @return TRUE if added to report or information changed. +*/ +static uint8 gapProcessAdvertDevInfo( hciEvt_DevInfo_t* pDevInfo ) +{ + uint8 stateFlags = 0; // State flag (Flags AD type) + uint8* ADToken = NULL; // Holds a advertisement data token + gapAdvertRec_t* pRec; // advertisement record pointer + + // Are we in scan mode? + if ( pGapDiscReq == NULL ) + { + // Ignore the record + return ( FALSE ); + } + + // Don't process the data field of a directed advertisement + if ( pDevInfo->eventType != GAP_ADRPT_ADV_DIRECT_IND ) + { + uint8 ADLen; // Token length + // What kind of advertisement is this? + ADToken = gapFindADType( GAP_ADTYPE_FLAGS, &ADLen, + pDevInfo->dataLen, pDevInfo->rspData ); + } + + // Was the Flags token found + if ( ADToken ) + { + stateFlags = *ADToken; + } + + // Filter type based on filter mode, only filter Advertisement reports + if ( pDevInfo->eventType != GAP_ADRPT_SCAN_RSP ) + { + uint8 passedFilter = FALSE; + + if ( pGapDiscReq->mode == DEVDISC_MODE_ALL ) + { + // Send all through + passedFilter = TRUE; + } + else if ( (pGapDiscReq->mode == DEVDISC_MODE_NONDISCOVERABLE) + && (stateFlags == 0) ) + { + // no discovery bits + passedFilter = TRUE; + } + else if ( ADToken ) + { + if ( (pGapDiscReq->mode == DEVDISC_MODE_GENERAL) + && (stateFlags & (GAP_ADTYPE_FLAGS_GENERAL | GAP_ADTYPE_FLAGS_LIMITED)) ) + { + // Must have general discovery bit set + passedFilter = TRUE; + } + else if ( (pGapDiscReq->mode == DEVDISC_MODE_LIMITED) + && (stateFlags & GAP_ADTYPE_FLAGS_LIMITED) ) + { + // Must have limited discovery bit set + passedFilter = TRUE; + } + } + + if ( passedFilter == FALSE ) + { + // Ignore the record, didn't pass the filter + return ( FALSE ); + } + } + + // Convert from LL Address type to Host Address type + pDevInfo->addrType = gapDetermineAddrType( pDevInfo->addrType, pDevInfo->addr ); + // Find an existing advertisement record + pRec = gapFindScanRec( pDevInfo->addrType, pDevInfo->addr ); + + if ( pRec ) + { + gapAdvertRecData_t* pRecData; // Data field pointer + + if ( pDevInfo->eventType != GAP_ADRPT_SCAN_RSP ) + { + pRecData = pRec->pAdData; + } + else + { + pRecData = pRec->pScanData; + } + + if ( pRecData + && !(pGlobal_config[LL_SWITCH] & GAP_DUP_RPT_FILTER_DISALLOW)) // A2 add: duplicate adv report filter could be switch off due to Mindtree mesh request + { + if ( (pRecData->dataLen == pDevInfo->dataLen) + && (osal_memcmp( pRecData->dataField, pDevInfo->rspData, pDevInfo->dataLen ) == TRUE) ) + { + // Same, ignore this report + pRecData = (gapAdvertRecData_t*)NULL; + pRec = (gapAdvertRec_t*)NULL; + } + } + + if ( pRecData ) + { + if ( pDevInfo->eventType != GAP_ADRPT_SCAN_RSP ) + { + // Clear the Advertisement data + if ( (pRec) && (pRec->pAdData) ) + { + osal_mem_free( pRec->pAdData ); + pRec->pAdData = NULL; + } + } + else + { + // Clear the scan report data + if ( (pRec) && (pRec->pScanData) ) + { + osal_mem_free( pRec->pScanData ); + pRec->pScanData = NULL; + } + } + } + } + // Only make a new record for Advertisment Records + else if ( pDevInfo->eventType != GAP_ADRPT_SCAN_RSP ) + { + // Find an empty spot + pRec = gapFindEmptyScanRec(); + + if ( pRec ) + { + // Copy the new information + pRec->eventType = pDevInfo->eventType; + pRec->addrType = pDevInfo->addrType; + VOID osal_memcpy( pRec->addr, pDevInfo->addr, B_ADDR_LEN ); + } + } + + // save the new advertisement data or scan response data + if ( pRec ) + { + gapAdvertRecData_t* pRecData = (gapAdvertRecData_t*)osal_mem_alloc( (uint16)(pDevInfo->dataLen + 1) ); + + if ( pRecData ) + { + if ( pDevInfo->eventType != GAP_ADRPT_SCAN_RSP ) + { + pRec->pAdData = pRecData; + } + else + { + pRec->pScanData = pRecData; + } + + pRecData->dataLen = pDevInfo->dataLen; + VOID osal_memcpy( pRecData->dataField, pDevInfo->rspData, pDevInfo->dataLen ); + } + + if ( pDevInfo->dataLen ) + { + return ( TRUE ); + } + } + + return ( FALSE ); +} + +/********************************************************************* + @fn gapSendDevDiscEvent + + @brief Send the GAP_DEVICE_DISCOVERY_EVENT. + + @param status - Reason for sending this message. + SUCCESS if all went well. + + @return none +*/ +static void gapSendDevDiscEvent( bStatus_t status ) +{ + gapDevDiscEvent_t* pMsg; // Message pointer + uint8 x; // Loop counter + uint8 numDevs = 0; // Number of devices found + uint16 totalMemSize; // Total buffer size needed + + // Mode check, make sure we are doing a scan + if ( pGapDiscReq == NULL || pGapScanRecs == NULL ) + { + return; + } + + // calculate the size of the message needed + if ( status == SUCCESS ) + { + for ( x = 0; x < gapMaxScanResponses; x++ ) + { + if ( pGapScanRecs[x].eventType != GAP_ADRPT_EMPTY ) + { + numDevs++; + } + } + } + + // Calculate total size of buffer needed + totalMemSize = (uint16)(sizeof ( gapDevDiscEvent_t )); + totalMemSize += (uint16)(sizeof ( gapDevRec_t ) * numDevs); + // Allocate the message to send + pMsg = (gapDevDiscEvent_t*)osal_msg_allocate( totalMemSize ); + + if ( pMsg == NULL ) + { + // There's not enough memory to allocate the whole buffer, so try to + // allocate enough for a error status message + pMsg = (gapDevDiscEvent_t*)osal_msg_allocate( (uint16)(sizeof ( gapDevDiscEvent_t )) ); + numDevs = 0; + status = bleMemAllocError; + } + + if ( pMsg ) + { + // Build the message + pMsg->hdr.event = GAP_MSG_EVENT; + pMsg->hdr.status = status; + pMsg->opcode = GAP_DEVICE_DISCOVERY_EVENT; + pMsg->numDevs = numDevs; + + if ( numDevs > 0 ) + { + gapDevRec_t* pDevList; + // Setup pointer for device list + pDevList = (gapDevRec_t*)(pMsg+1); + pMsg->pDevList = pDevList; + + // Copy the scan records into the message + for ( x = 0; (x < gapMaxScanResponses) && (numDevs > 0); x++ ) + { + if ( pGapScanRecs[x].eventType != GAP_ADRPT_EMPTY ) + { + pDevList->eventType = pGapScanRecs[x].eventType; + pDevList->addrType = pGapScanRecs[x].addrType; + VOID osal_memcpy( pDevList->addr, pGapScanRecs[x].addr, B_ADDR_LEN ); + pDevList++; + numDevs--; + } + } + } + else + { + pMsg->pDevList = NULL; // No records + } + + // Send the message to the app + VOID osal_msg_send( pGapDiscReq->taskID, (uint8*)pMsg ); + } + + // Clear the scan record. Not freed - just cleared. + gapFreeScanRecs( gapMaxScanResponses, FALSE ); + // Free all Device Discovery memory + osal_mem_free( pGapDiscReq ); + pGapDiscReq = NULL; +} + +/********************************************************************* + @fn gapSendScanEnable + + @brief Send the HCI message to turn enable/disable the + device discovery scan. + + @param enable - TRUE to turn on scan, FALSE to turn off scan. + + @return HCI return value +*/ +static bStatus_t gapSendScanEnable( uint8 enable ) +{ + uint8 filterDuplicates = GAP_GetParamValue( TGAP_FILTER_ADV_REPORTS ) ? TRUE : FALSE; + // Continue with scan + return ( HCI_LE_SetScanEnableCmd( enable, filterDuplicates ) ); +} + +/********************************************************************* + @fn gapSendDeviceInfoEvent + + @brief Send the GAP_DEVICE_INFO_EVENT. + + @param pDevInfo - Pointer to the HCI Advertisement or Scan Rsp. + + @return none +*/ +static void gapSendDeviceInfoEvent( hciEvt_DevInfo_t* pDevInfo ) +{ + if ( pGapDiscReq ) + { + gapDeviceInfoEvent_t* pRsp; + // Allocate structure and extra space to put the data buffer at the end + pRsp = (gapDeviceInfoEvent_t*)osal_msg_allocate( + ((uint16)(sizeof( gapDeviceInfoEvent_t )) + pDevInfo->dataLen) ); + + if ( pRsp ) + { + // Build the message + pRsp->hdr.event = GAP_MSG_EVENT; + pRsp->hdr.status = SUCCESS; + pRsp->opcode = GAP_DEVICE_INFO_EVENT; + pRsp->eventType = pDevInfo->eventType; + pRsp->rssi = pDevInfo->rssi; + pRsp->addrType = pDevInfo->addrType; + VOID osal_memcpy( pRsp->addr, pDevInfo->addr, B_ADDR_LEN ); + pRsp->dataLen = pDevInfo->dataLen; + + if ( pRsp->dataLen ) + { + // Point to the extra space at the end of the allocated memory + pRsp->pEvtData = (uint8*)(pRsp + 1); + VOID osal_memcpy( pRsp->pEvtData, pDevInfo->rspData, pRsp->dataLen ); + } + else + { + pRsp->pEvtData = NULL; + } + + VOID osal_msg_send( pGapDiscReq->taskID, (uint8*)pRsp ); + } + } +} + + +/**************************************************************************** +****************************************************************************/ + diff --git a/src/lib/ble_host/gap_centlinkmgr.c b/src/lib/ble_host/gap_centlinkmgr.c new file mode 100644 index 0000000..c5ae291 --- /dev/null +++ b/src/lib/ble_host/gap_centlinkmgr.c @@ -0,0 +1,374 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: gap_centlinkmgr.c + Revised: + Revision: + + Description: This file contains the GAP Celntral Link Manager. + + +**************************************************************************************************/ + + +/******************************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "gap.h" +#include "gap_internal.h" +#include "sm.h" +#include "sm_internal.h" +#include "smp.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +/********************************************************************* + LOCAL FUNCTIONS +*/ + +/********************************************************************* + API FUNCTIONS +*/ + +/********************************************************************* + Establish a link to a slave device. + + Public function defined in gap.h. +*/ +bStatus_t GAP_EstablishLinkReq( gapEstLinkReq_t* pParams ) +{ + bStatus_t stat; // Return status + + // This function is only good for Central devices + if ( (gapProfileRole & GAP_PROFILE_CENTRAL) == 0 ) + { + return ( bleIncorrectMode ); + } + + // Are are currently scanning? + if ( gapIsScanning() ) + { + return ( bleNotReady ); + } + + // Are we already connected to the max number of devices? + if ( GAP_NumActiveConnections() >= MAX_NUM_LL_CONN ) + { + return ( bleNoResources ); + } + + // We can only perform one establish connection request at a time. + if ( pEstLink ) + { + return ( bleAlreadyInRequestedMode ); + } + + // Make a copy of the link establishment request + pEstLink = (gapEstLinkReq_t*)osal_mem_alloc( (uint16)(sizeof ( gapEstLinkReq_t )) ); + + if ( pEstLink ) + { + uint16 scanInterval; + uint16 scanWindow; + uint8 ownAddrType; + VOID osal_memcpy( pEstLink, pParams, (unsigned int)(sizeof ( gapEstLinkReq_t )) ); + + // Request LL to make the connection + if ( pEstLink->highDutyCycle ) + { + scanInterval = GAP_GetParamValue( TGAP_CONN_HIGH_SCAN_INT ); + scanWindow = GAP_GetParamValue( TGAP_CONN_HIGH_SCAN_WIND ); + } + else + { + scanInterval = GAP_GetParamValue( TGAP_CONN_SCAN_INT ); + scanWindow = GAP_GetParamValue( TGAP_CONN_SCAN_WIND ); + } + + if ( gapDeviceAddrMode == ADDRTYPE_PUBLIC ) + { + ownAddrType = ADDRTYPE_PUBLIC; + } + else + { + ownAddrType = ADDRTYPE_RANDOM; + } + + // Request the LL to make the connection + stat = HCI_LE_CreateConnCmd( scanInterval, scanWindow, pEstLink->whiteList, + gapAddAddrAdj( pEstLink->addrTypePeer, pEstLink->peerAddr ), + pEstLink->peerAddr, ownAddrType, + GAP_GetParamValue( TGAP_CONN_EST_INT_MIN ), + GAP_GetParamValue( TGAP_CONN_EST_INT_MAX ), + GAP_GetParamValue( TGAP_CONN_EST_LATENCY ), + GAP_GetParamValue( TGAP_CONN_EST_SUPERV_TIMEOUT ), + GAP_GetParamValue( TGAP_CONN_EST_MIN_CE_LEN ), + GAP_GetParamValue( TGAP_CONN_EST_MAX_CE_LEN ) ); + + if ( stat != SUCCESS ) + { + gapFreeEstLink(); + } + } + else + { + stat = bleMemAllocError; + } + + return ( stat ); +} + +/********************************************************************* + @fn gapCancelLinkReq + + @brief Cancel a connection create request. + + @param taskID - requesting app's task id + @param connectionHandle - connection handle of link to terminate + + @return SUCCESS, bleIncorrectMode, or bleInvalidTaskID +*/ +bStatus_t gapCancelLinkReq( uint8 taskID, uint16 connectionHandle ) +{ + bStatus_t stat = bleIncorrectMode; // Return status + + // Are we trying to terminate a Establish Connection Request? + if ( connectionHandle == GAP_CONNHANDLE_INIT ) + { + // Does the task ID match the task ID of the Connection Request? + if ( pEstLink && pEstLink->taskID == taskID ) + { + // Connection Cancel Cmd + stat = HCI_LE_CreateConnCancelCmd(); + } + else + { + if ( pEstLink ) + { + // Not the correct taskID + stat = bleInvalidTaskID; + } + } + } + // Terminate All Connections? + else if ( connectionHandle == GAP_CONNHANDLE_ALL ) + { + // First are we currently trying to establish a connection + if ( pEstLink ) + { + // Connection Cancel Cmd + stat = HCI_LE_CreateConnCancelCmd(); + } + } + + return ( stat ); +} + +/********************************************************************* + Update the link parameters to a slave device. + + Public function defined in gap.h. +*/ +bStatus_t GAP_UpdateLinkParamReq( gapUpdateLinkParamReq_t* pParams ) +{ + // This function is only good for Central devices + if ( (gapProfileRole & GAP_PROFILE_CENTRAL) == 0 ) + { + return ( bleIncorrectMode ); + } + + // Check parameters + if ( !HCI_ValidConnTimeParams( pParams->intervalMin, + pParams->intervalMax, + pParams->connLatency, + pParams->connTimeout ) ) + { + return ( INVALIDPARAMETER ); + } + + // Make sure the physical connection is up + if ( !linkDB_Up( pParams->connectionHandle ) ) + { + return ( bleNotConnected ); + } + + return ( HCI_LE_ConnUpdateCmd( pParams->connectionHandle, pParams->intervalMin, + pParams->intervalMax, pParams->connLatency, + pParams->connTimeout, 0, 0 ) ); +} + +/********************************************************************* + @fn gapProcessCreateLLConnCmdStatus + + @brief Process the status for the HCI_BLECreateLLConnCmd(). + + @param status - create connection command status + + @return none +*/ +void gapProcessCreateLLConnCmdStatus( uint8 status ) +{ + if ( (status != SUCCESS) && (pEstLink != NULL) ) + { + // Send the connection notification to the app + sendEstLinkEvent( status, pEstLink->taskID, + pEstLink->addrTypePeer, pEstLink->peerAddr, 0, + // Fill with 0's for now, otherwise fill in what was asked for. + 0, 0, 0, 0 ); + // Clear the connection information + gapFreeEstLink(); + } +} + +/********************************************************************* + @fn gapTerminateConnComplete + + @brief Process the status for the HCI_BLECreateLLConnCancelCmd(). + + @param none + + @return none +*/ +void gapTerminateConnComplete( void ) +{ + // Free the establish link variables + gapFreeEstLink(); +} + +/********************************************************************* + @fn gapProcessConnUpdateCmdStatus + + @brief Process the status for the HCI_LE_ConnUpdateCmd(). + + @param status - connection update command status + + @return none +*/ +void gapProcessConnUpdateCmdStatus( uint8 status ) +{ + if ( status != SUCCESS ) + { + // Send the link update notification to the app + gapSendLinkUpdateEvent( status, 0, 0, 0, 0 ); + } +} + +/********************************************************************* + @fn gapProcessL2CAPSignalEvent + + @brief Process L2CAP Signaling messages. + + @param pCmd - pointer to received command + + @return none + *********************************************************************/ +void gapProcessL2CAPSignalEvt( l2capSignalEvent_t* pCmd ) +{ + #if defined ( TESTMODES ) + + if ( GAP_GetParamValue( TGAP_GAP_TESTCODE ) == GAP_TESTMODE_NO_RESPONSE ) + { + // just ignore the messages + return; + } + + #endif // TESTMODES + + // Process the signaling command + if ( pCmd->opcode == L2CAP_PARAM_UPDATE_REQ ) + { + // Depending on the parameters of other connections, the master's + // Host may accept the requested parameters and deliver them to the + // local Controller or reject the request. If the master's Host accepts + // the request, it shall send the Connection Parameter Update Response + // with result 0x00 (Parameters accepted) otherwise it shall set the + // result to 0x01 (request rejected). + l2capParamUpdateReq_t* pReq = &(pCmd->cmd.updateReq); + l2capParamUpdateRsp_t updateRsp; + + if ( HCI_ValidConnTimeParams( pReq->intervalMin, + pReq->intervalMax, + pReq->slaveLatency, + pReq->timeoutMultiplier ) + && ( GAP_GetParamValue( TGAP_REJECT_CONN_PARAMS ) == FALSE ) ) + { + updateRsp.result = L2CAP_CONN_PARAMS_ACCEPTED; + } + else + { + updateRsp.result = L2CAP_CONN_PARAMS_REJECTED; + } + + // First send response back... + VOID L2CAP_ConnParamUpdateRsp( pCmd->connHandle, pCmd->id, &updateRsp ); + + // ...then update Connection Parameters + if ( updateRsp.result == L2CAP_CONN_PARAMS_ACCEPTED ) + { + VOID HCI_LE_ConnUpdateCmd( pCmd->connHandle, pReq->intervalMin, + pReq->intervalMax, pReq->slaveLatency, + pReq->timeoutMultiplier, 0, 0 ); + } + } +} + + +/**************************************************************************** +****************************************************************************/ diff --git a/src/lib/ble_host/gap_configmgr.c b/src/lib/ble_host/gap_configmgr.c new file mode 100644 index 0000000..1f4dcfc --- /dev/null +++ b/src/lib/ble_host/gap_configmgr.c @@ -0,0 +1,968 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: gap_configmgr.c + Revised: + Revision: + + Description: This file contains the GAP Configuration Manager. + + +**************************************************************************************************/ + +#include "bcomdef.h" +#include "gap.h" +#include "gap_internal.h" +#include "linkdb.h" +#include "sm.h" +#include "sm_internal.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +// Default Timer values +#define TGAP_GEN_DISC_ADV_MIN_DEFAULT 0 // mSec (0 = no timeout) +#define TGAP_LIM_ADV_TIMEOUT_DEFAULT 180 // 180 seconds +#define TGAP_GEN_DISC_SCAN_DEFAULT 10240 // mSec +#define TGAP_LIM_DISC_SCAN_DEFAULT 10240 // mSec +#define TGAP_CONN_EST_ADV_TIMEOUT_DEFAULT 10240 // mSec +#define TGAP_CONN_PARAM_TIMEOUT_DEFAULT 30000 // mSec + +// GAP Constants defaults +#if defined ( GAP_STANDARDS ) + // Defined as defaults in spec + #define TGAP_LIM_DISC_ADV_INT_MIN_DEFAULT 2048 // 1280 mSec (n * 0.625 mSec) + #define TGAP_LIM_DISC_ADV_INT_MAX_DEFAULT 2048 // 1280 mSec (n * 0.625 mSec) + #define TGAP_GEN_DISC_ADV_INT_MIN_DEFAULT 2048 // 1280 mSec (n * 0.625 mSec) + #define TGAP_GEN_DISC_ADV_INT_MAX_DEFAULT 2048 // 1280 mSec (n * 0.625 mSec) + #define TGAP_CONN_ADV_INT_MIN_DEFAULT 2048 // 1280 mSec (n * 0.625 mSec) + #define TGAP_CONN_ADV_INT_MAX_DEFAULT 2048 // 1280 mSec (n * 0.625 mSec) + #define TGAP_CONN_SCAN_INT_DEFAULT 2048 // 1280 mSec (n * 0.625 mSec) + #define TGAP_CONN_SCAN_WIND_DEFAULT 18 // 11.25 mSec (n * 0.625 mSec) + #define TGAP_CONN_HIGH_SCAN_INT_DEFAULT 16 // 10 mSec (n * 0.625 mSec) + #define TGAP_CONN_HIGH_SCAN_WIND_DEFAULT 16 // 10 mSec (n * 0.625 mSec) + #define TGAP_GEN_DISC_SCAN_INT_DEFAULT 16 // 10 mSec (n * 0.625 mSec) + #define TGAP_GEN_DISC_SCAN_WIND_DEFAULT 16 // 10 mSec (n * 0.625 mSec) + #define TGAP_LIM_DISC_SCAN_INT_DEFAULT 16 // 10 mSec (n * 0.625 mSec) + #define TGAP_LIM_DISC_SCAN_WIND_DEFAULT 16 // 10 mSec (n * 0.625 mSec) + #define TGAP_CONN_EST_ADV_DEFAULT 80 // 50 mSec (n * 0.625 mSec) + #define TGAP_CONN_EST_INT_MIN_DEFAULT 400 // 500 mSec (n * 1.25 mSec) + #define TGAP_CONN_EST_INT_MAX_DEFAULT 400 // 500 mSec (n * 1.25 mSec) + #define TGAP_CONN_EST_SCAN_INT_DEFAULT 16 // 10 mSec (n * 0.625 mSec) + #define TGAP_CONN_EST_SCAN_WIND_DEFAULT 16 // 10 mSec (n * 0.625 mSec) + #define TGAP_CONN_EST_SUPERV_TIMEOUT_DEFAULT 2000 // 20 sec (n * 10 mSec) + #define TGAP_CONN_EST_LATENCY_DEFAULT 0 // (in number of connection events) + #define TGAP_CONN_EST_MIN_CE_LEN_DEFAULT 0 // (n * 0.625 mSec) + #define TGAP_CONN_EST_MAX_CE_LEN_DEFAULT 0 // (n * 0.625 mSec) + #define TGAP_PRIVATE_ADDR_INT_DEFAULT 15 // 15 minutes + #define TGAP_CONN_PAUSE_CENTRAL_DEFAULT 1 // 1 seconds + #define TGAP_CONN_PAUSE_PERIPHERAL_DEFAULT 5 // 5 seconds +#else + // Actually works + #define TGAP_LIM_DISC_ADV_INT_MIN_DEFAULT 160 // 100 mSec (n * 0.625 mSec) + #define TGAP_LIM_DISC_ADV_INT_MAX_DEFAULT 160 // 100 mSec (n * 0.625 mSec) + #define TGAP_GEN_DISC_ADV_INT_MIN_DEFAULT 160 // 100 mSec (n * 0.625 mSec) + #define TGAP_GEN_DISC_ADV_INT_MAX_DEFAULT 160 // 100 mSec (n * 0.625 mSec) + #define TGAP_CONN_ADV_INT_MIN_DEFAULT 2048 // 1280 mSec (n * 0.625 mSec) + #define TGAP_CONN_ADV_INT_MAX_DEFAULT 2048 // 1280 mSec (n * 0.625 mSec) + #define TGAP_CONN_SCAN_INT_DEFAULT 480 // 300 mSec (n * 0.625 mSec) + #define TGAP_CONN_SCAN_WIND_DEFAULT 240 // 150 mSec (n * 0.625 mSec) + #define TGAP_CONN_HIGH_SCAN_INT_DEFAULT 16 // 10 mSec (n * 0.625 mSec) + #define TGAP_CONN_HIGH_SCAN_WIND_DEFAULT 16 // 10 mSec (n * 0.625 mSec) + #define TGAP_GEN_DISC_SCAN_INT_DEFAULT 16 // 10 mSec (n * 0.625 mSec) + #define TGAP_GEN_DISC_SCAN_WIND_DEFAULT 16 // 10 mSec (n * 0.625 mSec) + #define TGAP_LIM_DISC_SCAN_INT_DEFAULT 16 // 10 mSec (n * 0.625 mSec) + #define TGAP_LIM_DISC_SCAN_WIND_DEFAULT 16 // 10 mSec (n * 0.625 mSec) + #define TGAP_CONN_EST_ADV_DEFAULT 80 // 50 mSec (n * 0.625 mSec) + #define TGAP_CONN_EST_INT_MIN_DEFAULT 80 // 100 mSec (n * 1.25 mSec) + #define TGAP_CONN_EST_INT_MAX_DEFAULT 80 // 100 mSec (n * 1.25 mSec) + #define TGAP_CONN_EST_SCAN_INT_DEFAULT 16 // 10 mSec (n * 0.625 mSec) + #define TGAP_CONN_EST_SCAN_WIND_DEFAULT 16 // 10 mSec (n * 0.625 mSec) + #define TGAP_CONN_EST_SUPERV_TIMEOUT_DEFAULT 2000 // 20 sec (n * 10 mSec) + #define TGAP_CONN_EST_LATENCY_DEFAULT 0 // (in number of connection events) + #define TGAP_CONN_EST_MIN_CE_LEN_DEFAULT 0 // (n * 0.625 mSec) + #define TGAP_CONN_EST_MAX_CE_LEN_DEFAULT 0 // (n * 0.625 mSec) + #define TGAP_PRIVATE_ADDR_INT_DEFAULT 15 // 15 minutes + #define TGAP_CONN_PAUSE_CENTRAL_DEFAULT 1 // 1 seconds + #define TGAP_CONN_PAUSE_PERIPHERAL_DEFAULT 5 // 5 seconds +#endif + +// Proprietary default values +#define TGAP_SM_TIMEOUT_DEFAULT 30000 // 30 seconds (milliseconds) +#define TGAP_SM_MIN_KEY_LEN_DEFAULT 7 // 7 Bytes minimum +#define TGAP_SM_MAX_KEY_LEN_DEFAULT 16 // 16 Bytes maximum +#define TGAP_FILTER_ADV_REPORTS_DEFAULT TRUE // Filter duplicate advertising reports +#define TGAP_SCAN_RSP_RSSI_MIN_DEFAULT -127 // Minimum RSSI required for scan responses +#define TGAP_REJECT_CONN_PARAMS_DEFAULT FALSE // Accept Connection Parameter Update Request + +#if defined ( TESTMODES ) + #define TGAP_GAP_TESTCODE_DEFAULT GAP_TESTMODE_OFF + #define TGAP_SM_TESTCODE_DEFAULT SM_TESTMODE_OFF +#endif + +#define TGAP_AUTH_TASK_ID_DEFAULT 0 // Default task ID, 0 if no default + +/********************************************************************* + TYPEDEFS +*/ + +// Used when reading variables from the HCI during initialization. +typedef enum +{ + GAP_INITSTATE_INVALID, + GAP_INITSTATE_BD_ADDR, + GAP_INITSTATE_BUFFERSIZE, + GAP_INITSTATE_READY +} gapLLParamsStates_t; + +typedef struct +{ + gapLLParamsStates_t state; // Holds the state during initialization + uint8* pIRK; // Pointer to the device's IRK, this space is actually allocated in the controlling application + uint8* pSRK; // Pointer to the device's SRK, this space is actually allocated in the controlling application + uint32* pSignCounter; // Pointer to the device's sign counter, this space is actually allocated in the controlling application + uint8 BD_ADDR[B_ADDR_LEN]; // The device's public address, this value is read from HCI + uint16 HC_LE_Data_Packet_Lenth; // Maximum HCI packet length + uint8 HC_Total_Num_LE_Data_Packets; // Total number of data packets that can be sent, read from HCI +} gapConfigLLParams_t; + +/********************************************************************* + GLOBAL VARIABLES - These are available as part of the internal API + (gap_internal.h), not part of the public API (gap.h) +*/ + +uint8 gapAppTaskID = INVALID_TASK_ID; // default task ID to send events +uint8 gapProfileRole = NULL; // device GAP Profile Role(s) + + +uint8 gapDeviceAddrMode = ADDRTYPE_PUBLIC; // Current device's address mode + +// Address change timeout, should only be non-0 if using ADDRTYPE_PRIVATE_RESOLVE +// Also, this timeout is in minutes. +uint16 gapPrivateAddrChangeTimeout = 0; + +// Flag to control auto private resolvable address changes. +uint8 gapAutoAdvPrivateAddrChange = FALSE; + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +// Device's parameters, established during GAP_DeviceInit(). +static gapConfigLLParams_t gapParams; + +// GAP settable parameters, these can be accessed through GAP_SetParamValue() and +// GAP_GetParamValue() public APIs. +static uint16 gapParameters[] = +{ + // Default Timer values + TGAP_GEN_DISC_ADV_MIN_DEFAULT, + TGAP_LIM_ADV_TIMEOUT_DEFAULT, + TGAP_GEN_DISC_SCAN_DEFAULT, + TGAP_LIM_DISC_SCAN_DEFAULT, + TGAP_CONN_EST_ADV_TIMEOUT_DEFAULT, + TGAP_CONN_PARAM_TIMEOUT_DEFAULT, + + // GAP Constants defaults + TGAP_LIM_DISC_ADV_INT_MIN_DEFAULT, + TGAP_LIM_DISC_ADV_INT_MAX_DEFAULT, + TGAP_GEN_DISC_ADV_INT_MIN_DEFAULT, + TGAP_GEN_DISC_ADV_INT_MAX_DEFAULT, + TGAP_CONN_ADV_INT_MIN_DEFAULT, + TGAP_CONN_ADV_INT_MAX_DEFAULT, + TGAP_CONN_SCAN_INT_DEFAULT, + TGAP_CONN_SCAN_WIND_DEFAULT, + TGAP_CONN_HIGH_SCAN_INT_DEFAULT, + TGAP_CONN_HIGH_SCAN_WIND_DEFAULT, + TGAP_GEN_DISC_SCAN_INT_DEFAULT, + TGAP_GEN_DISC_SCAN_WIND_DEFAULT, + TGAP_LIM_DISC_SCAN_INT_DEFAULT, + TGAP_LIM_DISC_SCAN_WIND_DEFAULT, + TGAP_CONN_EST_ADV_DEFAULT, + TGAP_CONN_EST_INT_MIN_DEFAULT, + TGAP_CONN_EST_INT_MAX_DEFAULT, + TGAP_CONN_EST_SCAN_INT_DEFAULT, + TGAP_CONN_EST_SCAN_WIND_DEFAULT, + TGAP_CONN_EST_SUPERV_TIMEOUT_DEFAULT, + TGAP_CONN_EST_LATENCY_DEFAULT, + TGAP_CONN_EST_MIN_CE_LEN_DEFAULT, + TGAP_CONN_EST_MAX_CE_LEN_DEFAULT, + TGAP_PRIVATE_ADDR_INT_DEFAULT, + TGAP_CONN_PAUSE_CENTRAL_DEFAULT, + TGAP_CONN_PAUSE_PERIPHERAL_DEFAULT, + + // Proprietary default values + TGAP_SM_TIMEOUT_DEFAULT, + TGAP_SM_MIN_KEY_LEN_DEFAULT, + TGAP_SM_MAX_KEY_LEN_DEFAULT, + TGAP_FILTER_ADV_REPORTS_DEFAULT, + (uint16)TGAP_SCAN_RSP_RSSI_MIN_DEFAULT, + TGAP_REJECT_CONN_PARAMS_DEFAULT, + #if defined ( TESTMODES ) + TGAP_GAP_TESTCODE_DEFAULT, + TGAP_SM_TESTCODE_DEFAULT, + #endif + TGAP_AUTH_TASK_ID_DEFAULT +}; + +// Storage for the current Random address (not Public). +static uint8 gapCurrentRandomAddr[B_ADDR_LEN] = {0,0,0,0,0,0}; + +/********************************************************************* + LOCAL FUNCTION PROTOTYPES +*/ +static void gapSendDeviceInitDoneEvent( uint8 status ); +static void gapSendRandomAddrChangeEvent( uint8 status, uint8* pNewAddr ); +static void gapSendSignUpdateEvent( uint8 taskID, uint8 addrType, + uint8* pDevAddr, uint32 signCounter ); + +/********************************************************************* + API FUNCTIONS +*/ + +/********************************************************************* + Set a GAP Parameter value. Use this function to change the default + GAP parameter values. + + Public function defined in gap.h. +*/ +bStatus_t GAP_SetParamValue( gapParamIDs_t paramID, uint16 paramValue ) +{ + // Check for invalid parameters + if ( (paramID < TGAP_PARAMID_MAX) && (paramValue != 0xFFFF) ) + { + #if defined ( TESTMODES ) + + if ( (paramID == TGAP_SM_TESTCODE) && (paramValue == SM_TESTMODE_SEND_CONFIRM) ) + { + smpPairingConfirm_t confirmMsg; // Parameters to build message + // Clear the confirm + VOID osal_memset( confirmMsg.confirmValue, 0, SMP_CONFIRM_LEN ); + // Send confirm message + return ( smSendPairingConfirm( 0, &confirmMsg ) ); + } + + #endif + // Good so far + gapParameters[paramID] = paramValue; + return ( SUCCESS ); + } + else + { + return ( INVALIDPARAMETER ); + } +} + +/********************************************************************* + @brief Get a GAP Parameter value. + + Public function defined in gap.h. +*/ +uint16 GAP_GetParamValue( gapParamIDs_t paramID ) +{ + // Check for invalid parameter + if ( paramID < TGAP_PARAMID_MAX ) + { + return ( gapParameters[paramID] ); + } + else + { + return ( 0xFFFF ); + } +} + +/********************************************************************* + GAP INTERNAL FUNCTIONS +*/ + +/********************************************************************* + @fn GAP_ParamsInit + + @brief Setup the device configuration parameters. + + @param taskID - Default task ID to send events. + @param profileRole - GAP Profile Roles + + @return SUCCESS or bleIncorrectMode +*/ +bStatus_t GAP_ParamsInit( uint8 taskID, uint8 profileRole ) +{ + bStatus_t stat; // Return status + // Initialize the GAP Parameters + VOID osal_memset( &gapParams, 0, (int)(sizeof ( gapConfigLLParams_t )) ); + gapAppTaskID = taskID; + gapProfileRole = profileRole; + // Start gathering LL (HCI) parameters + stat = HCI_ReadBDADDRCmd(); + + if ( stat == SUCCESS ) + { + // Set state to wait for the HCI event with the address + gapParams.state = GAP_INITSTATE_BD_ADDR; + } + else + { + // Enter an error state and setup the return for an error + gapParams.state = GAP_INITSTATE_INVALID; + stat = bleIncorrectMode; + } + + return ( stat ); +} + +/********************************************************************* + @fn GAP_SecParamsInit + + @brief Setup the device security configuration parameters. + + @param pIRK - pointer to Identity Root Key, NULLKEY (all zeroes) if the app + wants the GAP to generate the key. + @param pSRK - pointer to Sign Resolving Key, NULLKEY if the app + wants the GAP to generate the key. + @param pSignCounter - 32 bit value used in the SM Signing + algorithm that shall be initialized to zero and incremented + with every new signing. This variable must also be maintained + by the application. + + @return none +*/ +void GAP_SecParamsInit( uint8* pIRK, uint8* pSRK, uint32* pSignCounter ) +{ + gapParams.pSignCounter = pSignCounter; + // Copy the key pointers + gapParams.pSRK = pSRK; + gapParams.pIRK = pIRK; + + // Check if the buffer is all 0's, which means the the app expects + // that the GAP generate a random SRK + if ( osal_isbufset( pSRK, 0, KEYLEN ) == TRUE ) + { + // Generate a random number SRK + smGenerateRandBuf( gapParams.pSRK, KEYLEN ); + } + + // Check if the buffer is all 0's, which means the the app expects + // that the GAP generate a random IRK + if ( osal_isbufset( pIRK, 0, KEYLEN ) == TRUE ) + { + // Generate a random number IRK + smGenerateRandBuf( gapParams.pIRK, KEYLEN ); + } +} + +/********************************************************************* + Setup the device's address type. If ADDRTYPE_PRIVATE_RESOLVE + is selected, the address will change periodically. + + Public function defined in gap.h. +*/ +bStatus_t GAP_ConfigDeviceAddr( uint8 addrType, uint8* pStaticAddr ) +{ + uint8 currentAddrMode = gapDeviceAddrMode; // Save current address mode, before changing it + bStatus_t stat = SUCCESS; // Assume a successful return + uint8 newAddr[B_ADDR_LEN]; + + // Check for valid address type. + if ( (addrType > ADDRTYPE_PRIVATE_RESOLVE) ) + { + return ( INVALIDPARAMETER ); + } + + // Make sure that we have been initialized first. + if ( gapParams.state != GAP_INITSTATE_READY ) + { + return ( bleNotReady ); + } + + // Only allow an address mode change if we aren't already doing something. + if ( GAP_NumActiveConnections() || gapIsAdvertising() || gapIsScanning() ) + { + return ( bleIncorrectMode ); + } + + if ( (addrType == ADDRTYPE_STATIC) || (addrType == ADDRTYPE_PRIVATE_NONRESOLVE) ) + { + // Is the passed in pointer valid? + if ( pStaticAddr ) + { + // Make sure the not all zeros + VOID osal_memset( newAddr, 0, B_ADDR_LEN ); + + if ( osal_memcmp( pStaticAddr, newAddr, B_ADDR_LEN ) ) + { + return ( INVALIDPARAMETER ); + } + + // Make sure the not all ones + VOID osal_memset( newAddr, 0xFF, B_ADDR_LEN ); + + if ( osal_memcmp( pStaticAddr, newAddr, B_ADDR_LEN ) ) + { + return ( INVALIDPARAMETER ); + } + + // Use the passed in address + VOID osal_memcpy( newAddr, pStaticAddr, B_ADDR_LEN ); + } + else + { + // Not passed in - generate a new random address + smGenerateRandBuf( newAddr, B_ADDR_LEN ); + } + } + else if ( addrType == ADDRTYPE_PRIVATE_RESOLVE ) + { + // Change from Public to Random + stat = SM_CalcRandomAddr( gapParams.pIRK, newAddr ); + } + + // Save off the new address type + gapDeviceAddrMode = addrType; + // Default the Resolvable Private Address Change timer + VOID osal_stop_timerEx( gapTaskID, GAP_CHANGE_RESOLVABLE_PRIVATE_ADDR_EVT ); + gapPrivateAddrChangeTimeout = 0; + + if ( (stat == SUCCESS) && (addrType != ADDRTYPE_PUBLIC) ) + { + // Send the new "Random" address to the LL + stat = gapProcessNewAddr( newAddr ); + + if ( (stat == SUCCESS) && (addrType == ADDRTYPE_PRIVATE_RESOLVE) ) + { + // Private resolvable addresses are periodically changed, + // so setup a timer for the next change + gapPrivateAddrChangeTimeout = GAP_GetParamValue( TGAP_PRIVATE_ADDR_INT ); + + // Start a timer + if ( gapPrivateAddrChangeTimeout ) + { + VOID osal_start_reload_timer( gapTaskID, GAP_CHANGE_RESOLVABLE_PRIVATE_ADDR_EVT, + (uint32)GAP_PRIVATE_ADDR_CHANGE_RESOLUTION ); + } + } + } + + if ( stat != SUCCESS ) + { + // something went wrong, restore address type + gapDeviceAddrMode = currentAddrMode; + } + + return ( stat ); +} + +/********************************************************************* + @fn gapReadBD_ADDRStatus + + @brief Process the HCI Command Complete Event for the + call to HCI_ReadBDADDRCmd(). + + @param status - SUCESS or error + @param bdAddr - pointer to the received device address + + @return TRUE if expected, FALSE if not. +*/ +uint8 gapReadBD_ADDRStatus( uint8 status, uint8* pBdAddr ) +{ + uint8 expected = FALSE; // Assume we aren't expecting this HCI message + + if ( (status == SUCCESS) && (pBdAddr != NULL) ) + { + VOID osal_memcpy( gapParams.BD_ADDR, pBdAddr, B_ADDR_LEN ); + } + + // Are we expecting this message? + if ( gapParams.state == GAP_INITSTATE_BD_ADDR ) + { + expected = TRUE; // Yes, we are expecting this HCI message + + if ( status == SUCCESS ) + { + // Get the LL HCI Buffer size + gapParams.state = GAP_INITSTATE_BUFFERSIZE; + VOID HCI_LE_ReadBufSizeCmd(); + } + else + { + // Error state + gapParams.state = GAP_INITSTATE_INVALID; + gapSendDeviceInitDoneEvent( status ); + } + } + + return ( expected ); +} + +/********************************************************************* + @fn gapReadBufSizeCmdStatus + + @brief Process the HCI Command Complete Event for the + call to HCI_BLEReadBufSizeCmd(). + + @param cmdStat - command status parameters + + @return TRUE if expected, FALSE if not. +*/ +uint8 gapReadBufSizeCmdStatus( hciRetParam_LeReadBufSize_t* pCmdStat ) +{ + uint8 expected = FALSE; // Assume we aren't expecting this HCI message + + if ( pCmdStat ) + { + if ( pCmdStat->status == SUCCESS ) + { + gapParams.HC_LE_Data_Packet_Lenth = pCmdStat->dataPktLen; + gapParams.HC_Total_Num_LE_Data_Packets = pCmdStat->numDataPkts; + } + + if ( gapParams.state == GAP_INITSTATE_BUFFERSIZE ) + { + expected = TRUE; + + if ( pCmdStat->status == SUCCESS ) + { + gapParams.state = GAP_INITSTATE_READY; + } + else + { + gapParams.state = GAP_INITSTATE_INVALID; + } + + gapSendDeviceInitDoneEvent( pCmdStat->status ); + } + } + + return ( expected ); +} + +/********************************************************************* + @fn gapProcessNewAddr + + @brief Process the SM New Random Addr Event message. + + @param newAddr - Pointer to new address + + @return SUCCESS +*/ +bStatus_t gapProcessNewAddr( uint8* pNewAddr ) +{ + if ( gapDeviceAddrMode != ADDRTYPE_PUBLIC ) + { + VOID osal_memcpy( gapCurrentRandomAddr, pNewAddr, B_ADDR_LEN ); + VOID gapAddAddrAdj( gapDeviceAddrMode, gapCurrentRandomAddr ); + return ( HCI_LE_SetRandomAddressCmd( gapCurrentRandomAddr ) ); + } + else + { + return ( SUCCESS ); + } +} + +/********************************************************************* + @fn gapAddAddrAdj + + @brief Add the top two bits based on the address type. + + @param status - operation status - SUCCESS if successful. + + @return the LL address type ADDRTYPE_PUBLIC or ADDRTYPE_RANDOM +*/ +uint8 gapAddAddrAdj( uint8 addrType, uint8* pAddr ) +{ + // Assume public address + uint8 llAddrType = ADDRTYPE_PUBLIC; + + if ( (pAddr) && (addrType != ADDRTYPE_PUBLIC) ) + { + // Update the Random Address type + if ( addrType == ADDRTYPE_STATIC ) + { + // Set the header bits of the Static Address + pAddr[B_ADDR_LEN-1] |= STATIC_ADDR_HDR; + } + else + { + // Clear the header bits for Random addresses + pAddr[B_ADDR_LEN-1] &= ~(RANDOM_ADDR_HDR); + + if ( addrType == ADDRTYPE_PRIVATE_RESOLVE ) + { + // Set the address header bits + pAddr[B_ADDR_LEN-1] |= PRIVATE_RESOLVE_ADDR_HDR; + } + } + + // If not public, then it must be a random address (LL) + llAddrType = ADDRTYPE_RANDOM; + } + + return ( llAddrType ); +} + +/********************************************************************* + @fn gapDetermineAddrType + + @brief Determine the address type from the address. + + @param addrType - LL address type + @param addr - 6 byte address + + @return returns the type of Random address + ADDRTYPE_STATIC, ADDRTYPE_PRIVATE_NONRESOLVE + or ADDRTYPE_PRIVATE_RESOLVE +*/ +uint8 gapDetermineAddrType( uint8 addrType, uint8* pAddr ) // TODO +{ + // Don't need to convert if no address or type is already public + if ( (pAddr) && (addrType == 0x01)/*(addrType != ADDRTYPE_PUBLIC)*/ ) // HZF: HCI will report public or Random(static or private) for BLE4.0. + { + // BLE4.2 add 2 types: RPA_public(0x02) + RPA_static(0x03) + // Get just the random address header bits + uint8 addrTypeMask = (uint8)(pAddr[B_ADDR_LEN-1] & RANDOM_ADDR_HDR); + + // Get the address type from the address header + if ( addrTypeMask == STATIC_ADDR_HDR ) + { + addrType = ADDRTYPE_STATIC; + } + else if ( addrTypeMask == PRIVATE_RESOLVE_ADDR_HDR ) + { + addrType = ADDRTYPE_PRIVATE_RESOLVE; + } + else + { + // It must be this, it's the only one left + addrType = ADDRTYPE_PRIVATE_NONRESOLVE; + } + } + + return ( addrType ); +} + +/********************************************************************* + @fn gapProcessRandomAddrComplete + + @brief Process the HCI Random Address Complete Event message. + + @param status - operation status - SUCCESS if successful. + + @return none +*/ +void gapProcessRandomAddrComplete( uint8 status ) +{ + // Inform the application + gapSendRandomAddrChangeEvent( status, gapCurrentRandomAddr ); + + if ( gapAutoAdvPrivateAddrChange == TRUE ) + { + if ( pfnPeripheralCBs && pfnPeripheralCBs->pfnSetAdvParams ) + { + // Force an advertisement parameter update. + VOID pfnPeripheralCBs->pfnSetAdvParams(); + } + + // Start up the timer again + VOID osal_start_reload_timer( gapTaskID, GAP_CHANGE_RESOLVABLE_PRIVATE_ADDR_EVT, + (uint32)GAP_PRIVATE_ADDR_CHANGE_RESOLUTION ); + } +} + +/********************************************************************* + @fn gapGetSRK + + @brief Get pointer to the SRK. + + @param none + + @return pointer to the device's Signature Resolving Key +*/ +uint8* gapGetSRK( void ) +{ + return ( gapParams.pSRK ); +} + +/********************************************************************* + @fn gapGetSignCounter + + @brief Get the signature counter. + + @param none + + @return the device's Signature counter +*/ +uint32 gapGetSignCounter( void ) +{ + return ( *gapParams.pSignCounter ); +} + +/********************************************************************* + @fn gapIncSignCounter + + @brief Increment the signature counter. + + @param none + + @return none +*/ +void gapIncSignCounter( void ) +{ + // Increment the signCounter + (*(gapParams.pSignCounter))++; + + // Tell the app + if ( gapAppTaskID != INVALID_TASK_ID ) + { + VOID osal_set_event( gapAppTaskID, GAP_EVENT_SIGN_COUNTER_CHANGED ); + } +} + +/********************************************************************* + @fn gapUpdateConnSignCounter + + @brief Update a link's sign counter. + + @param none + + @return none +*/ +void gapUpdateConnSignCounter( uint16 connHandle, uint32 newSignCounter ) +{ + linkDBItem_t* pConnItem; + pConnItem = linkDB_Find( connHandle ); + + if ( pConnItem ) + { + uint8 taskID; + pConnItem->sec.signCounter = newSignCounter; + taskID = (uint8)GAP_GetParamValue( TGAP_AUTH_TASK_ID ); + + if ( taskID == 0 ) + { + taskID = pConnItem->taskID; + } + + // Tell the app + gapSendSignUpdateEvent( taskID, pConnItem->addrType, + pConnItem->addr, pConnItem->sec.signCounter ); + } +} + +/********************************************************************* + @fn gapGetDevAddressMode + + @brief Get the address mode of this device + + @param none + + @return address mode +*/ +uint8 gapGetDevAddressMode( void ) +{ + return ( gapDeviceAddrMode ); +} + +/********************************************************************* + @fn gapGetDevAddress + + @brief Get the address of this device + + @param real - TRUE to always return the BD_ADDR + FALSE - could be random if using random + + @return pointer to device address. +*/ +uint8* gapGetDevAddress( uint8 real ) +{ + uint8* pAddr = gapParams.BD_ADDR; + + if ( real == FALSE ) + { + if ( gapDeviceAddrMode != ADDRTYPE_PUBLIC ) + { + pAddr = gapCurrentRandomAddr; + } + } + + return ( pAddr ); +} + +/********************************************************************* + @fn gapGetIRK + + @brief Get the device's IRK + + @param none + + @return pointer to IRK +*/ +uint8* gapGetIRK( void ) +{ + return ( gapParams.pIRK ); +} + +/********************************************************************* + FILE LOCAL FUNCTIONS +*/ + +/********************************************************************* + @fn gapSendDeviceInitDoneEvent + + @brief Send the GAP_DEVICE_INIT_DONE_EVENT. + + @param status - Status of initialization + + @return none +*/ +static void gapSendDeviceInitDoneEvent( uint8 status ) +{ + if ( gapAppTaskID != INVALID_TASK_ID ) + { + gapDeviceInitDoneEvent_t* pRsp; + pRsp = (gapDeviceInitDoneEvent_t*)osal_msg_allocate( (uint16)(sizeof ( gapDeviceInitDoneEvent_t )) ); + + if ( pRsp ) + { + pRsp->hdr.event = GAP_MSG_EVENT; + pRsp->hdr.status = status; + pRsp->opcode = GAP_DEVICE_INIT_DONE_EVENT; + VOID osal_memcpy( pRsp->devAddr, gapParams.BD_ADDR, B_ADDR_LEN ); + pRsp->dataPktLen = gapParams.HC_LE_Data_Packet_Lenth; + pRsp->numDataPkts = gapParams.HC_Total_Num_LE_Data_Packets; + VOID osal_msg_send( gapAppTaskID, (uint8*)pRsp ); + } + } +} + +/********************************************************************* + @fn gapSendRandomAddrChangeEvent + + @brief Send the GAP_RANDOM_ADDR_CHANGED_EVENT. + + @param status - Status of initialization + @param pNewAddr - new address + + @return none +*/ +static void gapSendRandomAddrChangeEvent( uint8 status, uint8* pNewAddr ) +{ + if ( gapAppTaskID != INVALID_TASK_ID ) + { + gapRandomAddrEvent_t* pRsp; + pRsp = (gapRandomAddrEvent_t*)osal_msg_allocate( (uint16)(sizeof ( gapRandomAddrEvent_t )) ); + + if ( pRsp ) + { + pRsp->hdr.event = GAP_MSG_EVENT; + pRsp->hdr.status = status; + pRsp->opcode = GAP_RANDOM_ADDR_CHANGED_EVENT; + pRsp->addrType = gapDeviceAddrMode; + VOID osal_memcpy( pRsp->newRandomAddr, pNewAddr, B_ADDR_LEN ); + VOID osal_msg_send( gapAppTaskID, (uint8*)pRsp ); + } + } +} + +/********************************************************************* + @fn gapSendSignUpdateEvent + + @brief Send the GAP_SIGNATURE_UPDATED_EVENT. + + @param taskID - where to send this message + @param addrType - device address type + @param pDevAddr - device address of affected device + @param signCounter - new counter + + @return none +*/ +static void gapSendSignUpdateEvent( uint8 taskID, uint8 addrType, uint8* pDevAddr, uint32 signCounter ) +{ + gapSignUpdateEvent_t* pRsp; + pRsp = (gapSignUpdateEvent_t*)osal_msg_allocate( (uint16)(sizeof ( gapSignUpdateEvent_t )) ); + + if ( pRsp ) + { + pRsp->hdr.event = GAP_MSG_EVENT; + pRsp->hdr.status = SUCCESS; + pRsp->opcode = GAP_SIGNATURE_UPDATED_EVENT; + pRsp->addrType = addrType; + VOID osal_memcpy( pRsp->devAddr, pDevAddr, B_ADDR_LEN ); + pRsp->signCounter = signCounter; + VOID osal_msg_send( taskID, (uint8*)pRsp ); + } +} + +/********************************************************************* + @fn gapSendSlaveSecurityReqEvent + + @brief Send the GAP_SLAVE_REQUESTED_SECURITY_EVENT. + + @param taskID - where to send this message + @param connHandle - connection Handle + @param pDevAddr - device address of affected device + @param authReq - authentication request information + + @return none +*/ +void gapSendSlaveSecurityReqEvent( uint8 taskID, uint16 connHandle, uint8* pDevAddr, uint8 authReq ) +{ + gapSlaveSecurityReqEvent_t* pRsp; + pRsp = (gapSlaveSecurityReqEvent_t*)osal_msg_allocate( (uint16)(sizeof ( gapSlaveSecurityReqEvent_t )) ); + + if ( pRsp ) + { + pRsp->hdr.event = GAP_MSG_EVENT; + pRsp->hdr.status = SUCCESS; + pRsp->opcode = GAP_SLAVE_REQUESTED_SECURITY_EVENT; + pRsp->connectionHandle = connHandle; + VOID osal_memcpy( pRsp->deviceAddr, pDevAddr, B_ADDR_LEN ); + pRsp->authReq = authReq; + VOID osal_msg_send( taskID, (uint8*)pRsp ); + } +} + + +/********************************************************************* +*********************************************************************/ diff --git a/src/lib/ble_host/gap_devmgr.c b/src/lib/ble_host/gap_devmgr.c new file mode 100644 index 0000000..95034ef --- /dev/null +++ b/src/lib/ble_host/gap_devmgr.c @@ -0,0 +1,239 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: gap_devmgr.c + Revised: + Revision: + + Description: This file contains the GAP Device Manager. + + +**************************************************************************************************/ +#include "bcomdef.h" +#include "gap.h" +#include "gap_internal.h" + + + +/******************************************************************************* + INCLUDES +*/ + + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +// Device Discovery Parameters for Central +gapDevDiscReq_t* pGapDiscReq = NULL; + +// Discoverable State Parameters for Peripheral +gapAdvertState_t* pGapAdvertState = NULL; + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +/********************************************************************* + LOCAL FUNCTIONS +*/ + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/********************************************************************* + Resolves a private address against an IRK. + + Public function defined in gap.h. +*/ +bStatus_t GAP_ResolvePrivateAddr( uint8* pIRK, uint8* pAddr ) +{ + // SM will resolve the address + return ( SM_ResolveRandomAddrs( pIRK, pAddr ) ); +} + +/********************************************************************* + PUBLIC INTERNAL GAP FUNCTIONS +*/ + +/********************************************************************* + @fn gapIsAdvertising + + @brief Check if we are currently advertising. + + @param none + + @return TRUE if currently advertising, FALSE if not +*/ +uint8 gapIsAdvertising( void ) +{ + if ( pGapAdvertState ) + { + return ( TRUE ); + } + else + { + return ( FALSE ); + } +} + +/********************************************************************* + @fn gapIsScanning + + @brief Check if we are currently scanning. + + @param none + + @return TRUE if currently scanning, FALSE if not +*/ +uint8 gapIsScanning( void ) +{ + if ( pGapDiscReq ) + { + return ( TRUE ); + } + else + { + return ( FALSE ); + } +} + +/********************************************************************* + @fn gapValidADType + + @brief Is a Advertisement Data Type valid. + + @param adType - Advertisement data type + + @return TRUE is valid, FALSE is not valid +*/ +uint8 gapValidADType( uint8 adType ) +{ + if ( ((adType > 0) && (adType <= GAP_ADTYPE_SERVICE_DATA)) + || (adType == GAP_ADTYPE_MANUFACTURER_SPECIFIC) ) + { + return ( TRUE ); + } + else + { + return ( FALSE ); + } +} + +/********************************************************************* + @fn gapFindADType + + @brief Find Advertisement Data Type field in advertising data + field. + + @param adType - Advertisment Data type + @param pAdLen - pointer to variable, this value is updated + with found token's length + @param dataLen - length of the dataField + @param pDataField - pointer to the data field (advertisement data) + + @return found token pointer or NULL if not found +*/ +uint8* gapFindADType( uint8 adType, uint8* pAdLen, + uint8 dataLen, uint8* pDataField ) +{ + uint8 x = 0; // dataField index + *pAdLen = 0; // Initialize the field + + // Look through the dataField for tokens + while ( x < dataLen ) + { + // Get the token length + uint8 tokenLen = pDataField[x++]; + + // Check valid token lengths + if ( (tokenLen > 0) && ((x + tokenLen) <= dataLen) ) + { + // Get the token type - ADType + uint8 tokenType = pDataField[x++]; + + // Check the token's validity + if ( gapValidADType( tokenType ) == FALSE ) + { + // Advertisement packet is invalid, get out + return ( (uint8*)NULL ); + } + + // Save off the token data length + *pAdLen = (uint8)(tokenLen - 1); + + if ( tokenType == adType ) + { + // Found + return ( &pDataField[x] ); + } + else + { + // Skip the token data + x += (*pAdLen); + } + } + else + { + break; // Force end no more tokens + } + } + + // Not found + return ( (uint8*)NULL ); +} + + +/**************************************************************************** +****************************************************************************/ diff --git a/src/lib/ble_host/gap_linkmgr.c b/src/lib/ble_host/gap_linkmgr.c new file mode 100644 index 0000000..ea7e77a --- /dev/null +++ b/src/lib/ble_host/gap_linkmgr.c @@ -0,0 +1,1265 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: gap_linkmgr.c + Revised: + Revision: + + Description: This file contains the GAP Link Manager and the GAP Link + Database. + +**************************************************************************************************/ + + + +/******************************************************************************* + INCLUDES +*/ + +#include "bcomdef.h" +#include "gap.h" +#include "gap_internal.h" +#include "linkdb.h" +#include "sm.h" +#include "sm_internal.h" +#include "smp.h" +#include "jump_function.h" +#include "att.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +// Authentication States +#define AUTHSTATE_PAIRING 2 + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +// Created when an establish connections requested and freed when the +// connection is made. +gapEstLinkReq_t* pEstLink = NULL; + +// Created when a pairing is requested and freed when the pairing is complete. +gapAuthStateParams_t* pAuthLink[MAX_NUM_LL_CONN] = {NULL}; + +// Callback function pointers for Central +gapCentralConnCBs_t* pfnCentralConnCBs = NULL; + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +// Flag to disconnect all connections when requested. +static uint8 terminateAllTaskID = 0; +static uint8 terminateReason; + +/********************************************************************* + LOCAL FUNCTIONS +*/ + +static void sendTerminateEvent( uint8 status, uint8 taskID, + uint16 connectionHandle, uint8 reason ); +static bStatus_t disconnectNext( uint8 taskID, uint8 reason ); +static void sendAuthEvent( uint8 status, uint16 connectionHandle, + uint8 authState, + smSecurityInfo_t* pDevEncParams ); +static void gapFreeAuthLink( uint16 connectionHandle ); + +/********************************************************************* + API FUNCTIONS +*/ + +/********************************************************************* + Terminate a link connection. + + Public function defined in gap.h. +*/ +bStatus_t GAP_TerminateLinkReq( uint8 taskID, uint16 connectionHandle, uint8 reason ) +{ + bStatus_t stat = bleIncorrectMode; // Return status + + // Are we trying to terminate a Establish Connection Request? + if ( connectionHandle == GAP_CONNHANDLE_INIT ) + { + if ( pfnCentralConnCBs && pfnCentralConnCBs->pfnCancelLinkReq ) + { + stat = pfnCentralConnCBs->pfnCancelLinkReq( taskID, connectionHandle ); + } + } + // Terminate All Connections? + else if ( connectionHandle == GAP_CONNHANDLE_ALL ) + { + // First are we currently trying to establish a connection? + if ( pfnCentralConnCBs && pfnCentralConnCBs->pfnCancelLinkReq ) + { + stat = pfnCentralConnCBs->pfnCancelLinkReq( taskID, connectionHandle ); + } + + if ( stat == SUCCESS ) + { + terminateAllTaskID = taskID; + terminateReason = reason; + } + else + { + stat = disconnectNext( taskID, reason ); + + if ( stat == SUCCESS ) + { + terminateAllTaskID = taskID; + terminateReason = reason; + } + } + } + else + { + // First check for an existing connection + linkDBItem_t* pItem = linkDB_Find( connectionHandle ); + + if ( pItem ) + { + if ( pItem->taskID == taskID ) + { + stat = HCI_DisconnectCmd( connectionHandle, reason ); + } + else + { + // Not the correct taskID + stat = bleInvalidTaskID; + } + } + } + + return ( stat ); +} + +/********************************************************************* + Set up the connection to accept signed data. + + Public function defined in gap.h. +*/ +bStatus_t GAP_Signable( uint16 connectionHandle, uint8 authenticated, smSigningInfo_t* pParams ) +{ + linkDBItem_t* pLinkItem; + + // Check the GAP Role + if ( (gapProfileRole == GAP_PROFILE_OBSERVER) || (gapProfileRole == GAP_PROFILE_BROADCASTER) ) + { + return ( bleIncorrectMode ); + } + + // Check the parameters + if ( pParams == NULL ) + { + return ( INVALIDPARAMETER ); + } + + // Check if the connection is real + pLinkItem = linkDB_Find( connectionHandle ); + + if ( pLinkItem == NULL ) + { + return ( bleNotConnected ); + } + + // Is this signing information authenticated? + if ( authenticated ) + { + // Mark the link as authenticated. + pLinkItem->stateFlags |= LINK_AUTHENTICATED; + } + + // update the link's signing info + VOID osal_memcpy( pLinkItem->sec.srk, pParams->srk, KEYLEN ); + pLinkItem->sec.signCounter = pParams->signCounter; + return ( SUCCESS ); +} + +/********************************************************************* + Start the Authentication process with the requested device. + This function is used to Initiate/Allow pairing. + Called by both master and slave device (Central and Peripheral). + + NOTE: This function is called after the link is established. + + Public function defined in gap.h. +*/ +bStatus_t GAP_Authenticate( gapAuthParams_t* pParams, gapPairingReq_t* pPairReq ) +{ + linkDBItem_t* pLinkItem; + bStatus_t ret; + + // Check the GAP Role, also the pairReq parameter should only be used by a Peripheral. + if ( ((gapProfileRole == GAP_PROFILE_OBSERVER) || (gapProfileRole == GAP_PROFILE_BROADCASTER)) + || ((gapProfileRole == GAP_PROFILE_CENTRAL) && (pPairReq)) ) + { + return ( bleIncorrectMode ); + } + + // Check the parameter + if ( pParams == NULL ) + { + return ( INVALIDPARAMETER ); + } + + // Make sure we aren't already in the pairing mode. + if ( pAuthLink[pParams->connectionHandle] ) + { + return ( bleAlreadyInRequestedMode ); + } + + // Check for a valid connection handle + pLinkItem = linkDB_Find( pParams->connectionHandle ); + + if ( pLinkItem == NULL ) + { + return ( bleNotConnected ); + } + + // Allocate the pairing state variables + pAuthLink[pParams->connectionHandle] = (gapAuthStateParams_t*)osal_mem_alloc( (uint16)(sizeof ( gapAuthStateParams_t )) ); + + if ( pAuthLink[pParams->connectionHandle] == NULL ) + { + return ( bleMemAllocError ); + } + + VOID osal_memset( pAuthLink[pParams->connectionHandle], 0, (int)(sizeof( gapAuthStateParams_t )) ); + // Copy existing items + pAuthLink[pParams->connectionHandle]->connectionHandle = pParams->connectionHandle; + VOID osal_memcpy( &(pAuthLink[pParams->connectionHandle]->secReqs), &(pParams->secReqs), sizeof ( smLinkSecurityReq_t ) ); + // Start authentication + pAuthLink[pParams->connectionHandle]->state = AUTHSTATE_PAIRING; + // Let's try pairing +// ret = SM_StartPairing( ((gapProfileRole & GAP_PROFILE_CENTRAL) ? TRUE : FALSE), + ret = SM_StartPairing( ((pLinkItem->role == LL_LINK_CONNECT_COMPLETE_MASTER ) ? TRUE : FALSE), + gapTaskID, + pParams->connectionHandle, + &(pAuthLink[pParams->connectionHandle]->secReqs) ); + + if ( pPairReq ) + { + // We already received the Pairing Request, so force the processing of it now. + smProcessPairingReq( pLinkItem, pPairReq ); + } + + // If something went wrong, clear the auth memory + if ( ret != SUCCESS ) + { + gapFreeAuthLink(pParams->connectionHandle); + } + + return ( ret ); +} + +/********************************************************************* + Terminate an authentication/pairing process. + Called to send a pairing failure and stop the pairing process. + + Public function defined in gap.h. +*/ +bStatus_t GAP_TerminateAuth( uint16 connectionHandle, uint8 reason ) +{ + // Check for valid connection handle + if ( linkDB_Find( connectionHandle ) == NULL ) + { + return ( bleNotConnected ); + } + + // Simulate a pairing failed message + smpPairingFailed_t failedMsg; + failedMsg.reason = reason; + return ( smSendFailAndEnd( connectionHandle, &failedMsg ) ); +} + +/********************************************************************* + Update the passkey. This function is called by the + application/profile in response to receiving the GAP_PASSKEY_NEEDED_EVENT + message. + + Public function defined in gap.h. +*/ +bStatus_t GAP_PasskeyUpdate( uint8* pPasskey, uint16 connectionHandle ) +{ + uint8 x; // string index - starting from the end + uint32 y; // 10's place hold: 1, 10, 100, 1000 ... + uint32 key = 0; // Numeric Key Value + + // Check the parameter + if ( pPasskey == NULL ) + { + return ( INVALIDPARAMETER ); + } + + // Convert the string to key value + for ( y = 1, x = PASSKEY_LEN; x > 0; x-- ) + { + // Get the string character + uint8 c = pPasskey[x-1]; + + // Numeric check '0' - '9' + if ( c <= '9' && c >= '0' ) + { + // Convert character to decimal and multiply it + // times the 10's place holder, then add it to + // the key. + key += (c - '0') * y; + } + else + { + return ( INVALIDPARAMETER ); + } + + // Move to the next 10's place: + // 1, 10, 100, 1000 ... + y = y * 10; + } + + return ( GAP_PasscodeUpdate( key, connectionHandle ) ); +} + +/********************************************************************* + Update the passkey. This function is called by the + application/profile in response to receiving the GAP_PASSKEY_NEEDED_EVENT + message. + + Public function defined in gap.h. +*/ +bStatus_t GAP_PasscodeUpdate( uint32 passcode, uint16 connectionHandle ) +{ + uint8 tk[KEYLEN]; // typical key format + + // Check for valid connection handle + if ( linkDB_Find( connectionHandle ) == NULL ) + { + return ( bleIncorrectMode ); + } + + // Make sure the passcode is within range + if ( passcode > GAP_PASSCODE_MAX ) + { + return ( INVALIDPARAMETER ); + } + + // Convert passcode to key + VOID osal_memset( tk, 0, KEYLEN ); + tk[0] = BREAK_UINT32( passcode, 0 ); + tk[1] = BREAK_UINT32( passcode, 1 ); + tk[2] = BREAK_UINT32( passcode, 2 ); + tk[3] = BREAK_UINT32( passcode, 3 ); + // Pass key to SM + return ( SM_PasskeyUpdate( tk, connectionHandle ) ); +} + +/********************************************************************* + Set up the connection's bound paramaters. + + NOTE: This function is called after the link is established. + + Public function defined in gap.h. +*/ +bStatus_t GAP_Bond( uint16 connectionHandle, uint8 authenticated, + smSecurityInfo_t* pParams, uint8 startEncryption ) +{ + linkDBItem_t* pLinkItem; // Pointer to connection information + bStatus_t ret; // return value + + // Check GAP Role + if ( (gapProfileRole == GAP_PROFILE_OBSERVER) || (gapProfileRole == GAP_PROFILE_BROADCASTER) ) + { + return ( bleIncorrectMode ); + } + + // Check security parameter + if ( pParams == NULL ) + { + return ( INVALIDPARAMETER ); + } + + // Check for valid connection + pLinkItem = linkDB_Find( connectionHandle ); + + if ( pLinkItem == NULL ) + { + return ( bleNotConnected ); + } + + // Copy over Bound information + if ( pLinkItem->pEncParams ) + { + // If bound information already exists, free it + osal_mem_free( pLinkItem->pEncParams ); + } + + // Duplicate the params into the link information + pLinkItem->pEncParams = (encParams_t*)osal_memdup( pParams, sizeof( encParams_t ) ); + + if ( pLinkItem->pEncParams == NULL ) + { + // Report memory error + return ( bleMemAllocError ); + } + + // Central device? + if ( ( gapProfileRole & GAP_PROFILE_CENTRAL ) && startEncryption ) + { + // Start the key loading + ret = smStartEncryption( connectionHandle, pLinkItem->pEncParams->ltk, + pLinkItem->pEncParams->div, pLinkItem->pEncParams->rand, + pLinkItem->pEncParams->keySize ); + } + else + { + ret = SUCCESS; + } + + // Mark the link as bound + pLinkItem->stateFlags |= LINK_BOUND; + + // Is this bond authenticated? + if ( authenticated ) + { + // Mark the link as authenticated. + pLinkItem->stateFlags |= LINK_AUTHENTICATED; + } + + return ( ret ); +} + +/********************************************************************* + PUBLIC INTERNAL GAP FUNCTIONS +*/ + +/********************************************************************* + @fn gapProcessConnectionCompleteEvt + + @brief Process the LL HCI Connection Complete Event for the + call to HCI_BLECreateLLConnCmd(). + + @param pkt - HCI packet + + @return none +*/ +/* + bugfix for multi-role llConnState_t.llTbd1 for link role +*/ +#include "ll.h" +#include "ll_def.h" +void gapProcessConnectionCompleteEvt( hciEvt_BLEConnComplete_t* pPkt ) +{ + uint8 appTaskID; + /*bugfix for multi-role */ + llConnState_t* connPtr; + connPtr = &conn_param[ pPkt->connectionHandle ]; + connPtr->llTbd1 = pPkt->role; + /*bugfix end */ + + // Check parameter + if ( pPkt == NULL ) + { + return; + } + + // Determine who gets the event + if ( pEstLink ) + { + appTaskID = pEstLink->taskID; // Task that requested the connection + } + else + { + appTaskID = gapAppTaskID; // Task controlling the GAP + } + + // The LL stopped advertising, clean up the advertising state. + if ( pfnPeripheralCBs && pfnPeripheralCBs->pfnProcessAdvertisingEvt ) + { + pfnPeripheralCBs->pfnProcessAdvertisingEvt( FALSE ); + } + + // Convert from LL address type to Host address type + pPkt->peerAddrType = gapDetermineAddrType( pPkt->peerAddrType, pPkt->peerAddr ); + // Send the connection notification to the app + sendEstLinkEvent( pPkt->status, appTaskID, pPkt->peerAddrType, + pPkt->peerAddr, pPkt->connectionHandle, + pPkt->connInterval, pPkt->connLatency, + pPkt->connTimeout, pPkt->clockAccuracy ); + + if ( pPkt->status == SUCCESS ) + { + // Make link database entry + pPkt->status = linkDB_Add( appTaskID, pPkt->connectionHandle, LINK_CONNECTED,pPkt->role, + pPkt->peerAddrType, pPkt->peerAddr, pPkt->connInterval ); + } + + if ( pEstLink ) + { + // Get rid of the establish link information + gapFreeEstLink(); + + // Are we in the middle of a disconnect all + if ( terminateAllTaskID ) + { + // disconnect the next one + if ( disconnectNext( terminateAllTaskID, terminateReason ) != SUCCESS ) + { + // No more, send terminate message + sendTerminateEvent( pPkt->status, terminateAllTaskID, + pPkt->connectionHandle, pPkt->status ); + terminateAllTaskID = 0; + } + } + } + + ATT_UpdateMtuSize(pPkt->connectionHandle, ATT_MTU_SIZE_MIN); + L2CAP_ReassemblePkt_Reset(pPkt->connectionHandle); + L2CAP_SegmentPkt_Reset(pPkt->connectionHandle); +} + +/********************************************************************* + @fn gapProcessConnUpdateCompleteEvt + + @brief Process the LL HCI Connection Update Complete Event for the + call to HCI_BLEUpdateLLConnCmd(). + + @param pkt - HCI packet + + @return none +*/ +void gapProcessConnUpdateCompleteEvt( hciEvt_BLEConnUpdateComplete_t* pPkt ) +{ + // Send the link update notification to the app + gapSendLinkUpdateEvent( pPkt->status, pPkt->connectionHandle, + pPkt->connInterval, pPkt->connLatency, + pPkt->connTimeout ); +} + +/********************************************************************* + @fn gapProcessDisconnectCompleteEvt + + @brief Process the LL Disconnection Complete Event for the + call to HCI_DisconnectCmd(). + + @param pkt - HCI packet + + @return none +*/ +void gapProcessDisconnectCompleteEvt( hciEvt_DisconnComplete_t* pPkt ) +{ + uint8 taskID = 0; + linkDBItem_t* pItem = linkDB_Find( pPkt->connHandle ); // Find connection information + + if ( pItem ) + { + // if found, delete the link database entry + taskID = pItem->taskID; + VOID linkDB_Remove( pPkt->connHandle ); + } + + // Are we deleting all connections for a task ID? + if ( (terminateAllTaskID) && (taskID == terminateAllTaskID) ) + { + // Disconnect the next connection that matches the task ID + if ( disconnectNext( terminateAllTaskID, terminateReason ) == SUCCESS ) + { + // Don't send message now, we have more to terminate + taskID = 0; + } + else + { + // No more to disconnect + terminateAllTaskID = 0; + } + } + + if ( taskID ) + { + // Send the event to the app/profile + sendTerminateEvent( pPkt->status, taskID, pPkt->connHandle, pPkt->reason ); + } + + // If we are in the middle of a pairing? + if ( pAuthLink[pPkt->connHandle] ) + { + // Just remove the item + gapFreeAuthLink(pPkt->connHandle); + } + + ATT_UpdateMtuSize(pPkt->connHandle, ATT_MTU_SIZE_MIN); + L2CAP_ReassemblePkt_Reset(pPkt->connHandle); + L2CAP_SegmentPkt_Reset(pPkt->connHandle); +} + +/********************************************************************* + @fn sendEstLinkEvent + + @brief Build and send the GAP_LINK_ESTABLISHED_EVENT to the app. + + @param status - connection status + @param taskID - where to send message + @param devAddrType - connected device's device address type + @param pDevAddr - connected device's device address + @param connectionHandle - controller link connection handle. + @param connInterval - connection interval + @param connTimeout - connection timeout + @param clockAccuracy - LL clock accuracy + + @return none +*/ +void sendEstLinkEvent( uint8 status, uint8 taskID, uint8 devAddrType, + uint8* pDevAddr, uint16 connectionHandle, + uint16 connInterval, uint16 connLatency, + uint16 connTimeout, uint16 clockAccuracy ) +{ + gapEstLinkReqEvent_t* pRsp; + pRsp = (gapEstLinkReqEvent_t*)osal_msg_allocate( (uint16)(sizeof ( gapEstLinkReqEvent_t )) ); + + if ( pRsp ) + { + // Build the message + pRsp->hdr.event = GAP_MSG_EVENT; + pRsp->hdr.status = status; + pRsp->opcode = GAP_LINK_ESTABLISHED_EVENT; + pRsp->devAddrType = devAddrType; + + // If the address parameter is valid + if ( pDevAddr ) + { + VOID osal_memcpy( pRsp->devAddr, pDevAddr, B_ADDR_LEN ); + } + else + { + // Not valid, zero field + VOID osal_memset( pRsp->devAddr, 0, B_ADDR_LEN ); + } + + pRsp->connectionHandle = connectionHandle; + pRsp->connInterval = connInterval; + pRsp->connLatency = connLatency; + pRsp->connTimeout = connTimeout; + pRsp->clockAccuracy = clockAccuracy; + VOID osal_msg_send( taskID, (uint8*)pRsp ); + } +} + +/********************************************************************* + @fn sendTerminateEvent + + @brief Build and send the GAP_LINK_TERMINATED_EVENT to the app. + + @param status - terminate status + @param taskID - where to send message + @param connectionHandle - controller link connection handle. + @param reason - termination reason - (LL) + + @return none +*/ +static void sendTerminateEvent( uint8 status, uint8 taskID, + uint16 connectionHandle, uint8 reason ) +{ + // Allocate, build and send Terminate event + gapTerminateLinkEvent_t* pRsp; + pRsp = (gapTerminateLinkEvent_t*)osal_msg_allocate( (uint16)(sizeof ( gapTerminateLinkEvent_t )) ); + + if ( pRsp ) + { + pRsp->hdr.event = GAP_MSG_EVENT; + pRsp->hdr.status = status; + pRsp->opcode = GAP_LINK_TERMINATED_EVENT; + pRsp->connectionHandle = connectionHandle; + pRsp->reason = reason; + VOID osal_msg_send( taskID, (uint8*)pRsp ); + } +} + +/********************************************************************* + @fn gapSendLinkUpdateEvent + + @brief Build and send the GAP_LINK_PARAM_UPDATE_EVENT to the app. + + @param status - update status + @param connectionHandle - controller link connection handle + @param connInterval - connection interval + @param connLatency - conenction latency + @param connTimeout - connection timeout + + @return none +*/ +void gapSendLinkUpdateEvent( uint8 status, uint16 connectionHandle, + uint16 connInterval, uint16 connLatency, + uint16 connTimeout ) +{ + gapLinkUpdateEvent_t* rsp; + // Allocate, build and send Link Update event + rsp = (gapLinkUpdateEvent_t*)osal_msg_allocate( (uint16)(sizeof ( gapLinkUpdateEvent_t )) ); + + if ( rsp ) + { + uint8 appTaskID; + // Determine who gets the event + linkDBItem_t* pItem = linkDB_Find( connectionHandle ); + + if ( pItem ) + { + appTaskID = pItem->taskID; + } + else + { + appTaskID = gapAppTaskID; + } + + // Build the message + rsp->hdr.event = GAP_MSG_EVENT; + rsp->hdr.status = status; + rsp->opcode = GAP_LINK_PARAM_UPDATE_EVENT; + rsp->connectionHandle = connectionHandle; + rsp->connInterval = connInterval; + rsp->connLatency = connLatency; + rsp->connTimeout = connTimeout; + // Send the connection update to the app + VOID osal_msg_send( appTaskID, (uint8*)rsp ); + } +} + +/********************************************************************* + @fn disconnectNext + + @brief if we are in the middle of a disconnect all command + this function will send a disconnect for the next + connection for an app. + + @param taskID - task ID of the app/profile that created the task + @param reason - disconnect reason + + @return SUCCESS if initiated + bleIncorrectMode if connection not found +*/ +static bStatus_t disconnectNext( uint8 taskID, uint8 reason ) +{ + linkDBItem_t* pItem = linkDB_FindFirst( taskID ); + + if ( pItem ) + { + return ( HCI_DisconnectCmd( pItem->connectionHandle, reason ) ); + } + else + { + return ( bleIncorrectMode ); + } +} + +/********************************************************************* + @fn sendAuthEvent + + @brief Build and send the GAP_AUTHENTICATION_COMPLETE_EVENT to the app. + + @param status - authentication status + @param connectionHandle - controller link connection handle. + @param authState - TRUE if the pairing was authenticated, FALSE otherwise + @param devEncParams - pointer to the connected device's encryption parameters + + @return none +*/ +static void sendAuthEvent( uint8 status, uint16 connectionHandle, + uint8 authState, + smSecurityInfo_t* pDevEncParams ) +{ + linkDBItem_t* pLink; // pointer to connection information + // Find the connection information + pLink = linkDB_Find( connectionHandle ); + + // Was the connection information found and we are currently + // performing a pairing process? + if ( (pLink != NULL) && (pAuthLink[connectionHandle] != NULL) ) + { + gapAuthCompleteEvent_t* pRsp; // pointer to Event message + uint16 len; // Length of Event message + // Calculate the length of the event message + len = sizeof ( gapAuthCompleteEvent_t ); + + if ( pAuthLink[connectionHandle]->pSecurityInfo ) + { + len += sizeof ( smSecurityInfo_t ); + } + + if ( pAuthLink[connectionHandle]->pSigningInfo ) + { + len += sizeof ( smSigningInfo_t ); + } + + if ( pDevEncParams ) + { + len += sizeof ( smSecurityInfo_t ); + } + + if ( pAuthLink[connectionHandle]->pIdentityInfo ) + { + len += sizeof ( smIdentityInfo_t ); + } + + // Allocate the message with the calculated length + pRsp = (gapAuthCompleteEvent_t*)osal_msg_allocate( len ); + + if ( pRsp ) + { + uint16 taskID; // Where to send the message + uint8* pBuf; + // Clear the message + VOID osal_memset( pRsp, 0, sizeof ( gapAuthCompleteEvent_t ) ); + // Assume that GAP's App/Profile controller ID + taskID = GAP_GetParamValue( TGAP_AUTH_TASK_ID ); + + if ( taskID == 0 ) + { + // default to the connection's task ID + taskID = pLink->taskID; + } + + // Build and send + pRsp->hdr.event = GAP_MSG_EVENT; + pRsp->hdr.status = status; + pRsp->opcode = GAP_AUTHENTICATION_COMPLETE_EVENT; + pRsp->connectionHandle = connectionHandle; + pRsp->authState = authState; + pBuf = (uint8*)(pRsp + 1); + + // If it exists, copy security information generated by this device + if ( pAuthLink[connectionHandle]->pSecurityInfo ) + { + pRsp->pSecurityInfo = (smSecurityInfo_t*)pBuf; + pBuf = (uint8*)(pRsp->pSecurityInfo + 1); + VOID osal_memcpy( pRsp->pSecurityInfo, pAuthLink[connectionHandle]->pSecurityInfo, sizeof ( smSecurityInfo_t ) ); + } + + // If it exists, copy the connected device's signing information + if ( pAuthLink[connectionHandle]->pSigningInfo ) + { + pRsp->pSigningInfo = (smSigningInfo_t*)pBuf; + pBuf = (uint8*)(pRsp->pSigningInfo + 1); + VOID osal_memcpy( pRsp->pSigningInfo, pAuthLink[connectionHandle]->pSigningInfo, sizeof ( smSigningInfo_t ) ); + } + + // if it exists, copy security information for the connected device + if ( pDevEncParams ) + { + pRsp->pDevSecInfo = (smSecurityInfo_t*)pBuf; + pBuf = (uint8*)(pRsp->pDevSecInfo + 1); + VOID osal_memcpy( pRsp->pDevSecInfo, pDevEncParams, sizeof ( smSecurityInfo_t ) ); + } + + // If it exists, copy the connected device's identification information + if ( pAuthLink[connectionHandle]->pIdentityInfo ) + { + pRsp->pIdentityInfo = (smIdentityInfo_t*)pBuf; + VOID osal_memcpy( pRsp->pIdentityInfo, pAuthLink[connectionHandle]->pIdentityInfo, sizeof ( smIdentityInfo_t ) ); + } + + VOID osal_msg_send( taskID, (uint8*)pRsp ); + // Remove the pAuthLink[connectionHandle] + gapFreeAuthLink( connectionHandle); + } + } +} + +/********************************************************************* + @fn gapFreeAuthLink + + @brief Free the allocated memory used in pAuthLink[connectionHandle]. + + @param none + + @return none +*/ +static void gapFreeAuthLink( uint16 connectionHandle ) +{ + if ( pAuthLink[connectionHandle] ) + { + if ( pAuthLink[connectionHandle]->pSecurityInfo ) + { + osal_mem_free( pAuthLink[connectionHandle]->pSecurityInfo ); + } + + if ( pAuthLink[connectionHandle]->pIdentityInfo ) + { + osal_mem_free( pAuthLink[connectionHandle]->pIdentityInfo ); + } + + if ( pAuthLink[connectionHandle]->pSigningInfo ) + { + osal_mem_free( pAuthLink[connectionHandle]->pSigningInfo ); + } + + osal_mem_free( pAuthLink[connectionHandle] ); + pAuthLink[connectionHandle] = NULL; + } +} + +/********************************************************************* + @fn gapFreeEstLink + + @brief Free the establish link memory. + + @param status - authentication status + @param connectionHandle - controller link connection handle. + + @return none +*/ +void gapFreeEstLink( void ) +{ + if ( pEstLink ) + { + // Clear the connection information + osal_mem_free( pEstLink ); + pEstLink = NULL; + } +} + +/********************************************************************* + @fn gapSendBondCompleteEvent + + @brief Build and send the GAP_BOND_COMPLETE_EVENT to the app. + + @param status - authentication status + @param connectionHandle - controller link connection handle. + + @return none +*/ +void gapSendBondCompleteEvent( uint8 status, uint16 connectionHandle ) +{ + linkDBItem_t* pLink; + pLink = linkDB_Find( connectionHandle ); + + if ( pLink ) + { + uint16 taskID; + gapBondCompleteEvent_t* pRsp; + taskID = GAP_GetParamValue( TGAP_AUTH_TASK_ID ); + + if ( taskID == 0 ) + { + taskID = pLink->taskID; + } + + pRsp = (gapBondCompleteEvent_t*)osal_msg_allocate( sizeof ( gapBondCompleteEvent_t ) ); + + if ( pRsp ) + { + VOID osal_memset( (uint8*)pRsp, 0, sizeof ( gapBondCompleteEvent_t ) ); + pRsp->hdr.event = GAP_MSG_EVENT; + pRsp->hdr.status = status; + pRsp->opcode = GAP_BOND_COMPLETE_EVENT; + pRsp->connectionHandle = connectionHandle; + VOID osal_msg_send( taskID, (uint8*)pRsp ); + } + } +} + +/********************************************************************* + @fn gapSendPairingReqEvent + + @brief Build and send the GAP_PAIRING_REQ_EVENT to the app. + + @param status - authentication status + @param connectionHandle - controller link connection handle. + + @return none +*/ +void gapSendPairingReqEvent( uint8 status, uint16 connectionHandle, + uint8 ioCap, + uint8 oobDataFlag, + uint8 authReq, + uint8 maxEncKeySize, + keyDist_t keyDist ) +{ + linkDBItem_t* pLink; + pLink = linkDB_Find( connectionHandle ); + + if ( pLink ) + { + gapPairingReqEvent_t* pRsp; + pRsp = (gapPairingReqEvent_t*)osal_msg_allocate( sizeof ( gapPairingReqEvent_t ) ); + + if ( pRsp ) + { + uint16 taskID; + VOID osal_memset( (uint8*)pRsp, 0, sizeof ( gapPairingReqEvent_t ) ); + taskID = GAP_GetParamValue( TGAP_AUTH_TASK_ID ); + + if ( taskID == 0 ) + { + taskID = pLink->taskID; + } + + pRsp->hdr.event = GAP_MSG_EVENT; + pRsp->hdr.status = status; + pRsp->opcode = GAP_PAIRING_REQ_EVENT; + pRsp->connectionHandle = connectionHandle; + pRsp->pairReq.ioCap = ioCap; + pRsp->pairReq.oobDataFlag = oobDataFlag; + pRsp->pairReq.authReq = authReq; + pRsp->pairReq.maxEncKeySize = maxEncKeySize; + pRsp->pairReq.keyDist = keyDist; + VOID osal_msg_send( taskID, (uint8*)pRsp ); + } + } +} + +/********************************************************************* + @fn gapPasskeyNeededCB + + @brief Send GAP_PASSKEY_NEEDED_EVENT to app + + @param connectionHandle - connection needing the passkey + @param type - SM_PASSKEY_TYPE_INPUT and/or SM_PASSKEY_TYPE_DISPLAY + + @return none +*/ +void gapPasskeyNeededCB( uint16 connectionHandle, uint8 type ) +{ + linkDBItem_t* pLinkItem; // Connection information + // Find the connection information + pLinkItem = linkDB_Find( connectionHandle ); + + if ( pLinkItem ) + { + gapPasskeyNeededEvent_t* pRsp; // Pointer to event message + pRsp = (gapPasskeyNeededEvent_t*)osal_msg_allocate( (uint16)(sizeof ( gapPasskeyNeededEvent_t )) ); + + if ( pRsp ) + { + // Figure out where to send the event + uint16 taskID = GAP_GetParamValue( TGAP_AUTH_TASK_ID ); + + if ( taskID == 0 ) + { + // default to the connection's task ID + taskID = pLinkItem->taskID; + } + + // Build and send + pRsp->hdr.event = GAP_MSG_EVENT; + pRsp->hdr.status = SUCCESS; + pRsp->opcode = GAP_PASSKEY_NEEDED_EVENT; + VOID osal_memcpy( pRsp->deviceAddr, pLinkItem->addr, B_ADDR_LEN ); + pRsp->connectionHandle = connectionHandle; + + // Set the input field + if ( type & SM_PASSKEY_TYPE_INPUT ) + { + pRsp->uiInputs = TRUE; + } + else + { + pRsp->uiInputs = FALSE; + } + + // Set the output field + if ( type & SM_PASSKEY_TYPE_DISPLAY ) + { + pRsp->uiOutputs = TRUE; + } + else + { + pRsp->uiOutputs = FALSE; + } + + VOID osal_msg_send( taskID, (uint8*)pRsp ); + } + } +} + +/********************************************************************* + @fn gapPairingCompleteCB + + @brief Callback function from SM to inform that the Pairing Process + is complete + + @param connectionHandle - connection needing the passkey + @param type - SM_PASSKEY_TYPE_INPUT and/or SM_PASSKEY_TYPE_DISPLAY + + @return none +*/ +void gapPairingCompleteCB( uint8 status, uint8 initiatorRole, + uint16 connectionHandle, + uint8 authState, + smSecurityInfo_t* pEncParams, + smSecurityInfo_t* pDevEncParams, + smIdentityInfo_t* pIdInfo, + smSigningInfo_t* pSigningInfo ) +{ + linkDBItem_t* pLinkItem; // pointer to the connection information + // Find the connection information + pLinkItem = linkDB_Find( connectionHandle ); + + if ( pLinkItem ) + { + // Update the link if encrypted + if ( status == SUCCESS ) + { + // Update the encrypted state flag + pLinkItem->stateFlags |= LINK_ENCRYPTED; + + // Was the pairing authenticated? + if ( authState & SM_AUTH_STATE_AUTHENTICATED ) + { + pLinkItem->stateFlags |= LINK_AUTHENTICATED; + } + else + { + pLinkItem->stateFlags &= ~LINK_AUTHENTICATED; + } + + // Were there any keys exchanged? + if ( pEncParams || pDevEncParams || pIdInfo || pSigningInfo ) + { + pLinkItem->stateFlags |= LINK_BOUND; + } + else + { + pLinkItem->stateFlags &= ~LINK_BOUND; + } + + if ( pSigningInfo ) + { + // Copy the signing information + pLinkItem->sec.signCounter = pSigningInfo->signCounter; + VOID osal_memcpy( pLinkItem->sec.srk, pSigningInfo->srk, KEYLEN ); + } + + // Copy off the LTK if slave/responder and LTK exists + if ( (pEncParams) && (initiatorRole == FALSE) ) + { + if ( pLinkItem->pEncParams ) + { + osal_mem_free( pLinkItem->pEncParams ); + } + + pLinkItem->pEncParams = (encParams_t*)osal_memdup( pEncParams, sizeof ( encParams_t ) ); + } + else if ( (pDevEncParams) && (initiatorRole == TRUE) ) + { + if ( pLinkItem->pEncParams ) + { + osal_mem_free( pLinkItem->pEncParams ); + } + + pLinkItem->pEncParams = (encParams_t*)osal_memdup( pDevEncParams, sizeof ( encParams_t ) ); + } + } + } + + if ( pAuthLink[connectionHandle] ) + { + // Copy the new Auth data + if ( pEncParams ) + { + if ( pAuthLink[connectionHandle]->pSecurityInfo == NULL ) + { + pAuthLink[connectionHandle]->pSecurityInfo = (smSecurityInfo_t*)osal_mem_alloc( (uint16)(sizeof ( smSecurityInfo_t )) ); + } + + if ( pAuthLink[connectionHandle]->pSecurityInfo ) + { + VOID osal_memcpy( pAuthLink[connectionHandle]->pSecurityInfo, pEncParams, sizeof( smSecurityInfo_t ) ); + } + } + + // Copy the Identity information + if ( pIdInfo ) + { + if (pAuthLink[connectionHandle]->pIdentityInfo == NULL ) + { + pAuthLink[connectionHandle]->pIdentityInfo = (smIdentityInfo_t*)osal_mem_alloc( (uint16)(sizeof ( smIdentityInfo_t )) ); + } + + if ( pAuthLink[connectionHandle]->pIdentityInfo ) + { + VOID osal_memcpy( pAuthLink[connectionHandle]->pIdentityInfo, pIdInfo, sizeof( smIdentityInfo_t ) ); + } + } + + // Copy the signing information + if ( pSigningInfo ) + { + if ( pAuthLink[connectionHandle]->pSigningInfo == NULL ) + { + pAuthLink[connectionHandle]->pSigningInfo = (smSigningInfo_t*)osal_mem_alloc( (uint16)(sizeof ( smSigningInfo_t )) ); + } + + if ( pAuthLink[connectionHandle]->pSigningInfo ) + { + VOID osal_memcpy( pAuthLink[connectionHandle]->pSigningInfo, pSigningInfo, sizeof( smSigningInfo_t ) ); + } + } + + // Send the auth Complete Event message to app + sendAuthEvent( status, connectionHandle, authState, pDevEncParams ); + } +} + +/********************************************************************* + @fn gapRegisterCentralConn + + @brief Register Central's connection-related processing function + with GAP task. + + @param pfnCBs - pointer to Central's connection-related processing function + + @return none +*/ +void gapRegisterCentralConn( gapCentralConnCBs_t* pfnCBs ) +{ + pfnCentralConnCBs = pfnCBs; +} + + + +/**************************************************************************** +****************************************************************************/ diff --git a/src/lib/ble_host/gap_peridevmgr.c b/src/lib/ble_host/gap_peridevmgr.c new file mode 100644 index 0000000..538e98d --- /dev/null +++ b/src/lib/ble_host/gap_peridevmgr.c @@ -0,0 +1,1263 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: gap_peridevmgr.c + Revised: + Revision: + + Description: This file contains the GAP Peripheral Device Manager. + + +**************************************************************************************************/ + + + +/******************************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "hci_tl.h" +#include "gap.h" +#include "gap_internal.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +#define GAP_LIMITED_ADVERTISING_RESOLUTION 0xEA60 // Timer resolution is 1 minute + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +// App Task ID for Updating Advertising Data +static uint8 gapAdvAppTaskID = INVALID_TASK_ID; + +// GAP advertisement data types - tokens +static gapAdvToken_t* pGapAdvTokens = NULL; + +// Buffer to hold advertising data +static gapAdvertisingData_t* pGapAdData = NULL; + +// Buffer to hold extra advertising data (SCAN_RSP) +static gapAdvertisingData_t* pGapScanRspData = NULL; + +// Limited advertising timeout (in seconds) +static uint16 gapLimitedAdvertisingTimeout = 0; + +/********************************************************************* + LOCAL FUNCTIONS +*/ + +static uint8 gapPeriProcessHCICmdCompleteEvt( hciEvt_CmdComplete_t* pMsg ); +static void gapProcessAdvertisingEvt( uint8 timeout ); + +static void gapProcessAdvertisingTimeout( void ); +static void gapConnectedCleanUpAdvertising( void ); +static void gapSendMakeDiscEvent( bStatus_t status, uint16 interval ); +static void gapFreeAdvertState( void ); +static bStatus_t gapAllocAdvRecs( void ); +static void gapSendAdDataUpdateEvent( uint8 adType, uint8 status ); +static void gapSendEndDiscoverableEvent( uint8 status ); +static uint8 isLimitedDiscoverableMode( void ); + +/********************************************************************* + PERIPHERAL CALLBACKS +*/ + +// GAP Peripheral Callbacks +static gapPeripheralCBs_t gapPeripheralCBs = +{ + gapPeriProcessHCICmdCompleteEvt, // Process HCI Command Complete Event Callback + gapProcessAdvertisingEvt, // Process Advertising Event Callback + gapSetAdvParams // Set Advertisement Parameters Callback +}; + +/********************************************************************* + PUBLIC FUNCTIONS +*/ + +/********************************************************************* + Setup or change advertising. Also starts advertising. + + Public function defined in gap.h. +*/ +bStatus_t GAP_MakeDiscoverable( uint8 taskID, gapAdvertisingParams_t* pParams ) +{ + bStatus_t stat; // Return status + + // Are we already advertising? + if ( pGapAdvertState ) + { + return ( bleAlreadyInRequestedMode ); + } + + // Is the profile role set properly to do this function? + if ( (gapProfileRole & (GAP_PROFILE_BROADCASTER | GAP_PROFILE_PERIPHERAL)) == 0 ) + { + return ( bleIncorrectMode ); + } + + // Do we have advertising data? + if ( (pGapAdData == NULL) || (pGapAdData->dataLen == 0) ) + { + return ( bleNotReady ); + } + + // Is profile role Broadcaster only and trying to send something other than + // a non-connectable advertisement or scannable event? Also, make sure that + // the advertisement type is correct while we are in a connection. + if ( ((gapProfileRole & GAP_PROFILE_BROADCASTER) || (GAP_NumActiveConnections() > 0)) + && (pParams->eventType != GAP_ADTYPE_ADV_NONCONN_IND) + && (pParams->eventType != GAP_ADTYPE_ADV_SCAN_IND) + && (pParams->eventType != GAP_ADTYPE_ADV_IND)) + { + return ( bleIncorrectMode ); + } + + // Setup the variables needed + pGapAdvertState = (gapAdvertState_t*)osal_mem_alloc( (uint16)(sizeof ( gapAdvertState_t )) ); + + if ( pGapAdvertState ) + { + // Save parameters + pGapAdvertState->taskID = taskID; + pGapAdvertState->state = GAP_ADSTATE_SET_PARAMS; + VOID osal_memcpy( &(pGapAdvertState->params), + pParams, (unsigned int)(sizeof( gapAdvertisingParams_t )) ); + stat = gapSetAdvParams(); + + if ( stat != SUCCESS ) + { + // Failure, free the advertisement state structure + gapFreeAdvertState(); + } + else + { + if ( gapDeviceAddrMode == ADDRTYPE_PRIVATE_RESOLVE ) + { + // Setup the timer to change the Private Resolvable Address + gapPrivateAddrChangeTimeout = GAP_GetParamValue( TGAP_PRIVATE_ADDR_INT ); + + // Start a timer + if ( gapPrivateAddrChangeTimeout ) + { + VOID osal_start_reload_timer( gapTaskID, GAP_CHANGE_RESOLVABLE_PRIVATE_ADDR_EVT, + (uint32)GAP_PRIVATE_ADDR_CHANGE_RESOLUTION ); + } + } + } + } + else + { + // Memory Error + stat = bleMemAllocError; + } + + return ( stat ); +} + +/********************************************************************* + Setup or change advertising and scan response data. + + NOTE: if the return status from this function is SUCCESS, + the task isn't complete until the GAP_ADV_DATA_UPDATE_DONE_EVENT + is sent to the calling application task. + + Public function defined in gap.h. +*/ +bStatus_t GAP_UpdateAdvertisingData( uint8 taskID, uint8 adType, + uint8 dataLen, uint8* pAdvertData ) +{ + gapAdvertisingData_t* pDestAdData = NULL; + bStatus_t stat; + + if ( (gapProfileRole & (GAP_PROFILE_PERIPHERAL | GAP_PROFILE_BROADCASTER)) == 0 ) + { + // This is only allowed for Peripheral or Broadcaster profile roles + return ( bleIncorrectMode ); + } + + if ( ((gapProfileRole & (GAP_PROFILE_PERIPHERAL | GAP_PROFILE_BROADCASTER)) == 0) && + (adType == FALSE) ) + { + // Scan Response data is only allowed for Peripheral or Broadcaster profile roles + return ( bleIncorrectMode ); + } + + // Check for advertisement data type + if ( adType == TRUE ) + { + // Advertisement data + if ( pGapAdData ) + { + pDestAdData = pGapAdData; + } + } + else + { + // Scan Response data + if ( pGapScanRspData ) + { + pDestAdData = pGapScanRspData; + } + } + + if ( pDestAdData ) + { + // Make sure data length isn't greater than the allowed size + if ( dataLen > B_MAX_ADV_LEN ) + { + return( INVALIDPARAMETER ); + } + + // Check if there's supposed to be data + if ( ( dataLen > 0 ) && ( pAdvertData == NULL ) ) + { + return( INVALIDPARAMETER ); + } + + gapAdvAppTaskID = taskID; + VOID osal_memset( pDestAdData->dataField, 0, B_MAX_ADV_LEN ); + VOID osal_memcpy( pDestAdData->dataField, pAdvertData, dataLen ); + pDestAdData->dataLen = dataLen; + + if ( adType ) + { + stat = HCI_LE_SetAdvDataCmd( pDestAdData->dataLen, pDestAdData->dataField ); + } + else + { + stat = HCI_LE_SetScanRspDataCmd( pDestAdData->dataLen, pDestAdData->dataField ); + } + } + else + { + stat = bleIncorrectMode; + } + + return ( stat ); +} + +/********************************************************************* + Stops advertising. + + Public function defined in gap.h. +*/ +bStatus_t GAP_EndDiscoverable( uint8 taskID ) +{ + // Check for the correct state. + if ( pGapAdvertState == NULL ) + { + return ( bleIncorrectMode ); + } + + // Parameter check, make sure it came from the task that started the advertising + if ( pGapAdvertState->taskID != taskID ) + { + return ( bleInvalidTaskID ); + } + + // Stop the advertising timer + VOID osal_stop_timerEx( gapTaskID, GAP_END_ADVERTISING_EVT ); + gapLimitedAdvertisingTimeout = 0; + // Stop any address changing timers + VOID osal_stop_timerEx( gapTaskID, GAP_CHANGE_RESOLVABLE_PRIVATE_ADDR_EVT ); + gapPrivateAddrChangeTimeout = 0; + // Send the disable to HCI advertise enable + pGapAdvertState->state = GAP_ADSTATE_ENDING; + return ( HCI_LE_SetAdvEnableCmd( HCI_DISABLE_ADV ) ); +} + +/********************************************************************* + Called to setup a GAP Advertisement token. + + Public function defined in gap.h. +*/ +bStatus_t GAP_SetAdvToken( gapAdvDataToken_t* pToken ) +{ + uint8 adLen; + uint8 srLen; + + if ( (gapProfileRole & (GAP_PROFILE_PERIPHERAL |GAP_PROFILE_BROADCASTER)) == 0 ) + { + // Not allowed for this device type + return ( bleIncorrectMode ); + } + + // Check for an invalid parameter + if ( (pToken == NULL) || ( gapValidADType( pToken->adType ) == FALSE ) ) + { + return ( INVALIDPARAMETER ); + } + + // Make sure the token isn't too big + if ( (pToken->attrLen + ADV_TOKEN_HDR) > B_MAX_ADV_LEN ) + { + return ( INVALID_MEM_SIZE ); + } + + // Make sure each token is unique + if ( gapFindAdvToken( pToken->adType ) ) + { + return ( bleInvalidRange ); + } + + // See if there is enough space in the advertisement or Scan response for this token + gapCalcAdvTokenDataLen( &adLen, &srLen ); + + if ( srLen ) + { + // Check if it will fit in the scan response data, since we are already + // using scan response, the advertisement data is already filled. + if ( (srLen + (pToken->attrLen + ADV_TOKEN_HDR)) > B_MAX_ADV_LEN ) + { + return ( INVALID_MEM_SIZE ); + } + } + + // Add token to the list + return ( gapAddAdvToken( pToken ) ); +} + +/********************************************************************* + Called to read a GAP Advertisement token. + + Public function defined in gap.h. +*/ +gapAdvDataToken_t* GAP_GetAdvToken( uint8 adType ) +{ + gapAdvToken_t* pAdItem; + + if ( (gapProfileRole & (GAP_PROFILE_PERIPHERAL |GAP_PROFILE_BROADCASTER)) == 0 ) + { + // Not allowed for this device type + return ((gapAdvDataToken_t*)NULL ); + } + + pAdItem = gapFindAdvToken( adType ); + + if ( pAdItem ) + { + // Found + return ( pAdItem->pToken ); + } + else + { + // Not found + return ( (gapAdvDataToken_t*)NULL ); + } +} + +/********************************************************************* + Called to remove a GAP Advertisement token. + + Public function defined in gap.h. +*/ +gapAdvDataToken_t* GAP_RemoveAdvToken( uint8 adType ) +{ + if ( (gapProfileRole & (GAP_PROFILE_PERIPHERAL |GAP_PROFILE_BROADCASTER)) == 0 ) + { + // Not allowed for this device type + return ( (gapAdvDataToken_t*)NULL ); + } + + // Delete the token from the list, but don't free the token space + // let the application/profile do that + return ( gapDeleteAdvToken( adType ) ); +} + +/********************************************************************* + Called to rebuild and load Advertisement and Scan Response data + from existing GAP Advertisement Tokens. + + Public function defined in gap.h. +*/ +bStatus_t GAP_UpdateAdvTokens( void ) +{ + if ( (gapProfileRole & (GAP_PROFILE_PERIPHERAL |GAP_PROFILE_BROADCASTER)) == 0 ) + { + // Not allowed for this device type + return ( bleIncorrectMode ); + } + + // Build and update (send advertisement and scan response data to LL) + return ( gapBuildADTokens() ); +} + +/********************************************************************* + PUBLIC INTERNAL GAP FUNCTIONS +*/ + +/********************************************************************* + @fn GAP_PeriDevMgrInit + + @brief Initialize the GAP Peripheral Dev Manager. + + @param none + + @return SUCCESS or bleMemAllocError +*/ +bStatus_t GAP_PeriDevMgrInit( void ) +{ + // Free the space first + if ( pGapAdData ) + { + osal_mem_free( pGapAdData ); + pGapAdData = NULL; + } + + if ( pGapScanRspData ) + { + osal_mem_free( pGapScanRspData ); + pGapScanRspData = NULL; + } + + if ( gapProfileRole & (GAP_PROFILE_PERIPHERAL | GAP_PROFILE_BROADCASTER) ) + { + // Set up Peripheral's processing functions + gapRegisterPeripheral( &gapPeripheralCBs ); + return ( gapAllocAdvRecs() ); + } + + gapRegisterPeripheral( NULL ); + return ( SUCCESS ); +} + +/********************************************************************* + @fn gapPeriProcessHCICmdCompleteEvt + + @brief Process an incoming GAP Peripheral Event. + + @param pMsg - message to process + + @return TRUE if processed and safe to deallocate, FALSE if passed + off to another task. +*/ +static uint8 gapPeriProcessHCICmdCompleteEvt( hciEvt_CmdComplete_t* pMsg ) +{ + uint8 safeToDealloc = TRUE; + + switch ( pMsg->cmdOpcode ) + { + case HCI_LE_SET_ADV_PARAM: + safeToDealloc = gapSetAdvParamsStatus( *(pMsg->pReturnParam) ); + break; + + case HCI_LE_SET_ADV_ENABLE: + safeToDealloc = gapWriteAdvEnableStatus( pMsg->pReturnParam[0], + BUILD_UINT16( pMsg->pReturnParam[1], pMsg->pReturnParam[2] ) ); + break; + + case HCI_LE_SET_SCAN_RSP_DATA: + case HCI_LE_SET_ADV_DATA: + { + uint8 adType; + + if ( pMsg->cmdOpcode == HCI_LE_SET_ADV_DATA ) + { + adType = TRUE; + } + else + { + adType = FALSE; + } + + gapWriteAdvDataStatus( adType, *(pMsg->pReturnParam) ); + } + break; + + case HCI_LE_SET_CONNLESS_CTE_TRANS_PARAMETER: + LOG("CTE Param status 0x%02X\n",pMsg->pReturnParam[0]); + break; + + case HCI_LE_SET_CONNLESS_CTE_TRANS_ENABLE: + LOG("CTE enable status 0x%02X\n",pMsg->pReturnParam[0]); + break; + + case HCI_LE_SET_CONNLESS_IQ_SAMPLE_ENABLE: + case HCI_LE_SET_CONNCTE_RECV_PARAMETER: + case HCI_LE_SET_CONN_CTE_TRANSMIT_PARAMETER: + case HCI_LE_CONN_CTE_REQUEST_ENABLE: + case HCI_LE_CONN_CTE_RESPONSE_ENABLE: + case HCI_LE_READ_ANTENNA_INFO: + LOG("gapPeriProcessHCICmdCompleteEvt Opcode 0x%X\n",pMsg->cmdOpcode); + break; + + default: + safeToDealloc = FALSE; // send this message to the app + break; + } + + return ( safeToDealloc ); +} + +/********************************************************************* + @fn gapAllocAdvRecs + + @brief Allocate and initialize the advertising data and + extra advertising data (SCAN_RSP) records. + + @param none + + @return SUCCESS or bleMemAllocError +*/ +static bStatus_t gapAllocAdvRecs( void ) +{ + bStatus_t stat = SUCCESS; + + // Peripheral and Broadcaster's will advertise and support LL SCAN_RSP + if ( gapProfileRole & (GAP_PROFILE_PERIPHERAL | GAP_PROFILE_BROADCASTER) ) + { + pGapAdData = (gapAdvertisingData_t*)osal_mem_alloc( (uint16)(sizeof ( gapAdvertisingData_t )) ); + + if ( pGapAdData ) + { + VOID osal_memset( pGapAdData, 0, (int)(sizeof ( gapAdvertisingData_t )) ); + pGapScanRspData = (gapAdvertisingData_t*)osal_mem_alloc( (uint16)(sizeof ( gapAdvertisingData_t )) ); + + if ( pGapScanRspData ) + { + VOID osal_memset( pGapScanRspData, 0, (int)(sizeof ( gapAdvertisingData_t )) ); + } + else + { + osal_mem_free( pGapAdData ); + pGapAdData = NULL; + stat = bleMemAllocError; + } + } + else + { + stat = bleMemAllocError; + } + } + + return ( stat ); +} + +/********************************************************************* + @fn gapSetAdvParams + + @brief Write the Advertisement Parameters from the saved parameters + in pGapAdvertState. + + @param none + + @return SUCCESS + FAILURE +*/ +bStatus_t gapSetAdvParams( void ) +{ + if ( pGapAdvertState ) + { + uint16 advIntervalMin; + uint16 advIntervalMax; + uint8 advType; + uint8 ownAddrType; + // Setup to send the Advertising parameters to the LL + advType = pGapAdvertState->params.eventType; + + // Are we already in an active connection + if ( GAP_NumActiveConnections() ) + { + advIntervalMin = GAP_GetParamValue( TGAP_CONN_ADV_INT_MIN ); + advIntervalMax = GAP_GetParamValue( TGAP_CONN_ADV_INT_MAX ); + } + else if ( isLimitedDiscoverableMode() ) + { + advIntervalMin = GAP_GetParamValue( TGAP_LIM_DISC_ADV_INT_MIN ); + advIntervalMax = GAP_GetParamValue( TGAP_LIM_DISC_ADV_INT_MAX ); + } + else + { + advIntervalMin = GAP_GetParamValue( TGAP_GEN_DISC_ADV_INT_MIN ); + advIntervalMax = GAP_GetParamValue( TGAP_GEN_DISC_ADV_INT_MAX ); + } + + if ( gapDeviceAddrMode == ADDRTYPE_PUBLIC ) + { + ownAddrType = ADDRTYPE_PUBLIC; + } + else + { + ownAddrType = ADDRTYPE_RANDOM; + } + + return ( HCI_LE_SetAdvParamCmd( advIntervalMin, advIntervalMax, advType, + ownAddrType, + gapAddAddrAdj( pGapAdvertState->params.initiatorAddrType, + pGapAdvertState->params.initiatorAddr ), + pGapAdvertState->params.initiatorAddr, + pGapAdvertState->params.channelMap, + pGapAdvertState->params.filterPolicy ) ); + } + else + { + return ( FAILURE ); + } +} + +/********************************************************************* + @fn gapSetAdvParamsStatus + + @brief Process HCI Command Complete Event status for + the call to HCI_BLESetAdvParamCmd(). + + @param status - HCI Set Advertisement Parameters status + + @return TRUE if expected, FALSE if not +*/ +uint8 gapSetAdvParamsStatus( uint8 status ) +{ + if ( pGapAdvertState ) + { + if ( status == SUCCESS ) + { + // Move on to the next stage - Enable advertising + pGapAdvertState->state = GAP_ADSTATE_SET_MODE; + status = HCI_LE_SetAdvEnableCmd( HCI_ENABLE_ADV ); + } + + if ( status != SUCCESS ) + { + // End the Make Discoverable process + gapSendMakeDiscEvent( status, 0 ); + } + + return ( TRUE ); + } + else + { + return ( FALSE ); + } +} + +/********************************************************************* + @fn gapWriteAdvEnableStatus + + @brief Process HCI Command Complete Event status for + the call to HCI_BLEWriteAdvEnableCmd(). + + @param status - HCI Write Advertisement Enable status + @param interval - Advertisement interval (0x0020 = 0x4000) + interval * 0.625 msec + + @return TRUE if expected, FALSE if not +*/ +uint8 gapWriteAdvEnableStatus( uint8 status, uint16 interval ) +{ + if ( pGapAdvertState ) + { + if ( pGapAdvertState->state == GAP_ADSTATE_SET_MODE ) + { + uint32 timeout; + + // Setup the advertising timeout + if ( isLimitedDiscoverableMode() ) + { + // Use the Limited Discoverable Timeout [Tgap(lim_adv_timeout)] + timeout = GAP_GetParamValue( TGAP_LIM_ADV_TIMEOUT ); + + // Maximum timeout value is 65 seconds + if ( timeout > 65 ) + { + // Start a reload timer with 1 minute resoultion + VOID osal_start_reload_timer( gapTaskID, GAP_END_ADVERTISING_EVT, + (uint32)GAP_LIMITED_ADVERTISING_RESOLUTION ); + // Calculate the remaining timeout + gapLimitedAdvertisingTimeout = timeout - 60; + timeout = 0; + } + else + { + // Convert it to mSec + timeout *= 1000; + } + } + else + { + // assume the General Discoverable advertising timeout [Tgap(gen_disc_adv_min)] + timeout = GAP_GetParamValue( TGAP_GEN_DISC_ADV_MIN ); + } + + // Start a timer + if ( timeout > 0 ) + { + VOID osal_start_timerEx( gapTaskID, GAP_END_ADVERTISING_EVT, timeout ); + } + + // Update the state + pGapAdvertState->state = GAP_ADSTATE_ADVERTISING; + + // Send the Make Discoverable Event message to the app + if ( gapAutoAdvPrivateAddrChange == FALSE ) + { + gapSendMakeDiscEvent( status, interval ); + } + else + { + gapAutoAdvPrivateAddrChange = FALSE; + } + } + else + { + if ( gapAutoAdvPrivateAddrChange == FALSE ) + { + // Send the End Discoverable Event message to the app + gapSendEndDiscoverableEvent( status ); + // Free the Advertising state + gapFreeAdvertState(); + } + } + + return ( TRUE ); + } + else + { + return ( FALSE ); + } +} + +/********************************************************************* + @fn gapWriteAdvDataStatus + + @brief Process HCI Command Complete Event status for + the call to HCI_BLEWriteAdvDataCmd() or + HCI_BLEWriteScanRspDataCmd(). + + @param adType - TRUE for Advertising Data Status + FALSE for SCAN_RSP Data status + @param status - HCI Write Advertisement Data + of Scan Response Data status + + @return none +*/ +void gapWriteAdvDataStatus( uint8 adType, uint8 status ) +{ + // Send the Make Discoverable Event message to the app + gapSendAdDataUpdateEvent( adType, status ); +} + +/********************************************************************* + @fn gapProcessAdvertisingEvt + + @brief Process Advertising event. + + @param timeout - TRUE if advertising timeout, FALSE otherwise + + @return none +*/ +static void gapProcessAdvertisingEvt( uint8 timeout ) +{ + if ( timeout == TRUE ) + { + // Time to stop (limited or general) advertising? + if ( ( gapLimitedAdvertisingTimeout == 0 ) || gapAutoAdvPrivateAddrChange ) + { + gapProcessAdvertisingTimeout(); + } + else + { + // Calculate the Limited Advertising remaining timeout + if ( gapLimitedAdvertisingTimeout >= 60 ) + { + // Decrement the seconds in the timeout value + gapLimitedAdvertisingTimeout -= 60; + } + else + { + // Cancel the reloaded timer since its resolution is 1 minute + VOID osal_stop_timerEx( gapTaskID, GAP_END_ADVERTISING_EVT ); + // Start a new timer for the remaining timeout (in mSec) + VOID osal_start_timerEx( gapTaskID, GAP_END_ADVERTISING_EVT, + (uint32)(gapLimitedAdvertisingTimeout*1000) ); + gapLimitedAdvertisingTimeout = 0; + } + } + } + else + { + gapConnectedCleanUpAdvertising(); + } +} + +/********************************************************************* + @fn gapProcessAdvertisingTimeout + + @brief Advertising time expired, stop advertising. + + @param none + + @return none +*/ +static void gapProcessAdvertisingTimeout( void ) +{ + // Are we in adverising state? + if ( pGapAdvertState ) + { + // Advertising time expired, stop advertising + VOID GAP_EndDiscoverable( pGapAdvertState->taskID ); + } +} + +/********************************************************************* + @fn gapConnectedCleanUpAdvertising + + @brief This will clean up the advertising state. + + @param none + + @return none +*/ +static void gapConnectedCleanUpAdvertising( void ) +{ + // Make sure we're in Peripheral role (we could be in Central & Broadcaster role) + if ( pGapAdvertState && ( gapProfileRole & GAP_PROFILE_PERIPHERAL ) ) + { + // Stop the timer + VOID osal_stop_timerEx( gapTaskID, GAP_END_ADVERTISING_EVT ); + gapLimitedAdvertisingTimeout = 0; + // Free the Advertising state + gapFreeAdvertState(); + } +} + +/********************************************************************* + @fn gapAddAdvToken + + @brief Add token to the end of the list. + + @param pToken - pointer to data token structure + + @return SUCCESS - advertisement token added to the GAP list
+ bleMemAllocError - Memory allocation error
+*/ +bStatus_t gapAddAdvToken( gapAdvDataToken_t* pToken ) +{ + gapAdvToken_t* pItem; + pItem = (gapAdvToken_t*)osal_mem_alloc( (uint16)sizeof ( gapAdvToken_t ) ); + + if ( pItem ) + { + VOID osal_memset( pItem, 0, (int)sizeof ( gapAdvToken_t ) ); + + if ( pGapAdvTokens ) + { + gapAdvToken_t* pList; + // Start at the top of the list + pList = pGapAdvTokens; + + while ( pList->pNext ) + { + pList = pList->pNext; + } + + // Make this one the last in the list + pList->pNext = pItem; + } + else + { + // Make this one the first in the list + pGapAdvTokens = pItem; + } + + pItem->pToken = pToken; + return ( SUCCESS ); + } + else + { + return ( bleMemAllocError ); + } +} + +/********************************************************************* + @fn gapDeleteAdvToken + + @brief Remove a token from the list + + @param ADType - Advertisement data type + + @return Pointer to removed advertisement data token, + NULL if not found +*/ +gapAdvDataToken_t* gapDeleteAdvToken( uint8 ADType ) +{ + gapAdvToken_t* pPrevItem = NULL; + gapAdvToken_t* pList; + // Start at the top of the list + pList = pGapAdvTokens; + + while ( pList ) + { + if ( pList->pToken->adType == ADType ) + { + gapAdvDataToken_t* pToken = pList->pToken; + + // Remove from the list + if ( pPrevItem ) + { + pPrevItem->pNext = pList->pNext; + } + else + { + pGapAdvTokens = pList->pNext; + } + + // Deallocate the item + osal_mem_free( pList ); + // Return the token memory for someone else to release + return ( pToken ); + } + + pPrevItem = pList; + pList = pList->pNext; + } + + return ( (gapAdvDataToken_t*)NULL ); +} + +/********************************************************************* + @fn gapFindAdvToken + + @brief Find a Advertisement data token from the advertisement type. + + @param ADType - Advertisement data type + + @return Pointer to the advertisement token, + NULL if not found +*/ +gapAdvToken_t* gapFindAdvToken( uint8 ADType ) +{ + gapAdvToken_t* pList; + // Start at the top of the list + pList = pGapAdvTokens; + + while ( pList ) + { + if ( pList->pToken->adType == ADType ) + { + // found + return ( pList ); + } + + pList = pList->pNext; + } + + return ( (gapAdvToken_t*)NULL ); +} + +/********************************************************************* + @fn gapCalcAdvTokenDataLen + + @brief Find a Advertisement data token from the advertisement type. + + @param pAdLen - pointer to advertisement data length used + @param pSrLen - pointer to scan response data length used + + @return none +*/ +void gapCalcAdvTokenDataLen( uint8* pAdLen, uint8* pSrLen ) +{ + gapAdvToken_t* pList; + uint8 scan_rsp = FALSE; + *pAdLen = 0; + *pSrLen = 0; + // Start at the top of the list + pList = pGapAdvTokens; + + while ( pList ) + { + if ( scan_rsp == FALSE ) + { + if ( (*pAdLen + (pList->pToken->attrLen + ADV_TOKEN_HDR)) > B_MAX_ADV_LEN ) + { + // Switch to scan response + scan_rsp = TRUE; + } + } + + if ( scan_rsp ) + { + *pSrLen += (pList->pToken->attrLen + ADV_TOKEN_HDR); + } + else + { + *pAdLen += (pList->pToken->attrLen + ADV_TOKEN_HDR); + } + + // Next in list + pList = pList->pNext; + } +} + +/********************************************************************* + @fn gapBuildADTokens + + @brief Is a Advertisement Data Type valid. + + @param none + + @return SUCCESS, bleIncorrectMode, or bleMemAllocError +*/ +bStatus_t gapBuildADTokens( void ) +{ + gapAdvToken_t* pList; + uint8 scan_rsp = FALSE; + + if ( (gapProfileRole & (GAP_PROFILE_PERIPHERAL | GAP_PROFILE_BROADCASTER)) == 0 ) + { + return ( bleIncorrectMode ); + } + + if ( pGapAdData == NULL ) + { + pGapAdData = (gapAdvertisingData_t*)osal_mem_alloc( (uint16)(sizeof ( gapAdvertisingData_t )) ); + } + + if ( pGapScanRspData == NULL ) + { + pGapScanRspData = (gapAdvertisingData_t*)osal_mem_alloc( (uint16)(sizeof ( gapAdvertisingData_t )) ); + } + + if ( pGapAdData == NULL || pGapScanRspData == NULL ) + { + return ( bleMemAllocError ); + } + + VOID osal_memset( pGapAdData, 0, (int)(sizeof ( gapAdvertisingData_t )) ); + VOID osal_memset( pGapScanRspData, 0, (int)(sizeof ( gapAdvertisingData_t )) ); + // Start at the top of the list + pList = pGapAdvTokens; + + while ( pList ) + { + uint8* pDataBuf; + + if ( scan_rsp == FALSE ) + { + if ( (pGapAdData->dataLen + (pList->pToken->attrLen + ADV_TOKEN_HDR)) > B_MAX_ADV_LEN ) + { + // Switch to scan response + scan_rsp = TRUE; + } + } + + if ( scan_rsp ) + { + pDataBuf = &(pGapScanRspData->dataField[pGapScanRspData->dataLen]); + pGapScanRspData->dataLen += (pList->pToken->attrLen + ADV_TOKEN_HDR); + } + else + { + pDataBuf = &(pGapAdData->dataField[pGapAdData->dataLen]); + pGapAdData->dataLen += (pList->pToken->attrLen + ADV_TOKEN_HDR); + } + + // Make the token in the data field. + pDataBuf[0] = pList->pToken->attrLen + 1; // Token length (data + adType) + pDataBuf[1] = pList->pToken->adType; // Advertisement Type + VOID osal_memcpy( &pDataBuf[2], pList->pToken->pAttrData, pList->pToken->attrLen ); + // Next in list + pList = pList->pNext; + } + + VOID HCI_LE_SetAdvDataCmd( pGapAdData->dataLen, pGapAdData->dataField ); + VOID HCI_LE_SetScanRspDataCmd( pGapScanRspData->dataLen, pGapScanRspData->dataField ); + return ( SUCCESS ); +} + +/********************************************************************* + LOCAL FUNCTIONS +*/ + +/********************************************************************* + @fn gapSendMakeDiscEvent + + @brief Send the GAP_MAKE_DISCOVERY_EVENT. + + @param status - Reason for sending this message. + SUCCESS if all went well. + + @return none +*/ +static void gapSendMakeDiscEvent( bStatus_t status, uint16 interval ) +{ + // Check advertising state + if ( pGapAdvertState ) + { + gapMakeDiscoverableRspEvent_t* pRsp; + pRsp = (gapMakeDiscoverableRspEvent_t*)osal_msg_allocate( (uint16)(sizeof( gapMakeDiscoverableRspEvent_t )) ); + + if ( pRsp ) + { + // Build the message + pRsp->hdr.event = GAP_MSG_EVENT; + pRsp->hdr.status = status; + pRsp->opcode = GAP_MAKE_DISCOVERABLE_DONE_EVENT; + pRsp->interval = interval; + VOID osal_msg_send( pGapAdvertState->taskID, (uint8*)pRsp ); + } + + if ( status != SUCCESS ) + { + // Release Advertising data + gapFreeAdvertState(); + } + } +} + +/********************************************************************* + @fn gapSendAdDataUpdateEvent + + @brief Send the GAP_ADV_DATA_UPDATE_DONE_EVENT. + + @param adType - TRUE for Advertising Data Status + FALSE for SCAN_RSP Data status + @param status - HCI Write Advertisement Data + of Scan Response Data status + + @return none +*/ +static void gapSendAdDataUpdateEvent( uint8 adType, uint8 status ) +{ + if ( gapAdvAppTaskID != INVALID_TASK_ID ) + { + gapAdvDataUpdateEvent_t* pRsp; + pRsp = (gapAdvDataUpdateEvent_t*)osal_msg_allocate( (uint16)(sizeof ( gapAdvDataUpdateEvent_t )) ); + + if ( pRsp ) + { + pRsp->hdr.event = GAP_MSG_EVENT; + pRsp->hdr.status = status; + pRsp->opcode = GAP_ADV_DATA_UPDATE_DONE_EVENT; + pRsp->adType = adType; + VOID osal_msg_send( gapAdvAppTaskID, (uint8*)pRsp ); + } + } +} + +/********************************************************************* + @fn gapSendEndDiscoverableEvent + + @brief Send the GAP_END_DISCOVERABLE_DONE_EVENT. + + @param status - HCI Advertisement Enable status + + @return none +*/ +static void gapSendEndDiscoverableEvent( uint8 status ) +{ + if ( pGapAdvertState ) + { + gapEndDiscoverableRspEvent_t* pRsp; + pRsp = (gapEndDiscoverableRspEvent_t*)osal_msg_allocate( (uint16)(sizeof ( gapEndDiscoverableRspEvent_t )) ); + + if ( pRsp ) + { + pRsp->hdr.event = GAP_MSG_EVENT; + pRsp->hdr.status = status; + pRsp->opcode = GAP_END_DISCOVERABLE_DONE_EVENT; + VOID osal_msg_send( pGapAdvertState->taskID, (uint8*)pRsp ); + } + } +} + +/********************************************************************* + @fn gapFreeAdvertState + + @brief Free the memory associated with the Advertising state. + + @param none + + @return none +*/ +static void gapFreeAdvertState( void ) +{ + if ( pGapAdvertState ) + { + osal_mem_free( pGapAdvertState ); + pGapAdvertState = NULL; + } +} + +/********************************************************************* + @fn isLimitedDiscoverableMode + + @brief Looks through the advertising data to determine if + the device is in Limited Discovery Mode. + + @param none + + @return TRUE if in Limited Discovery Mode, FALSE if not. +*/ +static uint8 isLimitedDiscoverableMode( void ) +{ + if ( pGapAdData ) + { + uint8 ADLen; + uint8* pADToken = gapFindADType( GAP_ADTYPE_FLAGS, &ADLen, + pGapAdData->dataLen, pGapAdData->dataField ); + + if ( (pADToken) && (*pADToken & GAP_ADTYPE_FLAGS_LIMITED) ) + { + return ( TRUE ); + } + } + + return ( FALSE ); +} + + +/**************************************************************************** +****************************************************************************/ diff --git a/src/lib/ble_host/gap_perilinkmgr.c b/src/lib/ble_host/gap_perilinkmgr.c new file mode 100644 index 0000000..e715bb7 --- /dev/null +++ b/src/lib/ble_host/gap_perilinkmgr.c @@ -0,0 +1,142 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: gap_perilinkmgr.c + Revised: + Revision: + + Description: This file contains the GAP Peripheral Link Manager. + + +**************************************************************************************************/ + + + +/******************************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "gap.h" +#include "gap_internal.h" +#include "linkdb.h" +#include "sm.h" +#include "sm_internal.h" +#include "smp.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +/********************************************************************* + LOCAL FUNCTIONS +*/ + +/********************************************************************* + API FUNCTIONS +*/ + + +/********************************************************************* + Generate a Slave Requested Security message to the master. + + Public function defined in gap.h. +*/ +bStatus_t GAP_SendSlaveSecurityRequest( uint16 connectionHandle, uint8 authReq ) +{ + linkDBItem_t* pItem; // Link parameters pointer + + // Check for wrong role + if ( (gapProfileRole & GAP_PROFILE_PERIPHERAL) == 0 ) + { + return ( bleIncorrectMode ); + } + + // Check for connection + pItem = linkDB_Find( connectionHandle ); + + if ( pItem ) + { + smpSecurityReq_t sReq; + uint8 tmp; + + // Are we already setup in an pAuthLink[connectionHandle]? + if ( pAuthLink[connectionHandle] ) + { + // Use the pAuthLink[connectionHandle]'s requirements + tmp = pAuthLink[connectionHandle]->secReqs.authReq; + } + else + { + // Use the passed in requirements + tmp = authReq; + } + + // Convert byte to struct + smUint8ToAuthReq( &(sReq.authReq), tmp ); + // Tell SM to send the Slave Security Request + return ( smSendSecurityReq( connectionHandle, &sReq ) ); + } + else + { + return ( bleNotConnected ); + } +} + + + +/**************************************************************************** +****************************************************************************/ diff --git a/src/lib/ble_host/gap_simpletask.c b/src/lib/ble_host/gap_simpletask.c new file mode 100644 index 0000000..be04a1d --- /dev/null +++ b/src/lib/ble_host/gap_simpletask.c @@ -0,0 +1,391 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: gap_simpletask.c + Revised: + Revision: + + Description: This file contains the GAP Simple Task. + + +**************************************************************************************************/ + +#if !( HOST_CONFIG & ( CENTRAL_CFG | PERIPHERAL_CFG ) ) + +/******************************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "hci_tl.h" + +#include "gap.h" +#include "gap_internal.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ +uint8 gapTaskID; // The GAP's Task ID +uint8 gapUnwantedTaskID = INVALID_TASK_ID; // The task ID of an app/profile that +// wants unexpected HCI messages. + +// Callback function pointers for Peripheral +gapPeripheralCBs_t* pfnPeripheralCBs = NULL; + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +// Callback function pointers for Central +static gapCentralCBs_t* pfnCentralCBs = NULL; + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static uint8 gapProcessOSALMsg( osal_event_hdr_t* pMsg ); +static uint8 gapProcessBLEEvents( osal_event_hdr_t* pMsg ); +static uint8 gapProcessHCICmdCompleteEvt( hciEvt_CmdComplete_t* pMsg ); + +/********************************************************************* + API FUNCTIONS +*/ + +/********************************************************************* + Register your task ID to receive extra (unwanted) HCI status and + complete events. + + Public function defined in gap.h. +*/ +void GAP_RegisterForHCIMsgs( uint8 taskID ) +{ + gapUnwantedTaskID = taskID; +} + +/********************************************************************* + @fn GAP_Init + + @brief GAP Task initialization function. + + @param taskID - GAP task ID. + + @return void +*/ +void GAP_Init( uint8 task_id ) +{ + // Save our own Task ID + gapTaskID = task_id; + // Register with HCI to receive events + HCI_GAPTaskRegister( gapTaskID ); +} + +/********************************************************************* + @fn GAP_ProcessEvent + + @brief GAP Task event processing function. + + @param taskID - GAP task ID + @param events - GAP events. + + @return events not processed +*/ +uint16 GAP_ProcessEvent( uint8 task_id, uint16 events ) +{ + VOID task_id; // OSAL required parameter that isn't used in this function + + if ( events & SYS_EVENT_MSG ) + { + uint8* pMsg; + + if ( (pMsg = osal_msg_receive( gapTaskID )) != NULL ) + { + if ( !gapProcessOSALMsg( (osal_event_hdr_t*)pMsg ) ) + { + // Send it to the registered application. + if ( gapUnwantedTaskID != INVALID_TASK_ID ) + { + // This message wasn't processed in the GAP, send it + // to an app/profile that wants it. + if ( osal_msg_send( gapUnwantedTaskID, pMsg ) == SUCCESS ) + { + // return unprocessed events and don't dealloc + // the message because it was sent elsewhere + return (events ^ SYS_EVENT_MSG); + } + } + } + + // Release the OSAL message + VOID osal_msg_deallocate( pMsg ); + } + + // return unprocessed events + return (events ^ SYS_EVENT_MSG); + } + + if ( events & GAP_OSAL_TIMER_SCAN_DURATION_EVT ) + { + // Device Discovery time expired, stop the scan + if ( pfnCentralCBs && pfnCentralCBs->pfnProcessScanningEvt ) + { + pfnCentralCBs->pfnProcessScanningEvt( NULL ); + } + + return ( events ^ GAP_OSAL_TIMER_SCAN_DURATION_EVT ); + } + + if ( events & GAP_END_ADVERTISING_EVT ) + { + // Advertising time expired, stop advertising + if ( pfnPeripheralCBs && pfnPeripheralCBs->pfnProcessAdvertisingEvt ) + { + pfnPeripheralCBs->pfnProcessAdvertisingEvt( TRUE ); + } + + return ( events ^ GAP_END_ADVERTISING_EVT ); + } + + // If reach here, the events are unknown + // Discard or make more handlers + return 0; +} + +/********************************************************************* + @fn GAP_NumActiveConnections + + @brief Returns the number of active connections. + + @param none + + @return number of active connections +*/ +uint8 GAP_NumActiveConnections( void ) +{ + return ( 0 ); +} + +/********************************************************************* + @fn gapProcessOSALMsg + + @brief Process an incoming task message. + + @param pMsg - message to process + + @return TRUE if processed and safe to deallocate, FALSE if passed + off to another task. +*/ +static uint8 gapProcessOSALMsg( osal_event_hdr_t* pMsg ) +{ + uint8 safeToDealloc = TRUE; + + switch ( pMsg->event ) + { + case HCI_GAP_EVENT_EVENT: + { + switch( pMsg->status ) + { + case HCI_COMMAND_COMPLETE_EVENT_CODE: + safeToDealloc = gapProcessHCICmdCompleteEvt( (hciEvt_CmdComplete_t*)pMsg ); + break; + + case HCI_LE_EVENT_CODE: + // BLE Events + safeToDealloc = gapProcessBLEEvents( pMsg ); + break; + + default: + safeToDealloc = FALSE; // Send to app + break; + } + } + break; + + default: + safeToDealloc = FALSE; // Send to app + break; + } + + return ( safeToDealloc ); +} + +/********************************************************************* + @fn gapProcessBLEEvents + + @brief Process an incoming OSAL HCI BLE specific events. + + @param pMsg - message to process + + @return TRUE if processed and safe to deallocate, FALSE if passed + off to another task. +*/ +static uint8 gapProcessBLEEvents( osal_event_hdr_t* pMsg ) +{ + uint8 safeToDealloc = TRUE; + + switch ( ((hciEvt_BLEAdvPktReport_t*)(pMsg))->BLEEventCode ) + { + case HCI_BLE_ADV_REPORT_EVENT: + if ( pfnCentralCBs && pfnCentralCBs->pfnProcessScanningEvt ) + { + pfnCentralCBs->pfnProcessScanningEvt( (hciEvt_BLEAdvPktReport_t*)pMsg ); + } + + break; + + default: + safeToDealloc = FALSE; + break; + } + + return ( safeToDealloc ); +} + +/********************************************************************* + @fn gapProcessHCICmdCompleteEvt + + @brief Process an incoming OSAL HCI Command Complete Event. + + @param pMsg - message to process + + @return TRUE if processed and safe to deallocate, FALSE if passed + off to another task. +*/ +static uint8 gapProcessHCICmdCompleteEvt( hciEvt_CmdComplete_t* pMsg ) +{ + uint8 safeToDealloc = TRUE; + + switch ( pMsg->cmdOpcode ) + { + case HCI_LE_SET_RANDOM_ADDR: + gapProcessRandomAddrComplete( *(pMsg->pReturnParam) ); + break; + + case HCI_LE_READ_BUFFER_SIZE: + safeToDealloc = gapReadBufSizeCmdStatus( + (hciRetParam_LeReadBufSize_t*)pMsg->pReturnParam ); + break; + + case HCI_READ_BDADDR: + safeToDealloc = gapReadBD_ADDRStatus( pMsg->pReturnParam[0], + &(pMsg->pReturnParam[1]) ); + break; + + case HCI_LE_SET_SCAN_ENABLE: + if ( *(pMsg->pReturnParam) == SUCCESS ) + { + break; + } + + // fallthrough + case HCI_LE_SET_SCAN_PARAM: + if ( pfnCentralCBs && pfnCentralCBs->pfnProcessHCICmdEvt ) + { + safeToDealloc = pfnCentralCBs->pfnProcessHCICmdEvt( pMsg->cmdOpcode, pMsg ); + } + + break; + + case HCI_LE_CREATE_CONNECTION_CANCEL: + break; + + case HCI_LE_SET_ADV_PARAM: + case HCI_LE_SET_ADV_ENABLE: + case HCI_LE_SET_SCAN_RSP_DATA: + case HCI_LE_SET_ADV_DATA: + if ( pfnPeripheralCBs && pfnPeripheralCBs->pfnProcessHCICmdCompleteEvt ) + { + safeToDealloc = pfnPeripheralCBs->pfnProcessHCICmdCompleteEvt( pMsg ); + } + + break; + + default: + safeToDealloc = FALSE; // send this message to the app + break; + } + + return ( safeToDealloc ); +} + +/********************************************************************* + @fn gapRegisterCentral + + @brief Register Central's processing function with GAP task. + + @param pfnCBs - pointer to Central's processing function + + @return none +*/ +void gapRegisterCentral( gapCentralCBs_t* pfnCBs ) +{ + pfnCentralCBs = pfnCBs; +} + +/********************************************************************* + @fn gapRegisterPeripheral + + @brief Register Peripheral's processing function with GAP task. + + @param pfnCBs - pointer to Peripheral's processing function + + @return none +*/ +void gapRegisterPeripheral( gapPeripheralCBs_t* pfnCBs ) +{ + pfnPeripheralCBs = pfnCBs; +} + +#endif // !( CENTRAL_CFG | PERIPHERAL_CFG ) + +/**************************************************************************** +****************************************************************************/ + diff --git a/src/lib/ble_host/gap_task.c b/src/lib/ble_host/gap_task.c new file mode 100644 index 0000000..73f57d1 --- /dev/null +++ b/src/lib/ble_host/gap_task.c @@ -0,0 +1,540 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: gap_task.c + Revised: + Revision: + + Description: This file contains the GAP Task. + + +**************************************************************************************************/ + + + +/******************************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "hci_tl.h" +#include "l2cap.h" +#include "gatt.h" +#include "gap.h" +#include "gap_internal.h" +#include "linkdb.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ +uint8 gapTaskID; // The GAP's Task ID +uint8 gapUnwantedTaskID = INVALID_TASK_ID; // The task ID of an app/profile that +// wants unexpected HCI messages. + +// Callback function pointers for Peripheral +gapPeripheralCBs_t* pfnPeripheralCBs = NULL; + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +// Callback function pointers for Central +static const gapCentralCBs_t* pfnCentralCBs = NULL; + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static uint8 gapProcessOSALMsg( osal_event_hdr_t* pMsg ); +static uint8 gapProcessBLEEvents( osal_event_hdr_t* pMsg ); +static uint8 gapProcessHCICmdCompleteEvt( hciEvt_CmdComplete_t* pMsg ); +static uint8 gapProcessCommandStatusEvt( hciEvt_CommandStatus_t* pMsg ); + +/********************************************************************* + API FUNCTIONS +*/ + +/********************************************************************* + Register your task ID to receive extra (unwanted) HCI status and + complete events. + + Public function defined in gap.h. +*/ +void GAP_RegisterForHCIMsgs( uint8 taskID ) +{ + gapUnwantedTaskID = taskID; +} + +/********************************************************************* + @fn GAP_Init + + @brief GAP Task initialization function. + + @param taskID - GAP task ID. + + @return void +*/ +void GAP_Init( uint8 task_id ) +{ + // Save our own Task ID + gapTaskID = task_id; + // Initialize the Link Database + linkDB_Init(); + // Register with HCI to receive events + HCI_GAPTaskRegister( gapTaskID ); + // Register with L2CAP to receive unprocessed Signaling messages + VOID L2CAP_RegisterApp( gapTaskID, L2CAP_CID_SIG ); +} + +/********************************************************************* + @fn GAP_ProcessEvent + + @brief GAP Task event processing function. + + @param taskID - GAP task ID + @param events - GAP events. + + @return events not processed +*/ +uint16 GAP_ProcessEvent( uint8 task_id, uint16 events ) +{ + VOID task_id; // OSAL required parameter that isn't used in this function + + if ( events & SYS_EVENT_MSG ) + { + uint8* pMsg; + + if ( (pMsg = osal_msg_receive( gapTaskID )) != NULL ) + { + if ( !gapProcessOSALMsg( (osal_event_hdr_t*)pMsg ) ) + { + // Send it to the registered application. + if ( gapUnwantedTaskID != INVALID_TASK_ID ) + { + // This message wasn't processed in the GAP, send it + // to an app/profile that wants it. + if ( osal_msg_send( gapUnwantedTaskID, pMsg ) == SUCCESS ) + { + // return unprocessed events and don't dealloc + // the message because it was sent elsewhere + return (events ^ SYS_EVENT_MSG); + } + } + } + + // Release the OSAL message + VOID osal_msg_deallocate( pMsg ); + } + + // return unprocessed events + return (events ^ SYS_EVENT_MSG); + } + + if ( events & GAP_OSAL_TIMER_SCAN_DURATION_EVT ) + { + // Device Discovery time expired, stop the scan + if ( pfnCentralCBs && pfnCentralCBs->pfnProcessScanningEvt ) + { + pfnCentralCBs->pfnProcessScanningEvt( NULL ); + } + + return ( events ^ GAP_OSAL_TIMER_SCAN_DURATION_EVT ); + } + + if ( events & GAP_END_ADVERTISING_EVT ) + { + // Advertising time expired, stop advertising + if ( pfnPeripheralCBs && pfnPeripheralCBs->pfnProcessAdvertisingEvt ) + { + pfnPeripheralCBs->pfnProcessAdvertisingEvt( TRUE ); + } + + return ( events ^ GAP_END_ADVERTISING_EVT ); + } + + if ( events & GAP_CHANGE_RESOLVABLE_PRIVATE_ADDR_EVT ) + { + // Are we in Addr Change mode? + if ( gapPrivateAddrChangeTimeout ) + { + // Decrement the seconds in the timeout value + gapPrivateAddrChangeTimeout--; + + // Time to change the Resolvable Private Address? + if ( gapPrivateAddrChangeTimeout == 0 ) + { + uint8 newAddr[B_ADDR_LEN]; // space for the new address + + // Are we advertising now? + if ( gapIsAdvertising() ) + { + gapAutoAdvPrivateAddrChange = TRUE; + + // Stop any advertising + if ( pfnPeripheralCBs && pfnPeripheralCBs->pfnProcessAdvertisingEvt ) + { + pfnPeripheralCBs->pfnProcessAdvertisingEvt( TRUE ); + } + } + + // Calculate a new address + VOID SM_CalcRandomAddr( gapGetIRK(), newAddr ); + // Send the new address to the app/profile + VOID gapProcessNewAddr( newAddr ); + // Reset the timer + gapPrivateAddrChangeTimeout = GAP_GetParamValue( TGAP_PRIVATE_ADDR_INT ); + } + } + else + { + // It shouldn't be set, so stop the timer + VOID osal_stop_timerEx( gapTaskID, GAP_CHANGE_RESOLVABLE_PRIVATE_ADDR_EVT ); + } + + return ( events ^ GAP_CHANGE_RESOLVABLE_PRIVATE_ADDR_EVT ); + } + + // If reach here, the events are unknown + // Discard or make more handlers + return 0; +} + +/********************************************************************* + @fn GAP_NumActiveConnections + + @brief Returns the number of active connections. + + @param none + + @return number of active connections +*/ +uint8 GAP_NumActiveConnections( void ) +{ + return ( linkDB_NumActive() ); +} + +/********************************************************************* + @fn gapProcessOSALMsg + + @brief Process an incoming task message. + + @param pMsg - message to process + + @return TRUE if processed and safe to deallocate, FALSE if passed + off to another task. +*/ +static uint8 gapProcessOSALMsg( osal_event_hdr_t* pMsg ) +{ + uint8 safeToDealloc = TRUE; + + switch ( pMsg->event ) + { + case HCI_GAP_EVENT_EVENT: + { + switch( pMsg->status ) + { + case HCI_COMMAND_COMPLETE_EVENT_CODE: + safeToDealloc = gapProcessHCICmdCompleteEvt( (hciEvt_CmdComplete_t*)pMsg ); + break; + + case HCI_DISCONNECTION_COMPLETE_EVENT_CODE: + gapProcessDisconnectCompleteEvt( (hciEvt_DisconnComplete_t*)pMsg ); + break; + + case HCI_COMMAND_STATUS_EVENT_CODE: + safeToDealloc = gapProcessCommandStatusEvt( (hciEvt_CommandStatus_t*)pMsg ); + break; + + case HCI_LE_EVENT_CODE: + // BLE Events + safeToDealloc = gapProcessBLEEvents( pMsg ); + break; + + default: + safeToDealloc = FALSE; // Send to app + break; + } + } + break; + + case L2CAP_SIGNAL_EVENT: + + // & --> == bugfix for multi-role + if ( gapProfileRole == GAP_PROFILE_PERIPHERAL ) + { + l2capSignalEvent_t* pCmd = (l2capSignalEvent_t*)pMsg; + l2capCmdReject_t cmdReject; + // If the slave's Host receives a Connection Parameter Update Request + // packet it shall respond with a Command Reject packet with reason + // 0x0000 (Command not understood). + cmdReject.reason = L2CAP_REJECT_CMD_NOT_UNDERSTOOD; + VOID L2CAP_CmdReject( pCmd->connHandle, pCmd->id, &cmdReject ); + } + else if ( pfnCentralConnCBs && pfnCentralConnCBs->pfnProcessConnEvt ) + { + VOID pfnCentralConnCBs->pfnProcessConnEvt( L2CAP_PARAM_UPDATE, + (hciEvt_CommandStatus_t*)pMsg ); + } + + break; + + default: + safeToDealloc = FALSE; // Send to app + break; + } + + return ( safeToDealloc ); +} + +/********************************************************************* + @fn gapProcessBLEEvents + + @brief Process an incoming OSAL HCI BLE specific events. + + @param pMsg - message to process + + @return TRUE if processed and safe to deallocate, FALSE if passed + off to another task. +*/ +static uint8 gapProcessBLEEvents( osal_event_hdr_t* pMsg ) +{ + uint8 safeToDealloc = TRUE; + + switch ( ((hciEvt_BLEAdvPktReport_t*)(pMsg))->BLEEventCode ) + { + case HCI_BLE_ADV_REPORT_EVENT: + if ( pfnCentralCBs && pfnCentralCBs->pfnProcessScanningEvt ) + { + pfnCentralCBs->pfnProcessScanningEvt( (hciEvt_BLEAdvPktReport_t*)pMsg ); + } + + break; + + case HCI_BLE_CONNECTION_COMPLETE_EVENT: + gapProcessConnectionCompleteEvt( (hciEvt_BLEConnComplete_t*)pMsg ); + break; + + case HCI_BLE_CONN_UPDATE_COMPLETE_EVENT: + gapProcessConnUpdateCompleteEvt( (hciEvt_BLEConnUpdateComplete_t*)pMsg ); + break; + + case HCI_LE_CONNECTIONLESS_IQ_REPORT_EVENT: + LOG("gapProcessBLEEvents HCI_LE_CONNECTIONLESS_IQ_REPORT_EVENT \n"); + break; + + case HCI_LE_CONNECTION_IQ_REPORT_EVENT: + LOG("gapProcessBLEEvents HCI_LE_CONNECTION_IQ_REPORT_EVENT \n"); + break; + + default: + safeToDealloc = FALSE; + break; + } + + return ( safeToDealloc ); +} + +/********************************************************************* + @fn gapProcessHCICmdCompleteEvt + + @brief Process an incoming OSAL HCI Command Complete Event. + + @param pMsg - message to process + + @return TRUE if processed and safe to deallocate, FALSE if passed + off to another task. +*/ +static uint8 gapProcessHCICmdCompleteEvt( hciEvt_CmdComplete_t* pMsg ) +{ + uint8 safeToDealloc = TRUE; + + switch ( pMsg->cmdOpcode ) + { + case HCI_LE_SET_RANDOM_ADDR: + gapProcessRandomAddrComplete( *(pMsg->pReturnParam) ); + break; + + case HCI_LE_READ_BUFFER_SIZE: + safeToDealloc = gapReadBufSizeCmdStatus( + (hciRetParam_LeReadBufSize_t*)pMsg->pReturnParam ); + break; + + case HCI_READ_BDADDR: + safeToDealloc = gapReadBD_ADDRStatus( pMsg->pReturnParam[0], + &(pMsg->pReturnParam[1]) ); + break; + + case HCI_LE_SET_SCAN_ENABLE: + if ( *(pMsg->pReturnParam) == SUCCESS ) + { + break; + } + + /*lint --fallthrough */ + case HCI_LE_SET_SCAN_PARAM: + if ( pfnCentralCBs && pfnCentralCBs->pfnProcessHCICmdEvt ) + { + safeToDealloc = pfnCentralCBs->pfnProcessHCICmdEvt( pMsg->cmdOpcode, pMsg ); + } + + break; + + case HCI_LE_CREATE_CONNECTION_CANCEL: + if ( pfnCentralConnCBs && pfnCentralConnCBs->pfnProcessConnEvt ) + { + safeToDealloc = pfnCentralConnCBs->pfnProcessConnEvt( pMsg->cmdOpcode, + (hciEvt_CommandStatus_t*)pMsg ); + } + + break; + + case HCI_LE_SET_ADV_PARAM: + case HCI_LE_SET_ADV_ENABLE: + case HCI_LE_SET_SCAN_RSP_DATA: + case HCI_LE_SET_ADV_DATA: + if ( pfnPeripheralCBs && pfnPeripheralCBs->pfnProcessHCICmdCompleteEvt ) + { + safeToDealloc = pfnPeripheralCBs->pfnProcessHCICmdCompleteEvt( pMsg ); + } + + break; + + // 2020-01-16 add for CTE related + case HCI_LE_SET_CONNLESS_CTE_TRANS_PARAMETER: + case HCI_LE_SET_CONNLESS_CTE_TRANS_ENABLE: + case HCI_LE_SET_CONNLESS_IQ_SAMPLE_ENABLE: + case HCI_LE_SET_CONNCTE_RECV_PARAMETER: + case HCI_LE_SET_CONN_CTE_TRANSMIT_PARAMETER: + case HCI_LE_CONN_CTE_REQUEST_ENABLE: + case HCI_LE_CONN_CTE_RESPONSE_ENABLE: + case HCI_LE_READ_ANTENNA_INFO: + if ( pfnPeripheralCBs && pfnPeripheralCBs->pfnProcessHCICmdCompleteEvt ) + { + safeToDealloc = pfnPeripheralCBs->pfnProcessHCICmdCompleteEvt( pMsg ); + } + + break; + + default: + safeToDealloc = FALSE; // send this message to the app + break; + } + + return ( safeToDealloc ); +} + +/********************************************************************* + @fn gapProcessCommandStatusEvt + + @brief Process an incoming OSAL HCI Command Status Event. + + @param pMsg - message to process + + @return TRUE if processed and safe to deallocate, FALSE if passed + off to another task. +*/ +static uint8 gapProcessCommandStatusEvt( hciEvt_CommandStatus_t* pMsg ) +{ + uint8 safeToDealloc = TRUE; + + switch ( pMsg->cmdOpcode ) + { + case HCI_LE_CREATE_CONNECTION: + case HCI_LE_CONNECTION_UPDATE: + if ( pfnCentralConnCBs && pfnCentralConnCBs->pfnProcessConnEvt ) + { + safeToDealloc = pfnCentralConnCBs->pfnProcessConnEvt( pMsg->cmdOpcode, pMsg ); + } + + break; + + default: + safeToDealloc = FALSE; // Send to app + break; + } + + return ( safeToDealloc ); +} + +/********************************************************************* + @fn gapRegisterCentral + + @brief Register Central's processing function with GAP task. + + @param pfnCBs - pointer to Central's processing function + + @return none +*/ +void gapRegisterCentral( gapCentralCBs_t* pfnCBs ) +{ + pfnCentralCBs = pfnCBs; +} + +/********************************************************************* + @fn gapRegisterPeripheral + + @brief Register Peripheral's processing function with GAP task. + + @param pfnCBs - pointer to Peripheral's processing function + + @return none +*/ +void gapRegisterPeripheral( gapPeripheralCBs_t* pfnCBs ) +{ + pfnPeripheralCBs = pfnCBs; +} + + + +/**************************************************************************** +****************************************************************************/ + diff --git a/src/lib/ble_host/gatt_client.c b/src/lib/ble_host/gatt_client.c new file mode 100644 index 0000000..c475f3e --- /dev/null +++ b/src/lib/ble_host/gatt_client.c @@ -0,0 +1,2739 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: gatt_client.c + Revised: + Revision: + + Description: This file contains the Generic Attribute Profile Client. + + +**************************************************************************************************/ + + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "linkdb.h" + +#include "gatt.h" +#include "gatt_uuid.h" +#include "gatt_internal.h" + + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ +// Structure to keep Client info +typedef struct +{ + // Info maintained for Client that expecting a response back + uint16 connHandle; // connection message was sent out + uint8 method; // type of response to be received + gattParseRsp_t pfnParseRsp; // function to parse response to be received + uint8 timerId; // response timeout timer id + uint8 taskId; // task to be notified of response + + // GATT Request message + gattMsg_t req; // request message + + // Info maintained for GATT Response message + uint8 numRsps; // number of responses received +} gattClientInfo_t; + +/********************************************************************* + GLOBAL VARIABLES +*/ +// Client Info table (one entry per each physical link) +gattClientInfo_t clientInfoTbl[GATT_MAX_NUM_CONN]; + +// Task to be notified of Notification and Indication messages +uint8 indTaskId = INVALID_TASK_ID; + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static void gattProcessMultiReqs( uint16 connHandle, gattClientInfo_t* pClient, + uint8 method, gattMsg_t* pMsg ); +static uint8 gattProcessFindInfo( gattClientInfo_t* pClient, + uint8 method, gattMsg_t* pMsg ); +static uint8 gattProcessFindByTypeValue( gattClientInfo_t* pClient, + uint8 method, gattMsg_t* pMsg ); +static uint8 gattProcessReadByType( gattClientInfo_t* pClient, + uint8 method, gattMsg_t* pMsg ); +static uint8 gattProcessReadLong( gattClientInfo_t* pClient, + uint8 method, gattMsg_t* pMsg ); +static uint8 gattProcessReadByGrpType( gattClientInfo_t* pClient, + uint8 method, gattMsg_t* pMsg ); +static bStatus_t gattProcessWriteLong( gattClientInfo_t* pClient, + uint8 method, gattMsg_t* pMsg ); +static bStatus_t gattProcessReliableWrites( gattClientInfo_t* pClient, + uint8 method, gattMsg_t* pMsg ); + +static void gattStoreClientInfo( gattClientInfo_t* pClient, gattMsg_t* pReq, + uint8 method, gattParseRsp_t pfnParseRsp, uint8 taskId ); +static gattClientInfo_t* gattFindClientInfo( uint16 connHandle ); +static bStatus_t gattGetClientStatus( uint16 connHandle, gattClientInfo_t** p2pClient ); +static void gattResetClientInfo( gattClientInfo_t* pClient ); +static void gattClientStartTimer( uint8* pData, uint16 timeout, uint8* pTimerId ); + +static bStatus_t gattFindInfo( uint16 connHandle, attFindInfoReq_t* pReq, uint8 taskId ); +static bStatus_t gattFindByTypeValue( uint16 connHandle, attFindByTypeValueReq_t* pReq, + uint8 taskId ); +static bStatus_t gattReadByType( uint16 connHandle, attReadByTypeReq_t* pReq, + uint8 discByCharUUID, uint8 taskId ); +static bStatus_t gattRead( uint16 connHandle, attReadReq_t* pReq, uint8 taskId ); +static bStatus_t gattReadLong( uint16 connHandle, attReadBlobReq_t* pReq, uint8 taskId ); +static bStatus_t gattReadByGrpType( uint16 connHandle, attReadByGrpTypeReq_t* pReq, uint8 taskId ); +static bStatus_t gattWrite( uint16 connHandle, attWriteReq_t* pReq, uint8 taskId ); +static bStatus_t gattWriteLong( uint16 connHandle, gattPrepareWriteReq_t* pReq, uint8 taskId ); + +// Callback functions +static bStatus_t gattClientProcessMsgCB( uint16 connHandle, attPacket_t* pPkt ); +static void gattClientHandleTimerCB( uint8* pData ); +static void gattClientHandleConnStatusCB( uint16 connectionHandle, uint8 changeType ); + +/********************************************************************* + API FUNCTIONS +*/ + +/* ------------------------------------------------------------------- + GATT Client Public APIs +*/ + +/****************************************************************************** + @fn GATT_InitClient + + @brief Initialize the Generic Attribute Profile Client. + + @return SUCCESS: Client initialized successfully. +*/ +bStatus_t GATT_InitClient( void ) +{ + uint8 i; + + // Mark all records as unused + for ( i = 0; i < GATT_MAX_NUM_CONN; i++ ) + { + gattClientInfo_t* pClient = &clientInfoTbl[i]; + + // Initialize connection handle + if ( i == 0 ) + { + pClient->connHandle = LOOPBACK_CONNHANDLE; + } + else + { + pClient->connHandle = INVALID_CONNHANDLE; + } + + // Initialize response info + pClient->method = 0; + pClient->taskId = INVALID_TASK_ID; + pClient->timerId = INVALID_TIMER_ID; + // Initialize GATT Response message info + pClient->numRsps = 0; + // Initialize request info + VOID osal_memset( &(pClient->req), 0, sizeof( gattMsg_t ) ); + } + + // Set up the client's processing function + gattRegisterClient( gattClientProcessMsgCB ); + // Register with Link DB to receive link status change callback + linkDB_Register( gattClientHandleConnStatusCB ); + return ( SUCCESS ); +} + +/****************************************************************************** + @fn GATT_RegisterForInd + + @brief Register to receive incoming ATT Indications or Notifications + of attribute values. + + @param taskId - task to forward indications or notifications to + + @return void +*/ +void GATT_RegisterForInd( uint8 taskId ) +{ + indTaskId = taskId; +} + +/********************************************************************* + @fn GATT_PrepareWriteReq + + @brief The Prepare Write Request is used to request the server to + prepare to write the value of an attribute. + + Note: This function is needed only for GATT testing. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_PrepareWriteReq( uint16 connHandle, attPrepareWriteReq_t* pReq, uint8 taskId ) +{ + uint8 status; + + if ( pReq != NULL ) + { + gattClientInfo_t* pClient; + // Make sure we're allowed to send a new request + status = gattGetClientStatus( connHandle, &pClient ); + + if ( status == SUCCESS ) + { + // Send the request + status = ATT_PrepareWriteReq( connHandle, pReq ); + + if ( status == SUCCESS ) + { + // Store client info + gattStoreClientInfo( pClient, NULL, ATT_PREPARE_WRITE_RSP, + ATT_ParsePrepareWriteRsp, taskId ); + } + } + } + else + { + status = INVALIDPARAMETER; + } + + return ( status ); +} + +/********************************************************************* + @fn GATT_ExecuteWriteReq + + @brief The Execute Write Request is used to request the server to + write or cancel the write of all the prepared values currently + held in the prepare queue from this client. + + Note: This function is needed only for GATT testing. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_ExecuteWriteReq( uint16 connHandle, attExecuteWriteReq_t* pReq, uint8 taskId ) +{ + uint8 status; + + if ( pReq != NULL ) + { + gattClientInfo_t* pClient; + // Make sure we're allowed to send a new request + status = gattGetClientStatus( connHandle, &pClient ); + + if ( status == SUCCESS ) + { + // Send the request + status = ATT_ExecuteWriteReq( connHandle, pReq ); + + if ( status == SUCCESS ) + { + // Store client info + gattStoreClientInfo( pClient, NULL, ATT_EXECUTE_WRITE_RSP, + ATT_ParseExecuteWriteRsp, taskId ); + } + } + } + else + { + status = INVALIDPARAMETER; + } + + return ( status ); +} + +/* ------------------------------------------------------------------- + GATT Client Sub-Procedure APIs +*/ + +/********************************************************************* + @fn GATT_ExchangeMTU + + @brief This sub-procedure is used by the client to set the ATT_MTU + to the maximum possible value that can be supported by both + devices when the client supports a value greater than the + default ATT_MTU for the Attribute Protocol. This sub-procedure + shall only be initiated once during a connection. + + The ATT Exchange MTU Request is used by this sub-procedure. + + If the return status from this function is SUCCESS, the calling + application task will receive an OSAL GATT_MSG_EVENT message. + The type of the message will be either ATT_EXCHANGE_MTU_RSP or + ATT_ERROR_RSP. + + Note: This sub-procedure is complete when either ATT_EXCHANGE_MTU_RSP + (with SUCCESS or bleTimeout status) or ATT_ERROR_RSP (with + SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_ExchangeMTU( uint16 connHandle, attExchangeMTUReq_t* pReq, uint8 taskId ) +{ + gattClientInfo_t* pClient; + uint8 status; + // Make sure we're allowed to send a new request + status = gattGetClientStatus( connHandle, &pClient ); + + if ( status == SUCCESS ) + { + // Send the request + status = ATT_ExchangeMTUReq( connHandle, pReq ); + + if ( status == SUCCESS ) + { + g_attMtuClientServer.clientMTU=pReq->clientRxMTU; + // Store client info + gattStoreClientInfo( pClient, (gattMsg_t*)pReq, ATT_EXCHANGE_MTU_RSP, // update 2020-03-18, the store message follow the style of other function, e.g.gattFindInfo + ATT_ParseExchangeMTURsp, taskId ); // but note that there is a potential risk read uninitial memory when invoke osal_memcpy in gattStoreClientInfo + } + } + + return ( status ); +} + +/********************************************************************* + @fn GATT_DiscAllPrimaryServices + + @brief This sub-procedure is used by a client to discover all + the primary services on a server. + + The ATT Read By Group Type Request is used with the Attribute + Type parameter set to the UUID for "Primary Service". The + Starting Handle is set to 0x0001 and the Ending Handle is + set to 0xFFFF. + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_READ_BY_GRP_TYPE_RSP + or ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_READ_BY_GRP_TYPE_RSP + (with bleProcedureComplete or bleTimeout status) or ATT_ERROR_RSP + (with SUCCESS status) is received by the calling application + task. + + @param connHandle - connection to use + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_DiscAllPrimaryServices( uint16 connHandle, uint8 taskId ) +{ + attReadByGrpTypeReq_t req; + req.startHandle = GATT_MIN_HANDLE; + req.endHandle = GATT_MAX_HANDLE; + req.type.len = ATT_BT_UUID_SIZE; + req.type.uuid[0] = LO_UINT16( GATT_PRIMARY_SERVICE_UUID ); + req.type.uuid[1] = HI_UINT16( GATT_PRIMARY_SERVICE_UUID ); + return ( gattReadByGrpType( connHandle, &req,taskId ) ); +} + +/********************************************************************* + @fn GATT_DiscPrimaryServiceByUUID + + @brief This sub-procedure is used by a client to discover a specific + primary service on a server when only the Service UUID is + known. The specific primary service may exist multiple times + on a server. The primary service being discovered is identified + by the service UUID. + + The ATT Find By Type Value Request is used with the Attribute + Type parameter set to the UUID for "Primary Service" and the + Attribute Value set to the 16-bit Bluetooth UUID or 128-bit + UUID for the specific primary service. The Starting Handle shall + be set to 0x0001 and the Ending Handle shall be set to 0xFFFF. + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_FIND_BY_TYPE_VALUE_RSP + or ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_FIND_BY_TYPE_VALUE_RSP + (with bleProcedureComplete or bleTimeout status) or ATT_ERROR_RSP + (with SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pValue - pointer to value to look for + @param len - length of value + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_DiscPrimaryServiceByUUID( uint16 connHandle, uint8* pValue, + uint8 len, uint8 taskId ) +{ + if ( ( ( len == ATT_BT_UUID_SIZE ) || ( len == ATT_UUID_SIZE ) ) && ( pValue != NULL ) ) + { + attFindByTypeValueReq_t req; + req.startHandle = GATT_MIN_HANDLE; + req.endHandle = GATT_MAX_HANDLE; + req.type.len = ATT_BT_UUID_SIZE; + req.type.uuid[0] = LO_UINT16( GATT_PRIMARY_SERVICE_UUID ); + req.type.uuid[1] = HI_UINT16( GATT_PRIMARY_SERVICE_UUID ); + req.len = len; + VOID osal_memcpy( req.value, pValue, len ); + return ( gattFindByTypeValue( connHandle, &req, taskId ) ); + } + + return ( INVALIDPARAMETER ); +} + +/********************************************************************* + @fn GATT_FindIncludedServices + + @brief This sub-procedure is used by a client to find include + service declarations within a service definition on a + server. The service specified is identified by the service + handle range. + + The ATT Read By Type Request is used with the Attribute + Type parameter set to the UUID for "Included Service". The + Starting Handle is set to starting handle of the specified + service and the Ending Handle is set to the ending handle + of the specified service. + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_READ_BY_TYPE_RSP + or ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_READ_BY_TYPE_RSP + (with bleProcedureComplete or bleTimeout status) or ATT_ERROR_RSP + (with SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param startHandle - starting handle + @param endHandle - end handle + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_FindIncludedServices( uint16 connHandle, uint16 startHandle, + uint16 endHandle, uint8 taskId ) +{ + attReadByTypeReq_t req; + req.startHandle = startHandle; + req.endHandle = endHandle; + req.type.len = ATT_BT_UUID_SIZE; + req.type.uuid[0] = LO_UINT16( GATT_INCLUDE_UUID ); + req.type.uuid[1] = HI_UINT16( GATT_INCLUDE_UUID ); + return ( gattReadByType( connHandle, &req, FALSE, taskId ) ); +} + +/********************************************************************* + @fn GATT_DiscAllChars + + @brief This sub-procedure is used by a client to find all the + characteristic declarations within a service definition on + a server when only the service handle range is known. The + service specified is identified by the service handle range. + + The ATT Read By Type Request is used with the Attribute Type + parameter set to the UUID for "Characteristic". The Starting + Handle is set to starting handle of the specified service and + the Ending Handle is set to the ending handle of the specified + service. + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_READ_BY_TYPE_RSP + or ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_READ_BY_TYPE_RSP + (with bleProcedureComplete or bleTimeout status) or ATT_ERROR_RSP + (with SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param startHandle - starting handle + @param endHandle - end handle + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_DiscAllChars( uint16 connHandle, uint16 startHandle, + uint16 endHandle, uint8 taskId ) +{ + attReadByTypeReq_t req; + req.startHandle = startHandle; + req.endHandle = endHandle; + req.type.len = ATT_BT_UUID_SIZE; + req.type.uuid[0] = LO_UINT16( GATT_CHARACTER_UUID ); + req.type.uuid[1] = HI_UINT16( GATT_CHARACTER_UUID ); + return ( gattReadByType( connHandle, &req, FALSE, taskId ) ); +} + +/********************************************************************* + @fn GATT_DiscCharsByUUID + + @brief This sub-procedure is used by a client to discover service + characteristics on a server when only the service handle + ranges are known and the characteristic UUID is known. + The specific service may exist multiple times on a server. + The characteristic being discovered is identified by the + characteristic UUID. + + The ATT Read By Type Request is used with the Attribute Type + is set to the UUID for "Characteristic" and the Starting + Handle and Ending Handle parameters is set to the service + handle range. + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_READ_BY_TYPE_RSP + or ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_READ_BY_TYPE_RSP + (with bleProcedureComplete or bleTimeout status) or ATT_ERROR_RSP + (with SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_DiscCharsByUUID( uint16 connHandle, attReadByTypeReq_t* pReq, uint8 taskId ) +{ + return ( gattReadByType( connHandle, pReq, TRUE, taskId ) ); +} + +/********************************************************************* + @fn GATT_DiscAllCharDescs + + @brief This sub-procedure is used by a client to find all the + characteristic descriptor�s Attribute Handles and Attribute + Types within a characteristic definition when only the + characteristic handle range is known. The characteristic + specified is identified by the characteristic handle range. + + The ATT Find Information Request is used with the Starting + Handle set to starting handle of the specified characteristic + and the Ending Handle set to the ending handle of the specified + characteristic. The UUID Filter parameter is NULL (zero length). + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_FIND_INFO_RSP or + ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_FIND_INFO_RSP + (with bleProcedureComplete or bleTimeout status) or ATT_ERROR_RSP + (with SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param startHandle - starting handle + @param endHandle - end handle + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_DiscAllCharDescs( uint16 connHandle, uint16 startHandle, + uint16 endHandle, uint8 taskId ) +{ + attFindInfoReq_t req; + req.startHandle = startHandle; + req.endHandle = endHandle; + return ( gattFindInfo( connHandle, &req, taskId ) ); +} + +/********************************************************************* + @fn GATT_ReadCharValue + + @brief This sub-procedure is used to read a Characteristic Value + from a server when the client knows the Characteristic Value + Handle. The ATT Read Request is used with the Attribute Handle + parameter set to the Characteristic Value Handle. The Read + Response returns the Characteristic Value in the Attribute + Value parameter. + + The Read Response only contains a Characteristic Value that + is less than or equal to (ATT_MTU-1) octets in length. If + the Characteristic Value is greater than (ATT_MTU-1) octets + in length, the Read Long Characteristic Value procedure may + be used if the rest of the Characteristic Value is required. + + If the return status from this function is SUCCESS, the calling + application task will receive an OSAL GATT_MSG_EVENT message. + The type of the message will be either ATT_READ_RSP or + ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_READ_RSP + (with SUCCESS or bleTimeout status) or ATT_ERROR_RSP (with + SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_ReadCharValue( uint16 connHandle, attReadReq_t* pReq, uint8 taskId ) +{ + return ( gattRead( connHandle, pReq, taskId ) ); +} + +/********************************************************************* + @fn GATT_ReadUsingCharUUID + + @brief This sub-procedure is used to read a Characteristic Value + from a server when the client only knows the characteristic + UUID and does not know the handle of the characteristic. + + The ATT Read By Type Request is used to perform the sub-procedure. + The Attribute Type is set to the known characteristic UUID and + the Starting Handle and Ending Handle parameters shall be set + to the range over which this read is to be performed. This is + typically the handle range for the service in which the + characteristic belongs. + + If the return status from this function is SUCCESS, the calling + application task will receive an OSAL GATT_MSG_EVENT messages. + The type of the message will be either ATT_READ_BY_TYPE_RSP + or ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_READ_BY_TYPE_RSP + (with SUCCESS or bleTimeout status) or ATT_ERROR_RSP (with + SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_ReadUsingCharUUID( uint16 connHandle, attReadByTypeReq_t* pReq, uint8 taskId ) +{ + return ( gattReadByType( connHandle, pReq, FALSE, taskId ) ); +} + +/********************************************************************* + @fn GATT_ReadLongCharValue + + @brief This sub-procedure is used to read a Characteristic Value from + a server when the client knows the Characteristic Value Handle + and the length of the Characteristic Value is longer than can + be sent in a single Read Response Attribute Protocol message. + + The ATT Read Blob Request is used in this sub-procedure. + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_READ_BLOB_RSP or + ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_READ_BLOB_RSP + (with bleProcedureComplete or bleTimeout status) or ATT_ERROR_RSP + (with SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_ReadLongCharValue( uint16 connHandle, attReadBlobReq_t* pReq, uint8 taskId ) +{ + return ( gattReadLong( connHandle, pReq, taskId ) ); +} + +/********************************************************************* + @fn GATT_ReadMultiCharValues + + @brief This sub-procedure is used to read multiple Characteristic Values + from a server when the client knows the Characteristic Value + Handles. The Attribute Protocol Read Multiple Requests is used + with the Set Of Handles parameter set to the Characteristic Value + Handles. The Read Multiple Response returns the Characteristic + Values in the Set Of Values parameter. + + The ATT Read Multiple Request is used in this sub-procedure. + + If the return status from this function is SUCCESS, the calling + application task will receive an OSAL GATT_MSG_EVENT message. + The type of the message will be either ATT_READ_MULTI_RSP + or ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_READ_MULTI_RSP + (with SUCCESS or bleTimeout status) or ATT_ERROR_RSP (with + SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_ReadMultiCharValues( uint16 connHandle, attReadMultiReq_t* pReq, uint8 taskId ) +{ + gattClientInfo_t* pClient; + uint8 status; + // Make sure we're allowed to send a new request + status = gattGetClientStatus( connHandle, &pClient ); + + if ( status == SUCCESS ) + { + // Send the request + status = ATT_ReadMultiReq( connHandle, pReq ); + + if ( status == SUCCESS ) + { + // Store client info + gattStoreClientInfo( pClient, NULL, ATT_READ_MULTI_RSP, + ATT_ParseReadMultiRsp, taskId ); + } + } + + return ( status ); +} + +/********************************************************************* + @fn GATT_WriteNoRsp + + @brief This sub-procedure is used to write a Characteristic Value + to a server when the client knows the Characteristic Value + Handle and the client does not need an acknowledgement that + the write was successfully performed. This sub-procedure + only writes the first (ATT_MTU-3) octets of a Characteristic + Value. This sub-procedure can not be used to write a long + characteristic; instead the Write Long Characteristic Values + sub-procedure should be used. + + The ATT Write Command is used for this sub-procedure. The + Attribute Handle parameter shall be set to the Characteristic + Value Handle. The Attribute Value parameter shall be set to + the new Characteristic Value. + + No response will be sent to the calling application task for this + sub-procedure. If the Characteristic Value write request is the + wrong size, or has an invalid value as defined by the profile, + then the write will not succeed and no error will be generated + by the server. + + @param connHandle - connection to use + @param pReq - pointer to command to be sent + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_WriteNoRsp( uint16 connHandle, attWriteReq_t* pReq ) +{ + gattClientInfo_t* pClient; + uint8 status; + // Make sure we're allowed to send a new request + status = gattGetClientStatus( connHandle, &pClient ); + + if ( status != bleTimeout ) + { + if ( ( pReq->sig == FALSE ) && ( pReq->cmd == TRUE ) ) + { + status = ATT_WriteReq( connHandle, pReq ); + } + else + { + status = INVALIDPARAMETER; + } + } + + return ( status ); +} + +/********************************************************************* + @fn GATT_SignedWriteNoRsp + + @brief This sub-procedure is used to write a Characteristic Value + to a server when the client knows the Characteristic Value + Handle and the ATT Bearer is not encrypted. This sub-procedure + shall only be used if the Characteristic Properties authenticated + bit is enabled and the client and server device share a bond as + defined in the GAP. + + This sub-procedure only writes the first (ATT_MTU-15) octets + of an Attribute Value. This sub-procedure cannot be used to + write a long Attribute. + + The ATT Write Command is used for this sub-procedure. The + Attribute Handle parameter shall be set to the Characteristic + Value Handle. The Attribute Value parameter shall be set to + the new Characteristic Value authenticated by signing the + value, as defined in the Security Manager. + + No response will be sent to the calling application task for this + sub-procedure. If the authenticated Characteristic Value that is + written is the wrong size, or has an invalid value as defined by + the profile, or the signed value does not authenticate the client, + then the write will not succeed and no error will be generated by + the server. + + @param connHandle - connection to use + @param pReq - pointer to command to be sent + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. + bleLinkEncrypted: Connection is already encrypted. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_SignedWriteNoRsp( uint16 connHandle, attWriteReq_t* pReq ) +{ + gattClientInfo_t* pClient; + uint8 status; + // Make sure we're allowed to send a new request + status = gattGetClientStatus( connHandle, &pClient ); + + if ( status != bleTimeout ) + { + if ( ( pReq->sig == TRUE ) && ( pReq->cmd == TRUE ) ) + { + status = ATT_WriteReq( connHandle, pReq ); + } + else + { + status = INVALIDPARAMETER; + } + } + + return ( status ); +} + +/********************************************************************* + @fn GATT_WriteCharValue + + @brief This sub-procedure is used to write a characteristic value + to a server when the client knows the characteristic value + handle. This sub-procedure only writes the first (ATT_MTU-3) + octets of a characteristic value. This sub-procedure can not + be used to write a long attribute; instead the Write Long + Characteristic Values sub-procedure should be used. + + The ATT Write Request is used in this sub-procedure. The + Attribute Handle parameter shall be set to the Characteristic + Value Handle. The Attribute Value parameter shall be set to + the new characteristic. + + If the return status from this function is SUCCESS, the calling + application task will receive an OSAL GATT_MSG_EVENT message. + The type of the message will be either ATT_WRITE_RSP + or ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_WRITE_RSP + (with SUCCESS or bleTimeout status) or ATT_ERROR_RSP (with + SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_WriteCharValue( uint16 connHandle, attWriteReq_t* pReq, uint8 taskId ) +{ + return ( gattWrite( (connHandle), (pReq), (taskId) ) ); +} + +/********************************************************************* + @fn GATT_WriteLongCharValue + + @brief This sub-procedure is used to write a Characteristic Value to + a server when the client knows the Characteristic Value Handle + but the length of the Characteristic Value is longer than can + be sent in a single Write Request Attribute Protocol message. + + The ATT Prepare Write Request and Execute Write Request are + used to perform this sub-procedure. + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_PREPARE_WRITE_RSP, + ATT_EXECUTE_WRITE_RSP or ATT_ERROR_RSP (if an error occurred on + the server). + + Note: This sub-procedure is complete when either ATT_PREPARE_WRITE_RSP + (with bleTimeout status), ATT_EXECUTE_WRITE_RSP (with SUCCESS + or bleTimeout status), or ATT_ERROR_RSP (with SUCCESS status) + is received by the calling application task. + + Note: The 'pReq->pValue' pointer will be freed when the sub-procedure + is complete. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_WriteLongCharValue( uint16 connHandle, gattPrepareWriteReq_t* pReq, uint8 taskId ) +{ + return ( gattWriteLong( connHandle, pReq, taskId ) ); +} + +/********************************************************************* + @fn GATT_ReliableWrites + + @brief This sub-procedure is used to write a Characteristic Value to + a server when the client knows the Characteristic Value Handle, + and assurance is required that the correct Characteristic Value + is going to be written by transferring the Characteristic Value + to be written in both directions before the write is performed. + This sub-procedure can also be used when multiple values must + be written, in order, in a single operation. + + The sub-procedure has two phases, the first phase prepares the + characteristic values to be written. Once this is complete, + the second phase performs the execution of all of the prepared + characteristic value writes on the server from this client. + + In the first phase, the ATT Prepare Write Request is used. + In the second phase, the attribute protocol Execute Write + Request is used. + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_PREPARE_WRITE_RSP, + ATT_EXECUTE_WRITE_RSP or ATT_ERROR_RSP (if an error occurred on + the server). + + Note: This sub-procedure is complete when either ATT_PREPARE_WRITE_RSP + (with bleTimeout status), ATT_EXECUTE_WRITE_RSP (with SUCCESS + or bleTimeout status), or ATT_ERROR_RSP (with SUCCESS status) + is received by the calling application task. + + Note: The 'pReqs' pointer will be freed when the sub-procedure is + complete. + + @param connHandle - connection to use + @param pReqs - pointer to requests to be sent (must be allocated) + @param numReqs - number of requests in pReq + @param flags - execute write request flags + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_ReliableWrites( uint16 connHandle, attPrepareWriteReq_t* pReqs, + uint8 numReqs, uint8 flags, uint8 taskId ) +{ + uint8 status; + + if ( ( pReqs != NULL ) && ( numReqs > 0 ) ) + { + gattClientInfo_t* pClient; + // Make sure we're allowed to send a new request + status = gattGetClientStatus( connHandle, &pClient ); + + if ( status == SUCCESS ) + { + // Send the first request + status = ATT_PrepareWriteReq( connHandle, &(pReqs[0]) ); + + if ( status == SUCCESS ) + { + gattReliableWritesReq_t reliableWritesReq; + // Save the number Prepare Write Requests to be sent + reliableWritesReq.numReqs = numReqs; + // Save the Prepare Write Requests to be sent + reliableWritesReq.pReqs = pReqs; + // Save the index of the last Prepare Write Request sent + reliableWritesReq.index = 0; + // Set Execute Write Request flags + reliableWritesReq.flags = flags; + // This is a reliable write request + reliableWritesReq.reliable = TRUE; + // Store client info + gattStoreClientInfo( pClient, (gattMsg_t*)&reliableWritesReq, + ATT_PREPARE_WRITE_RSP, ATT_ParsePrepareWriteRsp, taskId ); + } + } + } + else + { + status = INVALIDPARAMETER; + } + + return ( status ); +} + +/********************************************************************* + @fn GATT_ReadCharDesc + + @brief This sub-procedure is used to read a characteristic descriptor + from a server when the client knows the characteristic descriptor + declaration�s Attribute handle. + + The ATT Read Request is used for this sub-procedure. The Read + Request is used with the Attribute Handle parameter set to the + characteristic descriptor handle. The Read Response returns the + characteristic descriptor value in the Attribute Value parameter. + + If the return status from this function is SUCCESS, the calling + application task will receive an OSAL GATT_MSG_EVENT message. + The type of the message will be either ATT_READ_RSP or + ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_READ_RSP + (with SUCCESS or bleTimeout status) or ATT_ERROR_RSP (with + SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_ReadCharDesc( uint16 connHandle, attReadReq_t* pReq, uint8 taskId ) +{ + return ( gattRead( connHandle, pReq, taskId ) ); +} + +/********************************************************************* + @fn GATT_ReadLongCharDesc + + @brief This sub-procedure is used to read a characteristic descriptor + from a server when the client knows the characteristic descriptor + declaration�s Attribute handle and the length of the characteristic + descriptor declaration is longer than can be sent in a single Read + Response attribute protocol message. + + The ATT Read Blob Request is used to perform this sub-procedure. + The Attribute Handle parameter shall be set to the characteristic + descriptor handle. The Value Offset parameter shall be the offset + within the characteristic descriptor to be read. + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_READ_BLOB_RSP or + ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_READ_BLOB_RSP + (with bleProcedureComplete or bleTimeout status) or ATT_ERROR_RSP + (with SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_ReadLongCharDesc( uint16 connHandle, attReadBlobReq_t* pReq, uint8 taskId ) +{ + return ( gattReadLong( connHandle, pReq, taskId ) ); +} + +/********************************************************************* + @fn GATT_WriteCharDesc + + @brief This sub-procedure is used to write a characteristic + descriptor value to a server when the client knows the + characteristic descriptor handle. + + The ATT Write Request is used for this sub-procedure. The + Attribute Handle parameter shall be set to the characteristic + descriptor handle. The Attribute Value parameter shall be + set to the new characteristic descriptor value. + + If the return status from this function is SUCCESS, the calling + application task will receive an OSAL GATT_MSG_EVENT message. + The type of the message will be either ATT_WRITE_RSP + or ATT_ERROR_RSP (if an error occurred on the server). + + Note: This sub-procedure is complete when either ATT_WRITE_RSP + (with SUCCESS or bleTimeout status) or ATT_ERROR_RSP (with + SUCCESS status) is received by the calling application task. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_WriteCharDesc( uint16 connHandle, attWriteReq_t* pReq, uint8 taskId ) +{ + return ( gattWrite( connHandle, pReq, taskId ) ); +} + +/********************************************************************* + @fn GATT_WriteLongCharDesc + + @brief This sub-procedure is used to write a Characteristic Value to + a server when the client knows the Characteristic Value Handle + but the length of the Characteristic Value is longer than can + be sent in a single Write Request Attribute Protocol message. + + The ATT Prepare Write Request and Execute Write Request are + used to perform this sub-procedure. + + If the return status from this function is SUCCESS, the calling + application task will receive multiple OSAL GATT_MSG_EVENT messages. + The type of the messages will be either ATT_PREPARE_WRITE_RSP, + ATT_EXECUTE_WRITE_RSP or ATT_ERROR_RSP (if an error occurred on + the server). + + Note: This sub-procedure is complete when either ATT_PREPARE_WRITE_RSP + (with bleTimeout status), ATT_EXECUTE_WRITE_RSP (with SUCCESS + or bleTimeout status), or ATT_ERROR_RSP (with SUCCESS status) + is received by the calling application task. + + Note: The 'pReq->pValue' pointer will be freed when the sub-procedure + is complete. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_WriteLongCharDesc( uint16 connHandle, gattPrepareWriteReq_t* pReq, uint8 taskId ) +{ + return ( gattWriteLong( connHandle, pReq, taskId ) ); +} + +/* ------------------------------------------------------------------- + GATT Client Internal Functions +*/ + +/********************************************************************* + @fn gattFindInfo + + @brief The Find Information Request is used to obtain the mapping + of attribute handles with their associated types. This + allows a client to discover the list of attributes and + their types on a server. + + Only attributes with attribute handles between and including + the Starting Handle parameter and the Ending Handle parameter + will be returned. To read all attributes, the Starting Handle + parameter shall be set to 0x0001, and the Ending Handle + parameter shall be set to 0xFFFF. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +static bStatus_t gattFindInfo( uint16 connHandle, attFindInfoReq_t* pReq, uint8 taskId ) +{ + uint8 status; + gattClientInfo_t* pClient; + // Make sure we're allowed to send a new request + status = gattGetClientStatus( connHandle, &pClient ); + + if ( status == SUCCESS ) + { + // Send the request + status = ATT_FindInfoReq( connHandle, pReq ); + + if ( status == SUCCESS ) + { + // Store client info + gattStoreClientInfo( pClient, (gattMsg_t*)pReq, ATT_FIND_INFO_RSP, + ATT_ParseFindInfoRsp, taskId ); + } + } + + return ( status ); +} + +/********************************************************************* + @fn gattFindByTypeValue + + @brief The Find By Type Value Request is used to obtain the + handles of attributes that have a 16-bit UUID attribute + type and attribute value. This allows the range of handles + associated with a given attribute to be discovered when + the attribute type determines the grouping of a set of + attributes. + + Note: Generic Attribute Profile defines grouping of + attributes by attribute type. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +static bStatus_t gattFindByTypeValue( uint16 connHandle, attFindByTypeValueReq_t* pReq, + uint8 taskId ) +{ + uint8 status; + gattClientInfo_t* pClient; + // Make sure we're allowed to send a new request + status = gattGetClientStatus( connHandle, &pClient ); + + if ( status == SUCCESS ) + { + // Send the request + status = ATT_FindByTypeValueReq( connHandle, pReq ); + + if ( status == SUCCESS ) + { + // Store client info + gattStoreClientInfo( pClient, (gattMsg_t*)pReq, ATT_FIND_BY_TYPE_VALUE_RSP, + ATT_ParseFindByTypeValueRsp, taskId ); + } + } + + return ( status ); +} + +/********************************************************************* + @fn gattReadByType + + @brief The Read By Type Request is used to obtain the values + of attributes where the attribute type is known but the + handle is not known. + + Only the attributes with attribute handles between and + including the Starting Handle and the Ending Handle with + the attribute type that is the same as the Attribute Type + given will be returned. To search through all attributes, + the starting handle shall be set to 0x0001 and the ending + handle shall be set to 0xFFFF. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param discCharsByUUID - whether it's discover characteristics by UUID + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +static bStatus_t gattReadByType( uint16 connHandle, attReadByTypeReq_t* pReq, + uint8 discCharsByUUID, uint8 taskId ) +{ + uint8 status; + gattClientInfo_t* pClient; + // Make sure we're allowed to send a new request + status = gattGetClientStatus( connHandle, &pClient ); + + if ( status == SUCCESS ) + { + // Send the request + if ( discCharsByUUID ) + { + attReadByTypeReq_t req; + // This is Discover Characteristic by UUID + req.startHandle = pReq->startHandle; + req.endHandle = pReq->endHandle; + // Set Type to Characteristic UUID + req.type.len = ATT_BT_UUID_SIZE; + req.type.uuid[0] = LO_UINT16( GATT_CHARACTER_UUID ); + req.type.uuid[1] = HI_UINT16( GATT_CHARACTER_UUID ); + status = ATT_ReadByTypeReq( connHandle, &req ); + } + else + { + status = ATT_ReadByTypeReq( connHandle, pReq ); + } + + if ( status == SUCCESS ) + { + gattReadByTypeReq_t req; + VOID osal_memcpy( &(req.req), pReq, sizeof( attReadByTypeReq_t ) ); + req.discCharsByUUID = discCharsByUUID; + // Store client info + gattStoreClientInfo( pClient, (gattMsg_t*)&req, ATT_READ_BY_TYPE_RSP, + ATT_ParseReadByTypeRsp, taskId ); + } + } + + return ( status ); +} + +/********************************************************************* + @fn gattRead + + @brief The Read Request is used to request the server to read + the value of an attribute and return its value in a + Read Response. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +static bStatus_t gattRead( uint16 connHandle, attReadReq_t* pReq, uint8 taskId ) +{ + gattClientInfo_t* pClient; + uint8 status; + // Make sure we're allowed to send a new request + status = gattGetClientStatus( connHandle, &pClient ); + + if ( status == SUCCESS ) + { + // Send the request + status = ATT_ReadReq( connHandle, pReq ); + + if ( status == SUCCESS ) + { + // Store client info + gattStoreClientInfo( pClient, NULL, ATT_READ_RSP, ATT_ParseReadRsp, taskId ); + } + } + + return ( status ); +} + +/********************************************************************* + @fn gattReadLong + + @brief This sub-procedure shall be used to read the value of an + attribute from a server when the client knows the attribute + handle and the length of the value of this attribute may be + longer than can be communicated in a single Read Response + attribute protocol message. + + The ATT Read Blob Request is used in this sub-procedure. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +static bStatus_t gattReadLong( uint16 connHandle, attReadBlobReq_t* pReq, uint8 taskId ) +{ + uint8 status; + gattClientInfo_t* pClient; + // Make sure we're allowed to send a new request + status = gattGetClientStatus( connHandle, &pClient ); + + if ( status == SUCCESS ) + { + // Send the request + status = ATT_ReadBlobReq( connHandle, pReq ); + + if ( status == SUCCESS ) + { + // Store client info + gattStoreClientInfo( pClient, (gattMsg_t*)pReq, ATT_READ_BLOB_RSP, + ATT_ParseReadBlobRsp, taskId ); + } + } + + return ( status ); +} + +/********************************************************************* + @fn gattReadByGrpType + + @brief The Read By Group Type Request is used to obtain the values + of attributes where the attribute type is known, the type + of a grouping attribute as defined by a higher layer + specification, but the handle is not known. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +static bStatus_t gattReadByGrpType( uint16 connHandle, attReadByGrpTypeReq_t* pReq, uint8 taskId ) +{ + uint8 status; + gattClientInfo_t* pClient; + // Make sure we're allowed to send a new request + status = gattGetClientStatus( connHandle, &pClient ); + + if ( status == SUCCESS ) + { + // Send the request + status = ATT_ReadByGrpTypeReq( connHandle, pReq ); + + if ( status == SUCCESS ) + { + // Store client info + gattStoreClientInfo( pClient, (gattMsg_t*)pReq, ATT_READ_BY_GRP_TYPE_RSP, + ATT_ParseReadByGrpTypeRsp, taskId ); + } + } + + return ( status ); +} + +/********************************************************************* + @fn gattWrite + + @brief The Write Request is used to request the server to write + the value of an attribute and acknowledge that this has + been achieved in a Write Response. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +static bStatus_t gattWrite( uint16 connHandle, attWriteReq_t* pReq, uint8 taskId ) +{ + uint8 status; + + if ( ( pReq->sig == FALSE ) && ( pReq->cmd == FALSE ) ) + { + gattClientInfo_t* pClient; + // Make sure we're allowed to send a new request + status = gattGetClientStatus( connHandle, &pClient ); + + if ( status == SUCCESS ) + { + // Send the request + status = ATT_WriteReq( connHandle, pReq ); + + if ( status == SUCCESS ) + { + // Store client info + gattStoreClientInfo( pClient, NULL, ATT_WRITE_RSP, + ATT_ParseWriteRsp, taskId ); + } + } + } + else + { + status = INVALIDPARAMETER; + } + + return ( status ); +} + +/********************************************************************* + @fn gattWriteLong + + @brief This sub-procedure shall be used to write a characteristic + value to a server when the client knows the characteristic + value handle but the length of the characteristic value is + longer than can be sent in a single Write Request attribute + protocol message. + + The ATT Prepare Write Request and Execute Write Request are + used to perform this sub-procedure. + + @param connHandle - connection to use + @param pReq - pointer to request to be sent + @param taskId - task to be notified of response + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A response is pending with this server. + bleMemAllocError: Memory allocation error occurred. + bleTimeout: Previous transaction timed out. +*/ +static bStatus_t gattWriteLong( uint16 connHandle, gattPrepareWriteReq_t* pReq, uint8 taskId ) +{ + uint8 status; + gattClientInfo_t* pClient; + // Make sure we're allowed to send a new request + status = gattGetClientStatus( connHandle, &pClient ); + + if ( status == SUCCESS ) + { + attPrepareWriteReq_t req; + // Build Prepare Write Request message + req.handle = pReq->handle; + req.offset = pReq->offset; + + if ( pReq->len > ( gAttMtuSize[connHandle] - 5 ) ) + { + req.len = gAttMtuSize[connHandle] - 5; + } + else + { + // Last part of the attribute value + req.len = pReq->len; + } + + VOID osal_memcpy( req.value, pReq->pValue, req.len ); + // Send the request + status = ATT_PrepareWriteReq( connHandle, &req ); + + if ( status == SUCCESS ) + { + gattWriteLongReq_t writeLongReq; + // This is not a reliable write request + writeLongReq.reliable = FALSE; + // Save the original request + VOID osal_memcpy( &(writeLongReq.req), pReq, sizeof( gattPrepareWriteReq_t ) ); + // Save the offset just sent + writeLongReq.lastOffset = pReq->offset; + // Store client info + gattStoreClientInfo( pClient, (gattMsg_t*)&writeLongReq, ATT_PREPARE_WRITE_RSP, + ATT_ParsePrepareWriteRsp, taskId ); + } + } + + return ( status ); +} + +/********************************************************************* + @fn gattProcessClientMsgCB + + @brief GATT Client message processing function. + + @param connHandle - connection packet was received on + @param pPkt - pointer to received packet + + @return SUCCESS: Message processed successfully + ATT_ERR_UNSUPPORTED_REQ: Unsupported message + ATT_ERR_INVALID_PDU: Invalid PDU + bleMemAllocError: Memory allocation error occurred +*/ +static bStatus_t gattClientProcessMsgCB( uint16 connHandle, attPacket_t* pPkt ) +{ + gattMsg_t msg; + gattClientInfo_t* pClient; + uint8 status; + + // Make sure the incoming message is supported + if ( ( pPkt->sig != ATT_SIG_NOT_INCLUDED ) || ( pPkt->cmd == TRUE ) ) + { + // Unsupported message + return ( ATT_ERR_UNSUPPORTED_REQ ); + } + + // See if this is an indication or notification + if ( ( pPkt->method == ATT_HANDLE_VALUE_NOTI ) || ( pPkt->method == ATT_HANDLE_VALUE_IND ) ) + { + if ( indTaskId == INVALID_TASK_ID ) + { + // Application hasn't registered for it! + return ( ATT_ERR_UNSUPPORTED_REQ ); + } + + // Parse indication + status = ATT_ParseHandleValueInd( pPkt->sig, pPkt->cmd, pPkt->pParams, pPkt->len, (attMsg_t*)&msg ); + + if ( status == SUCCESS ) + { + // Forward the message to upper layer application + status = gattNotifyEvent( indTaskId, connHandle, SUCCESS, pPkt->method, &msg ); + } + + // We're done here + return ( status ); + } + + // Make sure we have the info about the Client that initiated the request + pClient = gattFindClientInfo( connHandle ); + + if ( pClient == NULL ) + { + // Request must have timed out + return ( SUCCESS ); + } + + // Parse the message + if ( pPkt->method == ATT_ERROR_RSP ) + { + status = ATT_ParseErrorRsp( pPkt->pParams, pPkt->len, (attMsg_t*)&msg ); + } + else + { + if ( ( pPkt->method == pClient->method ) && ( pClient->pfnParseRsp != NULL ) ) + { + status = (*pClient->pfnParseRsp)( pPkt->pParams, pPkt->len, (attMsg_t*)&msg ); + } + else + { + // We're not expecting this message! + status = ATT_ERR_INVALID_PDU; + } + } + + // Try to process the response + if ( status == SUCCESS ) + { + // See if this is a response to a GATT sub-procedure with multiple requests + if ( ( pClient->method == ATT_FIND_INFO_RSP ) || + ( pClient->method == ATT_FIND_BY_TYPE_VALUE_RSP ) || + ( pClient->method == ATT_READ_BY_TYPE_RSP ) || + ( pClient->method == ATT_READ_BLOB_RSP ) || + ( pClient->method == ATT_READ_BY_GRP_TYPE_RSP ) || + ( ( pClient->method == ATT_PREPARE_WRITE_RSP ) && + ( pClient->req.gattReliableWritesReq.pReqs != NULL ) ) ) // needed for GATT testing + { + gattProcessMultiReqs( connHandle, pClient, pPkt->method, &msg ); + } + else if ( ( pClient->method == ATT_EXCHANGE_MTU_RSP ) ) // add 2020-03-18 + { +// ATT_MTU_SIZE_UPDATE(MIN(msg.exchangeMTURsp.serverRxMTU, pClient->req.exchangeMTUReq.clientRxMTU)); + ATT_UpdateMtuSize(connHandle, MIN(msg.exchangeMTURsp.serverRxMTU, pClient->req.exchangeMTUReq.clientRxMTU)); + // Forward the message to upper layer application + status = gattNotifyEvent( pClient->taskId, connHandle, SUCCESS, pPkt->method, &msg ); + // Reset client info + gattResetClientInfo( pClient ); + } + else + { + // Forward the message to upper layer application + status = gattNotifyEvent( pClient->taskId, connHandle, SUCCESS, pPkt->method, &msg ); + // Reset client info + gattResetClientInfo( pClient ); + } + } + + return ( status ); +} + +/********************************************************************* + @fn gattProcessMultiReqs + + @brief Process a GATT sub-procedure that could generate multiple + request messages. + + The received response is forwarded up to the application, + or/and the sub-procedure complete is sent to the application + depending on the status returned from the process function: + + Forward Rsp Send Complete Reset Client Info + =========== ============= ================= + Pending Yes* No No + + Failure Yes No Yes + + Success Yes** Yes Yes + + * * = Except Prepare Write Response + * ** = Except Error Response that indicates end of sub-procedure + + @param connHandle - connection event belongs to + @param pClient - pointer to client info + @param method - type of message + @param pMsg - pointer to received message + + @return none +*/ +static void gattProcessMultiReqs( uint16 connHandle, gattClientInfo_t* pClient, + uint8 method, gattMsg_t* pMsg ) +{ + uint8 status; + + switch ( pClient->method ) + { + case ATT_FIND_INFO_RSP: + status = gattProcessFindInfo( pClient, method, pMsg ); + break; + + case ATT_FIND_BY_TYPE_VALUE_RSP: + status = gattProcessFindByTypeValue( pClient, method, pMsg ); + break; + + case ATT_READ_BY_TYPE_RSP: + status = gattProcessReadByType( pClient, method, pMsg ); + break; + + case ATT_READ_BLOB_RSP: + status = gattProcessReadLong( pClient, method, pMsg ); + break; + + case ATT_READ_BY_GRP_TYPE_RSP: + status = gattProcessReadByGrpType( pClient, method, pMsg ); + break; + + case ATT_PREPARE_WRITE_RSP: + if ( pClient->req.gattReliableWritesReq.reliable == TRUE ) + { + status = gattProcessReliableWrites( pClient, method, pMsg ); + } + else + { + status = gattProcessWriteLong( pClient, method, pMsg ); + } + + if ( status != FAILURE ) + { + // Must be an intermediate Prepare Write Response so no need to forward it + return; + } + + break; + + default: + // Should never get here! + status = FAILURE; + break; + } + + // Do not forward an Error Response that indicates the end of a sub-procedure + if ( ( status != SUCCESS ) || + ( method != ATT_ERROR_RSP ) || + ( pMsg->errorRsp.errCode != ATT_ERR_ATTR_NOT_FOUND ) ) + { + // Make sure there's data to be forwarded + if ( ( method != ATT_READ_BY_TYPE_RSP ) || ( pMsg->readByTypeRsp.numPairs > 0 ) ) + { + // Forward the message to upper layer application + VOID gattNotifyEvent( pClient->taskId, connHandle, SUCCESS, method, pMsg ); + } + } + + if ( status == SUCCESS ) + { + // Indicate sub-procedure completion to upper layer application + VOID gattNotifyEvent( pClient->taskId, connHandle, bleProcedureComplete, pClient->method, NULL ); + } + + if ( status != blePending ) + { + // Reset client info + gattResetClientInfo( pClient ); + } +} + +/********************************************************************* + @fn gattProcessFindInfo + + @brief Process a Find Information message. + + @param pClient - pointer to client info + @param method - type of message + @param pMsg - pointer to received + + @return SUCCESS: Sub-procedure completed + FAILURE: Sub-procedure failed + blePending: Sub-procedure still in progress +*/ +static uint8 gattProcessFindInfo( gattClientInfo_t* pClient, + uint8 method, gattMsg_t* pMsg ) +{ + // Response to Find Info Request + if ( method == ATT_FIND_INFO_RSP ) + { + attFindInfoRsp_t* pRsp = &(pMsg->findInfoRsp); // received response + attFindInfoReq_t* pReq = &(pClient->req.findInfoReq); // original request + uint16 endHandle; + pClient->numRsps++; // Increment number of responses + + // Find out the end handle + if ( pRsp->format == ATT_HANDLE_BT_UUID_TYPE ) + { + endHandle = pRsp->info.btPair[pRsp->numInfo-1].handle; + } + else // ATT_HANDLE_UUID_TYPE + { + endHandle = pRsp->info.pair[pRsp->numInfo-1].handle; + } + + // The sub-procedure is complete when the Find Information Response has + // an Attribute Handle that is equal to the Ending Handle of the request. + if ( endHandle < pReq->endHandle ) + { + // Update the start handle + pReq->startHandle = endHandle + 1; + // Send another Find Info Request + VOID ATT_FindInfoReq( pClient->connHandle, pReq ); + VOID osal_CbTimerUpdate( pClient->timerId, (ATT_MSG_TIMEOUT * 1000) ); + return ( blePending ); + } + } + else // ATT_ERROR_RSP + { + attErrorRsp_t* pErrorRsp = &pMsg->errorRsp; + + // See if an error occurred on the server + if ( ( pErrorRsp->errCode != ATT_ERR_ATTR_NOT_FOUND ) || ( pClient->numRsps == 0 ) ) + { + // Should never get here! + return ( FAILURE ); + } + + // The sub-procedure is complete when the Error Response is received and + // the Error Code is set to Attribute Not Found. + } + + // No more attributes can be discovered on the server; this sub-procedure is complete. + return ( SUCCESS ); +} + +/********************************************************************* + @fn gattProcessFindByTypeValue + + @brief Process a Find By Type Value message. + + @param pClient - pointer to client info + @param method - type of message + @param pMsg - pointer to received + + @return SUCCESS: Sub-procedure completed + FAILURE: Sub-procedure failed + blePending: Sub-procedure still in progress +*/ +static uint8 gattProcessFindByTypeValue( gattClientInfo_t* pClient, + uint8 method, gattMsg_t* pMsg ) +{ + // Response to Find By Type Value Request + if ( method == ATT_FIND_BY_TYPE_VALUE_RSP ) + { + attFindByTypeValueRsp_t* pRsp = &(pMsg->findByTypeValueRsp); // received response + attFindByTypeValueReq_t* pReq = &(pClient->req.findByTypeValueReq); // original request + pClient->numRsps++; // Increment number of responses + + // The sub-procedure is complete whe the Find By Type Value Response has + // an Attribute Handle that is equal to the Ending Handle of the request. + if ( pRsp->handlesInfo[pRsp->numInfo-1].handle < pReq->endHandle ) + { + // Update the start handle + pReq->startHandle = pRsp->handlesInfo[pRsp->numInfo-1].handle + 1; + // Send another Find By Type Value Request + VOID ATT_FindByTypeValueReq( pClient->connHandle, pReq ); + VOID osal_CbTimerUpdate( pClient->timerId, (ATT_MSG_TIMEOUT * 1000) ); + return ( blePending ); + } + } + else // ATT_ERROR_RSP + { + attErrorRsp_t* pErrorRsp = &pMsg->errorRsp; + + // See if an error occurred on the server + if ( ( pErrorRsp->errCode != ATT_ERR_ATTR_NOT_FOUND ) || ( pClient->numRsps == 0 ) ) + { + // The service declaration is readable and requires no authentication + // or authorization, therefore insufficient authentication or read not + // permitted errors shall not occur. + // Should never get here! + return ( FAILURE ); + } + + // The sub-procedure is complete when the Error Response is received and + // the Error Code is set to Attribute Not Found. + } + + // No more attributes can be discovered on the server; this sub-procedure is complete. + return ( SUCCESS ); +} + +/********************************************************************* + @fn gattProcessReadByType + + @brief Process a Read By Type message. + + @param pClient - pointer to client info + @param method - type of message + @param pMsg - pointer to received + + @return SUCCESS: Sub-procedure completed + FAILURE: Sub-procedure failed + blePending: Sub-procedure still in progress +*/ +static uint8 gattProcessReadByType( gattClientInfo_t* pClient, + uint8 method, gattMsg_t* pMsg ) +{ + gattReadByTypeReq_t* pReq = &(pClient->req.gattReadByTypeReq); // original request + uint16 lastHandle = GATT_MAX_HANDLE; + + // Response to Read By Type Request + if ( method == ATT_READ_BY_TYPE_RSP ) + { + attReadByTypeRsp_t* pRsp = &(pMsg->readByTypeRsp); // received response + uint8 lastIdx = ( pRsp->numPairs - 1 ) * pRsp->len; + pClient->numRsps++; // Increment number of responses + // Remember the last handle + lastHandle = BUILD_UINT16( pRsp->dataList[lastIdx], pRsp->dataList[lastIdx+1] ); + + // See if this is Discover Characteristics by UUID + if ( pReq->discCharsByUUID == TRUE ) + { + uint8 matchedLen = 0; + uint8 dataLen = pRsp->numPairs * pRsp->len; + // Let's assume no match will be found! + pRsp->numPairs = 0; + + // A list of Attribute Handle and Attribute Value pairs is returned. Each + // Attribute Value in the list is the Attribute Value for the characteristic + // declaration. The Attribute Value contains the characteristic properties, + // Characteristic Value Handle and characteristic UUID. + for ( uint8 i = 0; i < dataLen; i += pRsp->len ) + { + // Check the Attribute Value for each Attribute Handle and Attribute + // Value pairs for a matching characteristic UUID. + if ( ATT_CompareUUID( pReq->req.type.uuid, pReq->req.type.len, + &(pRsp->dataList[i+5]), pRsp->len-5 ) ) + { + if ( i != matchedLen ) + { + // Keep the matched attribute handle-value pair + VOID osal_memcpy( &(pRsp->dataList[matchedLen]), + &(pRsp->dataList[i]), pRsp->len ); + } + + // Increment the length of data matched so far + matchedLen += pRsp->len; + // Increment the number of the handle-value pairs found so far + pRsp->numPairs++; + } + } // for + } + } + else // ATT_ERROR_RSP + { + attErrorRsp_t* pErrorRsp = &pMsg->errorRsp; + + // See if an error occurred on the server + if ( ( pErrorRsp->errCode != ATT_ERR_ATTR_NOT_FOUND ) || ( pClient->numRsps == 0 ) ) + { + // The service, include and characteristic declarations are readable and + // require no authentication or authorization, therefore insufficient + // authentication or read not permitted errors shall not occur. + if ( !gattServiceType( pReq->req.type ) && + !gattIncludeType( pReq->req.type ) && + !gattCharacterType( pReq->req.type ) && + ( pErrorRsp->errCode == ATT_ERR_READ_NOT_PERMITTED || + pErrorRsp->errCode == ATT_ERR_INSUFFICIENT_AUTHEN || + pErrorRsp->errCode == ATT_ERR_INSUFFICIENT_AUTHOR || + pErrorRsp->errCode == ATT_ERR_INSUFFICIENT_ENCRYPT || + pErrorRsp->errCode == ATT_ERR_INSUFFICIENT_KEY_SIZE ) ) + { + // An attribute of the given type has been discovered but the value + // cannot be read. We should continue discovering. + pClient->numRsps++; // Increment number of responses + // Remember the last handle + lastHandle = pErrorRsp->handle; + } + else + { + // Should never get here! + return ( FAILURE ); + } + } + + // The sub-procedure is complete when the Error Response is received + // with the Error Code set to Attribute Not Found. + } + + // More attributes wish to be discovered? + if ( lastHandle != GATT_MAX_HANDLE ) + { + // The sub-procedure is complete whe the Read By Type Response has an + // Attribute Handle that is equal to the Ending Handle of the request. + if ( lastHandle < pReq->req.endHandle ) + { + // Update the start handle + pReq->req.startHandle = lastHandle + 1; + + // Send another Read By Type Request + if ( pReq->discCharsByUUID == TRUE ) + { + attReadByTypeReq_t req; + // This is Discover Characteristic by UUID + req.startHandle = pReq->req.startHandle; + req.endHandle = pReq->req.endHandle; + // Set Type to Characteristic UUID + req.type.len = ATT_BT_UUID_SIZE; + req.type.uuid[0] = LO_UINT16( GATT_CHARACTER_UUID ); + req.type.uuid[1] = HI_UINT16( GATT_CHARACTER_UUID ); + VOID ATT_ReadByTypeReq( pClient->connHandle, &req ); + } + else + { + VOID ATT_ReadByTypeReq( pClient->connHandle, &pReq->req ); + } + + VOID osal_CbTimerUpdate( pClient->timerId, (ATT_MSG_TIMEOUT * 1000) ); + return ( blePending ); + } + } + + // All attributes with the given type have been discovered; this sub-procedure is complete. + return ( SUCCESS ); +} + +/********************************************************************* + @fn gattProcessReadLong + + @brief Process Read Long message. + + @param pClient - pointer to client info + @param method - type of message + @param pMsg - pointer to received + + @return SUCCESS: Sub-procedure completed + FAILURE: Sub-procedure failed + blePending: Sub-procedure still in progress +*/ +static uint8 gattProcessReadLong( gattClientInfo_t* pClient, + uint8 method, gattMsg_t* pMsg ) +{ + // Response to Read Blob Request + if ( method == ATT_READ_BLOB_RSP ) + { + attReadBlobReq_t* pReq = &(pClient->req.readBlobReq); // original request + attReadBlobRsp_t* pRsp = &pMsg->readBlobRsp; // received response + pClient->numRsps++; // Increment number of responses + + // The Read Blob Request is repeated until the Read Blob Response�s + // Part Attribute Value parameter is shorter than (ATT_MTU-1). + if ( pRsp->len >= ( gAttMtuSize[pClient->connHandle] - 1 ) ) + { + // Update the offset. The offset for subsequent Read Blob Requests is + // the next octet that has yet to be read. + pReq->offset += pRsp->len; + // Try to read the next part of the attribute value + VOID ATT_ReadBlobReq( pClient->connHandle, pReq ); + VOID osal_CbTimerUpdate( pClient->timerId, (ATT_MSG_TIMEOUT * 1000) ); + return ( blePending ); + } + } + else // ATT_ERROR_RSP + { + attErrorRsp_t* pErrorRsp = &pMsg->errorRsp; + + // See if an error occurred on the server + if ( ( pErrorRsp->errCode != ATT_ERR_INVALID_OFFSET ) || ( pClient->numRsps == 0 ) ) + { + // Should never get here! + return ( FAILURE ); + } + + // The sub-procedure is complete when the Error Response is received + // with the Error Code set to Invalid Offset. + } + + // This sub-procedure is complete; send the response up to application. + return ( SUCCESS ); +} + +/********************************************************************* + @fn gattProcessReadByGrpType + + @brief Process a Read By Group Type message. + + @param pClient - pointer to client info + @param method - type of message + @param pMsg - pointer to received + + @return SUCCESS: Sub-procedure completed + FAILURE: Sub-procedure failed + blePending: Sub-procedure still in progress +*/ +static uint8 gattProcessReadByGrpType( gattClientInfo_t* pClient, + uint8 method, gattMsg_t* pMsg ) +{ + uint16 endGrpHandle; + + // Response to Read By Group Type Request + if ( method == ATT_READ_BY_GRP_TYPE_RSP ) + { + attReadByGrpTypeRsp_t* pRsp = &(pMsg->readByGrpTypeRsp); // received response + uint8 lastGrpIdx = ( pRsp->numGrps - 1 ) * pRsp->len; + pClient->numRsps++; // Increment number of responses + // Remember the end group handle + endGrpHandle = BUILD_UINT16( pRsp->dataList[lastGrpIdx+2], pRsp->dataList[lastGrpIdx+3] ); + } + else // ATT_ERROR_RSP + { + attErrorRsp_t* pErrorRsp = &pMsg->errorRsp; + + // See if an error occurred on the server + if ( ( pErrorRsp->errCode != ATT_ERR_ATTR_NOT_FOUND ) || ( pClient->numRsps == 0 ) ) + { + // The service declaration is readable and requires no authentication + // or authorization, therefore insufficient authentication or read not + // permitted errors shall not occur. + // Should never get here! + return ( FAILURE ); + } + + // The sub-procedure is complete when the Error Response is received and the + // Error Code is set to Attribute Not Found. + endGrpHandle = GATT_MAX_HANDLE; + } + + // More attributes wish to be discovered? + if ( endGrpHandle != GATT_MAX_HANDLE ) + { + attReadByGrpTypeReq_t* pReq = &(pClient->req.readByGrpTypeReq); // original request + // Update the start handle + pReq->startHandle = endGrpHandle + 1; + + // See if there're more attributes to be discovered + if ( pReq->startHandle <= pReq->endHandle ) + { + // Send another Read By Type Request + VOID ATT_ReadByGrpTypeReq( pClient->connHandle, pReq ); + VOID osal_CbTimerUpdate( pClient->timerId, (ATT_MSG_TIMEOUT * 1000) ); + return ( blePending ); + } + } + + // All attributes with the given type have been discovered; this sub-procedure is complete. + return ( SUCCESS ); +} + +/********************************************************************* + @fn gattProcessWriteLong + + @brief Process Write Long message. + + @param pClient - pointer to client info + @param method - type of message + @param pMsg - pointer to received + + @return SUCCESS: Sub-procedure completed + FAILURE: Sub-procedure failed + blePending: Sub-procedure still in progress +*/ +static bStatus_t gattProcessWriteLong( gattClientInfo_t* pClient, + uint8 method, gattMsg_t* pMsg ) +{ + attExecuteWriteReq_t executeReq; + VOID pMsg; // Not used here + + if ( method == ATT_PREPARE_WRITE_RSP ) + { + gattWriteLongReq_t* pReq = &(pClient->req.gattWriteLongReq); // original GATT request + uint16 transferredLen; + // Note: The values in the Prepare Write Response do not need to be + // verified in this sub-procedure. + // The offset for subsequent Prepare Write Requests is the next octet + // that has yet to be written. + pReq->lastOffset += ( gAttMtuSize[pClient->connHandle] - 5 ); // last packet could be less than this but it's ok + // The Prepare Write Request is repeated until the complete Characteristic + // Value has been transferred. + transferredLen = pReq->lastOffset - pReq->req.offset; + + if ( transferredLen < pReq->req.len ) + { + attPrepareWriteReq_t req; + + // Build the next Prepare Write Request + if ( ( pReq->req.len - transferredLen ) > ( gAttMtuSize[pClient->connHandle] - 5 ) ) + { + req.len = gAttMtuSize[pClient->connHandle] - 5; + } + else + { + // Last part of the attribute value + req.len = pReq->req.len - transferredLen; + } + + req.handle = pReq->req.handle; + req.offset = pReq->lastOffset; + VOID osal_memcpy( req.value, &(pReq->req.pValue[transferredLen]), req.len ); + // Try to send the next Prepare Write Request + VOID ATT_PrepareWriteReq( pClient->connHandle, &req ); + VOID osal_CbTimerUpdate( pClient->timerId, (ATT_MSG_TIMEOUT * 1000) ); + return ( blePending ); + } + else + { + // All Prepare Write Requests have been sent successfully. Immediately + // write all pending prepared values by transmitting an Execute Write + // Request with the Flags parameter set to 0x01. + executeReq.flags = ATT_WRITE_PREPARED_VALUES; + } + } + else // ATT_ERROR_RSP or error in ATT_PREPARE_WRITE_RSP + { + // An error has occured. Abort the sub-procedure by sending an Execute + // Write Request with the Flags parameter set to 0x00 to cancel all + // prepared writes. + executeReq.flags = ATT_CANCEL_PREPARED_WRITES; + } + + // The first phase is complete. Start the second phase by sending an + // Execute Write Request. Once the Execute Write Response has been + // received by the client, this procedure is complete. + VOID ATT_ExecuteWriteReq( pClient->connHandle, &executeReq ); + + if ( method == ATT_ERROR_RSP ) + { + // Send the response up to application; this sub-procedure is complete. + return ( FAILURE ); + } + + // Wait for the Execute Write Response + VOID osal_CbTimerUpdate( pClient->timerId, (ATT_MSG_TIMEOUT * 1000) ); + // Update the response info for this client + pClient->method = ATT_EXECUTE_WRITE_RSP; + pClient->pfnParseRsp = ATT_ParseExecuteWriteRsp; + return ( blePending ); +} + +/********************************************************************* + @fn gattProcessReliableWrites + + @brief Process Relaible Writes message. + + @param pClient - pointer to client info + @param method - type of message + @param pMsg - pointer to received + + @return SUCCESS: Sub-procedure completed + FAILURE: Sub-procedure failed + blePending: Sub-procedure still in progress +*/ +static bStatus_t gattProcessReliableWrites( gattClientInfo_t* pClient, + uint8 method, gattMsg_t* pMsg ) +{ + gattReliableWritesReq_t* pReq = &(pClient->req.gattReliableWritesReq); // original request + attExecuteWriteReq_t executeReq; + + if ( method == ATT_PREPARE_WRITE_RSP ) + { + attPrepareWriteRsp_t* pRsp = &(pMsg->prepareWriteRsp); + + // Check the attribute value in the response with the attribute value + // that was sent in the Prepare Write Request + if ( ( pReq->pReqs[pReq->index].handle == pRsp->handle ) && + ( pReq->pReqs[pReq->index].offset == pRsp->offset ) && + ( pReq->pReqs[pReq->index].len == pRsp->len ) && + ( osal_memcmp( pReq->pReqs[pReq->index].value, pRsp->value, pRsp->len ) ) ) + { + // See if all Prepare Write Requests have been sent + if ( ++pReq->index < pReq->numReqs ) + { + // Try to send the next Write Prepare Request + VOID ATT_PrepareWriteReq( pClient->connHandle, &(pReq->pReqs[pReq->index]) ); + VOID osal_CbTimerUpdate( pClient->timerId, (ATT_MSG_TIMEOUT * 1000) ); + return ( blePending ); + } + else + { + // All Prepare Write Requests have been sent successfully. Immediately + // write all pending prepared values by transmitting an Execute Write + // Request with the Flags parameter set to 0x01. + executeReq.flags = pReq->flags; + } + } + else + { + // The attribute value has been corrupted during transmission. Abort + // the sub-procedure by sending an Execute Write Request with the Flags + // parameter set to 0x00 to cancel all prepared writes. + executeReq.flags = ATT_CANCEL_PREPARED_WRITES; + } + } + else // ATT_ERROR_RSP + { + // An error has occured. Abort the sub-procedure by sending an Execute + // Write Request with the Flags parameter set to 0x00 to cancel all + // prepared writes. + executeReq.flags = ATT_CANCEL_PREPARED_WRITES; + } + + // The first phase is complete. Start the second phase by sending an + // Execute Write Request. Once the Execute Write Response has been + // received by the client, this procedure is complete. + VOID ATT_ExecuteWriteReq( pClient->connHandle, &executeReq ); + + if ( method == ATT_ERROR_RSP ) + { + // Send the response up to application; this sub-procedure is complete. + return ( FAILURE ); + } + + // Wait for the Execute Write Response + VOID osal_CbTimerUpdate( pClient->timerId, (ATT_MSG_TIMEOUT * 1000) ); + // Update the response info for this client + pClient->method = ATT_EXECUTE_WRITE_RSP; + pClient->pfnParseRsp = ATT_ParseExecuteWriteRsp; + return ( blePending ); +} + +/********************************************************************* + @fn gattStoreClientInfo + + @brief Store client info. + + @param connHandle ? connection to use + @param pMsg ? pointer to message to be sent + @param method ? response to expect + @param pfnParseRsp ? parse function for response + @param taskId ? task to be notified of response + + @return none +*/ +static void gattStoreClientInfo( gattClientInfo_t* pClient, gattMsg_t* pReq, + uint8 method, gattParseRsp_t pfnParseRsp, uint8 taskId ) +{ + if ( taskId != INVALID_TASK_ID ) + { + // Start a timeout timer for the response + gattClientStartTimer( (uint8*)pClient, ATT_MSG_TIMEOUT, &pClient->timerId ); + // Store task id to forward the response to + pClient->taskId = taskId; + // Store the response method + pClient->method = method; + // Store parse function for the response + pClient->pfnParseRsp = pfnParseRsp; + + // Store info for GATT request + if ( pReq != NULL ) + { + VOID osal_memcpy( &(pClient->req), pReq, sizeof( gattMsg_t ) ); + } + + // else pClient->req is already zero'ed out + } +} + +/********************************************************************* + @fn gattGetClientStatus + + @brief Get the status for a given client. + + @param connHandle - client connection to server + @param p2pClient - pointer to pointer to client info + + @return SUCCESS: No response pending + INVALIDPARAMETER: Invalid connection handle + blePending: Response pending + bleTimeout: Previous transaction timed out +*/ +static bStatus_t gattGetClientStatus( uint16 connHandle, gattClientInfo_t** p2pClient ) +{ + gattClientInfo_t* pClient; + pClient = gattFindClientInfo( connHandle ); + + if ( pClient != NULL ) + { + if ( p2pClient != NULL ) + { + *p2pClient = pClient; + } + + // Make sure there's no response pending or timed out with this server + return ( TIMER_STATUS( pClient->timerId ) ); + } + + // Connection handle not found + return ( INVALIDPARAMETER ); +} + +/********************************************************************* + @fn gattFindClientInfo + + @brief Find the client info. Uses the connection handle to search + the client info table. + + @param connHandle - connection handle. + + @return a pointer to the found item. NULL, otherwise. +*/ +static gattClientInfo_t* gattFindClientInfo( uint16 connHandle ) +{ + uint8 i; + + for ( i = 0; i < GATT_MAX_NUM_CONN; i++ ) + { + if ( clientInfoTbl[i].connHandle == connHandle ) + { + // Entry found + return ( &clientInfoTbl[i] ); + } + } + + return ( (gattClientInfo_t*)NULL ); +} + +/********************************************************************* + @fn gattResetClientInfo + + @brief Reset the client info. + + @param pClient - pointer to client info. + + @return none +*/ +static void gattResetClientInfo( gattClientInfo_t* pClient ) +{ + // First cancel the response timer + gattStopTimer( &pClient->timerId ); + + // Free the buffer provided by the application + if ( ( pClient->method == ATT_PREPARE_WRITE_RSP ) || + ( pClient->method == ATT_EXECUTE_WRITE_RSP ) ) + { + uint8* pBuf; + + if ( pClient->req.gattReliableWritesReq.reliable == TRUE ) + { + pBuf = (uint8*)(pClient->req.gattReliableWritesReq.pReqs); + } + else + { + pBuf = pClient->req.gattWriteLongReq.req.pValue; + } + + if ( pBuf != NULL ) + { + osal_mem_free( pBuf ); + } + } + + // Reset response info + pClient->method = 0; + pClient->taskId = INVALID_TASK_ID; + pClient->numRsps = 0; + // Reset request info + VOID osal_memset( &(pClient->req), 0, sizeof( gattMsg_t ) ); +} + +/********************************************************************* + @fn gattClientStartTimer + + @brief Start a client timer to expire in n seconds. + + @param pData - data to be passed in to callback function + @param timeout - in seconds. + @param pTimerId - will point to new timer Id (if not null) + + @return none +*/ +static void gattClientStartTimer( uint8* pData, uint16 timeout, uint8* pTimerId ) +{ + gattStartTimer( gattClientHandleTimerCB, pData, timeout, pTimerId ); +} + +/********************************************************************* + @fn gattClientHandleTimerCB + + @brief Handle a callback for a timer that has just expired. + + @param pData - pointer to timer data + + @return none +*/ +static void gattClientHandleTimerCB( uint8* pData ) +{ + gattClientInfo_t* pClient = (gattClientInfo_t*)pData; + + // Response timer has expired + if ( ( pClient != NULL ) && ( pClient->timerId != INVALID_TIMER_ID ) ) + { + // Notify the application about the timeout + VOID gattNotifyEvent( pClient->taskId, pClient->connHandle, bleTimeout, pClient->method, NULL ); + + if ( pClient->method == ATT_EXECUTE_WRITE_REQ ) + { + attExecuteWriteReq_t req; + // Cancel all prepared writes + req.flags = ATT_CANCEL_PREPARED_WRITES; + VOID ATT_ExecuteWriteReq( pClient->connHandle, &req ); + } + + // Timer has expired. If a transaction has not completed before it times + // out, then this transaction shall be considered to have failed. No more + // attribute protocol requests, commands, indications or notifications + // shall be sent to the target device on this ATT Bearer. +//ZQ 20181216 for test + //pClient->timerId = TIMEOUT_TIMER_ID; + // Reset client info + gattResetClientInfo( pClient ); + } +} + +/********************************************************************* + @fn gattClientHandleConnStatusCB + + @brief GATT link status change handler function. + + @param connHandle - connection handle + @param changeType - type of change + + @return none +*/ +static void gattClientHandleConnStatusCB( uint16 connHandle, uint8 changeType ) +{ + gattClientInfo_t* pClient = NULL; + + // Check to see if this is loopback connection + if ( connHandle == LOOPBACK_CONNHANDLE ) + { + return; + } + + if ( changeType == LINKDB_STATUS_UPDATE_NEW ) + { + // A new connection has been made + pClient = gattFindClientInfo( connHandle ); + + if ( pClient == NULL ) + { + // Entry not found; add it to the server table + pClient = gattFindClientInfo( INVALID_CONNHANDLE ); + + if ( pClient != NULL ) + { + // Empty entry found + pClient->connHandle = connHandle; + } + } + + // We're done here! + return; + } + + if ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) + { + pClient = gattFindClientInfo( connHandle ); + + if ( pClient != NULL ) + { + // Entry found; remove it from the client table + pClient->connHandle = INVALID_CONNHANDLE; + } + } + else if ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) + { + // Check to see if the connection has dropped + if ( !linkDB_Up( connHandle ) ) + { + pClient = gattFindClientInfo( connHandle ); + } + } + + // Connection has dropped + if ( pClient != NULL ) + { + if ( pClient->timerId != INVALID_TIMER_ID ) + { + if ( pClient->timerId != TIMEOUT_TIMER_ID ) + { + // Notify the application about the link disconnect + VOID gattNotifyEvent( pClient->taskId, connHandle, bleNotConnected, + pClient->method, NULL ); + } + + // Reset client info + gattResetClientInfo( pClient ); + // Just in case if we've timed out waiting for a response + pClient->timerId = INVALID_TIMER_ID; + } + } +} + + +/**************************************************************************** +****************************************************************************/ diff --git a/src/lib/ble_host/gatt_server.c b/src/lib/ble_host/gatt_server.c new file mode 100644 index 0000000..da762c3 --- /dev/null +++ b/src/lib/ble_host/gatt_server.c @@ -0,0 +1,1567 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: gatt_server.c + Revised: + Revision: + + Description: This file contains the Generic Attribute Profile Server. + + +**************************************************************************************************/ + + +/********************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "linkdb.h" + +#include "gatt.h" +#include "gatt_uuid.h" +#include "gatt_internal.h" + + +/********************************************************************* + MACROS +*/ +// Parse and process request function pointers +#define gattParseReq( method ) ( serverReqTbl[((method)/2)-1].pfnParseReq ) +#define gattProcessReq( method ) ( serverReqTbl[((method)/2)-1].pfnProcessReq ) + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ +// Service record list item +typedef struct _attAttrList +{ + struct _attAttrList* next; // pointer to next service record + gattService_t service; // service record +} gattServiceList_t; + +// Structure to keep Attribute Server info +typedef struct +{ + // Info maintained for Handle Value Confirmation message + uint16 connHandle; // connection message was sent on + uint8 timerId; // confirmation timeout timer id + uint8 taskId; // task to be notified of confirmation +} gattServerInfo_t; + +// Structure to keep the Parse and Process function pointers for Requests +typedef struct +{ + gattParseReq_t pfnParseReq; // function to parse an incoming request + gattProcessReq_t pfnProcessReq; // function to process an incoming request +} gattHandleReq_t; + +/********************************************************************* + GLOBAL VARIABLES +*/ + + +// Server Info table (one entry per each physical link) +gattServerInfo_t serverInfoTbl[GATT_MAX_NUM_CONN]; + +// Task to be notified of requests +uint8 reqTaskId = INVALID_TASK_ID; + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ +// GATT Service List +static gattServiceList_t* pServiceList = NULL; + +// Next available attribute handle +static uint16 nextHandle = GATT_MIN_HANDLE; + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static bStatus_t gattProcessExchangeMTUReq( uint16 connHandle, attMsg_t* pMsg ); +static bStatus_t gattProcessFindInfoReq( uint16 connHandle, attMsg_t* pMsg ); +static bStatus_t gattProcessFindByTypeValueReq( uint16 connHandle, attMsg_t* pMsg ); +static bStatus_t gattProcessReadByTypeReq( uint16 connHandle, attMsg_t* pMsg ); +static bStatus_t gattProcessReadReq( uint16 connHandle, attMsg_t* pMsg ); +static bStatus_t gattProcessReadMultiReq( uint16 connHandle, attMsg_t* pMsg ); +static bStatus_t gattProcessReadByGrpTypeReq( uint16 connHandle, attMsg_t* pMsg ); +static bStatus_t gattProcessWriteReq( uint16 connHandle, attMsg_t* pMsg ); +static bStatus_t gattProcessExecuteWriteReq( uint16 connHandle, attMsg_t* pMsg ); + +static void gattStoreServerInfo( gattServerInfo_t* pServer, uint8 taskId ); +static bStatus_t gattGetServerStatus( uint16 connHandle, gattServerInfo_t** p2pServer ); +static gattServerInfo_t* gattFindServerInfo( uint16 connHandle ); +static void gattResetServerInfo( gattServerInfo_t* pServer ); +static void gattServerStartTimer( uint8* pData, uint16 timeout, uint8* pTimerId ); +static uint16 gattServiceLastHandle( uint16 handle ); + +// Callback functions +static bStatus_t gattServerProcessMsgCB( uint16 connHandle, attPacket_t* pPkt ); +static void gattServerHandleTimerCB( uint8* pData ); +static void gattServerHandleConnStatusCB( uint16 connectionHandle, uint8 changeType ); + +/********************************************************************* + Server Handle Request Table +*/ +static CONST gattHandleReq_t serverReqTbl[] = +{ + { ATT_ParseExchangeMTUReq, gattProcessExchangeMTUReq }, /* ATT_EXCHANGE_MTU_REQ */ + { ATT_ParseFindInfoReq, gattProcessFindInfoReq }, /* ATT_FIND_INFO_REQ */ + { ATT_ParseFindByTypeValueReq, gattProcessFindByTypeValueReq }, /* ATT_FIND_BY_TYPE_VALUE_REQ */ + { ATT_ParseReadByTypeReq, gattProcessReadByTypeReq }, /* ATT_READ_BY_TYPE_REQ */ + { ATT_ParseReadReq, gattProcessReadReq }, /* ATT_READ_REQ */ + { ATT_ParseReadBlobReq, gattProcessReadReq }, /* ATT_READ_BLOB_REQ */ + { ATT_ParseReadMultiReq, gattProcessReadMultiReq }, /* ATT_READ_MULTI_REQ */ + { ATT_ParseReadByTypeReq, gattProcessReadByGrpTypeReq }, /* ATT_READ_BY_GRP_TYPE_REQ */ + { ATT_ParseWriteReq, gattProcessWriteReq }, /* ATT_WRITE_REQ */ + { NULL, NULL }, /* Undefined */ + { ATT_ParsePrepareWriteReq, gattProcessWriteReq }, /* ATT_PREPARE_WRITE_REQ */ + { ATT_ParseExecuteWriteReq, gattProcessExecuteWriteReq } /* ATT_EXECUTE_WRITE_REQ */ +}; + +/********************************************************************* + API FUNCTIONS +*/ + +/* ------------------------------------------------------------------- + GATT Server Public APIs +*/ + +/****************************************************************************** + @fn GATT_InitServer + + @brief Initialize the Generic Attribute Profile Server. + + @return SUCCESS: Server initialized successfully. +*/ +bStatus_t GATT_InitServer( void ) +{ + // Mark all Server records as unused + for ( uint8 i = 0; i < GATT_MAX_NUM_CONN; i++ ) + { + gattServerInfo_t* pServer = &serverInfoTbl[i]; + + // Initialize connection handle + if ( i == 0 ) + { + pServer->connHandle = LOOPBACK_CONNHANDLE; + } + else + { + pServer->connHandle = INVALID_CONNHANDLE; + } + + // Initialize Handle Value Confirmation info + pServer->taskId = INVALID_TASK_ID; + pServer->timerId = INVALID_TIMER_ID; + } + + // Set up the server's processing function + gattRegisterServer( gattServerProcessMsgCB ); + // Register with Link DB to receive link status change callback + linkDB_Register( gattServerHandleConnStatusCB ); + return ( SUCCESS ); +} + +/****************************************************************************** + @fn GATT_RegisterService + + @brief Register a service attribute list with the GATT Server. A service + is composed of characteristics or references to other services. + Each characteristic contains a value and may contain optional + information about the value. There are two types of services: + primary service and secondary service. + + A service definition begins with a service declaration and ends + before the next service declaration or the maximum Attribute Handle. + + A characteristic definition begins with a characteristic declaration + and ends before the next characteristic or service declaration or + maximum Attribute Handle. + + The attribute server will only keep a pointer to the attribute + list, so the calling application will have to maintain the code + and RAM associated with this list. + + @param pService - pointer to service attribute list to be registered + + @return SUCCESS: Service registered successfully. + INVALIDPARAMETER: Invalid service field. + FAILURE: Not enough attribute handles available. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t GATT_RegisterService( gattService_t* pService ) +{ + gattServiceList_t* pNewItem; + + // Make sure the service attribute list begins with a service declaration + if ( ( pService->numAttrs == 0 ) || !gattServiceType( pService->attrs[0].type ) ) + { + return ( INVALIDPARAMETER ); + } + + // Make sure we have enough attribute handles available for this service + if ( ( nextHandle == 0 ) || ( pService->numAttrs > ( GATT_MAX_HANDLE - nextHandle ) + 1 ) ) + { + return ( FAILURE ); + } + + // Allocate space for the new service item + pNewItem = (gattServiceList_t*)osal_mem_alloc( sizeof( gattServiceList_t ) ); + + if ( pNewItem == NULL ) + { + // Not enough memory + return ( bleMemAllocError ); + } + + // Assign attribute handles + for ( uint16 i = 0; i < pService->numAttrs; i++ ) + { + pService->attrs[i].handle = nextHandle++; + } + + // Set up new service item + pNewItem->next = NULL; + osal_memcpy( &(pNewItem->service), pService, sizeof( gattService_t ) ); + + // Find spot in list + if ( pServiceList == NULL ) + { + // First item in list + pServiceList = pNewItem; + } + else + { + gattServiceList_t* pLoop = pServiceList; + + // Look for end of list + while ( pLoop->next != NULL ) + { + pLoop = pLoop->next; + } + + // Put new item at end of list + pLoop->next = pNewItem; + } + + return ( SUCCESS ); +} + +/****************************************************************************** + @fn GATT_DeregisterService + + @brief Deregister a service attribute list with the GATT Server. + + NOTE: It's the caller's responsibility to free the service attribute + list returned from this API. + + @param handle - handle of service to be deregistered + @param pService - pointer to deregistered service (to be returned) + + @return SUCCESS: Service deregistered successfully. + FAILURE: Service not found. +*/ +bStatus_t GATT_DeregisterService( uint16 handle, gattService_t* pService ) +{ + gattServiceList_t* pLoop = pServiceList; + gattServiceList_t* pPrev = NULL; + + // Look for service + while ( pLoop != NULL ) + { + if ( pLoop->service.attrs[0].handle == handle ) + { + // Service found; unlink it + if ( pPrev == NULL ) + { + // First item in list + pServiceList = pLoop->next; + } + else + { + pPrev->next = pLoop->next; + } + + // Application will free the service attribute list + if ( pService != NULL ) + { + VOID osal_memcpy( pService, &(pLoop->service), sizeof( gattService_t ) ); + } + + // Free the service record + osal_mem_free( pLoop ); + return ( SUCCESS ); + } + + pPrev = pLoop; + pLoop = pLoop->next; + } + + // Service not found + return ( FAILURE ); +} + +/****************************************************************************** + @fn GATT_RegisterForReq + + @brief Register to receive incoming ATT Requests. + + @param taskId ? task to forward requests to + + @return void +*/ +void GATT_RegisterForReq( uint8 taskId ) +{ + reqTaskId = taskId; +} + +/********************************************************************* + @fn GATT_VerifyReadPermissions + + @brief Verify the permissions of an attribute for reading. + + @param connHandle - connection to use + @param permissions - attribute permissions + + @return SUCCESS: Attribute can be read + ATT_ERR_READ_NOT_PERMITTED: Attribute cannot be read + ATT_ERR_INSUFFICIENT_AUTHEN: Attribute requires authentication + ATT_ERR_INSUFFICIENT_KEY_SIZE: Key Size used for encrypting is insufficient + ATT_ERR_INSUFFICIENT_ENCRYPT: Attribute requires encryption +*/ +bStatus_t GATT_VerifyReadPermissions( uint16 connHandle, uint8 permissions ) +{ + // Make sure the requesting device has sufficient security + if ( gattPermitAuthorRead( permissions ) || gattPermitAuthenRead( permissions ) ) + { + // Authorization is handled by the application/profile but make sure the + // requesting device is authenticated and the link is encrypted. + return ( linkDB_Authen( connHandle, GATT_ENCRYPT_KEY_SIZE, TRUE ) ); + } + + if ( gattPermitEncryptRead( permissions ) ) + { + // Read operation requires an encrypted link (unauthenticated) + return ( linkDB_Authen( connHandle, GATT_ENCRYPT_KEY_SIZE, FALSE ) ); + } + + // Make sure the attribute has sufficient permissions to allow reading + if ( !gattPermitRead( permissions ) ) + { + return ( ATT_ERR_READ_NOT_PERMITTED ); + } + + return ( SUCCESS ); +} + +/********************************************************************* + @fn GATT_VerifyWritePermissions + + @brief Verify the permissions of an attribute for writing. + + @param connHandle - connection to use + @param permissions - attribute permissions + @param pReq - pointer to write request + + @return SUCCESS: Attribute can be written + ATT_ERR_READ_NOT_PERMITTED: Attribute cannot be written + ATT_ERR_INSUFFICIENT_AUTHEN: Attribute requires authentication + ATT_ERR_INSUFFICIENT_KEY_SIZE: Key Size used for encrypting is insufficient + ATT_ERR_INSUFFICIENT_ENCRYPT: Attribute requires encryption +*/ +bStatus_t GATT_VerifyWritePermissions( uint16 connHandle, uint8 permissions, attWriteReq_t* pReq ) +{ + // Make sure the requesting device has sufficient security + if ( gattPermitAuthorWrite( permissions ) ) + { + // Authorization is handled by the application/profile but make sure the + // requesting device is authenticated and the link is encrypted. + return ( linkDB_Authen( connHandle, GATT_ENCRYPT_KEY_SIZE, TRUE ) ); + } + + if ( gattPermitAuthenWrite( permissions ) || gattPermitEncryptWrite( permissions ) ) + { + uint8 status = linkDB_Authen( connHandle, GATT_ENCRYPT_KEY_SIZE, gattPermitAuthenWrite( permissions ) ); + + // Write operation requires an encrypted link or an authenticated signed command + if ( ( status != SUCCESS ) && ( ( pReq->cmd == FALSE ) || ( pReq->sig != ATT_SIG_VALID ) ) ) + { + return ( status ); + } + } + // Make sure the attribute has sufficient permissions to allow writing + else if ( !gattPermitWrite( permissions ) ) + { + return ( ATT_ERR_WRITE_NOT_PERMITTED ); + } + + return ( SUCCESS ); +} + +/********************************************************************* + @fn GATT_ServiceChangedInd + + @brief Send out a Service Changed Indication. + + @param connHandle - connection to use + @param taskId - task to be notified of confirmation + + @return SUCCESS: Indication was sent successfully. + FAILURE: Service Changed attribute not found. + INVALIDPARAMETER: Invalid connection handle or request field. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A confirmation is pending with this client. +*/ +uint8 GATT_ServiceChangedInd( uint16 connHandle, uint8 taskId ) +{ + gattAttribute_t* pAttr; + // Find the Service Changed attribute record + pAttr = GATT_FindHandleUUID( GATT_MIN_HANDLE, GATT_MAX_HANDLE, + serviceChangedUUID, ATT_BT_UUID_SIZE, NULL ); + + if ( pAttr != NULL ) + { + attHandleValueInd_t ind; + ind.handle = pAttr->handle; + // Set the affected Attribute Handle range to 0x0001 to 0xFFFF to + // indicate to the client to rediscover the entire set of Attribute + // Handles on the server. + ind.len = 4; + ind.value[0] = LO_UINT16( GATT_MIN_HANDLE ); + ind.value[1] = HI_UINT16( GATT_MIN_HANDLE ); + ind.value[2] = LO_UINT16( GATT_MAX_HANDLE ); + ind.value[3] = HI_UINT16( GATT_MAX_HANDLE ); + return ( GATT_Indication( connHandle, &ind, FALSE, taskId ) ); + } + + return ( FAILURE ); +} + +/********************************************************************* + @fn GATT_FindHandleUUID + + @brief Find the attribute record for a given handle and UUID. + + @param startHandle - first handle to look for + @param endHandle - last handle to look for + @param pUUID - pointer to UUID to look for + @param len - length of UUID + @param pHandle - handle of owner of attribute (to be returned) + + @return Pointer to attribute record. NULL, otherwise. +*/ +gattAttribute_t* GATT_FindHandleUUID( uint16 startHandle, uint16 endHandle, const uint8* pUUID, + uint16 len, uint16* pHandle ) +{ + gattServiceList_t* pLoop = pServiceList; + + while ( pLoop != NULL ) + { + for ( uint16 i = 0; i < pLoop->service.numAttrs; i++ ) + { + gattAttribute_t* pAttr = &(pLoop->service.attrs[i]); + + // Check to see if this handle falls within the starting and ending handles + if ( ( pAttr->handle >= startHandle ) && ( pAttr->handle <= endHandle ) ) + { + // Compare UUIDs if one is provided + if ( ( len == 0 ) || + ( ATT_CompareUUID( pAttr->type.uuid, pAttr->type.len, + pUUID, len ) ) ) + { + // Entry found + if ( pHandle != NULL ) + { + // Handle of the service that the attribute belongs to + *pHandle = pLoop->service.attrs[0].handle; + } + + return ( pAttr ); + } + } + } + + // Try next service + pLoop = pLoop->next; + } + + return ( (gattAttribute_t*)NULL ); +} + +/********************************************************************* + @fn GATT_FindHandle + + @brief Find the attribute record for a given handle + + @param handle - handle to look for + @param pHandle - handle of owner of attribute (to be returned) + + @return Pointer to attribute record. NULL, otherwise. +*/ +gattAttribute_t* GATT_FindHandle( uint16 handle, uint16* pHandle ) +{ + gattServiceList_t* pLoop = pServiceList; + + while ( pLoop != NULL ) + { + uint16 serviceHandle = pLoop->service.attrs[0].handle; + + // See if the handle falls within this service + if ( ( handle >= serviceHandle ) && ( handle < serviceHandle + pLoop->service.numAttrs ) ) + { + for ( uint16 i = 0; i < pLoop->service.numAttrs; i++ ) + { + gattAttribute_t* pAttr = &(pLoop->service.attrs[i]); + + if ( pAttr->handle == handle ) + { + // Entry found + if ( pHandle != NULL ) + { + // Handle of the service that the attribute belongs to + *pHandle = serviceHandle; + } + + return ( pAttr ); + } + } + } + + // Try next service + pLoop = pLoop->next; + } + + return ( (gattAttribute_t*)NULL ); +} + +/********************************************************************* + @fn GATT_FindNextAttr + + @brief Find the next attribute of the same type for a given attribute. + + @param pAttr - pointer to attribute to find a next for + @param endHandle - last handle to look for + @param service - handle of owner service + @param pLastHandle - handle of last attribute (to be returned) + + @return Pointer to next attribute record. NULL, otherwise. +*/ +gattAttribute_t* GATT_FindNextAttr( gattAttribute_t* pAttr, uint16 endHandle, + uint16 service, uint16* pLastHandle ) +{ + uint16 lastHandle; + gattAttribute_t* pNext = NULL; + uint16 owner = GATT_INVALID_HANDLE; + + // Try to find the next attribute of the same type + + // All attribute types are effectively compared as 128-bit UUIDs, + // even if a 16-bit UUID is provided in this request or defined + // for an attribute. + if ( pAttr->handle != GATT_MAX_HANDLE ) + { + pNext = GATT_FindHandleUUID( pAttr->handle+1, endHandle, pAttr->type.uuid, + pAttr->type.len, &owner ); + } + + // Try to find the handle of the last attribute + if ( gattServiceType( pAttr->type ) ) + { + // Get the handle of the last attribute withis this service + lastHandle = gattServiceLastHandle( pAttr->handle ); + } + else if ( gattCharacterType( pAttr->type ) ) + { + // Check to see if this is the last characteristic within the service + if ( ( pNext == NULL ) || ( owner != service ) ) + { + lastHandle = gattServiceLastHandle( service ); + } + else + { + lastHandle = pNext->handle - 1; + } + } + else + { + // Not a grouping attribute -- return its handle + lastHandle = pAttr->handle; + } + + if ( pLastHandle != NULL ) + { + *pLastHandle = lastHandle; + } + + return ( pNext ); +} + +/********************************************************************* + @fn GATT_ServiceNumAttrs + + @brief Get the number of attributes for a given service + + @param handle - service handle to look for + + @return Number of attributes. 0, otherwise. +*/ +uint16 GATT_ServiceNumAttrs( uint16 handle ) +{ + gattServiceList_t* pLoop = pServiceList; + + while ( pLoop != NULL ) + { + if ( pLoop->service.attrs[0].handle == handle ) + { + // Service found + return ( pLoop->service.numAttrs ); + } + + // Try next service + pLoop = pLoop->next; + } + + return ( 0 ); +} + +/* ------------------------------------------------------------------- + GATT Server Sub-Procedure APIs +*/ + +/********************************************************************* + @fn GATT_Indication + + @brief This sub-procedure is used when a server is configured to + indicate a characteristic value to a client and expects an + attribute protocol layer acknowledgement that the indication + was successfully received. + + The ATT Handle Value Indication is used in this sub-procedure. + + If the return status from this function is SUCCESS, the calling + application task will receive an OSAL GATT_MSG_EVENT message. + The type of the message will be ATT_HANDLE_VALUE_CFM. + + Note: This sub-procedure is complete when ATT_HANDLE_VALUE_CFM + (with SUCCESS or bleTimeout status) is received by the + calling application task. + + @param connHandle - connection to use + @param pInd - pointer to indication to be sent + @param taskId - task to be notified of confirmation + @param authenticated - whether an authenticated link is required + + @return SUCCESS: Indication was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + ATT_ERR_INSUFFICIENT_AUTHEN - link is not encrypted + ATT_ERR_INSUFFICIENT_KEY_SIZE - key size encrypted is not large enough + ATT_ERR_INSUFFICIENT_ENCRYPT - link is encrypted, but not authenticated + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + blePending: A confirmation is pending with this client. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_Indication( uint16 connHandle, attHandleValueInd_t* pInd, + uint8 authenticated, uint8 taskId ) +{ + gattServerInfo_t* pServer; + uint8 status; + // Make sure we're allowed to send a new indication + status = gattGetServerStatus( connHandle, &pServer ); + + if ( status == SUCCESS ) + { + // Make sure the link is authenticated if requested + if ( authenticated ) + { + // Indication operation requires authentication + status = linkDB_Authen( connHandle, GATT_ENCRYPT_KEY_SIZE, TRUE ); + } + + if ( status == SUCCESS ) + { + status = ATT_HandleValueInd( connHandle, pInd ); + + if ( status == SUCCESS ) + { + // Store server info + gattStoreServerInfo( pServer, taskId ); + } + } + } + + return ( status ); +} + +/********************************************************************* + @fn GATT_Notification + + @brief This sub-procedure is used when a server is configured to + notify a characteristic value to a client without expecting + any attribute protocol layer acknowledgement that the + notification was successfully received. + + The ATT Handle Value Notification is used in this sub-procedure. + + Note: A notification may be sent at any time and does not + invoke a confirmation. + + No confirmation will be sent to the calling application task for + this sub-procedure. + + @param connHandle - connection to use + @param pNoti - pointer to notification to be sent + @param authenticated - whether an authenticated link is required + + @return SUCCESS: Notification was sent successfully. + INVALIDPARAMETER: Invalid connection handle or request field. + ATT_ERR_INSUFFICIENT_AUTHEN - link is not encrypted + ATT_ERR_INSUFFICIENT_KEY_SIZE - key size encrypted is not large enough + ATT_ERR_INSUFFICIENT_ENCRYPT - link is encrypted, but not authenticated + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleTimeout: Previous transaction timed out. +*/ +bStatus_t GATT_Notification( uint16 connHandle, attHandleValueNoti_t* pNoti, + uint8 authenticated ) +{ + gattServerInfo_t* pServer; + uint8 status; + // Make sure we're allowed to send a new notification + status = gattGetServerStatus( connHandle, &pServer ); + + if ( status != bleTimeout ) + { + // Make sure the link is authenticated if requested + if ( authenticated ) + { + // Notification operation requires authentication + status = linkDB_Authen( connHandle, GATT_ENCRYPT_KEY_SIZE, TRUE ); + + if ( status != SUCCESS ) + { + return ( status ); + } + } + + status = ATT_HandleValueNoti( connHandle, pNoti ); + } + + return ( status ); +} + +/* ------------------------------------------------------------------- + GATT Server Internal Functions +*/ + +/********************************************************************* + @fn gattServiceLastHandle + + @brief Get the handle of the last attribute within a given service. + + @param handle - service handle + + @return Handle of last attribute for service. Handle, otherwise. +*/ +static uint16 gattServiceLastHandle( uint16 handle ) +{ + uint16 lastHandle; + // Find out the handle of the last attribute withis this service + lastHandle = GATT_ServiceNumAttrs( handle ); + + if ( lastHandle != 0 ) + { + lastHandle += (handle - 1); + } + else + { + lastHandle = handle; + } + + return ( lastHandle ); +} + +/********************************************************************* + @fn gattStoreServerInfo + + @brief Store server info. + + @param connHandle ? connection to use + @param taskId ? task to be notified of response + + @return void +*/ +static void gattStoreServerInfo( gattServerInfo_t* pServer, uint8 taskId ) +{ + if ( taskId != INVALID_TASK_ID ) + { + // Start a timeout timer for the confirmation + gattServerStartTimer( (uint8*)pServer, ATT_MSG_TIMEOUT, &pServer->timerId ); + // Store task id to forward the confirmation to + pServer->taskId = taskId; + } +} + +/********************************************************************* + @fn gattProcessServerMsgCB + + @brief GATT Server message processing function. + + @param connHandle - connection packet was received on + @param pPkt - pointer to received packet + + @return SUCCESS: Message processed successfully + ATT_ERR_UNSUPPORTED_REQ: Unsupported request or command + ATT_ERR_INVALID_PDU: Invalid PDU + bleMemAllocError: Memory allocation error occurred +*/ +static bStatus_t gattServerProcessMsgCB( uint16 connHandle, attPacket_t* pPkt ) +{ + gattMsg_t msg; + uint8 status; + + // See if this is a confirmation to an indication + if ( pPkt->method == ATT_HANDLE_VALUE_CFM ) + { + gattServerInfo_t* pServer; + // Make sure we have the info about the Server that sent the indication + pServer = gattFindServerInfo( connHandle ); + + if ( pServer != NULL ) + { + status = gattNotifyEvent( pServer->taskId, connHandle, SUCCESS, pPkt->method, NULL ); + // Reset server info + gattResetServerInfo( pServer ); + } + + // We're done here + return ( status ); + } + + // Make sure the incoming request or command is supported + if ( ( reqTaskId == INVALID_TASK_ID ) || + ( pPkt->method > ATT_EXECUTE_WRITE_REQ ) || + ( gattParseReq( pPkt->method ) == NULL ) || + ( gattProcessReq( pPkt->method ) == NULL ) || + ( ( ( pPkt->sig != ATT_SIG_NOT_INCLUDED ) || + ( pPkt->cmd == TRUE ) ) && + ( pPkt->method != ATT_WRITE_REQ ) ) ) + { + // Unsupported request or command + return ( ATT_ERR_UNSUPPORTED_REQ ); + } + + // Parse the incoming request or command + status = gattParseReq( pPkt->method )( pPkt->sig, pPkt->cmd, pPkt->pParams, + pPkt->len, (attMsg_t*)&msg ); + + if ( status == SUCCESS ) + { + // Try to process the request or command + status = gattProcessReq( pPkt->method )( connHandle, (attMsg_t*)&msg ); + + if ( status == SUCCESS ) + { + // Foward the request up to the application for further processing + if ( pPkt->method != ATT_FIND_INFO_REQ ) + { + status = gattNotifyEvent( reqTaskId, connHandle, SUCCESS, pPkt->method, &msg ); + } + } + // Do not send an error response back for any command + else if ( pPkt->cmd == FALSE ) + { + attErrorRsp_t errorRsp; + // Send an Error Response back + errorRsp.reqOpcode = pPkt->method; + errorRsp.errCode = status; + + // Set the handle + if ( ( pPkt->method == ATT_FIND_INFO_REQ ) || + ( pPkt->method == ATT_FIND_BY_TYPE_VALUE_REQ ) || + ( pPkt->method == ATT_READ_BY_TYPE_REQ ) || + ( pPkt->method == ATT_READ_BY_GRP_TYPE_REQ ) ) + { + // Set handle to the starting handle + errorRsp.handle = msg.findInfoReq.startHandle; + } + else + { + // All requests share the handle field + errorRsp.handle = msg.readReq.handle; + } + + // Send an Error Response back + VOID ATT_ErrorRsp( connHandle, &errorRsp ); + // We're done with this request + status = SUCCESS; + } + } + + return ( status ); +} + +/********************************************************************* + @fn gattProcessExchangeMTUReq + + @brief Process Exchange MTU Request. + + @param connHandle ? connection message was received on + @param pMsg - pointer to message structure + + @return SUCCESS: Forward the request up to the application +*/ +static bStatus_t gattProcessExchangeMTUReq( uint16 connHandle, attMsg_t* pMsg ) +{ + VOID connHandle; // Not used here + //VOID pMsg; // Not used here + attExchangeMTUReq_t* pReq = &pMsg->exchangeMTUReq; + g_attMtuClientServer.clientMTU=ATT_MTU_SIZE_MIN; + + if(pReq->clientRxMTU < ATT_MTU_SIZE_MIN) + { + return (ATT_ERR_INVALID_PDU); + } + + g_attMtuClientServer.clientMTU=pReq->clientRxMTU; + return ( SUCCESS ); +} + +/********************************************************************* + @fn gattProcessFindInfoReq + + @brief Process Find Information Request. + + @param connHandle ? connection message was received on + @param pMsg - pointer to message structure + + @return SUCCESS: Forward the request up to the application + ATT_ERR_INVALID_HANDLE: Invalid attribute handle + ATT_ERR_ATTR_NOT_FOUND: Attribute not found +*/ +static bStatus_t gattProcessFindInfoReq( uint16 connHandle, attMsg_t* pMsg ) +{ + attFindInfoReq_t* pReq = &pMsg->findInfoReq; + uint16 startHandle = pReq->startHandle; + attFindInfoRsp_t rsp; + uint8 done = FALSE; + + // If the starting handle greater than the ending handle or the starting + // handle is 0x0000 then return the status code Invalid Handle + if ( ( startHandle > pReq->endHandle ) || ( startHandle == 0 ) ) + { + return ( ATT_ERR_INVALID_HANDLE ); + } + + rsp.numInfo = 0; + + while ( !done ) + { + // All attribute types are effectively compared as 128 bit UUIDs, even if + // a 16 bit UUID is provided in this request or defined for an attribute. + gattAttribute_t* pAttr = GATT_FindHandleUUID( startHandle, pReq->endHandle, + NULL, 0, NULL ); + + // If the size of the UUID Filter parameter is 0 octets, then all attribute + // types will be returned. If the size of the UUID Filter parameter is 2 or + // 16 octets, then only attribute types with this UUID Filter will be returned. + if ( pAttr == NULL ) + { + // No more attributes found + break; + } + + // Is this the first UUID found? + if ( rsp.numInfo == 0 ) + { + // Set the Format field using the first UUID's length + if ( pAttr->type.len == ATT_BT_UUID_SIZE ) + { + // A list of 1 or more handles with their 16 bit Bluetooth UUIDs + rsp.format = ATT_HANDLE_BT_UUID_TYPE; + } + else + { + // A list of 1 or more handles with their 128 bit UUIDs + rsp.format = ATT_HANDLE_UUID_TYPE; + } + } + + // Copy handle and UUID into the response + if ( rsp.format == ATT_HANDLE_BT_UUID_TYPE ) + { + // Handle with its 16 bit Bluetooth UUID + if ( pAttr->type.len != ATT_BT_UUID_SIZE ) + { + // It's not possible to include attributes with differing UUID sizes + // into a single response + break; + } + + rsp.info.btPair[rsp.numInfo].handle = pAttr->handle; + VOID osal_memcpy( rsp.info.btPair[rsp.numInfo].uuid, pAttr->type.uuid, ATT_BT_UUID_SIZE ); + + if ( ( ++rsp.numInfo >= ATT_MAX_NUM_HANDLE_BT_UUID ) || + ( pAttr->handle == GATT_MAX_HANDLE ) ) + { + done = TRUE; // We're done successfully + } + } + else // ATT_HANDLE_UUID_TYPE + { + // Handle with its 128 bit Bluetooth UUID + rsp.info.pair[rsp.numInfo].handle = pAttr->handle; + VOID osal_memcpy( rsp.info.pair[rsp.numInfo].uuid, pAttr->type.uuid, ATT_UUID_SIZE ); + + if ( ( ++rsp.numInfo >= ATT_MAX_NUM_HANDLE_UUID ) || + ( pAttr->handle == GATT_MAX_HANDLE ) ) + { + done = TRUE; // We're done successfully + } + } + + // Update start handle and search again + startHandle = pAttr->handle + 1; + } + + // If no attribute is found then return the status code Attribute Not Found + if ( rsp.numInfo == 0 ) + { + return ( ATT_ERR_ATTR_NOT_FOUND ); + } + + // Send a Find Info Response back + VOID ATT_FindInfoRsp( connHandle, &rsp ); + return ( SUCCESS ); +} + +/********************************************************************* + @fn gattProcessFindByTypeVaueReq + + @brief Process Find By Type Value Request. + + @param connHandle ? connection message was received on + @param pMsg - pointer to message structure + + @return SUCCESS: Forward the request up to the application + ATT_ERR_INVALID_HANDLE: Invalid attribute handle + ATT_ERR_ATTR_NOT_FOUND: Attribute not found +*/ +static bStatus_t gattProcessFindByTypeValueReq( uint16 connHandle, attMsg_t* pMsg ) +{ + attFindByTypeValueReq_t* pReq = &pMsg->findByTypeValueReq; + VOID connHandle; // Not used here + + // If the starting handle greater than the ending handle or the starting + // handle is 0x0000 then return the status code Invalid Handle + if ( ( pReq->startHandle > pReq->endHandle ) || ( pReq->startHandle == 0 ) ) + { + return ( ATT_ERR_INVALID_HANDLE ); + } + + // Only attributes with attribute handles between and including the Starting + // Handle parameter and the Ending Handle parameter that match the requested + // attribute type and the attribute value will be returned. + + // All attribute types are effectively compared as 128 bit UUIDs, even if + // a 16 bit UUID is provided in this request or defined for an attribute. + if ( GATT_FindHandleUUID( pReq->startHandle, pReq->endHandle, + pReq->type.uuid, pReq->type.len, NULL ) == NULL ) + { + // If no attribute with the given type exists within the handle range + // then return the status code Attribute Not Found + return ( ATT_ERR_ATTR_NOT_FOUND ); + } + + // Forward the request up to the application + return ( SUCCESS ); +} + +/********************************************************************* + @fn gattProcessReadByTypeReq + + @brief Process Read By Type Request. + + @param connHandle ? connection message was received on + @param pMsg - pointer to message structure + + @return SUCCESS: Forward the request up to the application + ATT_ERR_INVALID_HANDLE: Invalid attribute handle + ATT_ERR_ATTR_NOT_FOUND: Attribute not found +*/ +static bStatus_t gattProcessReadByTypeReq( uint16 connHandle, attMsg_t* pMsg ) +{ + attReadByTypeReq_t* pReq = &pMsg->readByTypeReq; + VOID connHandle; // Not used here + + // If the starting handle greater than the ending handle or the starting + // handle is 0x0000 then return the status code Invalid Handle + if ( ( pReq->startHandle > pReq->endHandle ) || ( pReq->startHandle == 0 ) ) + { + return ( ATT_ERR_INVALID_HANDLE ); + } + + // Only an attribute with attribute type that is the same as the Type + // given will be returned. The attribute returned must be the attribute + // with the lowest handle within the handle range. + + // All attribute types are effectively compared as 128 bit UUIDs, even if + // a 16 bit UUID is provided in this request or defined for an attribute. + if ( GATT_FindHandleUUID( pReq->startHandle, pReq->endHandle, + pReq->type.uuid, pReq->type.len, NULL ) == NULL ) + { + // If no attribute with the given type exists within the handle range + // then return the status code Attribute Not Found + return ( ATT_ERR_ATTR_NOT_FOUND ); + } + + // Forward the request up to the application + return ( SUCCESS ); +} + +/********************************************************************* + @fn gattProcessReadReq + + @brief Process Read Request. + + @param connHandle ? connection message was received on + @param pMsg - pointer to message structure + + @return SUCCESS: Forward the request up to the application + ATT_ERR_INVALID_HANDLE: Invalid attribute handle + ATT_ERR_READ_NOT_PERMITTED: Attribute cannot be read + ATT_ERR_INSUFFICIENT_AUTHEN: Attribute requires authentication + ATT_ERR_INSUFFICIENT_KEY_SIZE: Key Size used for encrypting is insufficient + ATT_ERR_INSUFFICIENT_ENCRYPT: Attribute requires encryption +*/ +static bStatus_t gattProcessReadReq( uint16 connHandle, attMsg_t* pMsg ) +{ + gattAttribute_t* pAttr; + uint16 handle = pMsg->readReq.handle; + // Make sure the handle is valid + pAttr = GATT_FindHandle( handle, NULL ); + + if ( pAttr == NULL ) + { + return ( ATT_ERR_INVALID_HANDLE ); + } + + // Forward the request up to the application (if reading allowed) + return ( GATT_VerifyReadPermissions( connHandle, pAttr->permissions ) ); +} + +/********************************************************************* + @fn gattProcessReadMultiReq + + @brief Process Read Multiple Request. + + @param connHandle ? connection message was received on + @param pMsg - pointer to message structure + + @return SUCCESS: Forward the request up to the application + ATT_ERR_INVALID_HANDLE: Invalid attribute handle + ATT_ERR_READ_NOT_PERMITTED: Attribute cannot be read + ATT_ERR_INSUFFICIENT_AUTHEN: Attribute requires authentication + ATT_ERR_INSUFFICIENT_KEY_SIZE: Key Size used for encrypting is insufficient + ATT_ERR_INSUFFICIENT_ENCRYPT: Attribute requires encryption +*/ +static bStatus_t gattProcessReadMultiReq( uint16 connHandle, attMsg_t* pMsg ) +{ + attReadMultiReq_t* pReq = &pMsg->readMultiReq; + + // Make sure all the handles are valid and all attributes have sufficient + // permissions to allow reading. + for ( uint8 i = 0; i < pReq->numHandles; i++ ) + { + gattAttribute_t* pAttr; + uint8 status; + // Make sure the handle is valid + pAttr = GATT_FindHandle( pReq->handle[i], NULL ); + + if ( pAttr == NULL ) + { + // The handle of the first attribute causing the error + pReq->handle[0] = pReq->handle[i]; + return ( ATT_ERR_INVALID_HANDLE ); + } + + // Make sure the attribute has sufficient permissions to allow reading + status = GATT_VerifyReadPermissions( connHandle, pAttr->permissions ); + + if ( status != SUCCESS ) + { + // The handle of the first attribute causing the error + pReq->handle[0] = pReq->handle[i]; + return ( status ); + } + } + + // Forward the request up to the application + return ( SUCCESS ); +} + +/********************************************************************* + @fn gattProcessReadByGrpTypeReq + + @brief Process Read By Group Type Request. + + @param connHandle ? connection message was received on + @param pMsg - pointer to message structure + + @return SUCCESS: Forward the request up to the application + ATT_ERR_INVALID_HANDLE: Invalid attribute handle + ATT_ERR_UNSUPPORTED_GRP_TYPE: Group attribute type not supported + ATT_ERR_ATTR_NOT_FOUND: Attribute not found +*/ +static bStatus_t gattProcessReadByGrpTypeReq( uint16 connHandle, attMsg_t* pMsg ) +{ + attReadByGrpTypeReq_t* pReq = &pMsg->readByGrpTypeReq; + VOID connHandle; // Not used here + + // If the starting handle greater than the ending handle or the starting + // handle is 0x0000 then return the status code Invalid Handle + if ( ( pReq->startHandle > pReq->endHandle ) || ( pReq->startHandle == 0 ) ) + { + return ( ATT_ERR_INVALID_HANDLE ); + } + + // If the Attribute Group Type is not a supported grouping attribute + // the return the status code Unsupported Group Type + if ( !gattPrimaryServiceType( pReq->type ) ) + { + return ( ATT_ERR_UNSUPPORTED_GRP_TYPE ); + } + + // Only the attributes with attribute handles between and including the + // Starting Handle and the Ending Handle with the attribute type that + // is the same as the Attribute Group Type given will be returned. + + // All attribute types are effectively compared as 128 bit UUIDs, even if + // a 16 bit UUID is provided in this request or defined for an attribute. + if ( GATT_FindHandleUUID( pReq->startHandle, pReq->endHandle, + pReq->type.uuid, pReq->type.len, NULL ) == NULL ) + { + // If no attribute with the given type exists within the handle range + // then return the status code Attribute Not Found + return ( ATT_ERR_ATTR_NOT_FOUND ); + } + + // Forward the request up to the application + return ( SUCCESS ); +} + +/********************************************************************* + @fn gattProcessWriteReq + + @brief Process Write Request or Command. + + @param connHandle ? connection message was received on + @param pMsg - pointer to message structure + + @return SUCCESS: Forward the request up to the application + ATT_ERR_READ_NOT_PERMITTED: Attribute cannot be written + ATT_ERR_INSUFFICIENT_AUTHEN: Attribute requires authentication + ATT_ERR_INSUFFICIENT_KEY_SIZE: Key Size used for encrypting is insufficient + ATT_ERR_INSUFFICIENT_ENCRYPT: Attribute requires encryption +*/ +static bStatus_t gattProcessWriteReq( uint16 connHandle, attMsg_t* pMsg ) +{ + gattAttribute_t* pAttr; + attWriteReq_t* pReq = &(pMsg->writeReq); + // Make sure the handle is valid + pAttr = GATT_FindHandle( pReq->handle, NULL ); + + if ( pAttr == NULL ) + { + return ( ATT_ERR_INVALID_HANDLE ); + } + + // Forward the request up to the application (if writting allowed) + return ( GATT_VerifyWritePermissions( connHandle, pAttr->permissions, pReq ) ); +} + +/********************************************************************* + @fn gattProcessExecuteWriteReq + + @brief Process Execute Write Request. + + @param connHandle ? connection message was received on + @param pMsg - pointer to message structure + + @return SUCCESS: Forward the request up to the application +*/ +static bStatus_t gattProcessExecuteWriteReq( uint16 connHandle, attMsg_t* pMsg ) +{ + VOID connHandle; // Not used here + VOID pMsg; // Not used here + // Forward the request up to the application + return ( SUCCESS ); +} + +/********************************************************************* + @fn gattGetServerStatus + + @brief Get the status for a given server. + + @param connHandle - client connection to server + @param p2pServer - pointer to server info (to be returned) + + @return SUCCESS: No confirmation pending + INVALIDPARAMETER: Invalid connection handle + blePending: Confirmation pending + bleTimeout: Previous transaction timed out +*/ +static bStatus_t gattGetServerStatus( uint16 connHandle, gattServerInfo_t** p2pServer ) +{ + gattServerInfo_t* pServer; + pServer = gattFindServerInfo( connHandle ); + + if ( pServer != NULL ) + { + if ( p2pServer != NULL ) + { + *p2pServer = pServer; + } + + // Make sure there's no confirmation pending or timed out with this client + return ( TIMER_STATUS( pServer->timerId ) ); + } + + // Connection handle not found + return ( INVALIDPARAMETER ); +} + +/********************************************************************* + @fn attFindServerInfo + + @brief Find the server info. Uses the connection handle to search + the server info table. + + @param connHandle - connection handle. + + @return a pointer to the found item. NULL, otherwise. +*/ +static gattServerInfo_t* gattFindServerInfo( uint16 connHandle ) +{ + uint8 i; + + for ( i = 0; i < GATT_MAX_NUM_CONN; i++ ) + { + if ( serverInfoTbl[i].connHandle == connHandle ) + { + // Entry found + return ( &serverInfoTbl[i] ); + } + } + + return ( (gattServerInfo_t*)NULL ); +} + +/********************************************************************* + @fn gattResetServerInfo + + @brief Reset the server info. + + @param pServer - pointer to server info. + + @return void +*/ +static void gattResetServerInfo( gattServerInfo_t* pServer ) +{ + // Cancel the confirmation timer + gattStopTimer( &pServer->timerId ); + // Reset confirmation info + pServer->taskId = INVALID_TASK_ID; +} + +/********************************************************************* + @fn attServertStartTimer + + @brief Start a server timer to expire in n seconds. + + @param pData - data to be passed in to callback function + @param timeout - in milliseconds. + @param pTimerId - will point to new timer Id (if not null) + + @return void +*/ +static void gattServerStartTimer( uint8* pData, uint16 timeout, uint8* pTimerId ) +{ + gattStartTimer( gattServerHandleTimerCB, pData, timeout, pTimerId ); +} + +/********************************************************************* + @fn gattServerHandleTimerCB + + @brief Handle a callback for a timer that has just expired. + + @param pData - pointer to timer data + + @return void +*/ +static void gattServerHandleTimerCB( uint8* pData ) +{ + gattServerInfo_t* pServer = (gattServerInfo_t*)pData; + + // Response timer has expired + if ( ( pServer != NULL ) && TIMER_VALID( pServer->timerId ) ) + { + // Notify the application about the timeout + VOID gattNotifyEvent( pServer->taskId, pServer->connHandle, bleTimeout, + ATT_HANDLE_VALUE_CFM, NULL ); + // Timer has expired. If a transaction has not completed before it times + // out, then this transaction shall be considered to have failed. No more + // attribute protocol requests, commands, indications or notifications + // shall be sent to the target device on this ATT Bearer. + pServer->timerId = TIMEOUT_TIMER_ID; + // Reset confirmation info + pServer->taskId = INVALID_TASK_ID; + } +} + +/********************************************************************* + @fn gattServerHandleConnStatusCB + + @brief GATT link status change handler function. + + @param connHandle - connection handle + @param changeType - type of change + + @return void +*/ +static void gattServerHandleConnStatusCB( uint16 connHandle, uint8 changeType ) +{ + gattServerInfo_t* pServer = NULL; + + // Check to see if this is loopback connection + if ( connHandle == LOOPBACK_CONNHANDLE ) + { + return; + } + + if ( changeType == LINKDB_STATUS_UPDATE_NEW ) + { + // A new connection has been made + pServer = gattFindServerInfo( connHandle ); + + if ( pServer == NULL ) + { + // Entry not found; add it to the server table + pServer = gattFindServerInfo( INVALID_CONNHANDLE ); + + if ( pServer != NULL ) + { + // Empty entry found + pServer->connHandle = connHandle; + } + } + + // We're done here! + return; + } + + if ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) + { + pServer = gattFindServerInfo( connHandle ); + + if ( pServer != NULL ) + { + // Entry found; remove it from the server table + pServer->connHandle = INVALID_CONNHANDLE; + } + } + else if ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) + { + // Check to see if the connection has dropped + if ( !linkDB_Up( connHandle ) ) + { + pServer = gattFindServerInfo( connHandle ); + } + } + + // Connection has dropped; notify the application + if ( pServer != NULL ) + { + if ( pServer->timerId != INVALID_TIMER_ID ) + { + if ( pServer->timerId != TIMEOUT_TIMER_ID ) + { + // Notify the application about the link disconnect + VOID gattNotifyEvent( pServer->taskId, connHandle, bleNotConnected, + ATT_HANDLE_VALUE_CFM, NULL ); + } + + // Reset server info + gattResetServerInfo( pServer ); + // Just in case if we've timed out waiting for a confirmation + pServer->timerId = INVALID_TIMER_ID; + } + } +} + +/********************************************************************* + @fn GATT_SetNextHandle + + @brief Set the next available attribute handle. + + @param handle - next attribute handle + + @return void +*/ +void GATT_SetNextHandle( uint16 handle ) +{ + if ( handle >= nextHandle ) + { + #if defined ( GATT_QUAL ) + // Set next available attribute handle + nextHandle = handle; + #endif // GATT_QUAL + } +} + +/**************************************************************************** +****************************************************************************/ diff --git a/src/lib/ble_host/gatt_task.c b/src/lib/ble_host/gatt_task.c new file mode 100644 index 0000000..9ff939a --- /dev/null +++ b/src/lib/ble_host/gatt_task.c @@ -0,0 +1,411 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************** + Filename: gatt_task.c + Revised: + Revision: + + Description: This file contains Generic Attribute Profile (GATT) task. + + +**************************************************************************************************/ + + +/********************************************************************* + INCLUDES +*/ +#include "comdef.h" +#include "OSAL.h" +#include "osal_bufmgr.h" +//#include "OnBoard.h" +#include "bus_dev.h" +#include "mcu.h" + +#include "gatt.h" +#include "gatt_internal.h" + + +/********************************************************************* + MACROS +*/ +#define WRITE_CMD( method, cmd ) ( ( (method) == ATT_WRITE_REQ ) && ( (cmd) == TRUE ) ) + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + GLOBAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ +uint8 gattTaskID; + +// Function to call to process the Attribute Server messages. +static gattProcessMsg_t pfnServerProcessMsgCB = NULL; + +// Function to call to process the Attribute Client messages. +static gattProcessMsg_t pfnClientProcessMsgCB = NULL; + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static void gattProcessOSALMsg( osal_event_hdr_t* pMsg ); +static void gattProcessRxData( l2capDataEvent_t* pL2capMsg ); + +/********************************************************************* + API FUNCTIONS +*/ + +/********************************************************************* + @fn gattRegisterServer + + @brief Register the server's processing function with the GATT task. + + @param pfnProcessMsg - pointer to processing function + + @return none +*/ +void gattRegisterServer( gattProcessMsg_t pfnProcessMsg ) +{ + pfnServerProcessMsgCB = pfnProcessMsg; +} + +/********************************************************************* + @fn gattRegisterClient + + @brief Register the client's processing function with the GATT task. + + @param pfnProcessMsg - pointer to processing function + + @return none +*/ +void gattRegisterClient( gattProcessMsg_t pfnProcessMsg ) +{ + pfnClientProcessMsgCB = pfnProcessMsg; +} + +/********************************************************************* + @fn GATT_SetHostToAppFlowCtrl + + @brief This API is used by the Application to turn flow control on + or off for GATT messages sent from the Host to the Application. + + Note: If the flow control is enabled then the Application must + call the GATT_AppCompletedMsg() API when it completes + processing an incoming GATT message. + + @param flowCtrlMode - flow control mode: TRUE or FALSE + + @return none +*/ +void GATT_SetHostToAppFlowCtrl( uint16_t hostBufSize,uint8 flowCtrlMode ) +{ + // The Host buffer size is constrained to 1/3 the maximum heap size + L2CAP_SetControllerToHostFlowCtrl_DLE( hostBufSize/3, flowCtrlMode ); +} + +/********************************************************************* + @fn GATT_AppCompletedMsg + + @brief This API is used by the Application to notify GATT that + the processing of a message has been completed. + + @param pMsg - processed GATT message + + @return none +*/ +void GATT_AppCompletedMsg( gattMsgEvent_t* pMsg ) +{ + // Make sure the processed message is an ATT Write Command or Notification. + // All ATT Requests and Indication have a built-in flow control (i.e., + // have coressponding ATT Responses and Confirmation respectively), therefore + // a buffer credit was given to the Controller for all other ATT message + // types when they were processed by the GATT layer. + if ( ( pMsg->hdr.event == GATT_MSG_EVENT ) && + ( pMsg->hdr.status == SUCCESS ) && + ( WRITE_CMD( pMsg->method, pMsg->msg.writeReq.cmd ) || + ( pMsg->method == ATT_HANDLE_VALUE_NOTI ) ) ) + { + L2CAP_HostNumCompletedPkts( pMsg->connHandle, 1 ); + } +} + +/********************************************************************* + @fn GATT_Init + + @brief GATT Task initialization function. + + @param taskId - GATT task ID. + + @return none +*/ +void GATT_Init( uint8 taskId ) +{ + gattTaskID = taskId; + // Register with L2CAP + VOID L2CAP_RegisterApp( gattTaskID, L2CAP_CID_ATT ); + // Initialize GATT Server; it's mandatory on every device + VOID GATT_InitServer(); + VOID ATT_InitMtuSize(); +} + +/********************************************************************* + @fn GATT_ProcessEvent + + @brief GATT Task event processing function. + + @param taskId - GATT task ID + @param events - GATT events. + + @return events not processed +*/ +uint16 GATT_ProcessEvent( uint8 taskId, uint16 events ) +{ + uint8* pMsg; + VOID taskId; // OSAL required parameter that isn't used in this function + + if ( events & SYS_EVENT_MSG ) + { + if ( (pMsg = osal_msg_receive( gattTaskID )) != NULL ) + { + gattProcessOSALMsg( (osal_event_hdr_t*)pMsg ); + // Release the OSAL message + VOID osal_msg_deallocate( pMsg ); + } + + // Return unprocessed events + return (events ^ SYS_EVENT_MSG); + } + + // Discard unknown events + return 0; +} + +/********************************************************************* + @fn gattProcessOSALMsg + + @brief Process an incoming task message. + + @param pMsg - message to process + + @return none +*/ +static void gattProcessOSALMsg( osal_event_hdr_t* pMsg ) +{ + switch ( pMsg->event ) + { + case L2CAP_DATA_EVENT: + // Process incoming L2CAP Data message + gattProcessRxData( (l2capDataEvent_t*)pMsg ); + break; + + default: + // Unknown message - drop it. + break; + } +} + +/****************************************************************************** + @fn gattProcessRxData + + @brief Process data packet received from the L2CAP layer + + @param pL2capMsg ? pointer to received L2CAP message + + @return none +*/ +static void gattProcessRxData( l2capDataEvent_t* pL2capMsg ) +{ + attPacket_t pkt; + uint8 status; + // First parse the packet + status = ATT_ParsePacket( pL2capMsg, &pkt ); + + if ( status == SUCCESS ) + { + // Try to proccess the packet + if ( pkt.method & 0x01 ) + { + // It's a client message (odd method) + if ( pfnClientProcessMsgCB != NULL ) + { + status = (*pfnClientProcessMsgCB)( pL2capMsg->connHandle, &pkt ); + } + else + { + // Unsupported request + status = ATT_ERR_UNSUPPORTED_REQ; + } + } + else + { + // It's a server message (even method) + if ( pfnServerProcessMsgCB != NULL ) + { + status = (*pfnServerProcessMsgCB)( pL2capMsg->connHandle, &pkt ); + } + else + { + // Unsupported request + status = ATT_ERR_UNSUPPORTED_REQ; + } + + // Do not send an error response back for any command + if ( ( status != SUCCESS ) && ( pkt.cmd == FALSE ) ) + { + attErrorRsp_t errorRsp; + // Send an Error Response back to the client + errorRsp.reqOpcode = pkt.method; + errorRsp.handle = GATT_INVALID_HANDLE; + // Status should be either Invalid PDU or Unsupported request + errorRsp.errCode = status; + VOID ATT_ErrorRsp( pL2capMsg->connHandle, &errorRsp ); + } + } + } + + if ( pL2capMsg->pkt.pPayload != NULL ) + { + // Received buffer is processed so it's safe to free it + osal_bm_free( pL2capMsg->pkt.pPayload ); + } + + // Consider received message processed unless it's an ATT Write Command + // or Notification passed up to the App. Only these two ATT messages don't + // have a built-in flow control (i.e., don't have corresponding ATT Response + // or Confirmation respectively), therefore a buffer credit is given to the + // Controller here for all other ATT message types. + if ( ( status != SUCCESS ) || + ( !WRITE_CMD( pkt.method, pkt.cmd ) && + ( pkt.method != ATT_HANDLE_VALUE_NOTI ) ) ) + { + L2CAP_HostNumCompletedPkts( pL2capMsg->connHandle, 1 ); + } +} + +/********************************************************************* + @fn gattNotifyEvent + + @brief Send an event to upper layer application/protocol. + + @param taskId - application task + @param connHandle - connection event belongs to + @param status - status + @param method - type of message + @param pMsg - pointer to message to be sent + + @return SUCCESS or bleMemAllocError +*/ +bStatus_t gattNotifyEvent( uint8 taskId, uint16 connHandle, uint8 status, + uint8 method, gattMsg_t* pMsg ) +{ + gattMsgEvent_t* pEvent; + pEvent = (gattMsgEvent_t*)osal_msg_allocate( sizeof( gattMsgEvent_t ) ); + + if ( pEvent != NULL ) + { + // Set up the OSAL message header + pEvent->hdr.event = GATT_MSG_EVENT; + pEvent->hdr.status = status; + pEvent->connHandle = connHandle; + pEvent->method = method; + + if ( pMsg != NULL ) + { + VOID osal_memcpy( &(pEvent->msg), pMsg, sizeof( gattMsg_t ) ); + } + else + { + VOID osal_memset( &(pEvent->msg), 0, sizeof( gattMsg_t ) ); + } + + // send message through task message + VOID osal_msg_send( taskId, (uint8*)pEvent ); + return ( SUCCESS ); + } + + return ( bleMemAllocError ); +} + +/********************************************************************* + @fn gattStartTimer + + @brief Start a timer to expire in n seconds. + + @param pfnCbTimer - callback function to be called when timer expires + @param pData - data to be passed in to callback function + @param timeout - in seconds. + @param pTimerId - will point to new timer Id (if not null) + + @return none +*/ +void gattStartTimer( pfnCbTimer_t pfnCbTimer, uint8* pData, uint16 timeout, uint8* pTimerId ) +{ + // Timeout is in msec + VOID osal_CbTimerStart( pfnCbTimer, pData, (timeout * 1000), pTimerId ); +} + +/********************************************************************* + @fn gattStopTimer + + @brief Stop an active timer for a given channel. + + @param pTimerId - pointer to timer id + + @return none +*/ +void gattStopTimer( uint8* pTimerId ) +{ + if ( ( pTimerId != NULL ) && TIMER_VALID( *pTimerId ) ) + { + // Stop the timer + VOID osal_CbTimerStop( *pTimerId ); + // Reset timer id + *pTimerId = INVALID_TIMER_ID; + } +} + + +/**************************************************************************** +****************************************************************************/ diff --git a/src/lib/ble_host/gatt_uuid.c b/src/lib/ble_host/gatt_uuid.c new file mode 100644 index 0000000..5fb5a13 --- /dev/null +++ b/src/lib/ble_host/gatt_uuid.c @@ -0,0 +1,351 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************** + Filename: gatt_uuid.c + Revised: + Revision: + + Description: This file contains Generic Attribute Profile (GATT) + UUID types. + + +**************************************************************************************************/ + + +/********************************************************************* + INCLUDES +*/ +#include "comdef.h" +#include "OSAL.h" + +#include "gatt.h" +#include "gatt_uuid.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/** + GATT Services +*/ +// Generic Access Profile Service UUID +CONST uint8 gapServiceUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16( GAP_SERVICE_UUID ), HI_UINT16( GAP_SERVICE_UUID ) +}; + +// Generic Attribute Profile Service UUID +CONST uint8 gattServiceUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16( GATT_SERVICE_UUID ), HI_UINT16( GATT_SERVICE_UUID ) +}; + +/** + GATT Declarations +*/ +// Primary Service UUID +CONST uint8 primaryServiceUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16( GATT_PRIMARY_SERVICE_UUID ), HI_UINT16( GATT_PRIMARY_SERVICE_UUID ) +}; + +// Secondary Service UUID +CONST uint8 secondaryServiceUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16( GATT_SECONDARY_SERVICE_UUID ), HI_UINT16( GATT_SECONDARY_SERVICE_UUID ) +}; + +// Include UUID +CONST uint8 includeUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16( GATT_INCLUDE_UUID ), HI_UINT16( GATT_INCLUDE_UUID ) +}; + +// Characteristic UUID +CONST uint8 characterUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16( GATT_CHARACTER_UUID ), HI_UINT16( GATT_CHARACTER_UUID ) +}; + +/** + GATT Descriptors +*/ +// Characteristic Extended Properties UUID +CONST uint8 charExtPropsUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16( GATT_CHAR_EXT_PROPS_UUID ), HI_UINT16( GATT_CHAR_EXT_PROPS_UUID ) +}; + +// Characteristic User Description UUID +CONST uint8 charUserDescUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16( GATT_CHAR_USER_DESC_UUID ), HI_UINT16( GATT_CHAR_USER_DESC_UUID ) +}; + +// Client Characteristic Configuration UUID +CONST uint8 clientCharCfgUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16( GATT_CLIENT_CHAR_CFG_UUID ), HI_UINT16( GATT_CLIENT_CHAR_CFG_UUID ) +}; + +// Server Characteristic Configuration UUID +CONST uint8 servCharCfgUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16( GATT_SERV_CHAR_CFG_UUID ), HI_UINT16( GATT_SERV_CHAR_CFG_UUID ) +}; + +// Characteristic Presentation Format UUID +CONST uint8 charFormatUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16( GATT_CHAR_FORMAT_UUID ), HI_UINT16( GATT_CHAR_FORMAT_UUID ) +}; + +// Characteristic Aggregate Format UUID +CONST uint8 charAggFormatUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16( GATT_CHAR_AGG_FORMAT_UUID ), HI_UINT16( GATT_CHAR_AGG_FORMAT_UUID ) +}; + +/** + GATT Characteristics +*/ +// Device Name UUID +CONST uint8 deviceNameUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16( DEVICE_NAME_UUID ), HI_UINT16( DEVICE_NAME_UUID ) +}; + +// Appearance UUID +CONST uint8 appearanceUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16( APPEARANCE_UUID ), HI_UINT16( APPEARANCE_UUID ) +}; + +// Peripheral Privacy Flag UUID +CONST uint8 periPrivacyFlagUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16( PERI_PRIVACY_FLAG_UUID ), HI_UINT16( PERI_PRIVACY_FLAG_UUID ) +}; + +// Reconnection Address UUID +CONST uint8 reconnectAddrUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16( RECONNECT_ADDR_UUID ), HI_UINT16( RECONNECT_ADDR_UUID ) +}; + +// Peripheral Preferred Connection Parameters UUID +CONST uint8 periConnParamUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16( PERI_CONN_PARAM_UUID ), HI_UINT16( PERI_CONN_PARAM_UUID ) +}; + +// Service Changed UUID +CONST uint8 serviceChangedUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16( SERVICE_CHANGED_UUID ), HI_UINT16( SERVICE_CHANGED_UUID ) +}; + +// Valid Range UUID +CONST uint8 validRangeUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16( GATT_VALID_RANGE_UUID ), HI_UINT16( GATT_VALID_RANGE_UUID ) +}; + +// External Report Reference Descriptor +CONST uint8 extReportRefUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16( GATT_EXT_REPORT_REF_UUID ), HI_UINT16( GATT_EXT_REPORT_REF_UUID ) +}; + +// Report Reference characteristic descriptor +CONST uint8 reportRefUUID[ATT_BT_UUID_SIZE] = +{ + LO_UINT16( GATT_REPORT_REF_UUID ), HI_UINT16( GATT_REPORT_REF_UUID ) +}; + +/********************************************************************* + GLOBAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +/********************************************************************* + LOCAL FUNCTIONS +*/ + +/********************************************************************* + API FUNCTIONS +*/ + +/********************************************************************* + @fn GATT_FindUUIDRec + + @brief Find the UUID record for a given UUID. + + @param pUUID - UUID to look for. + @param len - length of UUID. + + @return Pointer to UUID record. NULL, otherwise. +*/ +const uint8* GATT_FindUUIDRec( const uint8* pUUID, uint8 len ) +{ + const uint8* pRec = NULL; + + if ( len == ATT_BT_UUID_SIZE ) + { + // 16-bit UUID + uint16 uuid = BUILD_UINT16( pUUID[0], pUUID[1] ); + + switch ( uuid ) + { + /*** GATT Services ***/ + case GAP_SERVICE_UUID: + pRec = gapServiceUUID; + break; + + case GATT_SERVICE_UUID: + pRec = gattServiceUUID; + break; + + /*** GATT Declarations ***/ + + case GATT_PRIMARY_SERVICE_UUID: + pRec = primaryServiceUUID; + break; + + case GATT_SECONDARY_SERVICE_UUID: + pRec = secondaryServiceUUID; + break; + + case GATT_INCLUDE_UUID: + pRec = includeUUID; + break; + + case GATT_CHARACTER_UUID: + pRec = characterUUID; + break; + + /*** GATT Descriptors ***/ + + case GATT_CHAR_EXT_PROPS_UUID: + pRec = charExtPropsUUID; + break; + + case GATT_CHAR_USER_DESC_UUID: + pRec = charUserDescUUID; + break; + + case GATT_CLIENT_CHAR_CFG_UUID: + pRec = clientCharCfgUUID; + break; + + case GATT_SERV_CHAR_CFG_UUID: + pRec = servCharCfgUUID; + break; + + case GATT_CHAR_FORMAT_UUID: + pRec = charFormatUUID; + break; + + case GATT_CHAR_AGG_FORMAT_UUID: + pRec = charAggFormatUUID; + break; + + case GATT_VALID_RANGE_UUID: + pRec = validRangeUUID; + break; + + case GATT_EXT_REPORT_REF_UUID: + pRec = extReportRefUUID; + break; + + case GATT_REPORT_REF_UUID: + pRec = reportRefUUID; + break; + + /*** GATT Characteristics ***/ + + case DEVICE_NAME_UUID: + pRec = deviceNameUUID; + break; + + case APPEARANCE_UUID: + pRec = appearanceUUID; + break; + + case RECONNECT_ADDR_UUID: + pRec = reconnectAddrUUID; + break; + + case PERI_PRIVACY_FLAG_UUID: + pRec = periPrivacyFlagUUID; + break; + + case PERI_CONN_PARAM_UUID: + pRec = periConnParamUUID; + break; + + case SERVICE_CHANGED_UUID: + pRec = serviceChangedUUID; + break; + + /*** GATT Units ***/ + + default: + break; + } + } + else if ( len == ATT_UUID_SIZE ) + { + // 128-bit UUID + } + + return ( pRec ); +} + +/**************************************************************************** +****************************************************************************/ diff --git a/src/lib/ble_host/l2cap_if.c b/src/lib/ble_host/l2cap_if.c new file mode 100644 index 0000000..9fb8c43 --- /dev/null +++ b/src/lib/ble_host/l2cap_if.c @@ -0,0 +1,347 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: l2cap_if.c + Revised: + Revision: + + Description: This file contains the interfaces that L2CAP provides to the + upper layer applications. + + +**************************************************************************************************/ + + +/******************************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "linkdb.h" +#include "ll_common.h" +#include "l2cap_internal.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +// The Controller to Host flow control mode +static uint8 l2capFlowCtrlMode = FALSE; + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +/********************************************************************* + LOCAL FUNCTIONS +*/ + +/********************************************************************* + API FUNCTIONS +*/ + +/********************************************************************* + @fn L2CAP_RegisterApp + + @brief Register a protocol/application with an L2CAP channel. + + @param taskId - task to be registered with channel. + @param CID - channel ID. + + @return SUCCESS: Registration was successfull. + INVALIDPARAMETER: Channel ID is invalid. +*/ +bStatus_t L2CAP_RegisterApp( uint8 taskId, uint16 CID ) +{ + // We only support fixed channels for now + if ( FIX_CHANNEL( CID ) ) + { + FIX_CHANNEL_REC( CID ).CID = CID; + FIX_CHANNEL_REC( CID ).taskId = taskId; + return ( SUCCESS ); + } + + return ( INVALIDPARAMETER ); +} + +/********************************************************************* + @fn L2CAP_SendData + + @brief Send data packet over an L2CAP channel established over a physical connection. + + Note: Packet 'pPayload' must be allocated using L2CAP_bm_alloc(). + + @param connHandle - connection to be used. + @param pPkt - pointer to packet to be sent. + + @return SUCCESS: Data was sent successfully. + INVALIDPARAMETER: Channel ID is invalid. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t L2CAP_SendData( uint16 connHandle, l2capPacket_t* pPkt ) +{ + // We only support fixed channels for now + if ( !FIX_CHANNEL( pPkt->CID ) ) + { + return ( INVALIDPARAMETER ); + } + + // Make sure the physical connection is up + if ( !linkDB_Up( connHandle ) ) + { + return ( bleNotConnected ); + } + + // Find out destination CID for dynamic channels. + // Note: The local and remote CIDs are the same for fixed channels but could + // be different for the dynamic channels (which currently not supported). + // Encapsulate and send data + return ( l2capEncapSendData( connHandle, pPkt ) ); +} + +/********************************************************************* + @fn L2CAP_CmdReject + + @brief Send Command Reject. + + @param connHandle - connection to use + @param id - identifier of the request packet being rejected + @param pCmdReject - pointer to Command Reject to be sent + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Data can not fit into one packet. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t L2CAP_CmdReject( uint16 connHandle, uint8 id, l2capCmdReject_t* pCmdReject ) +{ + return ( l2capSendCmd( connHandle, L2CAP_CMD_REJECT, id, + (uint8*)(pCmdReject), L2CAP_BuildCmdReject ) ); +} + +/********************************************************************* + @fn L2CAP_EchoReq + + @brief Send Ehco Request. + + @param connHandle - connection to use + @param pEchoReq - pointer to Echo Request to be sent + @param taskId - task to be notified about result + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Data can not fit into one packet. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleNoResources: No available resource. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t L2CAP_EchoReq( uint16 connHandle, l2capEchoReq_t* pEchoReq, uint8 taskId ) +{ + if ( ( pEchoReq->len == 0 ) || ( pEchoReq->pData != NULL ) ) + { + return ( l2capSendReq( connHandle, L2CAP_ECHO_REQ, (uint8*)(pEchoReq), + l2capBuildEchoReq, L2CAP_W4_ECHO_RSP, taskId ) ); + } + + return ( INVALIDPARAMETER ); +} + +/********************************************************************* + @fn L2CAP_InfoReq + + @brief Send Information Request. + + @param connHandle - connection to use + @param pInfoReq - pointer to Info Request to be sent + @param taskId - task to be notified about result + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Data can not fit into one packet. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleNoResources: No available resource + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t L2CAP_InfoReq( uint16 connHandle, l2capInfoReq_t* pInfoReq, uint8 taskId ) +{ + return ( l2capSendReq( connHandle, L2CAP_INFO_REQ, (uint8*)(pInfoReq), + l2capBuildInfoReq, L2CAP_W4_INFO_RSP, taskId ) ); +} + +/********************************************************************* + @fn L2CAP_ConnParamUpdateReq + + @brief Send Connection Parameter Update Request. + + @param connHandle - connection to use + @param pUpdateReq - pointer to Update Request to be sent + @param taskId - task to be notified about result + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Data can not fit into one packet. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleMemAllocError: Memory allocation error occurred. + bleNotConnected: Connection is down. + bleNoResources: No available resource +*/ +bStatus_t L2CAP_ConnParamUpdateReq( uint16 connHandle, l2capParamUpdateReq_t* pUpdateReq, uint8 taskId ) +{ + return ( l2capSendReq( connHandle, L2CAP_PARAM_UPDATE_REQ, (uint8*)(pUpdateReq), + l2capBuildParamUpdateReq, L2CAP_W4_PARAM_UPDATE_RSP, taskId ) ); +} + +/********************************************************************* + @fn L2CAP_ConnParamUpdateRsp + + @brief Send Connection Parameter Update Response. + + @param connHandle - connection to use + @param id - identifier received in request + @param pUpdateRsp - pointer to Update Response to be sent + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Data can not fit into one packet. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t L2CAP_ConnParamUpdateRsp( uint16 connHandle, uint8 id, l2capParamUpdateRsp_t* pUpdateRsp ) +{ + return ( l2capSendCmd( connHandle, L2CAP_PARAM_UPDATE_RSP, id, + (uint8*)(pUpdateRsp), L2CAP_BuildParamUpdateRsp ) ); +} + +/********************************************************************* + @fn L2CAP_SetControllerToHostFlowCtrl + + @brief This API is used by the upper layer to turn flow control on + or off for data packets sent from the Controller to the Host. + + @param hostBuffSize - total data buffer available on Host + @param flowCtrlMode - flow control mode: TRUE or FALSE + + @return none +*/ +void L2CAP_SetControllerToHostFlowCtrl( uint16 hostBuffSize, uint8 flowCtrlMode ) +{ + // Save the flow control mode + l2capFlowCtrlMode = flowCtrlMode; + + // See if the flow control is enabled + if ( l2capFlowCtrlMode == TRUE ) + { + uint16 hostNumPkts = hostBuffSize / L2CAP_PDU_SIZE; + // First turn flow control on for data sent from the Controller to Host + VOID HCI_SetControllerToHostFlowCtrlCmd( HCI_CTRL_TO_HOST_FLOW_CTRL_ACL_ON_SYNCH_OFF ); + // Set the number of ACL packets the Controller can send to the Host + VOID HCI_HostBufferSizeCmd( L2CAP_PDU_SIZE, 0, hostNumPkts, 0 ); + } + else + { + // Turn flow control off for data sent from the Controller to Host + VOID HCI_SetControllerToHostFlowCtrlCmd( HCI_CTRL_TO_HOST_FLOW_CTRL_OFF ); + } +} + +void L2CAP_SetControllerToHostFlowCtrl_DLE( uint16 hostBuffSize, uint8 flowCtrlMode ) +{ + // Save the flow control mode + l2capFlowCtrlMode = flowCtrlMode; + + // See if the flow control is enabled + if ( l2capFlowCtrlMode == TRUE ) + { + ll_pdu_length_ctrl_t pdu; + extern void LL_PLUS_GetCurrentPduDle(uint8_t connId, ll_pdu_length_ctrl_t* ppdu); + LL_PLUS_GetCurrentPduDle(/*connId*/0,&pdu); + uint16 hostNumPkts = hostBuffSize / (pdu.MaxRxOctets); + // First turn flow control on for data sent from the Controller to Host + VOID HCI_SetControllerToHostFlowCtrlCmd( HCI_CTRL_TO_HOST_FLOW_CTRL_ACL_ON_SYNCH_OFF ); + // Set the number of ACL packets the Controller can send to the Host + VOID HCI_HostBufferSizeCmd( 0, 0, hostNumPkts, 0 ); + } + else + { + // Turn flow control off for data sent from the Controller to Host + VOID HCI_SetControllerToHostFlowCtrlCmd( HCI_CTRL_TO_HOST_FLOW_CTRL_OFF ); + } +} + + +/********************************************************************* + @fn L2CAP_HostNumCompletedPkts + + @brief This API is used by the upper layer to notify L2CAP of the + number of data packets that have been completed for connection + handle since this API was previously called. + + @param connHandle - connection handle + @param numCompletedPkts - number of completed packets + + @return none +*/ +void L2CAP_HostNumCompletedPkts( uint16 connHandle, uint16 numCompletedPkts ) +{ + // Check if Controller to Host flow control is enabled + if ( l2capFlowCtrlMode == TRUE ) + { + // Note: It's assumed that the upper layer will only free one buffer at a time. + VOID HCI_HostNumCompletedPktCmd( 1, &connHandle, &numCompletedPkts ); + } +} + + +/**************************************************************************** +****************************************************************************/ diff --git a/src/lib/ble_host/l2cap_task.c b/src/lib/ble_host/l2cap_task.c new file mode 100644 index 0000000..e1ee350 --- /dev/null +++ b/src/lib/ble_host/l2cap_task.c @@ -0,0 +1,525 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: l2cap_task.c + Revised: + Revision: + + Description: This file contains the L2CAP Task. It also includes the + L2CAP Channel Manager and Resource Manager components. + + +**************************************************************************************************/ + + +/******************************************************************************* + INCLUDES +*/ + +#include "bcomdef.h" +#include "osal_bufmgr.h" +#include "osal_cbtimer.h" + +#include "hci.h" + +#include "l2cap_internal.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ +// L2CAP task id +uint8 l2capTaskID; + +// L2CAP Fixed Channels table +l2capFixedChannel_t l2capFixedChannels[L2CAP_NUM_FIXED_CHANNELS]; + +// L2CAP Dynamic Channels table +l2capChannel_t l2capChannels[L2CAP_NUM_CHANNELS]; + +/********************************************************************* + EXTERNAL VARIABLES +*/ +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static void l2capProcessOSALMsg( osal_event_hdr_t* pMsg ); +static void l2capProcessRxData( hciDataEvent_t* pHciMsg ); +static void l2capProcessSignal( uint16 connHandle, l2capPacket_t* pPkt ); +static bStatus_t l2capProcessRsp( uint16 connHandle, l2capSignalHdr_t* pHdr, uint8* pData ); +static bStatus_t l2capProcessReq( uint16 connHandle, l2capSignalHdr_t* pHdr, uint8* pData ); + +/********************************************************************* + API FUNCTIONS +*/ + +/********************************************************************* + @fn L2CAP_Init() + + @brief Initialize the L2CAP layer. + + @param taskId - Task identifier for the desired task + + @return none +*/ +void L2CAP_Init( uint8 taskId ) +{ + uint8 i; + l2capTaskID = taskId; + + // Initialize all fixed channel structures + for ( i = 0; i < L2CAP_NUM_FIXED_CHANNELS; i++ ) + { + l2capFixedChannels[i].CID = L2CAP_CID_NULL; + } + + // Initialize all dynamic channel structures + for ( i = 0; i < L2CAP_NUM_CHANNELS; i++ ) + { + l2capChannels[i].CID = L2CAP_CID_NULL; + l2capChannels[i].state = L2CAP_CLOSED; + l2capChannels[i].timerId = INVALID_TIMER_ID; + } + + // Register with HCI to receive data message + HCI_L2CAPTaskRegister( l2capTaskID ); + // resert SAR buffers + l2capSarBufReset(); + // Register with Link DB to receive link status change callback + //VOID linkDB_Register( pfnLinkDBCB pFunc ); // needed for dynamic channels +} + +/********************************************************************* + @fn L2CAP_ProcessEvent() + + @brief L2CAP Task event processing function. This function should + be called at periodic intervals when event occur. + + @param taskId - Task ID + @param events - Bitmap of events + + @return none +*/ +uint16 L2CAP_ProcessEvent( uint8 taskId, uint16 events ) +{ + uint8* pMsg; + VOID taskId; // required by OSAL but not used here + + if ( events & SYS_EVENT_MSG ) + { + if ( (pMsg = osal_msg_receive( l2capTaskID )) != NULL ) + { + l2capProcessOSALMsg( (osal_event_hdr_t*)pMsg ); + // Release the OSAL message + VOID osal_msg_deallocate( pMsg ); + } + + // Return unprocessed events + return (events ^ SYS_EVENT_MSG); + } + + // Discard unknown events + return 0; +} + +/********************************************************************* + @fn l2capProcessOSALMsg + + @brief Process an incoming OSAL task message. + + @param pMsg - message to process + + @return none +*/ +static void l2capProcessOSALMsg( osal_event_hdr_t* pMsg ) +{ + switch ( pMsg->event ) + { + case HCI_DATA_EVENT: + // Process incoming HCI Data message + l2capProcessRxData( (hciDataEvent_t*)pMsg ); + break; + + default: + // Unknown message - drop it. + break; + } +} + +/********************************************************************* + @fn l2capProcessRxData + + @brief Process an incoming HCI data message. + + @param pHciMsg - message to process + + @return none +*/ +static void l2capProcessRxData( hciDataEvent_t* pHciMsg ) +{ + l2capPacket_t pkt; + uint8 free; + uint16 connHandle = pHciMsg->connHandle; + // First parse the packet + free = l2capParsePacket( &pkt, pHciMsg ); + + if ( pkt.pPayload != NULL ) + { + // We received the entire packet; try to process it + if ( pkt.CID == L2CAP_CID_SIG ) + { + // Signaling protocol + l2capProcessSignal( connHandle, &pkt ); + } + else if ( ( pkt.CID == L2CAP_CID_ATT ) + || ( pkt.CID == L2CAP_CID_SMP ) + || ( pkt.CID == L2CAP_CID_GENERIC ) ) + { + // Application fixed channel data + if ( FIX_CHANNEL_REC( pkt.CID ).CID != L2CAP_CID_NULL ) + { + // Forward the data packet up to the application + // the pkt will be free in high layer-->ATT-->GATT + if ( l2capNotifyData( FIX_CHANNEL_REC( pkt.CID ).taskId, connHandle, &pkt ) == SUCCESS ) + { + // Consider received packet processed unless it's an ATT packet + if ( pkt.CID != L2CAP_CID_ATT ) + { + L2CAP_HostNumCompletedPkts( connHandle, 1 ); + } + + if ( free==TRUE) + { + // No need to hold on the received buffer any longer + if(pHciMsg->pData != NULL) + { + osal_bm_free( pHciMsg->pData ); + } + } + + return; // We're done here + } + } + } + else + { + // Unknown CID + } + + // We're done processing the packet + free = TRUE; + } + + if ( free == TRUE ) + { + // No need to hold on the received buffer any longer + if ( pHciMsg->pData != NULL ) + { + osal_bm_free( pHciMsg->pData ); + } + } + + // Consider received packet processed + L2CAP_HostNumCompletedPkts( connHandle, 1 ); +} + +/********************************************************************* + @fn l2capProcessSignal + + @brief Process an incoming L2CAP signaling packet. + + @param connHandle - connection packet was received on + @param pPkt - packet to process + + @return none +*/ +static void l2capProcessSignal( uint16 connHandle, l2capPacket_t* pPkt ) +{ + bStatus_t status = SUCCESS; + + // Make sure we've received enough data to proceed + if ( pPkt->len >= L2CAP_HDR_SIZE ) + { + l2capSignalHdr_t hdr; + // Parse Signaling header + l2capParseSignalHdr( &hdr, pPkt->pPayload ); + + // Make sure the information pPayload length doesn't exceed our Signaling MTU + if ( hdr.len <= L2CAP_SIG_MTU_SIZE ) + { + // Multiple commands in Signaling packet is not supported + if ( pPkt->len == L2CAP_HDR_SIZE + hdr.len ) + { + // Try to proccess the packet + if ( hdr.opcode & 0x01 ) + { + // It's a response message (odd opcode) + status = l2capProcessRsp( connHandle, &hdr, &(pPkt->pPayload[SIGNAL_HDR_SIZE]) ); + } + else + { + // It's a request message (even opcode) + status = l2capProcessReq( connHandle, &hdr, &(pPkt->pPayload[SIGNAL_HDR_SIZE]) ); + } + } + else + { + // Don't process the packet + status = FAILURE; + } + } + else + { + l2capCmdReject_t cmdReject; + // Send a Command Reject containing the supported Signaling MTU + cmdReject.reason = L2CAP_REJECT_SIGNAL_MTU_EXCEED; + cmdReject.maxSignalMTU = L2CAP_SIG_MTU_SIZE; + VOID L2CAP_CmdReject( connHandle, hdr.id, &cmdReject ); + } + } + + if ( status != SUCCESS ) + { + // The request or response message was received with an error + l2capHandleRxError( connHandle ); + } +} + +/********************************************************************* + @fn l2capProcessRsp + + @brief Process an incoming response message. + + @param connHandle - connection command was received on + @param pHdr - pointer to signaling header + @param pData - pointer to command data + + @return SUCCESS: Command was processed successfully. + INVALIDPARAMETER: Command length is invalid. +*/ +static bStatus_t l2capProcessRsp( uint16 connHandle, l2capSignalHdr_t* pHdr, uint8* pData ) +{ + l2capSignalCmd_t cmd; + l2capChannel_t* pChannel; + bStatus_t status = FAILURE; + // We sent the request; find the channel using the local identifier + pChannel = l2capFindLocalId( pHdr->id ); + + if ( pChannel == NULL ) + { + // Invalid response or channel has been closed + return ( SUCCESS ); + } + + // Reset the request identifier + pChannel->id = 0; + + // Parse and process the signaling command + switch ( pHdr->opcode ) + { + case L2CAP_CMD_REJECT: + // Parse the command + status = l2capParseCmdReject( &cmd, pData, pHdr->len ); + break; + #if 0 // No longer supported + + case L2CAP_ECHO_RSP: + if ( pChannel->state != L2CAP_W4_ECHO_RSP ) + { + // We're not expecting an Echo Response. + return ( SUCCESS ); + } + + // Parse the response + status = l2capParseEchoRsp( &cmd, pData, pHdr->len ); + break; + + case L2CAP_INFO_RSP: + if ( pChannel->state != L2CAP_W4_INFO_RSP ) + { + // We're not expecting an Information Response. + return ( SUCCESS ); + } + + // Parse the response + status = l2capParseInfoRsp( &cmd, pData, pHdr->len ) ; + break; + #endif + + case L2CAP_PARAM_UPDATE_RSP: + if ( pChannel->state != L2CAP_W4_PARAM_UPDATE_RSP ) + { + // We're not expecting a Connection Parameter Update Response. + return ( SUCCESS ); + } + + // Parse the response + status = l2capParseParamUpdateRsp( &cmd, pData, pHdr->len ); + break; + + default: + // Unknown command + return ( SUCCESS ); + } + + // Stop the timeout timer for this channel + l2capStopTimer( pChannel ); + // Forward the response to the application + l2capNotifySignal( pChannel->taskId, connHandle, status, pHdr->opcode, 0, &cmd ); + // Free the channel + l2capFreeChannel( pChannel ); + return ( status ); +} + +/********************************************************************* + @fn l2capProcessReq + + @brief Process an incoming request message. + + @param connHandle - connection command was received on + @param pHdr - pointer to signaling header + @param pData - pointer to command data + + @return SUCCESS: Command was processed successfully. + INVALIDPARAMETER: Command length is invalid. +*/ +static bStatus_t l2capProcessReq( uint16 connHandle, l2capSignalHdr_t* pHdr, uint8* pData ) +{ + bStatus_t status = SUCCESS; + + // Parse and process the signaling command + switch ( pHdr->opcode ) + { + #if 0 // No longer supported + + case L2CAP_ECHO_REQ: + // Nothing to parse; just echo back the received data + { + l2capEchoRsp_t echoRsp; + // Send an Echo Response. + echoRsp.pData = pData; + echoRsp.len = pHdr->len; + VOID l2capEchoRsp( connHandle, pHdr->id, &echoRsp ); + } + break; + + case L2CAP_INFO_REQ: + { + l2capSignalCmd_t cmd; + status = L2CAP_ParseInfoReq( &cmd, pData, pHdr->len ) ; + + if ( status == SUCCESS ) + { + l2capInfoRsp_t infoRsp; + // Send an Info Response. + infoRsp.infoType = cmd.infoReq.infoType; + + if ( infoRsp.infoType == L2CAP_INFO_EXTENDED_FEATURES ) + { + // Indicate that we support Fixed Channels feature + infoRsp.info.extendedFeatures = L2CAP_FIXED_CHANNELS; + infoRsp.result = L2CAP_INFO_SUCCESS; + } + else if ( infoRsp.infoType == L2CAP_INFO_FIXED_CHANNELS ) + { + VOID osal_memset( infoRsp.info.fixedChannels, 0, L2CAP_FIXED_CHANNELS_SIZE ); + // Indicate Fixed Channels that we support + infoRsp.info.fixedChannels[0] = ( L2CAP_FIXED_CHANNELS_ATT | + L2CAP_FIXED_CHANNELS_SIG | + L2CAP_FIXED_CHANNELS_SMP ); + infoRsp.result = L2CAP_INFO_SUCCESS; + } + else + { + infoRsp.result = L2CAP_INFO_NOT_SUPPORTED; + } + + VOID l2capInfoRsp( connHandle, pHdr->id, &infoRsp ); + } + } + break; + #endif + + case L2CAP_PARAM_UPDATE_REQ: + { + l2capSignalCmd_t cmd; + status = L2CAP_ParseParamUpdateReq( &cmd, pData, pHdr->len ); + + if ( status == SUCCESS ) + { + // Send the request up to the application for processing + if ( FIX_CHANNEL_REC( L2CAP_CID_SIG ).CID != L2CAP_CID_NULL ) + { + l2capNotifySignal( FIX_CHANNEL_REC( L2CAP_CID_SIG ).taskId, connHandle, + SUCCESS, pHdr->opcode, pHdr->id, &cmd ); + } + } + } + break; + + default: + // Unsupported command -- send a Command Reject back + { + l2capCmdReject_t cmdReject; + cmdReject.reason = L2CAP_REJECT_CMD_NOT_UNDERSTOOD; + VOID L2CAP_CmdReject( connHandle, pHdr->id, &cmdReject ); + } + break; + } + + return ( status ); +} + + + +/**************************************************************************** +****************************************************************************/ diff --git a/src/lib/ble_host/l2cap_util.c b/src/lib/ble_host/l2cap_util.c new file mode 100644 index 0000000..c84f36c --- /dev/null +++ b/src/lib/ble_host/l2cap_util.c @@ -0,0 +1,1744 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: l2cap_util.c + Revised: + Revision: + + Description: This file contains the L2CAP utility funtions. It includes the + L2CAP Encapsulation and Fragmentation/Recombination components. + + +**************************************************************************************************/ + + +/******************************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "osal_bufmgr.h" +#include "osal_cbtimer.h" + +#include "hci.h" +#include "linkdb.h" + +#include "l2cap_internal.h" + +#include "ll_def.h" +#include "ll_common.h" +#include "att.h" +#include "global_config.h" + +/********************************************************************* + MACROS +*/ + +// Return the next available Signaling identifier. +// Note: Signaling identifier of 0 is not valid. +#define NEXT_SIG_ID() ( ++l2capId == 0 ? l2capId = 1 : l2capId ) + +/********************************************************************* + CONSTANTS +*/ +// Length of Command Reject fixed field: reason (2) +#define CMD_REJECT_FIXED_SIZE 2 + +// Length of Information Request: Info type (2) +#define INFO_REQ_SIZE 2 + +// Length of Information Response fixed fields: Info type (2) + Result (2) +#define INFO_RSP_FIXED_SIZE ( 2 + 2 ) + +// Length of Connection Parameter Update Request: Int min (2) + Int max (2) + Latency (2) + Timeout (2) +#define PARAM_UPDATE_REQ_SIZE ( 2 + 2 + 2 + 2 ) + +// Length of Connection Parameter Update Response: Status (2) +#define PARAM_UPDATE_RSP_SIZE 2 + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ +l2capReassemblePkt_t l2capReassemblePkt[MAX_NUM_LL_CONN]; +l2capSegmentBuff_t l2capSegmentPkt[MAX_NUM_LL_CONN]; +l2capSARDbugCnt_t g_sarDbgCnt; +uint8 l2capExtendFragments = TRUE; +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +// L2CAP Signaling identifier +static uint8 l2capId = 0; + +/********************************************************************* + LOCAL FUNCTIONS +*/ +l2capChannel_t* l2capAllocChannel( uint8 taskId ); +static void l2capBuildSignalHdr( l2capSignalHdr_t* pHdr, uint8* pData ); +static bStatus_t l2capAllocConnChannel( uint16 connHandle, uint8 taskId, l2capChannel_t** p2pChannel ); +static void l2capStartTimer( l2capChannel_t* pChannel, uint16 timeout ); +static bStatus_t L2CAP_SendDataPkt( uint16 connHandle, uint16 pktLen, uint8* pData ); +static void l2capHandleTimerCB( uint8* pData ); + +/********************************************************************* + @fn l2capParseSignalHdr + + @brief Parse the L2CAP Signaling header. + + @param pHdr - pointer to signaling header + @param pData - pointer to message to be parsed + + @return none +*/ +void l2capParseSignalHdr( l2capSignalHdr_t* pHdr, uint8* pData ) +{ + // Parse the signaling header + pHdr->opcode = pData[0]; + pHdr->id = pData[1]; + pHdr->len = BUILD_UINT16( pData[2], pData[3] ); +} + +/********************************************************************* + @fn l2capBuildSignalHdr + + @brief Build the L2CAP Signaling header. + + @param pHdr - pointer to signaling header + @param pData - pointer to message to be built + + @return none +*/ +static void l2capBuildSignalHdr( l2capSignalHdr_t* pHdr, uint8* pData ) +{ + // Build the signaling header + pData[0] = pHdr->opcode; + pData[1] = pHdr->id; + pData[2] = LO_UINT16( pHdr->len ); + pData[3] = HI_UINT16( pHdr->len ); +} + +/********************************************************************* + @fn l2capSendReq + + @brief Send an L2CAP Signaling Request. + + @param connHandle - connection to use + @param opcode - type of command + @param pReq - request to be sent + @param pfnBuildCmd - function to build request + @param state - state of channel + @param taskId - task to be notified about result + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Data can not fit into one packet. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + FAILURE: Internal error occured. + bleMemAllocError: Memory allocation error occurred. + bleNotConnected: Connection is down. + bleNoResources: No available resource +*/ +bStatus_t l2capSendReq( uint16 connHandle, uint8 opcode, uint8* pReq, + pfnL2CAPBuildCmd_t pfnBuildCmd, uint8 state, uint8 taskId ) +{ + l2capChannel_t* pChannel; + uint8 status; + status = l2capAllocConnChannel( connHandle, taskId, &pChannel ); + + if ( status == SUCCESS ) + { + // Set up the channel info + pChannel->state = state; + pChannel->id = NEXT_SIG_ID(); + status = l2capSendCmd( connHandle, opcode, pChannel->id, pReq, pfnBuildCmd ); + + if ( status == SUCCESS ) + { + l2capStartTimer( pChannel, L2CAP_RTX_TIMEOUT ); + } + else + { + l2capFreeChannel( pChannel ); + } + } + + return ( status ); +} + +/********************************************************************* + @fn l2capSendCmd + + @brief Send an L2CAP Signaling command. + + @param connHandle - connection to use + @param opcode - type of command + @param id - identifier + @param pCmd - command data + @param pfnBuildCmd - function to build command + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Data can not fit into one packet. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t l2capSendCmd( uint16 connHandle, uint8 opcode, uint8 id, + uint8* pCmd, pfnL2CAPBuildCmd_t pfnBuildCmd ) +{ + uint8* pBuf; + bStatus_t status; + // Allocate space for the message + pBuf = (uint8*)L2CAP_bm_alloc( L2CAP_SIG_MTU_SIZE ); + + if ( pBuf != NULL ) + { + l2capPacket_t pkt; + l2capSignalHdr_t hdr; + // Set up the signaling header + hdr.opcode = opcode; + hdr.id = id; + + // First build the data field of the command + if ( pfnBuildCmd != NULL ) + { + // length of data field + hdr.len = (*pfnBuildCmd)( &(pBuf[SIGNAL_HDR_SIZE]), pCmd ); + } + else + { + // length of data field + hdr.len = 0; + } + + // Build the signaling header + l2capBuildSignalHdr( &hdr, pBuf ); + // Set up the L2CAP packet + pkt.CID = L2CAP_CID_SIG; // destination CID + pkt.pPayload = pBuf; + pkt.len = hdr.len + SIGNAL_HDR_SIZE; // length of pPayload + // Encapsulate and send the command + status = l2capEncapSendData( connHandle, &pkt ); + + if ( status != SUCCESS ) + { + // Free the buffer + osal_bm_free( pBuf ); + } + } + else + { + status = bleMemAllocError; + } + + return ( status ); +} + +/********************************************************************* + @fn l2capEncapSendData + + @brief Encapsulate and send an L2CAP data packet over a physical connection. + + Note: Packet 'pPayload' must be allocated using L2CAP_bm_alloc(). + + @param connHandle - connection handle to use + @param pPkt - pointer to packet to be sent (must contain destination CID) + + @return SUCCESS: Request was sent successfully. + INVALIDPARAMETER: Data can not fit into one packet. + MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. + bleNotConnected: Connection is down. + bleMemAllocError: Memory allocation error occurred. +*/ +bStatus_t l2capEncapSendData( uint16 connHandle, l2capPacket_t* pPkt ) +{ + uint8* pBuf; + uint8* pHdr; + uint8 totalLen; + // Get a pointer to basic L2CAP header + pBuf = osal_bm_adjust_header( pPkt->pPayload, L2CAP_HDR_SIZE ); + // Fill in L2CAP header fields + pHdr = pBuf; + *pHdr++ = LO_UINT16( pPkt->len ); // Payload length + *pHdr++ = HI_UINT16( pPkt->len ); + // Destination Channel ID + *pHdr++ = LO_UINT16( pPkt->CID ); + *pHdr++ = HI_UINT16( pPkt->CID ); + // Add PDU header length to total packet length + totalLen = pPkt->len + L2CAP_HDR_SIZE; + + // See if data can fit into one packet + if ( totalLen <= L2CAP_PDU_SIZE ) + { + uint8 status; + + // This is the first packet + if ( connHandle == LOOPBACK_CONNHANDLE ) + { + // Loop back the data packet + status = L2CAP_SendDataPkt( connHandle, totalLen, pBuf ); + } + else + { + #if 0 + // Send the data packet to the Controller + // Note: Host to Controller Data Flow Control is not supported yet! + // Host should use the LE Read Buffer Size command to determine + // the maximum size and the total number of HCI Data Packets. + status = HCI_SendDataPkt( connHandle, FIRST_PKT_HOST_TO_CTRL, totalLen, pBuf ); + + // Map HCI status codes to Host status codes + switch ( status ) + { + case HCI_ERROR_CODE_UNKNOWN_CONN_ID: + status = bleNotConnected; + break; + + case HCI_ERROR_CODE_INVALID_HCI_CMD_PARAMS: + status = INVALIDPARAMETER; + break; + + case HCI_ERROR_CODE_MEM_CAP_EXCEEDED: + status = MSG_BUFFER_NOT_AVAIL; + break; + + default: + // Should never get here! + break; + } + + #else + #if 0 + //========================================================== + // add by ZQ for l2capSAR 20181026 + //========================================================== + uint8 llBufLimit = g_llPduLen.local.MaxTxOctets;//LL_MAX_LINK_DATA_LEN; + + //See if need to do fragment + if(totalLen<=llBufLimit) + { + status=L2CAP_Fragment_SendDataPkt( connHandle, FIRST_PKT_HOST_TO_CTRL, totalLen, pBuf ); + } + else + { + uint8* fBuf; + uint8* pBufTmp = pBuf; + uint8 fpLen = totalLen / llBufLimit; + uint8 resLen = totalLen-fpLen*llBufLimit; + + for(uint8 i=0; i0) + { + fBuf=(uint8*) L2CAP_Fragment_bm_alloc(resLen); + osal_memcpy(fBuf, pBufTmp, resLen); + status=L2CAP_Fragment_SendDataPkt( connHandle, CONTINUING_PKT, resLen, fBuf ); + osal_bm_free(fBuf); + LOG("[SAR_TX] %08x %d \n",fBuf,status); + } + + //free the l2cap buf + if(status==SUCCESS) + { + osal_bm_free(pBuf); + } + } + } + + #else + +// LOG("%08x [EBUF_IN ] (D%d I%d F%d)\n",g_osal_mem_allo_cnt-g_osal_mem_free_cnt, +// l2capSegmentPkt.depth, +// l2capSegmentPkt.idx, +// l2capSegmentPkt.fragment); + //========================================================== + // add by ZQ for l2capSAR pingpang buffer 20181104 + //========================================================== + //-------------------------------------------------------------------- + //receiver l2cap to buffer + //-------------------------------------------------------------------- + //status is determinded by the reciver buff + //if the pkt is buffered, the status should be success + //otherwise, it should be return as HCI_ERROR_CODE_MEM_CAP_EXCEEDED + //when fragment is existed, new l2cPkt will not be buffed + + if(l2capSegmentPkt[connHandle].fragment==FALSE) + { + status = l2capPktToSegmentBuff(connHandle,&l2capSegmentPkt[connHandle],totalLen, pBuf ); + + if(status!=SUCCESS) + { + LOG("[SBUF FULL] ERR %d 0x%02x\n",g_sarDbgCnt.segmentMemAlocErr,status); + } + } + else + { + //fragment pkt being retx in next connIntv + status = HCI_ERROR_CODE_MEM_CAP_EXCEEDED; + g_sarDbgCnt.segmentErrCnt++; + LOG("[SBUF FRAG FULL]\n"); + } + +// LOG("%08x [SBUF_IN ] (D%d I%d F%d) 0x%02x\n",g_osal_mem_allo_cnt-g_osal_mem_free_cnt, +// l2capSegmentPkt.depth, +// l2capSegmentPkt.idx, +// l2capSegmentPkt.fragment, +// status); + + //-------------------------------------------------------------------- + //process buff + //-------------------------------------------------------------------- + //uint8 sendSatus=MSG_BUFFER_NOT_AVAIL; + + //only send the l2cap pkt form header here + //the fragment pkt will be processed in ll_salveEndCase... + if(l2capSegmentPkt[connHandle].fragment==FALSE) + { + l2capSegmentBuffToLinkLayer(connHandle,&l2capSegmentPkt[connHandle]); + } + +// LOG("%08x [SBUF_OUT] (D%d I%d F%d) 0x%02x\n",g_osal_mem_allo_cnt-g_osal_mem_free_cnt, +// l2capSegmentPkt.depth, +// l2capSegmentPkt.idx, +// l2capSegmentPkt.fragment, +// sendSatus); + #endif + #endif + } + + return ( status ); + } + + // Fragment data and send each fragment separately -- not supported yet! + return ( INVALIDPARAMETER ); +} + +/********************************************************************* + @fn l2capParsePacket + + @brief Parse an incoming L2CAP packet received over a physical connection. + + @param pPkt - pointer to L2CAP packet to be built. + @param pHciMsg - pointer to received HCI message. + + @return TRUE: Data buffer must be freed. + FALSE: Data buffer must not be freed. +*/ + +uint16 currSeqNum; +uint8 l2capParsePacket( l2capPacket_t* pPkt, hciDataEvent_t* pHciMsg ) +{ + uint16 connHandle = pHciMsg->connHandle; + // Initialize the payload + pPkt->pPayload = NULL; + + // See if this is the first segment + if ( pHciMsg->pbFlag == FIRST_PKT_CTRL_TO_HOST ) + { + // We need the first 4 bytes of the packet to proceed + if ( pHciMsg->len >= L2CAP_HDR_SIZE ) + { + // Get payload length and channel id + uint16 len = BUILD_UINT16( pHciMsg->pData[0], pHciMsg->pData[1] ); + uint16 CID = BUILD_UINT16( pHciMsg->pData[2], pHciMsg->pData[3] ); +// LOG("%08x [L2C_RX]L%04x C%04x ATT%02x %02x %02x %02x %02x\n",getMcuPrecisionCount(),len,CID, +// pHciMsg->pData[4], +// pHciMsg->pData[5], +// pHciMsg->pData[6], +// pHciMsg->pData[7], +// pHciMsg->pData[8]); + currSeqNum=BUILD_UINT16( pHciMsg->pData[8], pHciMsg->pData[7] ); + + // See if the packet was unsegmented + if ( ( len + L2CAP_HDR_SIZE ) == pHciMsg->len ) + { + // Make sure this is a valid channel; we only support fixed channels for now + if ( !FIX_CHANNEL( CID ) ) + { + // Indicate to the caller to free the data buffer + LOG("[SAR_RX ERR] NoSar c %x\n",CID); + return ( TRUE ); + } + + if(CID==L2CAP_CID_ATT && l2capReassemblePkt[connHandle].cIdx>0) + { + LOG("[SAR_RX ERR %d] %d %d\n",__LINE__,currSeqNum,l2capReassemblePkt[connHandle].cIdx); + L2CAP_ReassemblePkt_Reset(connHandle); + g_sarDbgCnt.reassembleErrInComp++; + } + + // We received the entire packet (unfragmented) + pPkt->len = len; + pPkt->CID = CID; + // Get a pointer to payload + pPkt->pPayload = osal_bm_adjust_header( pHciMsg->pData, -L2CAP_HDR_SIZE ); +// LOG("%08x [ABUF_IN] NoSar ( %08x L %d C %d) \n",g_osal_mem_allo_cnt-g_osal_mem_free_cnt, +// pPkt->pPayload ,len,CID); + // Indicate to the caller not to free the data buffer yet + return ( FALSE ); + } + else + { + // This is the start of a new fragmented packet -- fragmentation is NOW supported ! + //========================================================== + // add by ZQ for l2capSAR 20181026 + //========================================================== + // Make sure this is a valid channel; we only support fixed channels for now + if ( !FIX_CHANNEL( CID ) ) + { + // Indicate to the caller to free the data buffer + LOG("[SAR_RX ERR %d] %d %d\n",__LINE__,currSeqNum,CID); + g_sarDbgCnt.reassembleErrCID++; + return ( TRUE ); + } + + if(CID==L2CAP_CID_ATT && l2capReassemblePkt[connHandle].cIdx>0) + { + LOG("[SAR_RX ERR %d] %d %d\n",__LINE__,currSeqNum,l2capReassemblePkt[connHandle].cIdx); + L2CAP_ReassemblePkt_Reset(connHandle); + g_sarDbgCnt.reassembleErrInComp++; + } + + l2capReassemblePkt[connHandle].cIdx = 0; + l2capReassemblePkt[connHandle].pkt.len = len; + l2capReassemblePkt[connHandle].pkt.CID = CID; + l2capReassemblePkt[connHandle].pkt.pPayload = L2CAP_bm_alloc(len); + + if(l2capReassemblePkt[connHandle].pkt.pPayload!=NULL) + { + //for the first segment pkt, need copy from the l2cap header + osal_memcpy(l2capReassemblePkt[connHandle].pkt.pPayload, + osal_bm_adjust_header( pHciMsg->pData, -L2CAP_HDR_SIZE ), + pHciMsg->len-L2CAP_HDR_SIZE); + l2capReassemblePkt[connHandle].cIdx+=(pHciMsg->len-L2CAP_HDR_SIZE); + g_sarDbgCnt.reassembleInCnt++; +// LOG("%08x [ABUF_IN] ST ( %08x L %d C %d) \n",g_osal_mem_allo_cnt-g_osal_mem_free_cnt, +// l2capReassemblePkt[connHandle].pkt.pPayload,len,CID); + } + else + { + g_sarDbgCnt.resssambleMemAlocErr++; +// LOG("%08x [ABUF_IN ] FULL %d \n",g_osal_mem_allo_cnt-g_osal_mem_free_cnt,g_sarDbgCnt.resssambleMemAlocErr); + } + + // Indicate to the caller to free the data buffer + return ( TRUE ); + } + } + } + else + { + //========================================================== + // add by ZQ for l2capSAR 20181026 + //========================================================== + if( l2capReassemblePkt[connHandle].cIdx>0 + && l2capReassemblePkt[connHandle].pkt.pPayload!=NULL + && pHciMsg->pbFlag==CONTINUING_PKT ) + { + l2capReassemblePkt[connHandle].cIdx+=pHciMsg->len; + + if(l2capReassemblePkt[connHandle].cIdx<=l2capReassemblePkt[connHandle].pkt.len) + { + //for the residual segment pkt, need copy all + osal_memcpy(l2capReassemblePkt[connHandle].pkt.pPayload+l2capReassemblePkt[connHandle].cIdx-pHciMsg->len, + pHciMsg->pData,pHciMsg->len); + +// LOG("%08x [ABUF_IN] Idx++ %d %02x\n",g_osal_mem_allo_cnt-g_osal_mem_free_cnt, +// l2capReassemblePkt[connHandle].cIdx, +// pHciMsg->pData[0]); + + if(l2capReassemblePkt[connHandle].cIdx==l2capReassemblePkt[connHandle].pkt.len) + { + // We received the entire packet (fragmented) + pPkt->len = l2capReassemblePkt[connHandle].pkt.len; + pPkt->CID = l2capReassemblePkt[connHandle].pkt.CID; + // Get a pointer to payload + pPkt->pPayload = l2capReassemblePkt[connHandle].pkt.pPayload; + l2capReassemblePkt[connHandle].cIdx = 0; + g_sarDbgCnt.reassembleOutCnt++; + // Indicate to the caller not to free the data buffer yet + return ( TRUE ); + } + } + else + { + //error case +// LOG("[SAR_RX ERR %d %d] %d p%08x L %d C %d\n",__LINE__,currSeqNum, +// g_sarDbgCnt.reassembleErrIdx, +// l2capReassemblePkt.pkt.pPayload, +// l2capReassemblePkt.pkt.len, +// l2capReassemblePkt.cIdx); + g_sarDbgCnt.reassembleErrIdx++; + L2CAP_ReassemblePkt_Reset(connHandle); + } + } + else + { + //error case + LOG("[SAR_RX ERR %d %d] %d p%08x L %d C %d\n",__LINE__,currSeqNum, + g_sarDbgCnt.reassembleErrMiss, + l2capReassemblePkt[connHandle].pkt.pPayload, + l2capReassemblePkt[connHandle].pkt.len, + l2capReassemblePkt[connHandle].cIdx); + g_sarDbgCnt.reassembleErrMiss++; + L2CAP_ReassemblePkt_Reset(connHandle); + } + } + + // Indicate to the caller to free the data buffer + return ( TRUE ); +} + +/********************************************************************* + @fn L2CAP_BuildCmdReject + + @brief Build Command Reject. + + @param pBuf - pointer to buffer to hold command data + @param pCmd - pointer to command data + + @return length of the command data +*/ +uint16 L2CAP_BuildCmdReject( uint8* pBuf, uint8* pCmd ) +{ + uint16 len = CMD_REJECT_FIXED_SIZE; + l2capCmdReject_t* pReject = (l2capCmdReject_t*)pCmd; + // Reason + *pBuf++ = LO_UINT16( pReject->reason ); + *pBuf++ = HI_UINT16( pReject->reason ); + + // Reason data + if ( pReject->reason == L2CAP_REJECT_SIGNAL_MTU_EXCEED ) + { + // Signaling MTU + *pBuf++ = LO_UINT16( pReject->maxSignalMTU ); + *pBuf = HI_UINT16( pReject->maxSignalMTU ); + len += 2; + } + else if ( pReject->reason == L2CAP_REJECT_INVALID_CID ) + { + // Local CID + *pBuf++ = LO_UINT16( pReject->invalidLocalCID ); + *pBuf++ = HI_UINT16( pReject->invalidLocalCID ); + // Remote CID + *pBuf++ = LO_UINT16( pReject->invalidRemoteCID ); + *pBuf = HI_UINT16( pReject->invalidRemoteCID ); + len += 4; + } + + // else no Reason Data for L2CAP_REJECT_CMD_NOT_UNDERSTOOD + return ( len ); +} + +/********************************************************************* + @fn l2capParseCmdReject + + @brief Parse Command Reject message. + + @param pCmd - pointer to command data to be built + @param pData - pointer to incoming command data to be parsed + @param len - length of incoming command data + + @return SUCCESS: Command was parsed successfully. + FAILURE: Command length is invalid. +*/ +bStatus_t l2capParseCmdReject( l2capSignalCmd_t* pCmd, uint8* pData, uint16 len ) +{ + if ( len >= CMD_REJECT_FIXED_SIZE ) + { + l2capCmdReject_t* pReject = &pCmd->cmdReject; + // Reason + pReject->reason = BUILD_UINT16( pData[0], pData[1] ); + + // Reason data + if ( pReject->reason == L2CAP_REJECT_SIGNAL_MTU_EXCEED ) + { + // Signaling MTU + pReject->maxSignalMTU = BUILD_UINT16( pData[2], pData[3] ); + } + else if ( pReject->reason == L2CAP_REJECT_INVALID_CID ) + { + // Local CID + pReject->invalidLocalCID = BUILD_UINT16( pData[2], pData[3] ); + // Remote CID + pReject->invalidRemoteCID = BUILD_UINT16( pData[4], pData[5] ); + } + + // else no Reason Data for L2CAP_REJECT_CMD_NOT_UNDERSTOOD + return ( SUCCESS ); + } + + return ( FAILURE ); +} + +/********************************************************************* + @fn l2capBuildEchoReq + + @brief Build Echo Request. + + @param pBuf - pointer to buffer to hold command data + @param pCmd - pointer to command data + + @return length of the command data +*/ +uint16 l2capBuildEchoReq( uint8* pBuf, uint8* pCmd ) +{ + uint16 len; + l2capEchoReq_t* pReq = (l2capEchoReq_t*)pCmd; + + if ( pReq->len > SIGNAL_DATA_SIZE ) + { + len = SIGNAL_DATA_SIZE; + } + else + { + len = pReq->len; + } + + // Copy data field over + if ( len > 0 ) + { + VOID osal_memcpy( pBuf, pReq->pData, len ); + } + + return ( len ); +} + +/********************************************************************* + @fn l2capBuildEchoRsp + + @brief Build Echo Response message. + + @param pBuf - pointer to buffer to hold command data + @param pCmd - pointer to command data + + @return length of the command data +*/ +uint16 l2capBuildEchoRsp( uint8* pBuf, uint8* pCmd ) +{ + l2capEchoRsp_t* pRsp = (l2capEchoRsp_t*)pCmd; + uint16 len = pRsp->len; + + if ( len > 0 ) + { + if ( len > SIGNAL_DATA_SIZE ) + { + // Reset it to the max + len = SIGNAL_DATA_SIZE; + } + + // Copy data field over + VOID osal_memcpy( pBuf, pRsp->pData, len ); + } + + return ( len ); +} + +/********************************************************************* + @fn l2capParseEchoRsp + + @brief Parse Echo Response message. + + @param pCmd - pointer to command data to be built + @param pData - pointer to incoming command data to be parsed + @param len - length of incoming command data + + @return SUCCESS: Command was parsed successfully. +*/ +bStatus_t l2capParseEchoRsp( l2capSignalCmd_t* pCmd, uint8* pData, uint16 len ) +{ + l2capEchoRsp_t* pRsp = &pCmd->echoRsp; + pRsp->len = len; + + // Allocate buffer and copy data over + if ( len > 0 ) + { + pRsp->pData = osal_mem_alloc( len ); + + if ( pRsp->pData != NULL ) + { + VOID osal_memcpy( pRsp->pData, pData, len ); + } + else + { + pRsp->len = 0; + } + } + else + { + pRsp->pData = NULL; + } + + return ( SUCCESS ); +} + +/********************************************************************* + @fn l2capBuildInfoReq + + @brief Build Information Request. + + @param pBuf - pointer to buffer to hold command data + @param pData - pointer to command data + + @return length of the command data +*/ +uint16 l2capBuildInfoReq( uint8* pBuf, uint8* pData ) +{ + l2capInfoReq_t* pReq = (l2capInfoReq_t*)pData; + // Info type + *pBuf++ = LO_UINT16( pReq->infoType ); + *pBuf = HI_UINT16( pReq->infoType ); + return ( INFO_REQ_SIZE ); +} + +/********************************************************************* + @fn L2CAP_ParseInfoReq + + @brief Parse Information Request message. + + @param pCmd - pointer to command data to be built + @param pData - pointer to incoming command data to be parsed + @param len - length of incoming command data + + @return SUCCESS: Command was parsed successfully. + FAILURE: Command length is invalid. +*/ +bStatus_t L2CAP_ParseInfoReq( l2capSignalCmd_t* pCmd, uint8* pData, uint16 len ) +{ + // Info type + if ( len == INFO_REQ_SIZE ) + { + l2capInfoReq_t* pReq = &pCmd->infoReq; + pReq->infoType = BUILD_UINT16( pData[0], pData[1] ); + return ( SUCCESS ); + } + + return ( FAILURE ); +} + +/********************************************************************* + @fn L2CAP_BuildInfoRsp + + @brief Build Information Response. + + @param pBuf - pointer to buffer to hold command data + @param pCmd - pointer to command data + + @return length of the command data +*/ +uint16 L2CAP_BuildInfoRsp( uint8* pBuf, uint8* pCmd ) +{ + uint16 len = INFO_RSP_FIXED_SIZE; + l2capInfoRsp_t* pRsp = (l2capInfoRsp_t*)pCmd; + // Info type + *pBuf++ = LO_UINT16( pRsp->infoType ); + *pBuf++ = HI_UINT16( pRsp->infoType ); + // Result + *pBuf++ = LO_UINT16( pRsp->result ); + *pBuf++ = HI_UINT16( pRsp->result ); + + if ( pRsp->result == L2CAP_INFO_SUCCESS ) + { + // Build the contents of Data field + if ( pRsp->infoType == L2CAP_INFO_EXTENDED_FEATURES ) + { + // Extended Features mask + VOID osal_buffer_uint32( pBuf, pRsp->info.extendedFeatures ); + len += L2CAP_EXTENDED_FEATURES_SIZE; + } + else if ( pRsp->infoType == L2CAP_INFO_FIXED_CHANNELS ) + { + // Fixed Channels mask + VOID osal_memcpy( pBuf, pRsp->info.fixedChannels, L2CAP_FIXED_CHANNELS_SIZE ); + len += L2CAP_FIXED_CHANNELS_SIZE; + } + + // else no Data for L2CAP_INFO_CONNLESS_MTU + } + + return ( len ); +} + +/********************************************************************* + @fn l2capParseInfoRsp + + @brief Parse Information Response message. + + @param pCmd - pointer to command data to be built + @param pData - pointer to incoming command data to be parsed + @param len - length of incoming command data + + @return SUCCESS: Command was parsed successfully. + FAILURE: Command length is invalid. +*/ +bStatus_t l2capParseInfoRsp( l2capSignalCmd_t* pCmd, uint8* pData, uint16 len ) +{ + // First check for fixed fields: Info type (2) and Result (2) + if ( len >= INFO_RSP_FIXED_SIZE ) + { + l2capInfoRsp_t* pRsp = &pCmd->infoRsp; + // Info type + pRsp->infoType = BUILD_UINT16( pData[0], pData[1] ); + pData += 2; + // Result + pRsp->result = BUILD_UINT16( pData[0], pData[1] ); + pData += 2; + + if ( pRsp->result == L2CAP_INFO_SUCCESS ) + { + // Parse the contents of Data field + if ( pRsp->infoType == L2CAP_INFO_EXTENDED_FEATURES ) + { + // Check for variable fields: Extended Features + if ( len == ( INFO_RSP_FIXED_SIZE + L2CAP_EXTENDED_FEATURES_SIZE ) ) + { + // Extended Features mask + pRsp->info.extendedFeatures = osal_build_uint32( pData, L2CAP_EXTENDED_FEATURES_SIZE ); + return ( SUCCESS ); + } + } + else if ( pRsp->infoType == L2CAP_INFO_FIXED_CHANNELS ) + { + // Check for variable fields: Fixed Channels + if ( len == ( INFO_RSP_FIXED_SIZE + L2CAP_FIXED_CHANNELS_SIZE ) ) + { + // Fixed Channels mask + VOID osal_memcpy( pRsp->info.fixedChannels, pData, L2CAP_FIXED_CHANNELS_SIZE ); + return ( SUCCESS ); + } + } + + // else no Data for L2CAP_INFO_CONNLESS_MTU + } + else if ( pRsp->result == L2CAP_INFO_NOT_SUPPORTED ) + { + // No Data field + if ( len == INFO_RSP_FIXED_SIZE ) + { + return ( SUCCESS ); + } + } + } + + return ( FAILURE ); +} + +/********************************************************************* + @fn l2capbuildParamUpdateReq + + @brief Build Connection Parameter Update Request. + + @param pBuf - pointer to buffer to hold command data + @param pData - pointer to command data + + @return length of the command data +*/ +uint16 l2capBuildParamUpdateReq( uint8* pBuf, uint8* pData ) +{ + l2capParamUpdateReq_t* pCmd = (l2capParamUpdateReq_t*)pData; + // Interval min + *pBuf++ = LO_UINT16( pCmd->intervalMin ); + *pBuf++ = HI_UINT16( pCmd->intervalMin ); + // Interval max + *pBuf++ = LO_UINT16( pCmd->intervalMax ); + *pBuf++ = HI_UINT16( pCmd->intervalMax ); + // Slave Latency + *pBuf++ = LO_UINT16( pCmd->slaveLatency ); + *pBuf++ = HI_UINT16( pCmd->slaveLatency ); + // Timeout Multiplier + *pBuf++ = LO_UINT16( pCmd->timeoutMultiplier ); + *pBuf = HI_UINT16( pCmd->timeoutMultiplier ); + return ( PARAM_UPDATE_REQ_SIZE ); +} + +/********************************************************************* + @fn L2CAP_ParseParamUpdateReq + + @brief Parse Connection Parameter Update Request. + + @param pCmd - pointer to command data to be built + @param pData - pointer to incoming command data to be parsed + @param len - length of incoming command data + + @return SUCCESS: Command was parsed successfully. + FAILURE: Command length is invalid. +*/ +bStatus_t L2CAP_ParseParamUpdateReq( l2capSignalCmd_t* pCmd, uint8* pData, uint16 len ) +{ + if ( len == PARAM_UPDATE_REQ_SIZE ) + { + l2capParamUpdateReq_t* pReq = &pCmd->updateReq; + // Interval min + pReq->intervalMin = BUILD_UINT16( pData[0], pData[1] ); + pData += 2; + // Interval max + pReq->intervalMax = BUILD_UINT16( pData[0], pData[1] ); + pData += 2; + // Slave Latency + pReq->slaveLatency = BUILD_UINT16( pData[0], pData[1] ); + pData += 2; + // Timeout Multiplier + pReq->timeoutMultiplier = BUILD_UINT16( pData[0], pData[1] ); + return ( SUCCESS ); + } + + return ( FAILURE ); +} + +/********************************************************************* + @fn L2CAP_BuildParamUpdateRsp + + @brief Build Connection Parameter Update Response. + + @param pBuf - pointer to buffer to hold command data + @param pData - pointer to command data + + @return length of the command data +*/ +uint16 L2CAP_BuildParamUpdateRsp( uint8* pBuf, uint8* pData ) +{ + l2capParamUpdateRsp_t* pRsp = (l2capParamUpdateRsp_t*)pData; + // Result + *pBuf++ = LO_UINT16( pRsp->result ); + *pBuf = HI_UINT16( pRsp->result ); + return ( PARAM_UPDATE_RSP_SIZE ); +} + +/********************************************************************* + @fn l2capParseParamUpdateRsp + + @brief Parse Connection Parameter Update Response. + + @param pCmd - pointer to command data to be built + @param pData - pointer to incoming command data to be parsed + @param len - length of incoming command data + + @return SUCCESS: Command was parsed successfully. + FAILURE: Command length is invalid. +*/ +bStatus_t l2capParseParamUpdateRsp( l2capSignalCmd_t* pCmd, uint8* pData, uint16 len ) +{ + if ( len == PARAM_UPDATE_RSP_SIZE ) + { + l2capParamUpdateRsp_t* pRsp = &pCmd->updateRsp; + // Result + pRsp->result = BUILD_UINT16( pData[0], pData[1] ); + return ( SUCCESS ); + } + + return ( FAILURE ); +} + +/********************************************************************* + @fn l2capNotifyData + + @brief Forward an incoming data message to upper layer application + or protocol. + + Note: Application must free packet 'pPayload' using osal_bm_free(). + + @param taskId - application task + @param connHandle - connection data was received on + @param pPkt - pointer to received packet + + @return SUCCESS: Message was sent. + FAILURE: Message was not sent. +*/ +bStatus_t l2capNotifyData( uint8 taskId, uint16 connHandle, l2capPacket_t* pPkt ) +{ + l2capDataEvent_t* pMsg; + pMsg = (l2capDataEvent_t*)osal_msg_allocate( sizeof( l2capDataEvent_t ) ); + + if ( pMsg != NULL ) + { + // Set up the OSAL message header + pMsg->hdr.event = L2CAP_DATA_EVENT; + pMsg->hdr.status = SUCCESS; + pMsg->connHandle = connHandle; + + if ( pPkt != NULL ) + { + VOID osal_memcpy( &(pMsg->pkt), pPkt, sizeof( l2capPacket_t ) ); + } + else + { + VOID osal_memset( &(pMsg->pkt), 0, sizeof( l2capPacket_t ) ); + } + + // Forward the data message up to the application + VOID osal_msg_send( taskId, (uint8*)pMsg ); + return ( SUCCESS ); + } + + return ( FAILURE ); +} + +/********************************************************************* + @fn l2capNotifySignal + + @brief Send a Signaling command to upper layer application/protocol. + + @param taskId - application task + @param connHandle - connection event belongs to + @param status - status + @param opcode - type of signaling command + @param id - identifier (applicable to requests only) + @param pCmd - pointer to command data + + @return none +*/ +void l2capNotifySignal( uint8 taskId, uint16 connHandle, uint8 status, + uint8 opcode, uint8 id, l2capSignalCmd_t* pCmd ) +{ + l2capSignalEvent_t* pEvent; + pEvent = (l2capSignalEvent_t*)osal_msg_allocate( sizeof( l2capSignalEvent_t ) ); + + if ( pEvent != NULL ) + { + // Set up the OSAL message header + pEvent->hdr.event = L2CAP_SIGNAL_EVENT; + pEvent->hdr.status = status; + pEvent->connHandle = connHandle; + pEvent->id = id; + pEvent->opcode = opcode; + + if ( pCmd != NULL ) + { + VOID osal_memcpy( &(pEvent->cmd), pCmd, sizeof( l2capSignalCmd_t ) ); + } + else + { + VOID osal_memset( &(pEvent->cmd), 0, sizeof( l2capSignalCmd_t ) ); + } + + // Forward the signaling message up to the application + VOID osal_msg_send( taskId, (uint8*)pEvent ); + } +} + +/********************************************************************* + @fn l2capAllocChannel + + @brief Allocate a channel. + + @param taskId - task the channel to be allocated for + + @return Pointer to channel, if allocated. NULL, otherwise. +*/ +l2capChannel_t* l2capAllocChannel( uint8 taskId ) +{ + uint8 i; + + for ( i = 0; i < L2CAP_NUM_CHANNELS; i++ ) + { + if ( l2capChannels[i].CID == L2CAP_CID_NULL ) + { + l2capChannels[i].state = L2CAP_CLOSED; + l2capChannels[i].CID = L2CAP_BASE_DYNAMIC_CID + i; + l2capChannels[i].taskId = taskId; + return ( &l2capChannels[i] ); + } + } + + return ( (l2capChannel_t*)NULL ); +} + +/********************************************************************* + @fn l2capAllocConnChannel + + @brief Allocate a channel for a given physical connection. + + @param connHandle - connection the channel to be allocated for + @param taskId - task the channel to be allocated for + @param p2pChannel - pointer to pointer to channel info (to be returned) + + @return SUUCESS: Channel allocated. + FAILURE: p2pChannel is NULL. + bleNoResources: No available resource. + bleNotConnected: Connection is down. +*/ +static bStatus_t l2capAllocConnChannel( uint16 connHandle, uint8 taskId, l2capChannel_t** p2pChannel ) +{ + uint8 status; + + // Make sure we can always return a pointer to the allocated channel + if ( p2pChannel != NULL ) + { + // Make sure the physical connection is up + if ( linkDB_Up( connHandle ) ) + { + l2capChannel_t* pChannel = l2capAllocChannel( taskId ); + + if ( pChannel != NULL ) + { + // Channel was allocated + pChannel->connHandle = connHandle; + *p2pChannel = pChannel; + status = SUCCESS; + } + else + { + status = bleNoResources; + } + } + else + { + status = bleNotConnected; + } + } + else + { + status = FAILURE; + } + + return ( status ); +} + +/********************************************************************* + @fn l2capFreeChannel + + @brief Free a channel. + + @param pChannel - pointer to channel to be freed + + @return none +*/ +void l2capFreeChannel( l2capChannel_t* pChannel ) +{ + pChannel->CID = L2CAP_CID_NULL; + pChannel->state = L2CAP_CLOSED; +} + +/********************************************************************* + @fn l2capFindLocalId + + @brief Find a channel using the local identifier. + + @param id - local identfier to look for + + @return Pointer to channel, if found. NULL, otherwise. +*/ +l2capChannel_t* l2capFindLocalId( uint8 id ) +{ + uint8 i; + + for ( i = 0; i < L2CAP_NUM_CHANNELS; i++ ) + { + if ( ( l2capChannels[i].CID != L2CAP_CID_NULL ) && ( l2capChannels[i].id == id ) ) + { + // Entry found + return ( &l2capChannels[i] ); + } + } + + return ( (l2capChannel_t*)NULL ); +} + +/********************************************************************* + @fn l2capStartTimer + + @brief Start a timer for a give channel. + + @param pChannel - channel to start a timer for + @param timeout - timeout in seconds + + @return none +*/ +static void l2capStartTimer( l2capChannel_t* pChannel, uint16 timeout ) +{ + // Timeout is in msec + osal_CbTimerStart( l2capHandleTimerCB, (uint8*)pChannel, + (timeout * 1000), &pChannel->timerId ); +} + +/********************************************************************* + @fn l2capStopTimer + + @brief Stop an active timer for a given channel. + + @param pChannel - channel with active timer + + @return none +*/ +void l2capStopTimer( l2capChannel_t* pChannel ) +{ + // Stop the timer + VOID osal_CbTimerStop( pChannel->timerId ); + // Reset timer id + pChannel->timerId = INVALID_TIMER_ID; +} + +/********************************************************************* + @fn l2capHandleTimerCB + + @brief Handle a callback for a timer that has just expired. + + @param pData - pointer to timer data + + @return none +*/ +static void l2capHandleTimerCB( uint8* pData ) +{ + l2capChannel_t* pChannel = (l2capChannel_t*)pData; + + // Response timer has expired + if ( ( pChannel != NULL ) && ( pChannel->CID != L2CAP_CID_NULL ) ) + { + uint8 opcode; + // Find out the response type + #if 0 // No longer supported + + if ( pChannel->state == L2CAP_W4_ECHO_RSP ) + { + opcode = L2CAP_ECHO_RSP; + } + else if ( pChannel->state == L2CAP_W4_INFO_RSP ) + { + opcode = L2CAP_INFO_RSP; + } + else + #endif + { + opcode = L2CAP_PARAM_UPDATE_RSP; + } + + // Notify the application about the timeout + l2capNotifySignal( pChannel->taskId, pChannel->connHandle, bleTimeout, opcode, 0, NULL ); + // Reset timer id + pChannel->timerId = INVALID_TIMER_ID; + // Free the channel + l2capFreeChannel( pChannel ); + } +} + +/********************************************************************* + @fn l2capHandleRxError + + @brief Handle an incoming packet error. + + @param connHandle - connection error occurred on + + @return none +*/ +void l2capHandleRxError( uint16 connHandle ) +{ + // Close the channel if it's dynamic -- not supported for now! + VOID connHandle; +} + +/********************************************************************* + @fn L2CAP_bm_alloc + + @brief L2CAP implementation of the allocator functionality. + + Note: This function should only be called by L2CAP and + the upper layer protocol/application. + + @param size - number of bytes to allocate from the heap. + + @return pointer to the heap allocation; NULL if error or failure. +*/ +void* L2CAP_bm_alloc( uint16 size ) +{ + uint8* pBuf; + pBuf = HCI_bm_alloc( size + L2CAP_HDR_SIZE ); + + if ( pBuf != NULL ) + { + // return pointer to user payload + return ( osal_bm_adjust_header( pBuf, -L2CAP_HDR_SIZE ) ); + } + + return ( (void*)NULL ); +} + +/********************************************************************* + @fn L2CAP_SendDataPkt + + @brief Loop back a data packet. + + @param connID - Connection handle + @param pktLen - Number of bytes of data to transmit + @param pData - Pointer to data buffer to transmit + + @return SUCCESS: Request was sent successfully. + bleMemAllocError: No buffer is available. +*/ +static bStatus_t L2CAP_SendDataPkt( uint16 connHandle, uint16 pktLen, uint8* pData ) +{ + hciDataEvent_t* pMsg; + // Loop it back to L2CAP task for now + pMsg = (hciDataEvent_t*)osal_msg_allocate( sizeof( hciDataEvent_t ) ); + + if ( pMsg != NULL ) + { + // Set up the OSAL message header + pMsg->hdr.event = HCI_DATA_EVENT; + pMsg->pbFlag = FIRST_PKT_CTRL_TO_HOST; + pMsg->connHandle = connHandle; + pMsg->pData = pData; + pMsg->len = pktLen; + // send message through task message + VOID osal_msg_send( l2capTaskID, (uint8*)pMsg ); + return ( SUCCESS ); + } + + return ( bleMemAllocError ); +} + +/********************************************************************* + @fn L2CAP_Fragment_bm_alloc + + @brief L2CAP implementation of the fragment allocator functionality. + + Note: This function should only be called by L2CAP and + the upper layer protocol/application. + + @param size - number of bytes to allocate from the heap. + + @return pointer to the heap allocation; NULL if error or failure. +*/ +void* L2CAP_Fragment_bm_alloc( uint16 size ) +{ + return( LL_TX_bm_alloc( size ) ); +} + + + +__ATTR_SECTION_SRAM__ uint8 L2CAP_Fragment_SendDataPkt( uint16 connHandle, uint8 fragFlg,uint16 pktLen, uint8* pBuf ) +{ + // Send the data packet to the Controller + // Note: Host to Controller Data Flow Control is not supported yet! + // Host should use the LE Read Buffer Size command to determine + // the maximum size and the total number of HCI Data Packets. + uint8 status = HCI_SendDataPkt( connHandle, fragFlg, pktLen, pBuf ); + +//LOG("%s,status %d\n",__func__,status); + // Map HCI status codes to Host status codes + switch ( status ) + { + case HCI_ERROR_CODE_UNKNOWN_CONN_ID: + status = bleNotConnected; + break; + + case HCI_ERROR_CODE_INVALID_HCI_CMD_PARAMS: + status = INVALIDPARAMETER; + break; + + case HCI_ERROR_CODE_MEM_CAP_EXCEEDED: + status = MSG_BUFFER_NOT_AVAIL; + g_sarDbgCnt.segmentSentToLinkLayerErr++; + break; + + default: + // Should never get here! + break; + } + + return status; +} + +void l2capSarBufReset(void) +{ + int i, j; + + for ( i = 0; i < MAX_NUM_LL_CONN; i ++) + { + l2capReassemblePkt[i].cIdx =0; + l2capReassemblePkt[i].pkt.len=0; + l2capReassemblePkt[i].pkt.CID=L2CAP_CID_NULL; + + if(l2capReassemblePkt[i].pkt.pPayload!=NULL) + { + osal_bm_free(l2capReassemblePkt[i].pkt.pPayload); + l2capReassemblePkt[i].pkt.pPayload=NULL; + } + + l2capSegmentPkt[i].depth=0; + l2capSegmentPkt[i].idx=0; + l2capSegmentPkt[i].fragment =0; + + if(l2capSegmentPkt[i].pBufScr!=NULL) + { + osal_bm_free(l2capSegmentPkt[i].pBufScr); + l2capSegmentPkt[i].pBufScr=NULL; + } + + for(j = 0; j < 10; j++) + { + if(l2capSegmentPkt[i].pkt[j].ptr!=NULL) + osal_bm_free(l2capSegmentPkt[i].pkt[j].ptr); + } + } + + LOG("[SAR_FREE]\n"); + return; +} + +void L2CAP_ReassemblePkt_Reset(uint16 connHandle) +{ + if (connHandle >= MAX_NUM_LL_CONN) + return; + + l2capReassemblePkt[connHandle].cIdx =0; + l2capReassemblePkt[connHandle].pkt.len=0; + l2capReassemblePkt[connHandle].pkt.CID=L2CAP_CID_NULL; + + if(l2capReassemblePkt[connHandle].pkt.pPayload!=NULL) + { + osal_bm_free(l2capReassemblePkt[connHandle].pkt.pPayload); + l2capReassemblePkt[connHandle].pkt.pPayload=NULL; + } + + LOG("[REA_FREE]\n"); + return; +} + +void L2CAP_SegmentPkt_Reset(uint16 connHandle) +{ + if (connHandle >= MAX_NUM_LL_CONN) + return; + + l2capSegmentPkt[connHandle].depth=0; + l2capSegmentPkt[connHandle].idx=0; + l2capSegmentPkt[connHandle].fragment =0; + + if(l2capSegmentPkt[connHandle].pBufScr!=NULL) + { + osal_bm_free(l2capSegmentPkt[connHandle].pBufScr); + l2capSegmentPkt[connHandle].pBufScr=NULL; + } + + for(uint8 j = 0; j < 10; j++) + { + if(l2capSegmentPkt[connHandle].pkt[j].ptr!=NULL) + osal_bm_free(l2capSegmentPkt[connHandle].pkt[j].ptr); + } + + LOG("[SEG_FREE]\n"); + return; +} + + +// TODO: whether we need this function +uint8 l2capPktToSegmentBuff(uint16 connHandle, l2capSegmentBuff_t* pSegBuf, uint8 blen,uint8* pBuf) +{ + uint8 llBufLimit = conn_param[connHandle].llPduLen.local.MaxTxOctets;//LL_MAX_LINK_DATA_LEN; + + if(llBufLimit>ATT_GetCurrentMTUSize(connHandle)+L2CAP_HDR_SIZE) + llBufLimit = ATT_GetCurrentMTUSize(connHandle)+L2CAP_HDR_SIZE; + +// LOG("%s,blen %d,llBufLimit %d\n",__func__,blen,llBufLimit); + if(blen<=llBufLimit) + { + #if (0) + //similar logical for NoSegment + pSegBuf->depth= 1; + pSegBuf->pBufScr = pBuf; + pSegBuf->pkt[0].len = blen; + pSegBuf->pkt[0].ptr= (uint8*) L2CAP_Fragment_bm_alloc(pSegBuf->pkt[0].len); + LOG("[SEG_PRT]%08x \n",pSegBuf->pkt[0].ptr);//pBuf = pSegBuf->pkt[0].ptr-sizeof(txData_t)-LL_PKT_HDR_LEN) (-4-2) + + if(pSegBuf->pkt[0].ptr!=NULL) + { + osal_memcpy(pSegBuf->pkt[0].ptr, pBuf, pSegBuf->pkt[0].len); + } + else + { + pSegBuf->pBufScr = NULL; + pSegBuf->depth= 0; + return bleMemAllocError; + } + + #else + //20181124 ZQ + //no segment happend ,just send data to LL_buf, no memory copy + return( L2CAP_Fragment_SendDataPkt(connHandle,LL_DATA_FIRST_PKT_HOST_TO_CTRL,blen,pBuf)); + #endif + } + else + { + pSegBuf->depth= blen /llBufLimit; + pSegBuf->pBufScr = pBuf; + uint8 resLen = blen - pSegBuf->depth*llBufLimit; + uint8 i; + uint8* pBufTmp= pBuf; + + if(resLen>0) + pSegBuf->depth+=1; + +// if( l2capExtendFragments==FALSE +// && pSegBuf->depth > getTxBufferFree()) +// { +// pSegBuf->depth= 0; +// pSegBuf->pBufScr = NULL; +// return HCI_ERROR_CODE_MEM_CAP_EXCEEDED; +// } + + for(i=0; idepth; i++) + { + pSegBuf->pkt[i].len = (0==resLen) ? llBufLimit : + ((i== pSegBuf->depth-1) ? resLen : llBufLimit); + pSegBuf->pkt[i].ptr = (uint8*) L2CAP_Fragment_bm_alloc(pSegBuf->pkt[i].len); + LOG("[SEG_PRT]%08x %02x\n",pSegBuf->pkt[i].ptr,*pBufTmp); + + if(pSegBuf->pkt[i].ptr!=NULL) + { + osal_memcpy(pSegBuf->pkt[i].ptr, pBufTmp, pSegBuf->pkt[i].len); + pBufTmp+=pSegBuf->pkt[i].len; + g_sarDbgCnt.segmentInCnt++; + } + else + { + pSegBuf->depth= 0; + pSegBuf->pBufScr = NULL; + + //free 0->i-1 bm_buff + for(uint8 k=0; kpkt[k].ptr); + + g_sarDbgCnt.segmentMemAlocErr++; + return bleMemAllocError; + } + } + + //free source buf + if(pSegBuf->pBufScr!=NULL) + { + osal_bm_free(pSegBuf->pBufScr); + pSegBuf->pBufScr = NULL; + } + } + + return SUCCESS; +} + + +__ATTR_SECTION_SRAM__ uint8 l2capSegmentBuffToLinkLayer(uint16 connHandle, l2capSegmentBuff_t* pSegBuf) +{ + uint8 status; + + while(pSegBuf->depth>0) + { + status = L2CAP_Fragment_SendDataPkt(connHandle, + (0==pSegBuf->idx) ? LL_DATA_FIRST_PKT_HOST_TO_CTRL : CONTINUING_PKT, + pSegBuf->pkt[pSegBuf->idx].len, + pSegBuf->pkt[pSegBuf->idx].ptr); + + if(status==SUCCESS) + { + //osal_bm_free(pSegBuf->pkt[pSegBuf->idx].ptr); + //when success,pkt[].ptr will be free in llProcessTxData() + //should not be free again + pSegBuf->pkt[pSegBuf->idx].ptr=NULL; + pSegBuf->idx++; + pSegBuf->depth--; + g_sarDbgCnt.segmentOutCnt++; + } + else + { + pSegBuf->fragment=TRUE; + return status; + } + } + + //-------------------------------------------- + //sbuf shold be sented + //reset idx + pSegBuf->idx=0; +// //free source buf +// if(pSegBuf->pBufScr!=NULL) +// { +// osal_bm_free(pSegBuf->pBufScr); +// pSegBuf->pBufScr = NULL; +// } + //no fragment pkt remained + pSegBuf->fragment=FALSE; + return SUCCESS; +} + +__ATTR_SECTION_SRAM__ void l2capPocessFragmentTxData(uint16 connHandle) +{ + if(l2capSegmentPkt[connHandle].fragment == TRUE) + { + l2capSegmentBuffToLinkLayer(connHandle, &l2capSegmentPkt[connHandle]); + g_sarDbgCnt.fragmentSendCounter++; + } + + return; +} + +void L2CAP_ExtendFramgents_Config(uint8 flag) +{ + l2capExtendFragments= flag; + return; +} + + +/**************************************************************************** +****************************************************************************/ diff --git a/src/lib/ble_host/linkdb.c b/src/lib/ble_host/linkdb.c new file mode 100644 index 0000000..a20d3b8 --- /dev/null +++ b/src/lib/ble_host/linkdb.c @@ -0,0 +1,523 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: linkdb.c + Revised: + Revision: + + Description: This file contains the Link Database. + + These functions are not intended to be used outside of the host base. + + +**************************************************************************************************/ + + +/******************************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "OSAL.h" +#include "linkdb.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +// Total number of tasks/apps that can be notified of a link database change. +#define LINKDB_MAX_CBS MAX_NUM_LL_CONN + 4 // 4 for the Stack and 10 for the Application + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +//#define MAX_NUM_LL_CONN 1 + +// This is the link database, 1 record for each connection +static linkDBItem_t linkDB[MAX_NUM_LL_CONN]; + +// Table of callbacks to make when a connection changes state +static pfnLinkDBCB_t linkCBs[LINKDB_MAX_CBS]; + +/********************************************************************* + LOCAL FUNCTIONS +*/ + +static void reportStatusChange( uint16 connectionHandle, uint8 changeType ); + +/********************************************************************* + FUNCTIONS +*/ + +/********************************************************************* + @fn linkDB_Init + + @brief Initialize the Link Database. + + @param none + + @return none +*/ +void linkDB_Init( void ) +{ + uint8 x; // loop counter + + // Initialize the table + for ( x = 0; x < MAX_NUM_LL_CONN; x++ ) + { + // Mark the record as unused. + linkDB[x].connectionHandle = INVALID_CONNHANDLE; + linkDB[x].stateFlags = LINK_NOT_CONNECTED; + linkDB[x].pEncParams = NULL; + } + + // Initialize the status callback registration table + for ( x = 0; x < LINKDB_MAX_CBS; x++ ) + { + // No callbacks + linkCBs[x] = (pfnLinkDBCB_t)NULL; + } +} + +/********************************************************************* + @fn linkDB_Register + + @brief Register with this function to receive a callback when + status changes on a connection. If the stateflag == 0, + then the connection has been disconnected. + + @param pFunc - function pointer to callback function + + @return SUCCESS if successful + bleMemAllocError if not table space available + +*/ +uint8 linkDB_Register( pfnLinkDBCB_t pFunc ) +{ + // Find an empty slot + for ( uint8 x = 0; x < LINKDB_MAX_CBS; x++ ) + { + if ( linkCBs[x] == NULL ) + { + linkCBs[x] = pFunc; + return ( SUCCESS ); + } + } + + return ( bleMemAllocError ); +} + +/********************************************************************* + @fn linkDB_Add + + @brief Adds a record to the link database. + + @param taskID - Application task ID + @param connectionHandle - new record connection handle + @param newState - starting connection state + @param addrType - new address type + @param pAddr - new address + @param connInterval - connection's communications interval (n * 1.23 ms) + + @return SUCCESS if successful + bleIncorrectMode - hasn't been initialized. + bleNoResources - table full + bleAlreadyInRequestedMode - already exist connectionHandle + +*/ +uint8 linkDB_Add( uint8 taskID, uint16 connectionHandle, uint8 stateFlags,uint8 role, + uint8 addrType, uint8* pAddr, uint16 connInterval ) +{ + // Check for existing record + linkDBItem_t* pItem = linkDB_Find( connectionHandle ); + + if ( pItem ) + { + // Item already exists - connectionHandle was found + return ( bleAlreadyInRequestedMode ); + } + else + { + pItem = linkDB_Find( INVALID_CONNHANDLE ); + + if ( pItem ) + { + // Copy link info + pItem->addrType = addrType; + VOID osal_memcpy( pItem->addr, pAddr, B_ADDR_LEN ); + pItem->connectionHandle = connectionHandle; + pItem->stateFlags = stateFlags; + pItem->role = role; + pItem->taskID = taskID; + pItem->pEncParams = NULL; + pItem->connInterval = connInterval; + reportStatusChange( connectionHandle, LINKDB_STATUS_UPDATE_NEW ); + return ( SUCCESS ); + } + else + { + // Table is full + return ( bleNoResources ); + } + } +} + +/********************************************************************* + @fn linkDB_Remove + + @brief Removes a record from the link database. + + @param connectionHandle - new record connection handle + + @return SUCCESS if successful + INVALIDPARAMETER - connectionHandle not found. + +*/ +uint8 linkDB_Remove( uint16 connectionHandle ) +{ + // Get record + linkDBItem_t* pItem = linkDB_Find( connectionHandle ); + + if ( pItem ) + { + reportStatusChange( pItem->connectionHandle, LINKDB_STATUS_UPDATE_REMOVED ); + + // Free memory for LTK + if ( pItem->pEncParams ) + { + osal_mem_free( pItem->pEncParams ); + } + + // Clear the entire entry + VOID osal_memset( pItem, 0, (int)(sizeof( linkDBItem_t )) ); + // Mark the record as unused. + pItem->connectionHandle = INVALID_CONNHANDLE; + pItem->stateFlags = LINK_NOT_CONNECTED; + return ( SUCCESS ); + } + else + { + // Record not found + return ( INVALIDPARAMETER ); + } +} + + +/********************************************************************* + @fn linkDB_Update + + @brief This function is used to update the stateFlags of + a link record. + + @param connectionHandle - maximum number of connections. + @param newState - new state flag. This value is OR'd in + to this field. + + @return SUCCESS if successful + bleNoResources - connectionHandle not found. + +*/ +uint8 linkDB_Update( uint16 connectionHandle, uint8 newState ) +{ + linkDBItem_t* pItem = linkDB_Find( connectionHandle ); + + // Find the right connection + if ( pItem ) + { + pItem->stateFlags |= newState; + reportStatusChange( pItem->connectionHandle, + LINKDB_STATUS_UPDATE_STATEFLAGS ); + return ( SUCCESS ); + } + else + { + return ( bleNoResources ); + } +} + +/********************************************************************* + @fn linkDB_Find + + @brief Find the link. Uses the connection handle to search + the link database. + + @param connectionHandle - controller link connection handle. + + @return a pointer to the found link item, NULL if not found +*/ +linkDBItem_t* linkDB_Find( uint16 connectionHandle ) +{ + // Find link record + for ( uint8 x = 0; x < MAX_NUM_LL_CONN; x++ ) + { + if ( linkDB[x].connectionHandle == connectionHandle ) + { + // Found + return ( &linkDB[x] ); + } + } + + // Not Found!! + return ( (linkDBItem_t*)NULL ); +} + +/********************************************************************* + @fn linkDB_FindFirst + + @brief Find the first link that matches the taskID. + + @param taskID - taskID of app + + @return a pointer to the found link item, NULL if not found +*/ +linkDBItem_t* linkDB_FindFirst( uint8 taskID ) +{ + // Find link record + for ( uint8 x = 0; x < MAX_NUM_LL_CONN; x++ ) + { + if ( (linkDB[x].connectionHandle != INVALID_CONNHANDLE) + && (linkDB[x].taskID == taskID) ) + { + // Found + return ( &linkDB[x] ); + } + } + + // Not Found!! + return ( (linkDBItem_t*)NULL ); +} + +/********************************************************************* + @fn linkDB_State + + @brief Check to see if a physical link is in a specific state. + + @param connectionHandle - controller link connection handle. + @param state - state to look for. + + @return TRUE if the link is found and state is set in + state flags. FALSE, otherwise. +*/ +uint8 linkDB_State( uint16 connectionHandle, uint8 state ) +{ + linkDBItem_t* pLink; + + // Check to see if this is loopback connection + if ( connectionHandle == LOOPBACK_CONNHANDLE ) + { + return ( TRUE ); + } + + // Check to see if the physical link is up + pLink = linkDB_Find( connectionHandle ); + + if ( ( pLink != NULL ) && ( pLink->stateFlags & state ) ) + { + return ( TRUE ); + } + + return ( FALSE ); +} + +/********************************************************************* + @fn linkDB_NumActive + + @brief Counts the number of active connections (not . + + @param connectionHandle - controller link connection handle. + + @return number of active connections +*/ +uint8 linkDB_NumActive( void ) +{ + uint8 count = 0; + + // Find link record + for ( uint8 x = 0; x < MAX_NUM_LL_CONN; x++ ) + { + if ( linkDB[x].stateFlags ) + { + count++; + } + } + + return ( count ); +} + +/********************************************************************* + @fn linkDB_Authen + + @brief Check to see if the physical link is encrypted + and authenticated. + + @param connectionHandle - item's connection handle + @param keySize - minimum key size + @param mitmRequired - whether MITM protection is required + + @return SUCCESS if link is authenticated. + bleNotConnected - connection handle is invalid + LINKDB_ERR_INSUFFICIENT_AUTHEN - link is not encrypted + LINBDB_ERR_INSUFFICIENT_KEYSIZE - key size encrypted is not large enough + LINKDB_ERR_INSUFFICIENT_ENCRYPTION - link is encrypted, but not authenticated +*/ +uint8 linkDB_Authen( uint16 connectionHandle, uint8 keySize, uint8 mitmRequired ) +{ + linkDBItem_t* pItem = linkDB_Find( connectionHandle ); + + // Check that a connection exists + if ( pItem == NULL ) + { + // Check for loopback connection + if ( connectionHandle == LOOPBACK_CONNHANDLE ) + { + return ( SUCCESS ); + } + else + { + return ( bleNotConnected ); + } + } + + // If an LTK is not available, the service request shall be rejected with the + // error code "Insufficient Authentication". + + // Note: When the link is not encrypted, the error code "Insufficient + // Authentication" does not indicate that MITM protection is required. + if ( (pItem->pEncParams == NULL) && ((pItem->stateFlags & LINK_ENCRYPTED) == 0) ) + { + return ( LINKDB_ERR_INSUFFICIENT_AUTHEN ); + } + + // If an authenticated pairing is required but only an unauthenticated pairing + // has occurred and the link is currently encrypted, the service request shall + // be rejected with the error code "Insufficient Authentication." + + // Note: When unauthenticated pairing has occurred and the link is currently + // encrypted, the error code "Insufficient Authentication" indicates that MITM + // protection is required. + if ( (pItem->pEncParams != NULL ) && (pItem->stateFlags & LINK_ENCRYPTED) && + ((pItem->stateFlags & LINK_AUTHENTICATED) == 0) && mitmRequired ) + { + return ( LINKDB_ERR_INSUFFICIENT_AUTHEN ); + } + + // If an LTK is available and encryption is required (LE security mode 1) but + // encryption is not enabled, the service request shall be rejected with the + // error code “Insufficient Encryption?. + if ( (pItem->stateFlags & LINK_ENCRYPTED) == 0 ) + { + return ( LINKDB_ERR_INSUFFICIENT_ENCRYPTION ); + } + + // If the encryption is enabled with insufficient key size then the service + // request shall be rejected with the error code “Insufficient Encryption Key + // Size.? + if ( pItem->pEncParams->keySize < keySize ) + { + return ( LINBDB_ERR_INSUFFICIENT_KEYSIZE ); + } + + return ( SUCCESS ); +} + +/********************************************************************* + @fn linkDB_PerformFunc + + @brief This function will call "cb" for every entry in the link database. + + @param cb - function pointer to the function to call + + @return none +*/ +void linkDB_PerformFunc( pfnPerformFuncCB_t cb ) +{ + if ( cb ) + { + for ( uint8 x = 0; x < MAX_NUM_LL_CONN; x++ ) + { + if ( linkDB[x].connectionHandle != INVALID_CONNHANDLE ) + { + cb( &linkDB[x] ); + } + } + } +} + +/********************************************************************* + @fn reportStatusChange + + @brief Call all callback functions with the state update. + + @param connectionHandle - item's connection handle + @param changeType - Change Type: + LINKDB_STATUS_UPDATE_NEW - added to the database + LINKDB_STATUS_UPDATE_REMOVED - deleted from the database + LINKDB_STATUS_UPDATE_STATEFLAGS - stateFlag item has changed + + @return void +*/ +static void reportStatusChange( uint16 connectionHandle, uint8 changeType ) +{ + for ( uint8 x = 0; x < LINKDB_MAX_CBS; x++ ) + { + if ( linkCBs[x] ) + { + linkCBs[x]( connectionHandle, changeType ); + } + } +} + + +/**************************************************************************** +****************************************************************************/ + diff --git a/src/lib/ble_host/sm_intpairing.c b/src/lib/ble_host/sm_intpairing.c new file mode 100644 index 0000000..71a2fe1 --- /dev/null +++ b/src/lib/ble_host/sm_intpairing.c @@ -0,0 +1,901 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: sm_intpairing.c + Revised: + Revision: + + Description: This file contains the SM Initiator Pairing Manager. + + +**************************************************************************************************/ + + +/******************************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "l2cap.h" +#include "gap_internal.h" +#include "linkdb.h" +#include "sm.h" +#include "sm_internal.h" +#include "smp.h" +#include "osal_cbtimer.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL VARIABLES +*/ +extern uint8 smState_CBTimer[]; + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static uint8 smpInitiatorProcessIncoming( linkDBItem_t* pLinkItem, uint8 cmdID, smpMsgs_t* pParsedMsg ); +static uint8 smpInitiatorProcessPairingRsp( uint16 connectionHandle,smpPairingRsp_t* parsedMsg ); +static uint8 smpInitiatorProcessPairingConfirm( uint16 connectionHandle,smpPairingConfirm_t* pParsedMsg ); +static uint8 smpInitiatorProcessPairingRandom( uint16 connectionHandle,smpPairingRandom_t* pParsedMsg ); +static uint8 smpInitiatorProcessEncryptionInformation( uint16 connectionHandle,smpEncInfo_t* pParsedMsg ); +static uint8 smpInitiatorProcessMasterID( uint16 connectionHandle,smpMasterID_t* pParsedMsg ); +static uint8 smpInitiatorProcessIdentityInfo( uint16 connectionHandle,smpIdentityInfo_t* pParsedMsg ); +static uint8 smpInitiatorProcessIdentityAddrInfo( uint16 connectionHandle,smpIdentityAddrInfo_t* pParsedMsg ); +static uint8 smpInitiatorProcessSigningInfo( uint16 connectionHandle,smpSigningInfo_t* pParsedMsg ); + +static void setupInitiatorKeys( uint16 connectionHandle ); +static void smInitiatorSendNextKeyInfo( uint16 connectionHandle ); + +/********************************************************************* + INITIATOR CALLBACKS +*/ + +// SM Initiator Callbacks +static smInitiatorCBs_t smInitiatorCBs = +{ + smpInitiatorProcessIncoming, // Process SMP Message Callback + smInitiatorSendNextKeyInfo, // Send Next Key Message Callback + SM_StartEncryption // Start Encrypt Callback +}; + +/********************************************************************* + API FUNCTIONS +*/ + + +/********************************************************************* + FUNCTIONS - MASTER API - Only use these in a master device +*/ + +/********************************************************************* + Initialize SM Initiator on a master device. + + Public function defined in sm.h. +*/ +bStatus_t SM_InitiatorInit( void ) +{ + if ( gapProfileRole & GAP_PROFILE_CENTRAL ) + { + // Set up Initiator's processing function + smRegisterInitiator( &smInitiatorCBs ); + } + else + { + smRegisterInitiator( NULL ); + } + + return ( SUCCESS ); +} + +/********************************************************************* + @fn smEncLTK + + @brief Start LKT Encryption on an Initiator. + + @param none + + @return none +*/ +void smEncLTK( uint16 connectionHandle ) +{ + // Make sure we are in the right state + if ( (pPairingParams[connectionHandle]) && (pPairingParams[connectionHandle]->initiator) + && (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_ENCRYPT) + && (pPairingParams[connectionHandle]->pDevEncParams) ) + { + if ( SM_StartEncryption( pPairingParams[connectionHandle]->connectionHandle, + pPairingParams[connectionHandle]->pDevEncParams->ltk, + pPairingParams[connectionHandle]->pDevEncParams->div, + pPairingParams[connectionHandle]->pDevEncParams->rand, + pPairingParams[connectionHandle]->pDevEncParams->keySize ) != SUCCESS ) + { + // Start encryption failed + smEndPairing( connectionHandle,SMP_PAIRING_FAILED_UNSPECIFIED ); + } + } +} + +/********************************************************************* + @fn SM_StartEncryption + + @brief Send Start Encrypt through HCI + + @param connHandle - Connection Handle + @param pLTK - pointer to 16 byte lkt + @param div - div or ediv + @param pRandNum - pointer to 8 byte random number + @param keyLen - length of LTK (bytes) + + @return SUCCESS + INVALIDPARAMETER + other from HCI/LL +*/ +bStatus_t SM_StartEncryption( uint16 connHandle, uint8* pLTK, uint16 div, uint8* pRandNum, uint8 keyLen ) +{ + uint8 eDiv[2]; // LTK div + uint8 key[KEYLEN]; // LTK + uint8 random[B_RANDOM_NUM_SIZE]; // LTK Random + + // check the parameters + if ( pLTK == NULL ) + { + return ( INVALIDPARAMETER ); + } + + // Setup encryption parameters + eDiv[0] = LO_UINT16( div ); + eDiv[1] = HI_UINT16( div ); + VOID osal_memset( key, 0, KEYLEN ); + VOID osal_memcpy( key, pLTK, keyLen ); + + // A null randNum means to build a random number of all zero's + if ( pRandNum ) + { + VOID osal_memcpy( random, pRandNum, B_RANDOM_NUM_SIZE ); + } + else + { + VOID osal_memset( random, 0, B_RANDOM_NUM_SIZE ); + } + + return ( HCI_LE_StartEncyptCmd( connHandle, random, eDiv, key ) ); +} + +/********************************************************************* + @fn smpInitiatorProcessIncoming + + @brief Process incoming parsed SM Initiator message. + + @param pLinkItem - connection information + @param cmdID - command ID + @param pParsedMsg - pointer to parsed message + + @return SUCCESS + SMP_PAIRING_FAILED_PASSKEY_ENTRY_FAILED + SMP_PAIRING_FAILED_OOB_NOT_AVAIL + SMP_PAIRING_FAILED_AUTH_REQ + SMP_PAIRING_FAILED_CONFIRM_VALUE + SMP_PAIRING_FAILED_NOT_SUPPORTED + SMP_PAIRING_FAILED_ENC_KEY_SIZE + SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED + SMP_PAIRING_FAILED_UNSPECIFIED + SMP_PAIRING_FAILED_REPEATED_ATTEMPTS +*/ +static uint8 smpInitiatorProcessIncoming( linkDBItem_t* pLinkItem, uint8 cmdID, smpMsgs_t* pParsedMsg ) +{ + uint8 reason = SUCCESS; // return value + + // check for pairing mode + if ( pPairingParams[pLinkItem->connectionHandle] == NULL ) + { + if ( cmdID == SMP_SECURITY_REQUEST ) + { + // Notify app/profile + gapSendSlaveSecurityReqEvent( pLinkItem->taskID, pLinkItem->connectionHandle, + pLinkItem->addr, smAuthReqToUint8( &(pParsedMsg->secReq.authReq) ) ); + return ( SUCCESS ); + } + else + { + // Ignore the message, don't respond + return ( SUCCESS ); + } + } + + // We can only handle one pairing at a time + if ( pPairingParams[pLinkItem->connectionHandle]->connectionHandle != pLinkItem->connectionHandle ) + { + return ( SMP_PAIRING_FAILED_UNSPECIFIED ); + } + + if ( pPairingParams[pLinkItem->connectionHandle]->initiator == FALSE ) + { + return ( SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED ); + } + + // Process the pairing messages + switch ( cmdID ) + { + case SMP_PAIRING_RSP: + reason = smpInitiatorProcessPairingRsp( pLinkItem->connectionHandle,(smpPairingRsp_t*)pParsedMsg ); + break; + + case SMP_PAIRING_CONFIRM: + reason = smpInitiatorProcessPairingConfirm( pLinkItem->connectionHandle,(smpPairingConfirm_t*)pParsedMsg ); + break; + + case SMP_PAIRING_RANDOM: + reason = smpInitiatorProcessPairingRandom( pLinkItem->connectionHandle,(smpPairingRandom_t*)pParsedMsg ); + break; + + case SMP_ENCRYPTION_INFORMATION: + reason = smpInitiatorProcessEncryptionInformation( pLinkItem->connectionHandle,(smpEncInfo_t*)pParsedMsg ); + break; + + case SMP_MASTER_IDENTIFICATION: + reason = smpInitiatorProcessMasterID( pLinkItem->connectionHandle,(smpMasterID_t*)pParsedMsg ); + break; + + case SMP_IDENTITY_INFORMATION: + reason = smpInitiatorProcessIdentityInfo( pLinkItem->connectionHandle,(smpIdentityInfo_t*)pParsedMsg ); + break; + + case SMP_IDENTITY_ADDR_INFORMATION: + reason = smpInitiatorProcessIdentityAddrInfo( pLinkItem->connectionHandle,(smpIdentityAddrInfo_t*)pParsedMsg ); + break; + + case SMP_SIGNING_INFORMATION: + reason = smpInitiatorProcessSigningInfo( pLinkItem->connectionHandle,(smpSigningInfo_t*)pParsedMsg ); + break; + + case SMP_SECURITY_REQUEST: + if ( pPairingParams[pLinkItem->connectionHandle] ) + { + // We are currently pairing. Ignore the message, don't respond + return ( SUCCESS ); + } + + break; + + case SMP_PAIRING_FAILED: + smEndPairing( pLinkItem->connectionHandle,pParsedMsg->pairingFailed.reason ); + break; + + default: + reason = SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED; + break; + } + + return ( reason ); +} + +/********************************************************************* + @fn smpInitiatorProcessPairingRsp + + @brief Process incoming parsed Pairing Response. + + @param pParsedMsg - pointer to parsed message + + @return SUCCESS + SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED + SMP_PAIRING_FAILED_UNSPECIFIED + SMP_PAIRING_FAILED_AUTH_REQ +*/ +static uint8 smpInitiatorProcessPairingRsp( uint16 connectionHandle,smpPairingRsp_t* pParsedMsg ) +{ + uint8 reason = SUCCESS; // return value + bStatus_t stat; // status field + // Save the response information into pPairingParams[connectionHandle] + stat = smSavePairInfo( connectionHandle,pParsedMsg ); + + if ( stat == SUCCESS ) + { + // Check for bonding + if ( (pPairingParams[connectionHandle]->pSecReqs->authReq & SM_AUTH_STATE_BONDING) + && (pPairingParams[connectionHandle]->pPairDev->authReq.bonding == SM_AUTH_REQ_BONDING) ) + { + pPairingParams[connectionHandle]->authState |= SM_AUTH_STATE_BONDING; + } + + if ( (pPairingParams[connectionHandle]->type == SM_PAIRING_TYPE_PASSKEY_INITIATOR_INPUTS) + || (pPairingParams[connectionHandle]->type == SM_PAIRING_TYPE_PASSKEY_RESPONDER_INPUTS) + || (pPairingParams[connectionHandle]->type == SM_PAIRING_TYPE_PASSKEY_BOTH_INPUTS) ) + { + uint8 type; + + // Determine the passkey input/output user requirements + if ( (pPairingParams[connectionHandle]->type == SM_PAIRING_TYPE_PASSKEY_BOTH_INPUTS) + || (pPairingParams[connectionHandle]->type == SM_PAIRING_TYPE_PASSKEY_INITIATOR_INPUTS) ) + { + type = SM_PASSKEY_TYPE_INPUT; + } + else + { + type = SM_PASSKEY_TYPE_DISPLAY; + } + + // Ask the app for passkey + gapPasskeyNeededCB( pPairingParams[connectionHandle]->connectionHandle, type ); + pPairingParams[connectionHandle]->authState |= SM_AUTH_STATE_AUTHENTICATED; + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_PASSKEY; + } + else if ( (pPairingParams[connectionHandle]->type == SM_PAIRING_TYPE_JUST_WORKS) + || (pPairingParams[connectionHandle]->type == SM_PAIRING_TYPE_OOB) ) + { + // Get ready for the Confirm + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_CONFIRM; + // Initialize TK space + VOID osal_memset( pPairingParams[connectionHandle]->tk, 0, KEYLEN ); + + // Setup TK + if ( pPairingParams[connectionHandle]->type != SM_PAIRING_TYPE_JUST_WORKS ) + { + // OOB + VOID osal_memcpy( pPairingParams[connectionHandle]->tk, pPairingParams[connectionHandle]->pSecReqs->oob, KEYLEN ); + pPairingParams[connectionHandle]->authState |= SM_AUTH_STATE_AUTHENTICATED; + } + + // Generate Rand (MRand) + smGenerateRandBuf( pPairingParams[connectionHandle]->myComp.rand, SMP_RANDOM_LEN ); + // Generate Confirm (MConfirm) + sm_c1( connectionHandle,pPairingParams[connectionHandle]->tk, + pPairingParams[connectionHandle]->myComp.rand, + pPairingParams[connectionHandle]->myComp.confirm ); + #if defined ( TESTMODES ) + + if ( GAP_GetParamValue( TGAP_SM_TESTCODE ) == SM_TESTMODE_SEND_BAD_CONFIRM ) + { + VOID osal_memset( pPairingParams[connectionHandle]->myComp.confirm, 0, KEYLEN ); + } + + #endif // TESTMODE + + if ( smGenerateConfirm( connectionHandle) != SUCCESS ) + { + reason = SMP_PAIRING_FAILED_UNSPECIFIED; + } + } + } + else if ( stat == bleInvalidRange ) + { + reason = SMP_PAIRING_FAILED_AUTH_REQ; + } + else + { + reason = SMP_PAIRING_FAILED_UNSPECIFIED; + } + + return ( reason ); +} + +/********************************************************************* + @fn smpInitiatorProcessPairingConfirm + + @brief Process incoming parsed Pairing Confirm. + + @param pParsedMsg - pointer to parsed message + + @return SUCCESS + SMP_PAIRING_FAILED_UNSPECIFIED +*/ +static uint8 smpInitiatorProcessPairingConfirm( uint16 connectionHandle,smpPairingConfirm_t* pParsedMsg ) +{ + uint8 reason = SUCCESS; // return value + VOID osal_memcpy( pPairingParams[connectionHandle]->devComp.confirm, pParsedMsg->confirmValue, KEYLEN ); + + // Received Responder Confirm, send Rand message + if ( smGenerateRandMsg(connectionHandle) != SUCCESS ) + { + reason = SMP_PAIRING_FAILED_UNSPECIFIED; + } + + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_RANDOM; + return ( reason ); +} + +/********************************************************************* + @fn smpInitiatorProcessPairingRandom + + @brief Process incoming parsed Pairing Random. + + @param parsedMsg - pointer to parsed message + + @return SUCCESS + SMP_PAIRING_FAILED_CONFIRM_VALUE + SMP_PAIRING_FAILED_UNSPECIFIED +*/ +static uint8 smpInitiatorProcessPairingRandom( uint16 connectionHandle,smpPairingRandom_t* pParsedMsg ) +{ + uint8 reason = SUCCESS; // return value + uint8 confirm[KEYLEN]; // working area to calculate a confirm value + VOID osal_memcpy( pPairingParams[connectionHandle]->devComp.rand, pParsedMsg->randomValue, SMP_RANDOM_LEN ); + // Check device's Confirm value + sm_c1(connectionHandle, pPairingParams[connectionHandle]->tk, + pPairingParams[connectionHandle]->devComp.rand, + confirm ); + + // Make sure that the calculated confirm matches the confirm from the other device + if ( osal_memcmp( confirm, pPairingParams[connectionHandle]->devComp.confirm, KEYLEN ) == TRUE ) + { + uint8 stk[KEYLEN]; // a place to generate the STK + + // Received Responder, generate STK + if ( sm_s1( pPairingParams[connectionHandle]->tk, pPairingParams[connectionHandle]->devComp.rand, + pPairingParams[connectionHandle]->myComp.rand, stk ) == SUCCESS ) + { + // Start Encrypt with STK + if ( SM_StartEncryption( pPairingParams[connectionHandle]->connectionHandle, + stk, 0, 0, smDetermineKeySize( connectionHandle) ) != SUCCESS ) + { + reason = SMP_PAIRING_FAILED_UNSPECIFIED; + } + } + else + { + reason = SMP_PAIRING_FAILED_UNSPECIFIED; + } + + // Wait for STK to finish + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_STK; + } + else + { + reason = SMP_PAIRING_FAILED_CONFIRM_VALUE; + } + + return ( reason ); +} + +/********************************************************************* + @fn smpInitiatorProcessEncryptionInformation + + @brief Process incoming parsed Encryption Information. + + @param pParsedMsg - pointer to parsed message + + @return SUCCESS + SMP_PAIRING_FAILED_UNSPECIFIED +*/ +static uint8 smpInitiatorProcessEncryptionInformation( uint16 connectionHandle,smpEncInfo_t* pParsedMsg ) +{ + if ( pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_SLAVE_ENCRYPTION_INFO ) + { + // Save off the connected device's encryption information (LTK and key size) + if ( pPairingParams[connectionHandle]->pDevEncParams == NULL ) + { + pPairingParams[connectionHandle]->pDevEncParams = (smSecurityInfo_t*)osal_mem_alloc( (uint16)sizeof (smSecurityInfo_t ) ); + } + + if ( pPairingParams[connectionHandle]->pDevEncParams ) + { + VOID osal_memcpy( pPairingParams[connectionHandle]->pDevEncParams->ltk, pParsedMsg->ltk, KEYLEN ); + pPairingParams[connectionHandle]->pDevEncParams->keySize = smDetermineKeySize( connectionHandle); + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_SLAVE_MASTER_INFO; + return ( SUCCESS ); + } + } + + return ( SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED ); +} + +/********************************************************************* + @fn smpInitiatorProcessMasterID + + @brief Process incoming parsed Master Identification. + + @param parsedMsg - pointer to parsed message + + @return SUCCESS + SMP_PAIRING_FAILED_UNSPECIFIED +*/ +static uint8 smpInitiatorProcessMasterID( uint16 connectionHandle,smpMasterID_t* pParsedMsg ) +{ + if ( (pPairingParams[connectionHandle]->pDevEncParams != NULL) + && (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_SLAVE_MASTER_INFO) ) + { + // Save off the rest of the connected device's encryption information + pPairingParams[connectionHandle]->pDevEncParams->div = pParsedMsg->ediv; + VOID osal_memcpy( pPairingParams[connectionHandle]->pDevEncParams->rand, pParsedMsg->rand, B_RANDOM_NUM_SIZE ); + + // Setup the next state + if ( (pPairingParams[connectionHandle]->pSecReqs->keyDist.sIdKey) && (pPairingParams[connectionHandle]->pPairDev->keyDist.sIdKey) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_SLAVE_IDENTITY_INFO; + } + else if ( (pPairingParams[connectionHandle]->pSecReqs->keyDist.sSign) && (pPairingParams[connectionHandle]->pPairDev->keyDist.sSign) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_SLAVE_SIGNING_INFO; + } + else + { + setupInitiatorKeys(connectionHandle); + } + + return ( SUCCESS ); + } + else + { + return ( SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED ); + } +} + +/********************************************************************* + @fn smpInitiatorProcessIdentityInfo + + @brief Process incoming parsed Identity Information. + + @param parsedMsg - pointer to parsed message + + @return SUCCESS + SMP_PAIRING_FAILED_UNSPECIFIED +*/ +static uint8 smpInitiatorProcessIdentityInfo( uint16 connectionHandle,smpIdentityInfo_t* pParsedMsg ) +{ + if ( pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_SLAVE_IDENTITY_INFO ) + { + // Save off the info + if ( pPairingParams[connectionHandle]->pIdInfo == NULL ) + { + pPairingParams[connectionHandle]->pIdInfo = (smIdentityInfo_t*)osal_mem_alloc( (uint16)sizeof (smIdentityInfo_t ) ); + } + + if ( pPairingParams[connectionHandle]->pIdInfo ) + { + VOID osal_memcpy( pPairingParams[connectionHandle]->pIdInfo->irk, pParsedMsg->irk, KEYLEN ); + } + + // Determine next state + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_SLAVE_IDENTITY_ADDR_INFO; + return ( SUCCESS ); + } + else + { + return ( SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED ); + } +} + +/********************************************************************* + @fn smpInitiatorProcessIdentityAddrInfo + + @brief Process incoming parsed Identity Address Information. + + @param pParsedMsg - pointer to parsed message + + @return SUCCESS + SMP_PAIRING_FAILED_UNSPECIFIED +*/ +static uint8 smpInitiatorProcessIdentityAddrInfo( uint16 connectionHandle,smpIdentityAddrInfo_t* pParsedMsg ) +{ + if ( pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_SLAVE_IDENTITY_ADDR_INFO ) + { + VOID osal_memcpy( pPairingParams[connectionHandle]->pIdInfo->bd_addr, pParsedMsg->bdAddr, B_ADDR_LEN ); + + // Determine the next state + if ( (pPairingParams[connectionHandle]->pSecReqs->keyDist.sSign) && (pPairingParams[connectionHandle]->pPairDev->keyDist.sSign) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_SLAVE_SIGNING_INFO; + } + else + { + // Start sending initiator (master) keys + setupInitiatorKeys(connectionHandle); + } + + return ( SUCCESS ); + } + else + { + return ( SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED ); + } +} + +/********************************************************************* + @fn smpInitiatorProcessSigningInfo + + @brief Process incoming parsed Signing Information. + + @param parsedMsg - pointer to parsed message + + @return SUCCESS + SMP_PAIRING_FAILED_UNSPECIFIED +*/ +static uint8 smpInitiatorProcessSigningInfo( uint16 connectionHandle,smpSigningInfo_t* pParsedMsg ) +{ + if ( pPairingParams[connectionHandle] ) + { + if ( pPairingParams[connectionHandle]->pSigningInfo == NULL ) + { + pPairingParams[connectionHandle]->pSigningInfo = (smSigningInfo_t*)osal_mem_alloc( (uint16)sizeof( smSigningInfo_t ) ); + + if ( pPairingParams[connectionHandle]->pSigningInfo == NULL ) + { + // Only error available for memory error, this will end the pairing process + return ( SMP_PAIRING_FAILED_UNSPECIFIED ); + } + } + + // Copy signature information + if ( pPairingParams[connectionHandle]->pSigningInfo ) + { + VOID osal_memcpy( pPairingParams[connectionHandle]->pSigningInfo->srk, pParsedMsg->signature, KEYLEN ); + pPairingParams[connectionHandle]->pSigningInfo->signCounter = GAP_INIT_SIGN_COUNTER; + } + + // Send the initiator key messages + setupInitiatorKeys(connectionHandle); + return ( SUCCESS ); + } + else + { + return ( SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED ); + } +} + +/********************************************************************* + @fn setupInitiatorKeys + + @brief Setup Initiator Key distribution + + @param none + + @return none +*/ +static void setupInitiatorKeys( uint16 connectionHandle ) +{ + if ( ((pPairingParams[connectionHandle]->pSecReqs->keyDist.mEncKey) && (pPairingParams[connectionHandle]->pPairDev->keyDist.mEncKey)) + || ((pPairingParams[connectionHandle]->pSecReqs->keyDist.mIdKey) && (pPairingParams[connectionHandle]->pPairDev->keyDist.mIdKey)) + || ((pPairingParams[connectionHandle]->pSecReqs->keyDist.mSign) && (pPairingParams[connectionHandle]->pPairDev->keyDist.mSign)) ) + { + // Setup to send initiator key messages + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_STK; + smInitiatorSendNextKeyInfo(connectionHandle); + } + else + { + // No keys to send + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_DONE; + } + + if ( pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_DONE ) + { + smEndPairing( connectionHandle,SUCCESS ); + } +} + +/********************************************************************* + @fn smInitiatorSendNextKeyInfo + + @brief Initiator role: sends next key message, and sets state + for next event. + + @param none + + @return none +*/ +static void smInitiatorSendNextKeyInfo( uint16 connectionHandle ) +{ + if ( pPairingParams[connectionHandle]->initiator == TRUE ) + { + smLinkSecurityReq_t* pSecReq = pPairingParams[connectionHandle]->pSecReqs; + smpPairingReq_t* pPairReq = pPairingParams[connectionHandle]->pPairDev; + uint8 state = pPairingParams[connectionHandle]->state; + + // Determine key to send + if ( state == SM_PAIRING_STATE_WAIT_STK ) + { + if ( (pPairReq->keyDist.mEncKey) && (pSecReq->keyDist.mEncKey) ) + { + state = SM_PAIRING_STATE_WAIT_MASTER_ENCRYPTION_INFO; + } + else if ( (pPairReq->keyDist.mIdKey) && (pSecReq->keyDist.mIdKey) ) + { + state = SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_INFO; + } + else if ( (pPairReq->keyDist.mSign) && (pSecReq->keyDist.mSign) ) + { + state = SM_PAIRING_STATE_WAIT_MASTER_SIGNING_INFO; + } + } + + // Send the correct message + switch ( state ) + { + case SM_PAIRING_STATE_WAIT_MASTER_ENCRYPTION_INFO: + + // send Encryption Information. + if ( pPairingParams[connectionHandle]->pEncParams == NULL ) + { + pPairingParams[connectionHandle]->pEncParams = (smSecurityInfo_t*)osal_mem_alloc( (uint16)sizeof (smSecurityInfo_t ) ); + + if ( pPairingParams[connectionHandle]->pEncParams ) + { + VOID osal_memset( pPairingParams[connectionHandle]->pEncParams, 0, sizeof (smSecurityInfo_t ) ); + } + } + + if ( pPairingParams[connectionHandle]->pEncParams ) + { + smSecurityInfo_t* pEnc = pPairingParams[connectionHandle]->pEncParams; + + // Default the key size to the key size of this encryption session. + if ( pEnc->keySize == 0 ) + { + pEnc->keySize = smDetermineKeySize( connectionHandle); + } + + // For now, temp random the LTK, EDIV and RAND + VOID osal_memset( pEnc->ltk, 0, KEYLEN ); + smGenerateRandBuf( pEnc->ltk, pPairingParams[connectionHandle]->pEncParams->keySize ); + pEnc->div = osal_rand(); + smGenerateRandBuf( pEnc->rand, B_RANDOM_NUM_SIZE ); + // Send the Encryption Info + smPairingSendEncInfo( pPairingParams[connectionHandle]->connectionHandle, pEnc->ltk ); + } + + break; + + case SM_PAIRING_STATE_WAIT_MASTER_MASTER_INFO: + if ( pPairingParams[connectionHandle]->pEncParams ) + { + smPairingSendMasterID( pPairingParams[connectionHandle]->connectionHandle, + pPairingParams[connectionHandle]->pEncParams->div, + pPairingParams[connectionHandle]->pEncParams->rand ); + } + + break; + + case SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_INFO: + smPairingSendIdentityInfo( pPairingParams[connectionHandle]->connectionHandle, gapGetIRK() ); + break; + + case SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_ADDR_INFO: + { + uint8 getRealAddr = TRUE; + uint8 addrType = gapGetDevAddressMode(); + + if ( addrType == ADDRTYPE_STATIC ) + { + getRealAddr = FALSE; + } + else + { + addrType = ADDRTYPE_PUBLIC; + } + + smPairingSendIdentityAddrInfo( pPairingParams[connectionHandle]->connectionHandle, + addrType, gapGetDevAddress( getRealAddr ) ); + } + break; + + case SM_PAIRING_STATE_WAIT_MASTER_SIGNING_INFO: + smPairingSendSingingInfo( pPairingParams[connectionHandle]->connectionHandle, gapGetSRK() ); + break; + + default: + break; + } + + // Determine the next state + if ( state == SM_PAIRING_STATE_WAIT_MASTER_ENCRYPTION_INFO ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_MASTER_INFO; + } + else if ( state == SM_PAIRING_STATE_WAIT_MASTER_MASTER_INFO ) + { + if ( (pPairReq->keyDist.mIdKey) && (pSecReq->keyDist.mIdKey) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_INFO; + } + else if ((pPairReq->keyDist.mSign) && (pSecReq->keyDist.mSign) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_SIGNING_INFO; + } + else + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_DONE; + } + } + else if ( state == SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_INFO ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_ADDR_INFO; + } + else if ( state == SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_ADDR_INFO ) + { + if ( (pPairReq->keyDist.mSign) && (pSecReq->keyDist.mSign) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_SIGNING_INFO; + } + else + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_DONE; + } + } + else + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_DONE; + } + + if ( (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_MASTER_ENCRYPTION_INFO) + || (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_MASTER_MASTER_INFO) + || (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_INFO) + || (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_ADDR_INFO) + || (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_MASTER_SIGNING_INFO) ) + { + linkDBItem_t* linkItem; + uint32 timeout; + linkItem = linkDB_Find( pPairingParams[connectionHandle]->connectionHandle ); + + if ( linkItem != NULL ) + { + // Make the timeout 1.5 * connInterval (connInterval = 1.25 ms) + timeout = linkItem->connInterval; + timeout += linkItem->connInterval / 2; + } + else + { + timeout = SM_PAIRING_STATE_WAIT; + } + + // Set up the next send + smState_CBTimer[connectionHandle] = connectionHandle; + osal_CbTimerStart( smState_timerCB, &smState_CBTimer[connectionHandle],timeout, &pPairingParams[connectionHandle]->stateID ); + } + } +} + + + +/********************************************************************* +*********************************************************************/ diff --git a/src/lib/ble_host/sm_mgr.c b/src/lib/ble_host/sm_mgr.c new file mode 100644 index 0000000..7b05c2d --- /dev/null +++ b/src/lib/ble_host/sm_mgr.c @@ -0,0 +1,1219 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: sm_mgr.c + Revised: + Revision: + + Description: This file contains the SM Manager. + + +**************************************************************************************************/ + +#include "bcomdef.h" +#include "OSAL.h" +#include "hci.h" +#include "gap_internal.h" +#include "linkdb.h" +#include "sm.h" +#include "sm_internal.h" +#include "smp.h" +#include "osal_cbtimer.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +// Generate Key States +#define GENERATE_KEY_INIT 0 // Initial state of key generation +#define GENERATE_KEY_RAND1 1 // Performing a Rand on the key + +#define LEN_64BIT 8 // Number of bytes in a 64 bit number +#define LEN_32BIT 4 // Number of bytes in a 32 bit number +#define LEN_24BIT 3 // Number of bytes in a 24 bit number + +#define PRAND_SIZE LEN_24BIT // PRAND size in the Private Resolvable Address calculation + +// Defines used in the sm_c1new() function +#define PADDINGLEN 4 // Padding length (bytes) +#define P1LEN (SMP_PAIRING_RSP_LEN + SMP_PAIRING_REQ_LEN + 1 + 1) +#define P2LEN (PADDINGLEN + B_ADDR_LEN + B_ADDR_LEN ) + +/********************************************************************* + TYPEDEFS +*/ + +// Structure used to generate a Key +typedef struct +{ + uint8 state; // Key Generation State + uint8 taskID; // Task ID of task that wants the key + uint8 key[KEYLEN]; // Place to put the key +} smGenKey_t; + +// Encrypt function structure +typedef struct +{ + uint8 key[KEYLEN]; // Key to encrypt with + uint8 plainTextData[KEYLEN]; // Plain Text data to encrypt + uint8 result[KEYLEN]; // Result of encrypt (key + Plain Text data) +} sm_Encrypt_t; + +/********************************************************************* + GLOBAL VARIABLES +*/ +uint8 smTO_CBTimer[15]= {0}; + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +// Variables used in key generation +static smGenKey_t* pSmGenKey = (smGenKey_t*)NULL; + +// Const table used in key calculations +static CONST uint8 const_Rb[16] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87 +}; + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static void smSendGenKeyEvent( uint8 status ); +static bStatus_t smEncrypt( sm_Encrypt_t* pParam ); +static bStatus_t smEncryptLocal( uint8* pKey, uint8* pPlaintextData, uint8* pEncryptedData ); + +static void sm_xor( uint8* p1, uint8* p2 ); +static bStatus_t sm_CMAC( uint8* pK, uint8* pM, uint8 mLen, uint8* pMac ); +static bStatus_t generate_subkey( uint8* pKey, uint8* pK1, uint8* pK2 ); +static void xor_128( uint8* pA, CONST uint8* pB, uint8* pOutcome ); +static void padding ( uint8* pLastb, uint8* pPad, uint8 length ); +static void leftshift_onebit( uint8* pInp, uint8* pOutp ); + +// The next section is used to validate the Key Calculation Algorithm +// used during the pairing process. +#if defined ( TEST_CMAC ) +// Test function to test key calculation algorithm - Spec test +void Testsm_CMAC( void ); + +// Tables used to test key calculation algorithm - Spec Test +unsigned char M[64] = +{ + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 +}; +unsigned char key[16] = +{ + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c +}; + +// Test function from the AES-CMAC Algorithm Network Working Group Spec (NIST) - June 2006 +void Testsm_CMAC( void ) +{ + static unsigned char T[16]; + // printf("--------------------------------------------------\n"); + // printf("K "); print128(key); printf("\n"); + // osal_memset( L, 0, 16 ); + // osal_memset( K1, 0, 16 ); + // osal_memset( K2, 0, 16 ); + osal_memset( T, 0, 16 ); + // osal_memset( TT, 0, 16 ); + // printf("\nSubkey Generation\n"); + // AES_128(key,const_Zero,L); + // VOID smEncryptLocal( key, const_Zero, L ); + // printf("AES_128(key,0) "); print128(L); printf("\n"); + // generate_subkey(key,K1,K2); + // printf("K1 "); print128(K1); printf("\n"); + // printf("K2 "); print128(K2); printf("\n"); + // printf("\nExample 1: len = 0\n"); + // printf("M "); printf("\n"); + // AES_CMAC(key,M,0,T); + sm_CMAC( key, M, 0, T ); + // printf("AES_CMAC "); print128(T); printf("\n"); + // printf("\nExample 2: len = 16\n"); + // printf("M "); print_hex(" ",M,16); + // AES_CMAC(key,M,16,T); + sm_CMAC( key, M, 16, T ); + // printf("AES_CMAC "); print128(T); printf("\n"); + // printf("\nExample 3: len = 40\n"); + // printf("M "); print_hex(" ",M,40); + // AES_CMAC(key,M,40,T); + sm_CMAC( key, M, 40, T ); + // printf("AES_CMAC "); print128(T); printf("\n"); + // printf("\nExample 4: len = 64\n"); + // printf("M "); print_hex(" ",M,64); + // AES_CMAC(key,M,64,T); + sm_CMAC( key, M, 64, T ); + return; +} +#endif + +/********************************************************************* + Generate a key with a random value. + + Public function defined in sm.h. +*/ +bStatus_t SM_NewRandKey( uint8 taskID ) +{ + // Already doing something? + if ( smInProcess() ) + { + return ( bleNotReady ); + } + + // Ask for a random number + if ( HCI_LE_RandCmd() == SUCCESS ) + { + // Keep the state of the random generation + pSmGenKey = (smGenKey_t*)osal_mem_alloc( sizeof( smGenKey_t ) ); + + if ( pSmGenKey ) + { + pSmGenKey->state = GENERATE_KEY_INIT; + pSmGenKey->taskID = taskID; + return ( SUCCESS ); + } + else + { + return ( bleMemAllocError ); + } + } + else + { + return ( FAILURE ); + } +} + +/********************************************************************* + Calculate a new Private Resolvable address. + + Public function defined in sm.h. +*/ +bStatus_t SM_CalcRandomAddr( uint8* pIRK, uint8* pNewAddr ) +{ + bStatus_t status; // return value + uint8 PRand[PRAND_SIZE]; // Place to hold the PRAND + + // parameter validation + if ( (pIRK == NULL) || (pNewAddr == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + // Generate Random number + smGenerateRandBuf( PRand, PRAND_SIZE ); + // Clear the Random Address header bits and force the address type + PRand[PRAND_SIZE-1] &= ~(RANDOM_ADDR_HDR); + PRand[PRAND_SIZE-1] |= PRIVATE_RESOLVE_ADDR_HDR; + // Create the new address + status = sm_ah( pIRK, PRand, pNewAddr ); + + if ( status == SUCCESS ) + { + // attach the PRAND to the new address + VOID osal_memcpy( &(pNewAddr[PRAND_SIZE]), PRand, PRAND_SIZE ); + } + + return ( status ); +} + +/********************************************************************* + Resolve a Private Resolvable Address. + + Public function defined in sm.h. +*/ +bStatus_t SM_ResolveRandomAddrs( uint8* pIRK, uint8* pAddr ) +{ + bStatus_t stat; // return value + uint8 rand[PRAND_SIZE]; // place for PRAND + uint8 hash[PRAND_SIZE]; // place for hash (calc PRAND) + + // Parameter check + if ( (pIRK == NULL) || (pAddr == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + // Get PRAND out of address + VOID osal_memcpy( rand, &(pAddr[PRAND_SIZE]), PRAND_SIZE ); + // Clear the Random Address header bits and force the address type + rand[PRAND_SIZE-1] &= ~(RANDOM_ADDR_HDR); + rand[PRAND_SIZE-1] |= PRIVATE_RESOLVE_ADDR_HDR; + // Calculate Hash from PRAND + stat = sm_ah( pIRK, rand, hash ); + + if ( stat != SUCCESS ) + { + // Something went wrong with hash function + return ( stat ); + } + + // Compare hash to address portion of address + if ( osal_memcmp( hash, pAddr, LEN_24BIT ) == TRUE ) + { + // Matched + return ( SUCCESS ); + } + else + { + // not Matched + return ( FAILURE ); + } +} + +/********************************************************************* + Encrypt the plain text data with the key. + + Public function defined in sm.h. +*/ +bStatus_t SM_Encrypt( uint8* pKey, uint8* pPlainText, uint8* pResult ) +{ + bStatus_t stat; // return value + sm_Encrypt_t param; // place to perform work + + // Check Parameters + if ( (pKey == NULL) || (pPlainText == NULL) || (pResult == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + // Copy MSByte first + VOID osal_revmemcpy( param.key, pKey, KEYLEN ); + VOID osal_revmemcpy( param.plainTextData, pPlainText, KEYLEN ); + // Perform Encrypt + stat = smEncrypt( ¶m ); + // Reverse results + VOID osal_revmemcpy( pResult, param.result, KEYLEN ); + return ( stat ); +} + +/********************************************************************* + Generate an outgoing Authentication Signature. + + Public function defined in sm.h. +*/ +bStatus_t SM_GenerateAuthenSig( uint8* pData, uint8 len, uint8* pAuthenSig ) +{ + bStatus_t stat; // return value + uint8* pM; // "M" variable in CMAC algorithm + uint32 signCounter; // Sign Counter + uint8 mLen; // Length of "M" needed + uint8 mac[LEN_64BIT]; // CMAC result + uint8 revKey[KEYLEN]; // A place to hold the reverse SRK + + // Check parameters + if ( (pData == NULL) || (pAuthenSig == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + // Calculate the space needed for "M" and allocate "M" + mLen = len + LEN_32BIT; + pM = osal_mem_alloc( mLen ); + + if ( pM ) + { + // Get this device's sign counter + signCounter = gapGetSignCounter(); + // Pass all variables to CMAC in MSByte order + VOID osal_revmemcpy( &pM[LEN_32BIT], pData, len ); + pM[3] = BREAK_UINT32( signCounter, 0 ); + pM[2] = BREAK_UINT32( signCounter, 1 ); + pM[1] = BREAK_UINT32( signCounter, 2 ); + pM[0] = BREAK_UINT32( signCounter, 3 ); + VOID osal_revmemcpy( revKey, gapGetSRK(), KEYLEN ); + // Perform CMAC algorithm + stat = sm_CMAC( revKey, pM, mLen, mac ); + + if ( stat == SUCCESS ) + { + // Build message authentication + pAuthenSig[0] = BREAK_UINT32( signCounter, 0 ); + pAuthenSig[1] = BREAK_UINT32( signCounter, 1 ); + pAuthenSig[2] = BREAK_UINT32( signCounter, 2 ); + pAuthenSig[3] = BREAK_UINT32( signCounter, 3 ); + VOID osal_revmemcpy( &pAuthenSig[LEN_32BIT], mac, LEN_64BIT ); + // Increment this device's signature counter + gapIncSignCounter(); + } + + osal_mem_free( pM ); // Not needed anymore + } + else + { + stat = bleMemAllocError; + } + + return ( stat ); +} + +/********************************************************************* + Verify an Authentication Signature. + + Public function defined in sm.h. +*/ +bStatus_t SM_VerifyAuthenSig( uint16 connHandle, uint8 authentication, + uint8* pData, uint16 len, uint8* pAuthenSig ) +{ + bStatus_t stat; // return value + linkDBItem_t* pConnItem; // pointer to connection information + uint32 signCounter; // sign counter in pAuthenSig field + uint8* pM; // "M" variable + uint8 mLen; // Length of "M" + uint8 mac[LEN_64BIT]; // CMAC + uint8 revmac[LEN_64BIT]; // A place to reverse CMAC + uint8 revKey[KEYLEN]; // A place to reverse the SRK + + // Check parameters + if ( (pData == NULL) || (pAuthenSig == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + // Find the connection information + pConnItem = linkDB_Find( connHandle ); + + if ( pConnItem == NULL ) + { + return ( bleNotConnected ); + } + + // Check sign counter and make sure it's more than the last sign counter received. + signCounter = BUILD_UINT32( pAuthenSig[0], pAuthenSig[1], pAuthenSig[2], pAuthenSig[3] ); + + if ( (signCounter <= pConnItem->sec.signCounter) + && (pConnItem->sec.signCounter != GAP_INIT_SIGN_COUNTER) ) + { + return ( INVALIDPARAMETER ); + } + + // Check authentication level + if ( (authentication) && ((pConnItem->stateFlags & LINK_AUTHENTICATED) == 0) ) + { + // Signing information wasn't authenticated + return ( FAILURE ); + } + + // Initialize CMAC + VOID osal_memset( mac, 0, LEN_64BIT ); + // Adjust the M length for the sign counter and allocate space for "M" + mLen = len + LEN_32BIT; + pM = osal_mem_alloc( mLen ); + + if ( pM == NULL ) + { + return ( bleMemAllocError ); + } + + // Pass all variables to CMAC in MSByte order + VOID osal_revmemcpy( &pM[LEN_32BIT], pData, len ); + VOID osal_revmemcpy( pM, pAuthenSig, LEN_32BIT ); + VOID osal_revmemcpy( revKey, pConnItem->sec.srk, KEYLEN ); + // perform CMAC algorithm + stat = sm_CMAC( revKey, pM, mLen, mac ); + + if ( stat == SUCCESS ) + { + // Compare the calculated CMAC against the CMAC in the signature + VOID osal_revmemcpy( revmac, mac, LEN_64BIT ); + + if ( osal_memcmp( revmac, &pAuthenSig[LEN_32BIT], LEN_64BIT ) != TRUE ) + { + stat = FAILURE; + } + else + { + // Update the connection's signCounter + gapUpdateConnSignCounter( connHandle, signCounter ); + } + } + + osal_mem_free( pM ); // Don't need "M" anymore + return ( stat ); +} + +/********************************************************************* + @fn smProcessRandComplete + + @brief Process the HCI Random Complete Event. + + @param status - status of the command. + @param rand - pointer to the 8 bytes random string + + @return TRUE if we asked for this message + FALSE if we aren't expecting this messsage +*/ +uint8 smProcessRandComplete( uint8 status, uint8* rand ) +{ + if ( pSmGenKey ) + { + uint8 stateDone = FALSE; // Process finish flag + + if ( status == SUCCESS ) + { + // Are we generating a key? + if ( pSmGenKey->state == GENERATE_KEY_INIT ) + { + // Save off the random bytes + VOID osal_memcpy( pSmGenKey->key, rand, LEN_64BIT ); + + // Ask for more random bytes + if ( HCI_LE_RandCmd() == SUCCESS ) + { + // Mark the state + pSmGenKey->state = GENERATE_KEY_RAND1; + } + else + { + // Error + stateDone = TRUE; + status = FAILURE; + } + } + else + { + // This is the second set of random bytes, we are done + VOID osal_memcpy( &(pSmGenKey->key[LEN_64BIT]), rand, LEN_64BIT ); + stateDone = TRUE; + } + } + else + { + // Error + stateDone = TRUE; + } + + if ( stateDone ) + { + // Send the key + smSendGenKeyEvent( status ); + } + + return ( TRUE ); + } + else + { + // Don't know why we received this message + return ( FALSE ); + } +} + +/********************************************************************* + @fn smStartRspTimer + + @brief Start the SM Response Timer. + + @param none + + @return none +*/ + +void smStartRspTimer( uint16 connectionHandle ) +{ + // Get the timeout value + uint32 timeout = GAP_GetParamValue( TGAP_SM_TIMEOUT ); + + if( pPairingParams[connectionHandle] ) + { + if ( timeout ) + { + if( ( pPairingParams[connectionHandle]->timerID != INVALID_TASK_ID) && (osal_CbTimerUpdate(pPairingParams[connectionHandle]->timerID,timeout ) == SUCCESS )) + { + LOG("%s,update connectionHandle %d timerID %d\n",__func__,connectionHandle,pPairingParams[connectionHandle]->timerID); + } + else + { + smTO_CBTimer[connectionHandle] = connectionHandle; + osal_CbTimerStart( smTo_timerCB, &smTO_CBTimer[connectionHandle], + timeout, &pPairingParams[connectionHandle]->timerID ); + LOG("%s,start connectionHandle %d timerid %d\n",__func__,connectionHandle,pPairingParams[connectionHandle]->timerID ); + } + } + } + else + { + LOG("pPairingParams[%d] NULL \n",connectionHandle); + } +} + +/********************************************************************* + @fn smStopRspTimer + + @brief Stop the SM Response Timer. + + @param none + + @return none +*/ +void smStopRspTimer( uint16 connectionHandle ) +{ +// VOID osal_stop_timerEx( smTaskID, SM_TIMEOUT_EVT ); + if( pPairingParams[connectionHandle] ) + { + LOG("smStopRspTimer connectionHandle %d timerID %d\n",connectionHandle,pPairingParams[connectionHandle]->timerID); + osal_CbTimerStop( pPairingParams[connectionHandle]->timerID ); + pPairingParams[connectionHandle]->timerID = INVALID_TASK_ID; + } + else + { + LOG("pPairingParams[%d] NULL \n",connectionHandle); + } +} + +/********************************************************************* + @fn smInProcess + + @brief Checks to see if the SM is already processing something. + + @param none + + @return TRUE if already processing, FALSE if not +*/ +uint8 smInProcess( void ) +{ + if ( pSmGenKey ) + { + return ( TRUE ); + } + else + { + return ( FALSE ); + } +} + +/********************************************************************* + @fn sm_d1 + + @brief SM diversifying function d1 + + @param pK - key is 128 bits, LSByte first + @param d - 16 bit + @param pD1 - pointer to 128 bit results space + + @return status +*/ +bStatus_t sm_d1( uint8* pK, uint16 d, uint8* pD1 ) +{ + bStatus_t stat; // return value + sm_Encrypt_t param; // place to work for the encrypt function + // Clear the encrypt parameters + VOID osal_memset( ¶m, 0, sizeof ( sm_Encrypt_t ) ); + // Copy the encrypt variables + VOID osal_revmemcpy( param.key, pK, KEYLEN ); + param.plainTextData[KEYLEN - 2] = HI_UINT16( d ); + param.plainTextData[KEYLEN - 1] = LO_UINT16( d ); + stat = smEncrypt( ¶m ); + // Copy the results + VOID osal_revmemcpy( pD1, param.result, KEYLEN ); + return ( stat ); +} + +/********************************************************************* + @fn sm_ah + + @brief Random address hash function. + + @param pK - key is 128 bits, LSByte first + @param pR - 24 bit, LSByte first + @param pAh - pointer to 24 bit results space + + @return status +*/ +bStatus_t sm_ah( uint8* pK, uint8* pR, uint8* pAh ) +{ + bStatus_t stat; // return value + sm_Encrypt_t param; // place to work for the encrypt function + // Clear the encrypt parameters + VOID osal_memset( ¶m, 0, sizeof ( sm_Encrypt_t ) ); + // Copy the encrypt variables + VOID osal_revmemcpy( param.key, pK, KEYLEN ); + VOID osal_revmemcpy( &(param.plainTextData[KEYLEN - LEN_24BIT]), + pR, LEN_24BIT ); + stat = smEncrypt( ¶m ); + // Copy the results + VOID osal_revmemcpy( pAh, &(param.result[KEYLEN - LEN_24BIT]), LEN_24BIT ); + return ( stat ); +} + +/********************************************************************* + @fn sm_dm + + @brief SM DIV Maxk generation function dm + + @param pK - key is 128 bits, LSByte first + @param pR - 64 bit, LSByte first + @param pDm - pointer to 16 bit result + + @return status +*/ +bStatus_t sm_dm( uint8* pK, uint8* pR, uint16* pDm ) +{ + bStatus_t stat; // return value + sm_Encrypt_t param; // place to work for the encrypt function + // Clear the encrypt parameters + VOID osal_memset( ¶m, 0, sizeof ( sm_Encrypt_t ) ); + // Copy the encrypt variables + VOID osal_revmemcpy( param.key, pK, KEYLEN ); + VOID osal_revmemcpy( &(param.plainTextData[KEYLEN - LEN_64BIT]), pR, LEN_64BIT ); + stat = smEncrypt( ¶m ); + // Copy the results + *pDm = BUILD_UINT16( param.result[KEYLEN - 1], param.result[KEYLEN - 2] ); + return ( stat ); +} + +/********************************************************************* + @fn sm_c1new + + @brief SM Confirm value generation function c1. This function + implements the following formula from the spec: + + p1 = pres || preq || rat?|| iat? + p2 = padding || ia || ra + e(k, e(k, r XOR p1) XOR p2) + + @param pK - key is 128 bits, LSByte first + @param pR - 128 bit, LSByte first + @param pRes - 65 bit, LSByte first - Pairing Response Command + @param pReq - 65 bit, LSByte first - Pairing Request Command + @param iat - 1 bit - Initiator Address Type + @param pIA - 48 bit, LSByte first - Initiator Address + @param rat - 1 bit - Responder Address Type + @param pRA - 48 bit, LSByte first - Responder Address + @param pC1 - pointer to 128 bit results space + + @return status +*/ +bStatus_t sm_c1new( uint8* pK, uint8* pR, uint8* pRes, uint8* pReq, + uint8 iat, uint8* pIA, uint8 rat, uint8* pRA, uint8* pC1 ) +{ + bStatus_t stat; // return value + uint8 p1[P1LEN]; // major formula variable + uint8 p2[P2LEN]; // major formula variable + sm_Encrypt_t c1param; // Place to work for the encrypt + // First, clear the structure + VOID osal_memset( &c1param, 0, sizeof ( sm_Encrypt_t ) ); + // Copy the key into the correct format + VOID osal_revmemcpy( c1param.key, pK, KEYLEN ); + // Make p1 + VOID osal_memset( p1, 0, P1LEN ); + VOID osal_revmemcpy( p1, pRes, SMP_PAIRING_RSP_LEN ); + VOID osal_revmemcpy( &p1[SMP_PAIRING_RSP_LEN], pReq, SMP_PAIRING_REQ_LEN ); + p1[SMP_PAIRING_RSP_LEN + SMP_PAIRING_REQ_LEN] = (rat > ADDRTYPE_PUBLIC) ? 1 : 0; + p1[SMP_PAIRING_RSP_LEN + SMP_PAIRING_REQ_LEN + 1] = (iat > ADDRTYPE_PUBLIC) ? 1 : 0; + // Make p2 + VOID osal_memset( p2, 0, P2LEN ); + VOID osal_revmemcpy( &(p2[PADDINGLEN]), pIA, B_ADDR_LEN ); + VOID osal_revmemcpy( &(p2[PADDINGLEN + B_ADDR_LEN]), pRA, B_ADDR_LEN ); + // copy r into the correct format + VOID osal_revmemcpy( c1param.plainTextData, pR, SMP_RANDOM_LEN ); + // r XOR p1 + sm_xor( c1param.plainTextData, p1 ); + // e(k, r XOR p1) + stat = smEncrypt( &c1param ); + VOID osal_memcpy( c1param.plainTextData, c1param.result, KEYLEN ); + // e(k, r XOR p1) XOR p2 + sm_xor( c1param.plainTextData, p2 ); + // e(k, e(k, r XOR p1) XOR p2) + stat |= smEncrypt( &c1param ); + // copy the result + VOID osal_revmemcpy( pC1, c1param.result, KEYLEN ); + return ( stat ); +} + + +/********************************************************************* + @fn sm_xor + + @brief xor 2 fix length arrays (16 bytes). + This function destroys p1. + + @param p1 - array #1 + @param p2 - array #2 + + @return none +*/ +static void sm_xor( uint8* p1, uint8* p2 ) +{ + uint8 x; // loop counter + + for ( x = 0; x < KEYLEN; x++, p1++, p2++ ) + { + // XOR byte by byte + *p1 = *p1 ^ *p2; + } +} + +/********************************************************************* + @fn sm_s1 + + @brief SM key generation function s1 + + @param pK - key is 128 bits, LSByte first + @param pR1 - 64 bit, LSByte first + @param pR2 - 64 bit, LSByte first + @param pS1 - pointer to 128 bit results space + + @return status +*/ +bStatus_t sm_s1( uint8* pK, uint8* pR1, uint8* pR2, uint8* pS1 ) +{ + bStatus_t stat; // return value + sm_Encrypt_t param; // place to work for the encrypt function + // Fill in the parameters + VOID osal_revmemcpy( param.key, pK, KEYLEN ); + VOID osal_revmemcpy( param.plainTextData, pR1, LEN_64BIT ); + VOID osal_revmemcpy( &(param.plainTextData[LEN_64BIT]), pR2, LEN_64BIT ); + stat = smEncrypt( ¶m ); + // Copy the results + VOID osal_revmemcpy( pS1, param.result, KEYLEN ); + return ( stat ); +} + +/********************************************************************* + @fn smGenerateRandBuf + + @brief Generate a buffer with random numbers. + + @param pRandNum - pointer to buffer + @param len - length of buffer. + + @return none +*/ +void smGenerateRandBuf( uint8* pRandNum, uint8 len ) +{ + uint8 x = 0; // loop counter + uint16 rand; // Random value + + while ( x < len ) + { + // Get a random value + rand = osal_rand(); + pRandNum[x] = HI_UINT16( rand ); + x++; + + // Can we use the other half? + if ( x < len ) + { + pRandNum[x] = LO_UINT16( rand ); + x++; + } + } +} + +/********************************************************************* + @fn smAuthReqToUint8 + + @brief Conversion function to convert authReq_t to uint8 + + @param pAuthReq - pointer to + + @return uint8 conversion +*/ +uint8 smAuthReqToUint8( authReq_t* pAuthReq ) +{ + uint8 tmp; + tmp = pAuthReq->bonding; + tmp |= (pAuthReq->mitm << 2); + tmp |= (pAuthReq->reserved << 3); + return ( tmp ); +} + +/********************************************************************* + @fn smUint8ToAuthReq + + @brief Conversion function to convert uint8 to authReq_t + + @param pAuthReq - pointer to structure + @param authReqUint8 - byte version of authReq + + @return none +*/ +void smUint8ToAuthReq( authReq_t* pAuthReq, uint8 authReqUint8 ) +{ + pAuthReq->bonding = (authReqUint8 & 0x03); + pAuthReq->mitm = (authReqUint8 & 0x04) ? TRUE : FALSE; + pAuthReq->reserved = (authReqUint8 >> 3) & 0x1F; +} + +/********************************************************************* + @fn smSendGenKeyEvent + + @brief Send the SM new random key Event message and free + pSmGenKey. + + @param status - status of the command. + + @return none +*/ +static void smSendGenKeyEvent( uint8 status ) +{ + if ( pSmGenKey ) + { + smNewRandKeyEvent_t* pRsp; + pRsp = (smNewRandKeyEvent_t*)osal_msg_allocate( sizeof ( smNewRandKeyEvent_t ) ); + + if ( pRsp ) + { + pRsp->hdr.event = SM_NEW_RAND_KEY_EVENT; + pRsp->hdr.status = status; + VOID osal_memcpy( pRsp->newKey, pSmGenKey->key, KEYLEN ); + VOID osal_msg_send( pSmGenKey->taskID, (uint8*)pRsp ); + } + + osal_mem_free( pSmGenKey ); + pSmGenKey = NULL; + } +} + +/********************************************************************* + @fn smEncrypt + + @brief Seperates the sm_Encrypt_t structure and calls + smEncryptLocal() + + @param pParam - pointer to the parameter structure + + @return Status_t +*/ +static bStatus_t smEncrypt( sm_Encrypt_t* pParam ) +{ + return ( smEncryptLocal( pParam->key, pParam->plainTextData, pParam->result ) ); +} + +/********************************************************************* + @fn smEncryptLocal + + @brief Perform the HCI Encrypt function. + + @param pKey - Encrypt Key + @param pPlaintextData - plain text to encrypt + @param pEncryptedData - pointer to result space + + @return Status_t +*/ +static bStatus_t smEncryptLocal( uint8* pKey, uint8* pPlaintextData, uint8* pEncryptedData ) +{ + // This function is kind of a cheat because it isn't going through + // HCI. If the host is to be used on different (from LL) processor + // it will have to provide a local copy of LL_Encrypt, or it will + // have to be written to use state machine events. + return ( LL_Encrypt( pKey, pPlaintextData, pEncryptedData ) ); +} + +/********************************************************************* + @fn sm_CMAC + + @brief An implementation of the CMAC algorithm. + + NOTE: All of the input and output buffers are MSByte first. + The calling function must take care of the byte order, before + and after calling this function + + @param pK - key + @param pM - data + @param mLen - data length + @param pMac - pointer to the 64 bit results + + @return bStatus_t +*/ +static bStatus_t sm_CMAC( uint8* pK, uint8* pM, uint8 mLen, uint8* pMac ) +{ + int16 n, i, flag; + uint8* pK1; + uint8* pK2; + bStatus_t stat; + // Allocate RAM needed + pK1 = osal_mem_alloc( KEYLEN ); + pK2 = osal_mem_alloc( KEYLEN ); + + // Make sure they allocated + if ( (pK1 != NULL) && (pK2 != NULL) ) + { + stat = generate_subkey( pK, pK1, pK2 ); + + if ( stat == SUCCESS ) + { + uint8* pX; + uint8* pM_last; + pX = osal_mem_alloc( KEYLEN ); + pM_last = osal_mem_alloc( KEYLEN ); + + if ( (pX != NULL) && (pM_last != NULL) ) + { + uint8 mIdx; + n = (mLen + 15)/16; /* n is number of rounds */ + + if ( n == 0 ) + { + n = 1; + flag = 0; + } + else + { + if ( (mLen%16) == 0 ) /* last block is a complete block */ + { + flag = 1; + } + else /* last block is not complete block */ + { + flag = 0; + } + } + + mIdx = (uint8)(16*(n-1)); + + if ( flag ) /* last block is complete block */ + { + xor_128( &pM[mIdx], pK1, pM_last ); + } + else + { + uint8 padded[KEYLEN]; + padding( &pM[mIdx], padded, mLen%16 ); + xor_128( padded, pK2, pM_last ); + } + + VOID osal_memset( pX, 0, KEYLEN ); + { + uint8 Y[KEYLEN]; + + for ( i = 0; (i < (n-1)) && (stat == SUCCESS); i++ ) + { + mIdx = (uint8)(16*i); + xor_128( pX, &pM[mIdx], Y ); /* Y := Mi (+) X */ + stat = smEncryptLocal( pK, Y, pX ); + } + + if ( stat == SUCCESS ) + { + xor_128( pX, pM_last, Y ); + stat = smEncryptLocal( pK, Y, pX ); + // T = MSB[Tlen]( Cn ); T = mac, Tlen = LEN_64BIT, Cn = X + VOID osal_memcpy( pMac, pX, LEN_64BIT ); + } + } + } + else + { + stat = bleMemAllocError; + } + + if ( pX ) + { + osal_mem_free( pX ); + } + + if ( pM_last ) + { + osal_mem_free( pM_last ); + } + } + } + else + { + stat = bleMemAllocError; + } + + if ( pK1 ) + { + osal_mem_free( pK1 ); + } + + if ( pK2 ) + { + osal_mem_free( pK2 ); + } + + return ( stat ); +} + +/********************************************************************* + @fn generate_subkey + + @brief Generate CMAC Subkeys. Only call from sm_CMAC. + + @param pKey - key + @param pK1 - sub key 1 + @param pK2 - sub key 2 + + @return bStatus_t +*/ +static bStatus_t generate_subkey( uint8* pKey, uint8* pK1, uint8* pK2 ) +{ + uint8* pL; + uint8* pTmp; + uint8 stat; + pL = osal_mem_alloc( KEYLEN ); + pTmp = osal_mem_alloc( KEYLEN ); + + if ( (pL != NULL) && (pTmp != NULL) ) + { + VOID osal_memset( pTmp, 0, KEYLEN ); + stat = smEncryptLocal( pKey, pTmp, pL ); + + if ( stat == SUCCESS ) + { + if ( (pL[0] & 0x80) == 0 ) /* If MSB(L) = 0, then K1 = L << 1 */ + { + leftshift_onebit( pL, pK1 ); + } + else /* Else pK1 = ( pL << 1 ) (+) Rb */ + { + leftshift_onebit( pL, pTmp ); + xor_128( pTmp, const_Rb, pK1 ); + } + + if ( (pK1[0] & 0x80) == 0 ) + { + leftshift_onebit( pK1, pK2 ); + } + else + { + leftshift_onebit( pK1, pTmp ); + xor_128( pTmp, const_Rb, pK2 ); + } + } + } + else + { + stat = bleMemAllocError; + } + + if ( pL ) + { + osal_mem_free( pL ); + } + + if ( pTmp ) + { + osal_mem_free( pTmp ); + } + + return ( stat ); +} + +/********************************************************************* + @fn xor_128 + + @brief XOR 128 bits - outcome = a XOR B + This function doesn't XOR in place. + + @param pA - var 1 + @param pB - var 2 + @param pOutcome - outcome + + @return None +*/ +static void xor_128( uint8* pA, CONST uint8* pB, uint8* pOutcome ) +{ + for ( uint8 i = 0; i < KEYLEN; i++ ) + { + pOutcome[i] = pA[i] ^ pB[i]; + } +} + +/********************************************************************* + @fn padding + + @brief add padding to "pad", first copy lastb, then on the last + byte of the "lastb" set to 0x80, the rest of the + buffer set to 0. + + @param pLastb - previous buffer (last block) + @param pPad - new buffer + @param length - length non-padding + + @return None +*/ +static void padding ( uint8* pLastb, uint8* pPad, uint8 length ) +{ + /* original last block */ + for ( uint8 j = 0; j < KEYLEN; j++ ) + { + if ( j < length ) + { + pPad[j] = pLastb[j]; + } + else if ( j == length ) + { + pPad[j] = 0x80; // mark the last non-pad byte + } + else + { + pPad[j] = 0x00; + } + } +} + +/********************************************************************* + @fn leftshift_onebit + + @brief Left shift 128 bits + + @param pInp - input buffer + @param pOutp - output buffer + + @return None +*/ +static void leftshift_onebit( uint8* pInp, uint8* pOutp ) +{ + uint8 overflow = 0; + + for ( int8 i = 15; i >= 0; i-- ) + { + pOutp[i] = pInp[i] << 1; + pOutp[i] |= overflow; + overflow = (pInp[i] & 0x80) ? 1 : 0; + } +} diff --git a/src/lib/ble_host/sm_pairing.c b/src/lib/ble_host/sm_pairing.c new file mode 100644 index 0000000..12c0548 --- /dev/null +++ b/src/lib/ble_host/sm_pairing.c @@ -0,0 +1,1215 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: sm_pairing.c + Revised: + Revision: + + Description: This file contains the SM Pairing Manager. + + +**************************************************************************************************/ + +#include "bcomdef.h" +#include "l2cap.h" +#include "gap_internal.h" +#include "linkdb.h" +#include "sm.h" +#include "sm_internal.h" +#include "smp.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +// Defines just for the IOCapMatrix table below +#define JUST_WORKS SM_PAIRING_TYPE_JUST_WORKS +#define INIT_INP SM_PAIRING_TYPE_PASSKEY_INITIATOR_INPUTS +#define RESP_INP SM_PAIRING_TYPE_PASSKEY_RESPONDER_INPUTS +#define BOTH_INP SM_PAIRING_TYPE_PASSKEY_BOTH_INPUTS + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +// Pairing parameters, NULL while not pairing +#if MAX_NUM_LL_CONN==1 +smPairingParams_t* pPairingParams[MAX_NUM_LL_CONN]= {NULL}; +#elif MAX_NUM_LL_CONN==5 +smPairingParams_t* pPairingParams[MAX_NUM_LL_CONN] = {NULL,NULL,NULL,NULL,NULL}; +#else +smPairingParams_t* pPairingParams[MAX_NUM_LL_CONN] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; +#endif + +// Callback function pointers for Responder +smResponderCBs_t* pfnResponderCBs = NULL; + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +// Callback function pointers for Initiator +static const smInitiatorCBs_t* pfnInitiatorCBs = NULL; + +// Determine the Pairing passkey requirement (from the spec): +// IOCapMatrix[Responder's IOCapability][Initiator's IOCapability]; +static CONST uint8 IOCapMatrix[5][5] = +{ + /* Initiator: DisplayOnly, DisplayYesNo, KeyboardOnly, NoInputNoOutput, KeyboardDisplay */ + /* Responder: */ + /* DisplayOnly */ { JUST_WORKS, JUST_WORKS, INIT_INP, JUST_WORKS, INIT_INP }, + /* DisplayYesNo */ { JUST_WORKS, JUST_WORKS, INIT_INP, JUST_WORKS, INIT_INP }, + /* KeyboardOnly */ { RESP_INP, RESP_INP, BOTH_INP, JUST_WORKS, RESP_INP }, + /* NoInputNoOutput */ { JUST_WORKS, JUST_WORKS, JUST_WORKS, JUST_WORKS, JUST_WORKS }, + /* KeyboardDisplay */ { RESP_INP, RESP_INP, INIT_INP, JUST_WORKS, RESP_INP } +}; + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static uint8 smpProcessIncoming( uint16 connHandle, uint8 cmdID, smpMsgs_t* pParsedMsg ); + +static bStatus_t smDetermineIOCaps( uint16 connectionHandle,uint8 initiatorIO, uint8 responderIO ); +static void smFreePairingParams( uint16 connectionHandle ); +static void smSetPairingReqRsp( uint16 connectionHandle,smpPairingReq_t* pReq ); + + +/********************************************************************* + API FUNCTIONS +*/ + + +/********************************************************************* + FUNCTIONS - MASTER API - Only use these in a master device +*/ + + +/********************************************************************* + Start the pairing process with a slave device. + + Public function defined in sm.h. +*/ +bStatus_t SM_StartPairing( uint8 initiator, + uint8 taskID, + uint16 connectionHandle, + smLinkSecurityReq_t* pSecReqs ) +{ + bStatus_t ret = SUCCESS; // Return value + + // Only one pairing at a time + if ( pPairingParams[connectionHandle] ) + { + return ( bleAlreadyInRequestedMode ); + } + + // Check parameters + if ( (pSecReqs == NULL) || (pSecReqs->maxEncKeySize < GAP_GetParamValue( TGAP_SM_MIN_KEY_LEN )) + || (pSecReqs->maxEncKeySize > GAP_GetParamValue( TGAP_SM_MAX_KEY_LEN )) ) + { + return ( INVALIDPARAMETER ); + } + + pPairingParams[connectionHandle] = ( smPairingParams_t*)osal_mem_alloc( (uint16)sizeof ( smPairingParams_t ) ); + + if ( pPairingParams[connectionHandle] == NULL ) + { + return ( bleMemAllocError ); + } + + VOID osal_memset( pPairingParams[connectionHandle], 0, sizeof( smPairingParams_t ) ); + // Save parameters + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_INITIALIZE; + pPairingParams[connectionHandle]->initiator = initiator; + pPairingParams[connectionHandle]->taskID = taskID; + pPairingParams[connectionHandle]->timerID = INVALID_TASK_ID; + pPairingParams[connectionHandle]->connectionHandle = connectionHandle; + pPairingParams[connectionHandle]->pSecReqs = pSecReqs; + pPairingParams[connectionHandle]->pPairDev = NULL; + pPairingParams[connectionHandle]->type = SM_PAIRING_TYPE_INIT; + + if ( initiator ) + { + // Start the pairing process + ret = smGeneratePairingReqRsp(connectionHandle); + } + + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_PAIRING_REQ_SENT; + + if ( ret != SUCCESS ) + { + // Free the mem - not successful. + smFreePairingParams( connectionHandle); + } + + return ( ret ); +} + +/********************************************************************* + Update the passkey for the pairing process. + + Public function defined in sm.h. +*/ +bStatus_t SM_PasskeyUpdate( uint8* pPasskey, uint16 connectionHandle ) +{ + bStatus_t ret = SUCCESS; // return value + uint8 sendConfirm = FALSE; // flag to send pairing confirm message + + // Are we pairing? + if ( pPairingParams[connectionHandle] == NULL ) + { + return ( bleIncorrectMode ); + } + + // Are we expecting the passkey? + if ( (pPairingParams[connectionHandle]->type != SM_PAIRING_TYPE_PASSKEY_INITIATOR_INPUTS) + && (pPairingParams[connectionHandle]->type != SM_PAIRING_TYPE_PASSKEY_RESPONDER_INPUTS) + && (pPairingParams[connectionHandle]->type != SM_PAIRING_TYPE_PASSKEY_BOTH_INPUTS) ) + { + return ( bleIncorrectMode ); + } + + // Is this the correct connection? + if ( pPairingParams[connectionHandle]->connectionHandle != connectionHandle ) + { + return ( INVALIDPARAMETER ); + } + + // Copy the passkey (tk) + VOID osal_memcpy( pPairingParams[connectionHandle]->tk, pPasskey, KEYLEN ); + // Generate Rand (MRand or SRand) + smGenerateRandBuf( pPairingParams[connectionHandle]->myComp.rand, SMP_RANDOM_LEN ); + // Generate Confirm (MConfirm or SConfirm) + sm_c1(connectionHandle, pPairingParams[connectionHandle]->tk, + pPairingParams[connectionHandle]->myComp.rand, + pPairingParams[connectionHandle]->myComp.confirm ); + + // Set the correct state + if ( (pPairingParams[connectionHandle]->initiator) + && (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_PASSKEY) ) + { + // Send Confirm + sendConfirm = TRUE; + // Next, wait for Responder Confirm + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_CONFIRM; + } + else if ( (pPairingParams[connectionHandle]->initiator == 0) + && (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_CONFIRM_PASSKEY) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_CONFIRM; + } + else if ( (pPairingParams[connectionHandle]->initiator == 0) + && (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_PASSKEY) ) + { + // We have both confirm and passkey, send our own confirm + sendConfirm = TRUE; + // Next, wait for Pairing Random + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_RANDOM; + } + + if ( sendConfirm ) + { + #if defined ( TESTMODES ) + + if ( GAP_GetParamValue( TGAP_SM_TESTCODE ) == SM_TESTMODE_SEND_BAD_CONFIRM ) + { + VOID osal_memset( pPairingParams[connectionHandle]->myComp.confirm, 0, KEYLEN ); + } + + #endif // TESTMODE + // Send the Pairing Confirm message + ret = smGenerateConfirm( connectionHandle); + } + + return ( ret ); +} + +/********************************************************************* + PUBLIC INTERNAL SM FUNCTIONS +*/ + +/********************************************************************* + @fn smRegisterInitiator + + @brief Register Initiator's processing function with SM task. + + @param pfnCBs - pointer to Initiator's processing function + + @return none +*/ +void smRegisterInitiator( smInitiatorCBs_t* pfnCBs ) +{ + pfnInitiatorCBs = pfnCBs; +} + +/********************************************************************* + @fn smRegisterResponder + + @brief Register Responder's processing function with SM task. + + @param pfnCBs - pointer to Responder's processing function + + @return none +*/ +void smRegisterResponder( smResponderCBs_t* pfnCBs ) +{ + pfnResponderCBs = pfnCBs; +} + +/********************************************************************* + @fn smLinkCheck + + @brief Callback for linkDB to indicate link changes. + + @param connectionHandle - link connection handle + @param changeType - link connection handle + ex. LINKDB_STATUS_UPDATE_REMOVED + + @return none +*/ +void smLinkCheck( uint16 connectionHandle, uint8 changeType ) +{ + if ( (pPairingParams[connectionHandle]) + && (pPairingParams[connectionHandle]->connectionHandle == connectionHandle) + && (changeType == LINKDB_STATUS_UPDATE_REMOVED) ) + { + // Connection is down, remove the pairing information + smFreePairingParams( connectionHandle); + } +} + +/********************************************************************* + @fn smTimedOut + + @brief Something didn't repond quickly enough. + + @param none + + @return none +*/ +void smTimedOut( uint16 connectionHandle ) +{ + smEndPairing( connectionHandle,bleTimeout ); +} + +/********************************************************************* + @fn smProcessDataMsg + + @brief Process incoming L2CAP messages. + + @param pMsg - pointer to message. + + @return none +*/ +void smProcessDataMsg( l2capDataEvent_t* pMsg ) +{ + smpMsgs_t parsedMsg; // Place to parse the message + bStatus_t stat = SUCCESS; // Return value + smpPairingFailed_t failed; // Pairing Failed message + uint8 cmdID; // Message command ID + #if defined ( TESTMODES ) + + if ( GAP_GetParamValue( TGAP_SM_TESTCODE ) == SM_TESTMODE_NO_RESPONSE ) + { + // just ignore the messages + return; + } + + #endif // TESTMODE + failed.reason = SUCCESS; // Default to success + // Parse the incoming message + cmdID = *(pMsg->pkt.pPayload); + + switch ( cmdID ) + { + case SMP_PAIRING_REQ: + case SMP_PAIRING_RSP: + stat = smpParsePairingReq( pMsg->pkt.pPayload, &(parsedMsg.pairingReq) ); + + if ( stat == bleIncorrectMode ) + { + failed.reason = SMP_PAIRING_FAILED_ENC_KEY_SIZE; + } + + break; + + case SMP_PAIRING_CONFIRM: + stat = smpParsePairingConfirm( pMsg->pkt.pPayload, &(parsedMsg.pairingConfirm) ); + break; + + case SMP_PAIRING_RANDOM: + stat = smpParsePairingRandom( pMsg->pkt.pPayload, &(parsedMsg.pairingRandom) ); + break; + + case SMP_PAIRING_FAILED: + stat = smpParsePairingFailed( pMsg->pkt.pPayload, &(parsedMsg.pairingFailed) ); + break; + + case SMP_ENCRYPTION_INFORMATION: + stat = smpParseEncInfo( pMsg->pkt.pPayload, &(parsedMsg.encInfo) ); + break; + + case SMP_MASTER_IDENTIFICATION: + stat = smpParseMasterID( pMsg->pkt.pPayload, &(parsedMsg.masterID) ); + break; + + case SMP_IDENTITY_INFORMATION: + stat = smpParseIdentityInfo( pMsg->pkt.pPayload, &(parsedMsg.idInfo) ); + break; + + case SMP_IDENTITY_ADDR_INFORMATION: + stat = smpParseIdentityAddrInfo( pMsg->pkt.pPayload, &(parsedMsg.idAddrInfo) ); + break; + + case SMP_SIGNING_INFORMATION: + stat = smpParseSigningInfo( pMsg->pkt.pPayload, &(parsedMsg.signingInfo) ); + break; + + case SMP_SECURITY_REQUEST: + stat = smpParseSecurityReq( pMsg->pkt.pPayload, &(parsedMsg.secReq) ); + break; + + default: + stat = bleIncorrectMode; + failed.reason = SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED; + break; + } + + // Process the incoming message + if ( stat == SUCCESS ) + { + failed.reason = smpProcessIncoming( pMsg->connHandle, cmdID, &parsedMsg ); + } + + // Check for fail indication + if ( failed.reason != SUCCESS ) + { + // Send Pairing Failed message and close the pairing process + smSendFailAndEnd( pMsg->connHandle, &failed ); + } + else + { + // Reset the timeout + smStartRspTimer(pMsg->connHandle); + } +} + +/********************************************************************* + @fn smSendFailAndEnd + + @brief Send the pairing failed message and end existing pairing. + + @param connHandle - link ID + @param pFailedMsg - Pairing Failed message + + @return SUCCESS if pairing failed sent + otherwise failure. +*/ +bStatus_t smSendFailAndEnd( uint16 connHandle, smpPairingFailed_t* pFailedMsg ) +{ + bStatus_t stat; // return value + // Send Pairing Failed message + stat = smSendPairingFailed( connHandle, pFailedMsg ); + // Clean up after error, end pairing process + smEndPairing( connHandle,pFailedMsg->reason ); + return ( stat ); +} + +/********************************************************************* + @fn smProcessEncryptChange + + @brief Process the HCI BLE Encryption Change Event. + + @param connectionHandle - link ID + @param reason - reason for change + + @return TRUE - We are always expecting this message +*/ +uint8 smProcessEncryptChange( uint16 connectionHandle, uint8 reason ) +{ + uint8 sendBondEnd = FALSE; // Assume not bonding + + // Check for the correct state and connection + if ( (pPairingParams[connectionHandle]) + && (pPairingParams[connectionHandle]->connectionHandle == connectionHandle) ) + { + if ( pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_STK ) + { + if ( pPairingParams[connectionHandle]->initiator ) + { + smLinkSecurityReq_t* pSecReq = pPairingParams[connectionHandle]->pSecReqs; + smpPairingReq_t* pPairReq = pPairingParams[connectionHandle]->pPairDev; + + // Wait for key distribute messages from Responder + if ( (pSecReq->keyDist.sEncKey) && (pPairReq->keyDist.sEncKey) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_SLAVE_ENCRYPTION_INFO; + } + else if ( (pSecReq->keyDist.sIdKey) && (pPairReq->keyDist.sIdKey) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_SLAVE_IDENTITY_INFO; + } + else if ( (pSecReq->keyDist.sSign) && (pPairReq->keyDist.sSign) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_SLAVE_SIGNING_INFO; + } + else + { + // Send the next key distribution message to the responder + if ( pfnInitiatorCBs && pfnInitiatorCBs->pfnSendNextKeyInfo ) + { + pfnInitiatorCBs->pfnSendNextKeyInfo(connectionHandle); + } + } + } + else + { + // Send the next key distribution message + if ( pfnResponderCBs && pfnResponderCBs->pfnSendNextKeyInfo ) + { + pfnResponderCBs->pfnSendNextKeyInfo(connectionHandle); + } + } + + // If we are done, end the pairing process + if ( pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_DONE ) + { + // Exit pairing + smEndPairing( connectionHandle,SUCCESS ); + } + } + else if ( pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_ENCRYPT ) + { + // We are waiting for the encrypt complete to complete pairing + if ( reason != SUCCESS ) + { + // Generic bond error + reason = bleGAPBondRejected; + } + + smEndPairing( connectionHandle,reason ); + } + else + { + // wasn't expecting + sendBondEnd = TRUE; + } + } + else + { + // loaded key + sendBondEnd = TRUE; + } + + if ( sendBondEnd == TRUE ) + { + if ( reason == SUCCESS ) + { + linkDBItem_t* pLink; // connection information + pLink = linkDB_Find( connectionHandle ); + + if ( pLink ) + { + // Change the connections state to include Encrypted + pLink->stateFlags |= LINK_ENCRYPTED; + } + } + + // Send the bond complete event to the app/profile + gapSendBondCompleteEvent( reason, connectionHandle ); + } + + return ( TRUE ); // We are always expecting this message +} + +/********************************************************************* + @fn smNextPairingState + + @brief Do the next Pairing key distribution state. + + @param none + + @return none +*/ +void smNextPairingState(uint16 connectionHandle ) +{ + if ( pPairingParams[connectionHandle] ) + { + if ( pPairingParams[connectionHandle]->initiator == FALSE ) + { + // Send next responder key distribution message + if ( pfnResponderCBs && pfnResponderCBs->pfnSendNextKeyInfo ) + { + pfnResponderCBs->pfnSendNextKeyInfo(connectionHandle); + } + } + else + { + // Send next initiator key distribution message + if ( pfnInitiatorCBs && pfnInitiatorCBs->pfnSendNextKeyInfo ) + { + pfnInitiatorCBs->pfnSendNextKeyInfo(connectionHandle); + } + } + + if ( pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_DONE ) + { + smEndPairing(connectionHandle,SUCCESS ); + } + } +} + +/********************************************************************* + @fn sm_c1 + + @brief SM Confirm value generation function c1 + + NOTE: This function can only be called during a connection + and during the pairing process. + + @param pK - key is 128 bits, LSByte first + @param pR - 128 bit, LSByte first + @param pC1 - pointer to 128 bit results space + + @return status +*/ +bStatus_t sm_c1(uint16 connectionHandle,uint8* pK, uint8* pR, uint8* pC1 ) +{ + bStatus_t stat; // return value + uint8 pres[SMP_PAIRING_RSP_LEN]; // Pairing Response message (raw) + uint8 preq[SMP_PAIRING_REQ_LEN]; // Pairing Request message (raw) + uint8 iat; // initiator address type + uint8 rat; // responder address type + uint8* pIA; // initiator address + uint8* pRA; // responder address + smpPairingReq_t pairingStruct; // Pairing Reqeust struct + smpPairingReq_t* pPairingReq; // Pairing Reqeust + smpPairingReq_t* pPairingRsp; // Pairing Response + linkDBItem_t* pLinkItem; // Connection information + + // Make sure we are in the correct mode + if ( pPairingParams[connectionHandle] == NULL ) + { + return ( bleIncorrectMode ); + } + + // Find the connection + pLinkItem = linkDB_Find( pPairingParams[connectionHandle]->connectionHandle ); + + if ( pLinkItem == NULL ) + { + return ( bleNotConnected ); + } + + // Setup pairing request/response parameters + smSetPairingReqRsp( connectionHandle,&pairingStruct ); + + if ( pPairingParams[connectionHandle]->initiator ) + { + // Setup all of the variables for an initiator + pPairingReq = &pairingStruct; + pPairingRsp = pPairingParams[connectionHandle]->pPairDev; + iat = gapGetDevAddressMode(); + pIA = gapGetDevAddress( FALSE ); + rat = pLinkItem->addrType; + pRA = pLinkItem->addr; + } + else + { + // Setup all of the variables for a responder + pPairingReq = pPairingParams[connectionHandle]->pPairDev; + pPairingRsp = &pairingStruct; + rat = gapGetDevAddressMode(); + pRA = gapGetDevAddress( FALSE ); + iat = pLinkItem->addrType; + pIA = pLinkItem->addr; + } + + // build the raw data for the Pairing Request and Pairing Response messages + VOID smpBuildPairingRsp( pPairingRsp, pres ); + VOID smpBuildPairingReq( pPairingReq, preq ); + // Calculate the cl + stat = sm_c1new( pK, pR, pres, preq, iat, pIA, rat, pRA, pC1 ); + return ( stat ); +} + +/********************************************************************* + @fn smpProcessIncoming + + @brief Process incoming parsed SM message. + + @param connHandle - connection Handle + @param cmdID - command ID + @param pParsedMsg - pointer to parsed message + + @return SUCCESS + SMP_PAIRING_FAILED_PASSKEY_ENTRY_FAILED + SMP_PAIRING_FAILED_OOB_NOT_AVAIL + SMP_PAIRING_FAILED_AUTH_REQ + SMP_PAIRING_FAILED_CONFIRM_VALUE + SMP_PAIRING_FAILED_NOT_SUPPORTED + SMP_PAIRING_FAILED_ENC_KEY_SIZE + SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED + SMP_PAIRING_FAILED_UNSPECIFIED + SMP_PAIRING_FAILED_REPEATED_ATTEMPTS +*/ +static uint8 smpProcessIncoming( uint16 connHandle, uint8 cmdID, smpMsgs_t* pParsedMsg ) +{ + linkDBItem_t* pLinkItem; // connection information + uint8 reason = SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED; // return value + // find the connection + pLinkItem = linkDB_Find( connHandle ); + + if ( pLinkItem == NULL ) + { + return ( SMP_PAIRING_FAILED_UNSPECIFIED ); + } + + if( pLinkItem->role == LL_LINK_CONNECT_COMPLETE_MASTER ) + { + if ( (gapProfileRole & GAP_PROFILE_CENTRAL) == GAP_PROFILE_CENTRAL ) + { + //printf("gapProfileRole & GAP_PROFILE_CENTRAL \n"); + // Process Initiator pairing messages + if ( pfnInitiatorCBs && pfnInitiatorCBs->pfnProcessMsg ) + { + reason = pfnInitiatorCBs->pfnProcessMsg( pLinkItem, cmdID, pParsedMsg ); + } + } + } + else if( pLinkItem->role == LL_LINK_CONNECT_COMPLETE_SLAVE ) + { + //printf("gapProfileRole & GAP_PROFILE_PERIPHERAL \n"); + // Process Responder pairing messages + if ( pfnResponderCBs && pfnResponderCBs->pfnProcessMsg ) + { + reason = pfnResponderCBs->pfnProcessMsg( pLinkItem, cmdID, pParsedMsg ); + } + } + else + { + return ( SMP_PAIRING_FAILED_NOT_SUPPORTED ); + } + + return ( reason ); +} + +/********************************************************************* + @fn smProcessPairingReq + + @brief Process Pairing Request. + + @param pLinkItem - pointer to link item + @param pParsedMsg - pointer to request + + @return void +*/ +void smProcessPairingReq( linkDBItem_t* pLinkItem, gapPairingReq_t* pPairReq ) +{ + if ( pfnResponderCBs && pfnResponderCBs->pfnProcessMsg ) + { + uint8 reason; + smpPairingReq_t pairingReq; + pairingReq.ioCapability = pPairReq->ioCap; + pairingReq.oobDataFlag = pPairReq->oobDataFlag; + smUint8ToAuthReq( &(pairingReq.authReq), pPairReq->authReq ); + pairingReq.maxEncKeySize = pPairReq->maxEncKeySize; + pairingReq.keyDist = pPairReq->keyDist; + reason = pfnResponderCBs->pfnProcessMsg( pLinkItem, SMP_PAIRING_REQ, + (smpMsgs_t*)&pairingReq ); + + if ( reason != SUCCESS ) + { + smpPairingFailed_t failedMsg; + failedMsg.reason = reason; + VOID smSendFailAndEnd( pLinkItem->connectionHandle, &failedMsg ); + } + } +} + +/********************************************************************* + @fn smStartEncryption + + @brief Perform Encrypt through HCI + + @param connHandle - Connection Handle + @param pLTK - pointer to 16 byte lkt + @param div - div or ediv + @param pRandNum - pointer to 8 byte random number + @param keyLen - length of LTK (bytes) + + @return SUCCESS + INVALIDPARAMETER + other from HCI/LL +*/ +bStatus_t smStartEncryption( uint16 connHandle, uint8* pLTK, uint16 div, + uint8* pRandNum, uint8 keyLen ) +{ + if ( pfnInitiatorCBs && pfnInitiatorCBs->pfnStartEncryption ) + { + return ( pfnInitiatorCBs->pfnStartEncryption( connHandle, pLTK, div, pRandNum, keyLen ) ); + } + + return ( INVALIDPARAMETER ); +} + +/********************************************************************* + @fn smGeneratePairingReqRsp + + @brief Generate a pairing req or response + + @param none + + @return SUCCESS, FAILURE +*/ +bStatus_t smGeneratePairingReqRsp( uint16 connectionHandle ) +{ + if ( pPairingParams[connectionHandle] ) + { + smpPairingReq_t pairingReq; // Structure to build message + // Setup pairing request/response parameters + smSetPairingReqRsp( connectionHandle,&pairingReq ); + + if ( pPairingParams[connectionHandle]->initiator ) + { + // Send Request + return ( smSendPairingReq( pPairingParams[connectionHandle]->connectionHandle, (smpMsgs_t*)(&pairingReq) ) ); + } + else + { + // Send Response + return ( smSendPairingRsp( pPairingParams[connectionHandle]->connectionHandle, (smpMsgs_t*)(&pairingReq) ) ); + } + } + else + { + return ( FAILURE ); + } +} + +/********************************************************************* + @fn smGenerateConfirm + + @brief Generate a Pairing Confirm + + @param none + + @return SUCCESS +*/ +bStatus_t smGenerateConfirm( uint16 connectionHandle ) +{ + smpPairingConfirm_t confirmMsg; // Parameters to build message + // Copy the confirm + VOID osal_memcpy( confirmMsg.confirmValue, + pPairingParams[connectionHandle]->myComp.confirm, SMP_CONFIRM_LEN ); + // Send confirm message + return ( smSendPairingConfirm( pPairingParams[connectionHandle]->connectionHandle, &confirmMsg ) ); +} + +/********************************************************************* + @fn smGenerateRandMsg + + @brief Generate a Pairing Random + + @param none + + @return SUCCESS +*/ +bStatus_t smGenerateRandMsg( uint16 connectionHandle ) +{ + smpPairingRandom_t randMsg; // Parameters to build message + // Build rand + VOID osal_memcpy( randMsg.randomValue, + pPairingParams[connectionHandle]->myComp.rand, SMP_RANDOM_LEN ); + // Send Random message + return ( smSendPairingRandom( pPairingParams[connectionHandle]->connectionHandle, &randMsg ) ); +} + +/********************************************************************* + @fn smSavePairInfo + + @brief Save the Pairing Req or Rsp information + + @param pPair - info to save + + @return SUCCESS + bleMemAllocError + bleInvalidRange - auth reqs don't match +*/ +bStatus_t smSavePairInfo( uint16 connectionHandle, smpPairingReq_t* pPair ) +{ + bStatus_t ret = SUCCESS; + // Allocate the pairing information + pPairingParams[connectionHandle]->pPairDev = (smpPairingReq_t*)osal_mem_alloc( (uint16)sizeof( smpPairingReq_t ) ); + + if ( pPairingParams[connectionHandle]->pPairDev ) + { + smLinkSecurityReq_t* pSecReq = pPairingParams[connectionHandle]->pSecReqs; + // Copy the pairing information into the pairingParam + VOID osal_memcpy( pPairingParams[connectionHandle]->pPairDev, pPair, (unsigned int)sizeof ( smpPairingReq_t ) ); + + if ( pPairingParams[connectionHandle]->initiator == FALSE ) + { + keyDist_t* pSecKey = &(pSecReq->keyDist); + keyDist_t* pPairKey = &(pPairingParams[connectionHandle]->pPairDev->keyDist); + // Responder: merge our key distribution plans with the initiator's + pSecKey->sEncKey = ( (pSecKey->sEncKey == pPairKey->sEncKey) && + (pSecKey->sEncKey == TRUE) ) ? TRUE : FALSE; + pSecKey->sIdKey = ( (pSecKey->sIdKey == pPairKey->sIdKey) && + (pSecKey->sIdKey == TRUE) ) ? TRUE : FALSE; + pSecKey->sSign = ( (pSecKey->sSign == pPairKey->sSign) && + (pSecKey->sSign == TRUE) ) ? TRUE : FALSE; + pSecKey->mEncKey = ( (pSecKey->mEncKey == pPairKey->mEncKey) && + (pSecKey->mEncKey == TRUE) ) ? TRUE : FALSE; + pSecKey->mIdKey = ( (pSecKey->mIdKey == pPairKey->mIdKey) && + (pSecKey->mIdKey == TRUE) ) ? TRUE : FALSE; + pSecKey->mSign = ( (pSecKey->mSign == pPairKey->mSign) && + (pSecKey->mSign == TRUE) ) ? TRUE : FALSE; + } + + // Determine the pairing type + if ( (pPair->oobDataFlag) && (pSecReq->oobAvailable) ) + { + pPairingParams[connectionHandle]->type = SM_PAIRING_TYPE_OOB; + } + else if ( ((pPair->authReq.mitm) == 0) && ((pSecReq->authReq & SMP_AUTHREQ_MITM) == 0) ) + { + // if either initiator and responder have no MITM + pPairingParams[connectionHandle]->type = SM_PAIRING_TYPE_JUST_WORKS; + } + else if ( (pPair->authReq.mitm) || (pSecReq->authReq & SMP_AUTHREQ_MITM) ) + { + uint8 initiatorIO; + uint8 responderIO; + + if ( pPairingParams[connectionHandle]->initiator ) + { + initiatorIO = pSecReq->ioCaps; + responderIO = pPair->ioCapability; + } + else + { + responderIO = pSecReq->ioCaps; + initiatorIO = pPair->ioCapability; + } + + // Update the pairingParam type field + ret = smDetermineIOCaps( connectionHandle,initiatorIO, responderIO ); + } + else + { + ret = bleInvalidRange; + } + } + else + { + ret = bleMemAllocError; + } + + return ( ret ); +} + +/********************************************************************* + @fn smDetermineIOCaps + + @brief Save the Pairing Req or Rsp information + + @param initiatorIO - initiator's IO Capabilities + @param responderIO - responder's IO Capabilities + + NOTE: Also updated is pPairingParams[connectionHandle]->type + + @return SUCCESS + bleInvalidRange - IO capability out of range +*/ +static bStatus_t smDetermineIOCaps( uint16 connectionHandle, uint8 initiatorIO, uint8 responderIO ) +{ + if ( (initiatorIO > SMP_IO_CAP_KEYBOARD_DISPLAY) || (responderIO > SMP_IO_CAP_KEYBOARD_DISPLAY) ) + { + return ( bleInvalidRange ); + } + + // From the Spec matrix determine the pairing type + pPairingParams[connectionHandle]->type = IOCapMatrix[responderIO][initiatorIO]; + return ( SUCCESS ); +} + +/********************************************************************* + @fn smPairingSendEncInfo + + @brief Send SM Encryption Information message + + @param connHandle - connection handle + @param pLTK - pointer to LTK + + @return SUCCESS + INVALIDPARAMETER + other from HCI/LL +*/ +void smPairingSendEncInfo( uint16 connHandle, uint8* pLTK ) +{ + // The smpEncInfo_t only has one field in it. + VOID smSendEncInfo( connHandle, (smpEncInfo_t*)pLTK ); +} + +/********************************************************************* + @fn smPairingSendMasterID + + @brief Send SM Master Identification message + + @param connHandle - connection handle + @param ediv - enhanced div + @param pRand - pointer to 8 byte random number string + + @return SUCCESS + INVALIDPARAMETER + other from HCI/LL +*/ +void smPairingSendMasterID( uint16 connHandle, uint16 ediv, uint8* pRand ) +{ + smpMasterID_t masterMsg; // Message structure + // Fill parameters + masterMsg.ediv = ediv; + VOID osal_memcpy( masterMsg.rand, pRand, B_RANDOM_NUM_SIZE ); + // Send Master ID message + VOID smSendMasterID( connHandle, &masterMsg ); +} + +/********************************************************************* + @fn smPairingSendIdentityInfo + + @brief Send SM Identity Information message + + @param connHandle - connection handle + @param pIRK - pointer to IRK + + @return SUCCESS + INVALIDPARAMETER + other from HCI/LL +*/ +void smPairingSendIdentityInfo( uint16 connHandle, uint8* pIRK ) +{ + VOID smSendIdentityInfo( connHandle, (smpIdentityInfo_t*)pIRK ); +} + +/********************************************************************* + @fn smPairingSendIdentityAddrInfo + + @brief Send SM Identity Addr Information message + + @param connHandle - connection handle + @param addrType - address type + @param pMACAddr - pointer to BD_ADDR + + @return SUCCESS + INVALIDPARAMETER + other from HCI/LL +*/ +void smPairingSendIdentityAddrInfo( uint16 connHandle, uint8 addrType, uint8* pMACAddr ) +{ + smpIdentityAddrInfo_t identityAddrMsg; // Message structure + // Fill in parameters + identityAddrMsg.addrType = addrType; + VOID osal_memcpy( identityAddrMsg.bdAddr, pMACAddr, B_ADDR_LEN ); + // Send message + VOID smSendIdentityAddrInfo( connHandle, &identityAddrMsg ); +} + +/********************************************************************* + @fn smPairingSendSingingInfo + + @brief Send SM Signing Information message + + @param connHandle - connection handle + @param pSRK - pointer to SRK + + @return SUCCESS + INVALIDPARAMETER + other from HCI/LL +*/ +void smPairingSendSingingInfo( uint16 connHandle, uint8* pSRK ) +{ + VOID smSendSigningInfo( connHandle, (smpSigningInfo_t*)pSRK ); +} + +/********************************************************************* + @fn smFreePairingParams + + @brief Free memory used in the Pairing Parameters + + @param none + + @return none +*/ +static void smFreePairingParams( uint16 connectionHandle ) +{ + #if !defined ( HOLD_PAIRING_PARAMETERS ) + // Clear the SM Timeout + smStopRspTimer( connectionHandle); + + if ( pPairingParams[connectionHandle] ) + { + // secReqs is not allocated in SM it's a borrowed struct from GAP. + // So, no dealloc here. + if ( pPairingParams[connectionHandle]->pPairDev ) + { + osal_mem_free( pPairingParams[connectionHandle]->pPairDev ); + } + + if ( pPairingParams[connectionHandle]->pEncParams ) + { + osal_mem_free( pPairingParams[connectionHandle]->pEncParams ); + } + + if ( pPairingParams[connectionHandle]->pDevEncParams ) + { + osal_mem_free( pPairingParams[connectionHandle]->pDevEncParams ); + } + + if ( pPairingParams[connectionHandle]->pIdInfo ) + { + osal_mem_free( pPairingParams[connectionHandle]->pIdInfo ); + } + + if ( pPairingParams[connectionHandle]->pSigningInfo ) + { + osal_mem_free( pPairingParams[connectionHandle]->pSigningInfo ); + } + + osal_mem_free( pPairingParams[connectionHandle] ); + pPairingParams[connectionHandle] = NULL; + } + + #endif +} + +/********************************************************************* + @fn smEndPairing + + @brief Pairing mode has ended. Yeah. Notify the GAP and free + up the memory used. + + @param status - how was the pairing completed + + @return none +*/ +void smEndPairing( uint16 connectionHandle,uint8 status ) +{ + if ( pPairingParams[connectionHandle] ) + { + gapPairingCompleteCB( status, pPairingParams[connectionHandle]->initiator, + pPairingParams[connectionHandle]->connectionHandle, + pPairingParams[connectionHandle]->authState, + pPairingParams[connectionHandle]->pEncParams, + pPairingParams[connectionHandle]->pDevEncParams, + pPairingParams[connectionHandle]->pIdInfo, + pPairingParams[connectionHandle]->pSigningInfo ); + // free up the pPairingParams[connectionHandle] + smFreePairingParams( connectionHandle); + } +} + +/********************************************************************* + @fn smDetermineKeySize + + @brief Determine the maximum encryption key size. + + @param none + + @return the negotiated key size +*/ +uint8 smDetermineKeySize( uint16 connectionHandle ) +{ + uint8 keySize = KEYLEN; + + if ( pPairingParams[connectionHandle] ) + { + if ( pPairingParams[connectionHandle]->pPairDev && pPairingParams[connectionHandle]->pSecReqs ) + { + if ( pPairingParams[connectionHandle]->pPairDev->maxEncKeySize < pPairingParams[connectionHandle]->pSecReqs->maxEncKeySize ) + { + keySize = pPairingParams[connectionHandle]->pPairDev->maxEncKeySize; + } + else + { + keySize = pPairingParams[connectionHandle]->pSecReqs->maxEncKeySize; + } + } + } + + return ( keySize ); +} + +/********************************************************************* + @fn smSetPairingReqRsp + + @brief Setup pairing request/response parameters. + + @param pReq - Request/Response to be set + + @return none +*/ +static void smSetPairingReqRsp( uint16 connectionHandle,smpPairingReq_t* pReq ) +{ + if ( pPairingParams[connectionHandle] && pPairingParams[connectionHandle]->pSecReqs ) + { + smLinkSecurityReq_t* pSecReq = pPairingParams[connectionHandle]->pSecReqs; + pReq->ioCapability = pSecReq->ioCaps; + pReq->oobDataFlag = pSecReq->oobAvailable; + smUint8ToAuthReq( &(pReq->authReq), pSecReq->authReq ); + pReq->maxEncKeySize = pSecReq->maxEncKeySize; + pReq->keyDist = pSecReq->keyDist; + } + else + { + VOID osal_memset( pReq, 0, sizeof( smpPairingReq_t ) ); + } +} + +/********************************************************************* +*********************************************************************/ diff --git a/src/lib/ble_host/sm_rsppairing.c b/src/lib/ble_host/sm_rsppairing.c new file mode 100644 index 0000000..0a8c6b3 --- /dev/null +++ b/src/lib/ble_host/sm_rsppairing.c @@ -0,0 +1,923 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: sm_rsppairing.c + Revised: + Revision: + + Description: This file contains the SM Responder Pairing Manager. + + +**************************************************************************************************/ + + +/******************************************************************************* + INCLUDES +*/ +#include "bcomdef.h" +#include "l2cap.h" +#include "gap_internal.h" +#include "linkdb.h" +#include "sm.h" +#include "sm_internal.h" +#include "smp.h" +#include "osal_cbtimer.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ +uint8 smState_CBTimer[15]= {0}; + + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static uint8 smpResponderProcessIncoming( linkDBItem_t* pLinkItem, uint8 cmdID, smpMsgs_t* pParsedMsg ); +static uint8 smpResponderProcessPairingConfirm( uint16 connectionHandle,smpPairingConfirm_t* pParsedMsg ); +static uint8 smpResponderProcessPairingRandom( uint16 connectionHandle,smpPairingRandom_t* pParsedMsg ); +static uint8 smpResponderProcessEncryptionInformation( uint16 connectionHandle,smpEncInfo_t* pParsedMsg ); +static uint8 smpResponderProcessMasterID( uint16 connectionHandle,smpMasterID_t* pParsedMsg ); +static uint8 smpResponderProcessIdentityInfo( uint16 connectionHandle,smpIdentityInfo_t* pParsedMsg ); +static uint8 smpResponderProcessIdentityAddrInfo( uint16 connectionHandle,smpIdentityAddrInfo_t* pParsedMsg ); +static uint8 smpResponderProcessSigningInfo( uint16 connectionHandle,smpSigningInfo_t* pParsedMsg ); + +static void smResponderSendNextKeyInfo( uint16 connectionHandle ); +static uint8 smResponderProcessLTKReq( uint16 connectionHandle, uint8* pRandom, uint16 encDiv ); + +/********************************************************************* + RESPONDER CALLBACKS +*/ + +// SM Responder Callbacks +static smResponderCBs_t smResponderCBs = +{ + smpResponderProcessIncoming, // Process SMP Message Callback + smResponderSendNextKeyInfo, // Send Next Key Message Callback + smResponderProcessLTKReq // HCI BLE LTK Request Callback +}; + +/********************************************************************* + API FUNCTIONS +*/ + +/********************************************************************* + FUNCTIONS - SLAVE API - Only use these in a slave device +*/ + +/********************************************************************* + Initialize SM Responder on a slave device. + + Public function defined in sm.h. +*/ +bStatus_t SM_ResponderInit( void ) +{ + if ( gapProfileRole & GAP_PROFILE_PERIPHERAL ) + { + // Set up Responder's processing function + smRegisterResponder( &smResponderCBs ); + } + else + { + smRegisterResponder( NULL ); + } + + return ( SUCCESS ); +} + +/********************************************************************* + @fn smResponderProcessLTKReq + + @brief Process the HCI BLE LTK Request Event on Responder. + + @param connectionHandle - link ID + @param pRandom - 8 byte random number + @param encDiv - encryption diversifier + + @return TRUE - We are always expecting this message +*/ +static uint8 smResponderProcessLTKReq( uint16 connectionHandle, uint8* pRandom, uint16 encDiv ) +{ + uint16 connHandle = 0; // Found connection handle + uint8 cmdLtk[KEYLEN]; // Place to hold the LTK or STK + bStatus_t stat = FAILURE; // Assume failure until verified + // Clear the LTK + VOID osal_memset( cmdLtk, 0, KEYLEN ); + + // Check the parameters + if ( (pPairingParams[connectionHandle]) + && (pPairingParams[connectionHandle]->connectionHandle == connectionHandle) + && (pPairingParams[connectionHandle]->initiator == FALSE) ) + { + // Do we want the STK? + if ( pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_STK ) + { + uint8 ltk[KEYLEN]; // A place to build the LTK + + // Received Responder, generate STK + if ( sm_s1( pPairingParams[connectionHandle]->tk, pPairingParams[connectionHandle]->myComp.rand, + pPairingParams[connectionHandle]->devComp.rand, ltk ) == SUCCESS ) + { + // Copy the STK to the LTK space + VOID osal_memcpy( cmdLtk, ltk, smDetermineKeySize( connectionHandle) ); + connHandle = connectionHandle; + stat = SUCCESS; + } + } + // How about the LTK? + else if ( (pPairingParams[connectionHandle]->pEncParams) + && (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_ENCRYPT) ) + { + // Check DIV and Rand first + if ( (encDiv == pPairingParams[connectionHandle]->pEncParams->div) + && (osal_memcmp( pRandom, pPairingParams[connectionHandle]->pEncParams->rand, B_RANDOM_NUM_SIZE ) == TRUE) ) + { + // Must be the LTK encryption + VOID osal_memcpy( cmdLtk, pPairingParams[connectionHandle]->pEncParams->ltk, smDetermineKeySize(connectionHandle) ); + connHandle = connectionHandle; + stat = SUCCESS; + } + else + { + // Rejected, end bonding + smEndPairing( connectionHandle, bleGAPBondRejected ); + } + } + else + { + // Not expecting but, if it's available - load the key + if ( (pPairingParams[connectionHandle]->pEncParams) + && (encDiv == pPairingParams[connectionHandle]->pEncParams->div) + && (osal_memcmp( pRandom, pPairingParams[connectionHandle]->pEncParams->rand, B_RANDOM_NUM_SIZE ) == TRUE) ) + { + VOID osal_memcpy( cmdLtk, pPairingParams[connectionHandle]->pEncParams->ltk, pPairingParams[connectionHandle]->pEncParams->keySize ); + connHandle = connectionHandle; + stat = SUCCESS; + } + } + } + + // Not directly handled, but make best attempt to load the key + if ( stat != SUCCESS ) + { + linkDBItem_t* pLinkItem; // connection information + // Find the connection + pLinkItem = linkDB_Find( connectionHandle ); + + if ( pLinkItem && (pLinkItem->pEncParams) + && (encDiv == pLinkItem->pEncParams->div) + && (osal_memcmp( pRandom, pLinkItem->pEncParams->rand, B_RANDOM_NUM_SIZE ) == TRUE) ) + { + // Use the key in the connection information + VOID osal_memcpy( cmdLtk, pLinkItem->pEncParams->ltk, pLinkItem->pEncParams->keySize ); + connHandle = connectionHandle; + stat = SUCCESS; + } + } + + if ( stat == SUCCESS ) + { + HCI_LE_LtkReqReplyCmd( connHandle, cmdLtk ); + } + else + { + HCI_LE_LtkReqNegReplyCmd( connectionHandle ); + } + + return ( TRUE ); // We are always expecting this message +} + +/********************************************************************* + @fn smpResponderProcessIncoming + + @brief Process incoming parsed SM Responder message. + + @param pLinkItem - connection information + @param cmdID - command ID + @param pParsedMsg - pointer to parsed message + + @return SUCCESS + SMP_PAIRING_FAILED_PASSKEY_ENTRY_FAILED + SMP_PAIRING_FAILED_OOB_NOT_AVAIL + SMP_PAIRING_FAILED_AUTH_REQ + SMP_PAIRING_FAILED_CONFIRM_VALUE + SMP_PAIRING_FAILED_NOT_SUPPORTED + SMP_PAIRING_FAILED_ENC_KEY_SIZE + SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED + SMP_PAIRING_FAILED_UNSPECIFIED + SMP_PAIRING_FAILED_REPEATED_ATTEMPTS +*/ +static uint8 smpResponderProcessIncoming( linkDBItem_t* pLinkItem, uint8 cmdID, smpMsgs_t* pParsedMsg ) +{ + uint8 reason = SUCCESS; // return value + + // check for pairing mode + if ( pPairingParams[pLinkItem->connectionHandle] == NULL ) + { + if ( cmdID == SMP_PAIRING_REQ ) + { + smpPairingReq_t* pairingReq = (smpPairingReq_t*)pParsedMsg; + // Notify the app + gapSendPairingReqEvent( SUCCESS, pLinkItem->connectionHandle, + pairingReq->ioCapability, + pairingReq->oobDataFlag, + smAuthReqToUint8( &(pairingReq->authReq) ), + pairingReq->maxEncKeySize, + pairingReq->keyDist ); + return ( SUCCESS ); + } + else + { + // Ignore the message, don't respond + return ( SUCCESS ); + } + } + + // We can only handle one pairing at a time + if ( pPairingParams[pLinkItem->connectionHandle]->connectionHandle != pLinkItem->connectionHandle ) + { + return ( SMP_PAIRING_FAILED_UNSPECIFIED ); + } + + if ( pPairingParams[pLinkItem->connectionHandle]->initiator == TRUE ) + { + return ( SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED ); + } + + // Process the pairing messages + switch ( cmdID ) + { + case SMP_PAIRING_REQ: + reason = smpResponderProcessPairingReq( pLinkItem->connectionHandle,(smpPairingReq_t*)pParsedMsg ); + break; + + case SMP_PAIRING_CONFIRM: + reason = smpResponderProcessPairingConfirm( pLinkItem->connectionHandle,(smpPairingConfirm_t*)pParsedMsg ); + break; + + case SMP_PAIRING_RANDOM: + reason = smpResponderProcessPairingRandom( pLinkItem->connectionHandle,(smpPairingRandom_t*)pParsedMsg ); + break; + + case SMP_ENCRYPTION_INFORMATION: + reason = smpResponderProcessEncryptionInformation( pLinkItem->connectionHandle,(smpEncInfo_t*)pParsedMsg ); + break; + + case SMP_MASTER_IDENTIFICATION: + reason = smpResponderProcessMasterID( pLinkItem->connectionHandle,(smpMasterID_t*)pParsedMsg ); + break; + + case SMP_IDENTITY_INFORMATION: + reason = smpResponderProcessIdentityInfo( pLinkItem->connectionHandle,(smpIdentityInfo_t*)pParsedMsg ); + break; + + case SMP_IDENTITY_ADDR_INFORMATION: + reason = smpResponderProcessIdentityAddrInfo( pLinkItem->connectionHandle,(smpIdentityAddrInfo_t*)pParsedMsg ); + break; + + case SMP_SIGNING_INFORMATION: + reason = smpResponderProcessSigningInfo( pLinkItem->connectionHandle,(smpSigningInfo_t*)pParsedMsg ); + break; + + case SMP_PAIRING_FAILED: + smEndPairing( pLinkItem->connectionHandle,pParsedMsg->pairingFailed.reason ); + break; + + default: + reason = SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED; + break; + } + + return ( reason ); +} + +/********************************************************************* + @fn smpResponderProcessPairingReq + + @brief Process incoming parsed Pairing Request. + + @param pParsedMsg - pointer to parsed message + + @return SUCCESS + SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED + SMP_PAIRING_FAILED_UNSPECIFIED + SMP_PAIRING_FAILED_AUTH_REQ +*/ +uint8 smpResponderProcessPairingReq( uint16 connectionHandle,smpPairingReq_t* pParsedMsg ) +{ + uint8 reason = SUCCESS; // return value + bStatus_t stat; // status field + // Save the pairing request information into pPairingParams[connectionHandle] + stat = smSavePairInfo( connectionHandle,pParsedMsg ); + + if ( stat == SUCCESS ) + { + // Send the response + smGeneratePairingReqRsp(connectionHandle); + + // Check if both sides have bonding + if ( (pPairingParams[connectionHandle]->pSecReqs->authReq & SM_AUTH_STATE_BONDING) + && (pPairingParams[connectionHandle]->pPairDev->authReq.bonding == SM_AUTH_REQ_BONDING) ) + { + pPairingParams[connectionHandle]->authState |= SM_AUTH_STATE_BONDING; + } + + // Do we need a passkey? + if ( (pPairingParams[connectionHandle]->type == SM_PAIRING_TYPE_PASSKEY_INITIATOR_INPUTS) + || (pPairingParams[connectionHandle]->type == SM_PAIRING_TYPE_PASSKEY_RESPONDER_INPUTS) + || (pPairingParams[connectionHandle]->type == SM_PAIRING_TYPE_PASSKEY_BOTH_INPUTS) ) + { + uint8 type; + + // Determine the passkey input/output requirements + if ( pPairingParams[connectionHandle]->type == SM_PAIRING_TYPE_PASSKEY_INITIATOR_INPUTS ) + { + type = SM_PASSKEY_TYPE_DISPLAY; + } + else + { + type = SM_PASSKEY_TYPE_INPUT; + } + + // Ask the app/profile for passkey + gapPasskeyNeededCB( pPairingParams[connectionHandle]->connectionHandle, type ); + pPairingParams[connectionHandle]->authState |= SM_AUTH_STATE_AUTHENTICATED; + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_CONFIRM_PASSKEY; + } + else if ( (pPairingParams[connectionHandle]->type == SM_PAIRING_TYPE_JUST_WORKS) + || (pPairingParams[connectionHandle]->type == SM_PAIRING_TYPE_OOB) ) + { + // Get ready for the Confirm + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_CONFIRM; + + // Setup TK + if ( pPairingParams[connectionHandle]->type == SM_PAIRING_TYPE_JUST_WORKS ) + { + // Just Wait + VOID osal_memset( pPairingParams[connectionHandle]->tk, 0, KEYLEN ); + } + else + { + // OOB + VOID osal_memcpy( pPairingParams[connectionHandle]->tk, pPairingParams[connectionHandle]->pSecReqs->oob, KEYLEN ); + pPairingParams[connectionHandle]->authState |= SM_AUTH_STATE_AUTHENTICATED; + } + + // Generate Rand (SRand) + smGenerateRandBuf( pPairingParams[connectionHandle]->myComp.rand, SMP_RANDOM_LEN ); + } + } + else if ( stat == bleInvalidRange ) + { + reason = SMP_PAIRING_FAILED_AUTH_REQ; + } + else + { + reason = SMP_PAIRING_FAILED_UNSPECIFIED; + } + + return ( reason ); +} + +/********************************************************************* + @fn smpResponderProcessPairingConfirm + + @brief Process incoming parsed Pairing Confirm. + + @param pParsedMsg - pointer to parsed message + + @return SUCCESS + SMP_PAIRING_FAILED_UNSPECIFIED +*/ +static uint8 smpResponderProcessPairingConfirm( uint16 connectionHandle,smpPairingConfirm_t* pParsedMsg ) +{ + uint8 reason = SUCCESS; // return value + VOID osal_memcpy( pPairingParams[connectionHandle]->devComp.confirm, pParsedMsg->confirmValue, KEYLEN ); + + // Received Initiator Confirm + if ( pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_CONFIRM_PASSKEY ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_PASSKEY; + } + else + { + // Generate Confirm (MConfirm) + sm_c1(connectionHandle, pPairingParams[connectionHandle]->tk, + pPairingParams[connectionHandle]->myComp.rand, + pPairingParams[connectionHandle]->myComp.confirm ); + #if defined ( TESTMODES ) + + if ( GAP_GetParamValue( TGAP_SM_TESTCODE ) == SM_TESTMODE_SEND_BAD_CONFIRM ) + { + VOID osal_memset( pPairingParams[connectionHandle]->myComp.confirm, 0, KEYLEN ); + } + + #endif // TESTMODE + + // Send our own confirm + if ( smGenerateConfirm( connectionHandle) != SUCCESS ) + { + reason = SMP_PAIRING_FAILED_UNSPECIFIED; + } + + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_RANDOM; + } + + return ( reason ); +} + +/********************************************************************* + @fn smpResponderProcessPairingRandom + + @brief Process incoming parsed Pairing Random. + + @param parsedMsg - pointer to parsed message + + @return SUCCESS + SMP_PAIRING_FAILED_CONFIRM_VALUE + SMP_PAIRING_FAILED_UNSPECIFIED +*/ +static uint8 smpResponderProcessPairingRandom( uint16 connectionHandle,smpPairingRandom_t* pParsedMsg ) +{ + uint8 reason = SUCCESS; // return value + uint8 confirm[KEYLEN]; // working area to calculate a confirm value + VOID osal_memcpy( pPairingParams[connectionHandle]->devComp.rand, pParsedMsg->randomValue, SMP_RANDOM_LEN ); + // Check device's Confirm value + sm_c1( connectionHandle,pPairingParams[connectionHandle]->tk, + pPairingParams[connectionHandle]->devComp.rand, + confirm ); + + // Make sure that the calculated confirm matches the confirm from the other device + if ( osal_memcmp( confirm, pPairingParams[connectionHandle]->devComp.confirm, KEYLEN ) == TRUE ) + { + // Received Initiator's Random, so send our own Random + if ( smGenerateRandMsg( connectionHandle) != SUCCESS ) + { + reason = SMP_PAIRING_FAILED_UNSPECIFIED; + } + else + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_STK; + } + } + else + { + reason = SMP_PAIRING_FAILED_CONFIRM_VALUE; + } + + return ( reason ); +} + +/********************************************************************* + @fn smpResponderProcessEncryptionInformation + + @brief Process incoming parsed Encryption Information. + + @param pParsedMsg - pointer to parsed message + + @return SUCCESS + SMP_PAIRING_FAILED_UNSPECIFIED +*/ +static uint8 smpResponderProcessEncryptionInformation( uint16 connectionHandle,smpEncInfo_t* pParsedMsg ) +{ + if ( pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_MASTER_ENCRYPTION_INFO ) + { + // Save off the connected device's encryption information (LTK and key size) + if ( pPairingParams[connectionHandle]->pDevEncParams == NULL ) + { + pPairingParams[connectionHandle]->pDevEncParams = (smSecurityInfo_t*)osal_mem_alloc( (uint16)sizeof (smSecurityInfo_t ) ); + } + + if ( pPairingParams[connectionHandle]->pDevEncParams ) + { + VOID osal_memcpy( pPairingParams[connectionHandle]->pDevEncParams->ltk, pParsedMsg->ltk, KEYLEN ); + pPairingParams[connectionHandle]->pDevEncParams->keySize = smDetermineKeySize(connectionHandle); + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_MASTER_INFO; + return ( SUCCESS ); + } + } + + return ( SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED ); +} + +/********************************************************************* + @fn smpResponderProcessMasterID + + @brief Process incoming parsed Master Identification. + + @param parsedMsg - pointer to parsed message + + @return SUCCESS + SMP_PAIRING_FAILED_UNSPECIFIED +*/ +static uint8 smpResponderProcessMasterID( uint16 connectionHandle,smpMasterID_t* pParsedMsg ) +{ + if ( (pPairingParams[connectionHandle]->pDevEncParams != NULL) + && (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_MASTER_MASTER_INFO) ) + { + // Save off the rest of the connected device's encryption information + pPairingParams[connectionHandle]->pDevEncParams->div = pParsedMsg->ediv; + VOID osal_memcpy( pPairingParams[connectionHandle]->pDevEncParams->rand, pParsedMsg->rand, B_RANDOM_NUM_SIZE ); + + // Setup the next state + if ( (pPairingParams[connectionHandle]->pSecReqs->keyDist.mIdKey) && (pPairingParams[connectionHandle]->pPairDev->keyDist.mIdKey) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_INFO; + } + else if ( (pPairingParams[connectionHandle]->pSecReqs->keyDist.mSign) && (pPairingParams[connectionHandle]->pPairDev->keyDist.mSign) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_SIGNING_INFO; + } + else + { + // Exit pairing + smEndPairing( connectionHandle,SUCCESS ); + } + + return ( SUCCESS ); + } + else + { + return ( SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED ); + } +} + +/********************************************************************* + @fn smpResponderProcessIdentityInfo + + @brief Process incoming parsed Identity Information. + + @param parsedMsg - pointer to parsed message + + @return SUCCESS + SMP_PAIRING_FAILED_UNSPECIFIED +*/ +static uint8 smpResponderProcessIdentityInfo( uint16 connectionHandle,smpIdentityInfo_t* pParsedMsg ) +{ + if ( pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_INFO ) + { + // Save off the info + if ( pPairingParams[connectionHandle]->pIdInfo == NULL ) + { + pPairingParams[connectionHandle]->pIdInfo = (smIdentityInfo_t*)osal_mem_alloc( (uint16)sizeof (smIdentityInfo_t ) ); + } + + if ( pPairingParams[connectionHandle]->pIdInfo ) + { + VOID osal_memcpy( pPairingParams[connectionHandle]->pIdInfo->irk, pParsedMsg->irk, KEYLEN ); + } + + // Determine next state + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_ADDR_INFO; + return ( SUCCESS ); + } + else + { + return ( SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED ); + } +} + +/********************************************************************* + @fn smpResponderProcessIdentityAddrInfo + + @brief Process incoming parsed Identity Address Information. + + @param pParsedMsg - pointer to parsed message + + @return SUCCESS + SMP_PAIRING_FAILED_UNSPECIFIED +*/ +static uint8 smpResponderProcessIdentityAddrInfo( uint16 connectionHandle,smpIdentityAddrInfo_t* pParsedMsg ) +{ + if ( pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_ADDR_INFO ) + { + VOID osal_memcpy( pPairingParams[connectionHandle]->pIdInfo->bd_addr, pParsedMsg->bdAddr, B_ADDR_LEN ); + + if ( (pPairingParams[connectionHandle]->pSecReqs->keyDist.mSign) && (pPairingParams[connectionHandle]->pPairDev->keyDist.mSign) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_SIGNING_INFO; + } + else + { + // All done + smEndPairing( connectionHandle,SUCCESS ); + } + + return ( SUCCESS ); + } + else + { + return ( SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED ); + } +} + +/********************************************************************* + @fn smpResponderProcessSigningInfo + + @brief Process incoming parsed Signing Information. + + @param parsedMsg - pointer to parsed message + + @return SUCCESS + SMP_PAIRING_FAILED_UNSPECIFIED +*/ +static uint8 smpResponderProcessSigningInfo( uint16 connectionHandle,smpSigningInfo_t* pParsedMsg ) +{ + if ( pPairingParams[connectionHandle] ) + { + if ( pPairingParams[connectionHandle]->pSigningInfo == NULL ) + { + pPairingParams[connectionHandle]->pSigningInfo = (smSigningInfo_t*)osal_mem_alloc( (uint16)sizeof( smSigningInfo_t ) ); + + if ( pPairingParams[connectionHandle]->pSigningInfo == NULL ) + { + // Only error available for memory error, this will end the pairing process + return ( SMP_PAIRING_FAILED_UNSPECIFIED ); + } + } + + // Copy signature information + if ( pPairingParams[connectionHandle]->pSigningInfo ) + { + VOID osal_memcpy( pPairingParams[connectionHandle]->pSigningInfo->srk, pParsedMsg->signature, KEYLEN ); + pPairingParams[connectionHandle]->pSigningInfo->signCounter = GAP_INIT_SIGN_COUNTER; + } + + // All done + smEndPairing( connectionHandle,SUCCESS ); + return ( SUCCESS ); + } + else + { + return ( SMP_PAIRING_FAILED_CMD_NOT_SUPPORTED ); + } +} + +/********************************************************************* + @fn smResponderSendNextKeyInfo + + @brief Responder role: sends next key message, and sets state + for next event. + + @param none + + @return none +*/ +static void smResponderSendNextKeyInfo( uint16 connectionHandle ) +{ + if ( pPairingParams[connectionHandle]->initiator == FALSE ) + { + smLinkSecurityReq_t* pSecReq = pPairingParams[connectionHandle]->pSecReqs; + smpPairingReq_t* pPairReq = pPairingParams[connectionHandle]->pPairDev; + uint8 state = pPairingParams[connectionHandle]->state; + + // Determine key to send + if ( state == SM_PAIRING_STATE_WAIT_STK ) + { + if ( (pSecReq->keyDist.sEncKey) && (pPairReq->keyDist.sEncKey) ) + { + state = SM_PAIRING_STATE_WAIT_SLAVE_ENCRYPTION_INFO; + } + else if ( (pSecReq->keyDist.sIdKey) && (pPairReq->keyDist.sIdKey) ) + { + state = SM_PAIRING_STATE_WAIT_SLAVE_IDENTITY_INFO; + } + else if ( (pSecReq->keyDist.sSign) && (pPairReq->keyDist.sSign) ) + { + state = SM_PAIRING_STATE_WAIT_SLAVE_SIGNING_INFO; + } + } + + // Send the correct message + switch ( state ) + { + case SM_PAIRING_STATE_WAIT_SLAVE_ENCRYPTION_INFO: + + // STK is setup, so send Encryption Information. + if ( pPairingParams[connectionHandle]->pEncParams == NULL ) + { + pPairingParams[connectionHandle]->pEncParams = (smSecurityInfo_t*)osal_mem_alloc( (uint16)sizeof (smSecurityInfo_t ) ); + } + + if ( pPairingParams[connectionHandle]->pEncParams ) + { + smSecurityInfo_t* pEnc = pPairingParams[connectionHandle]->pEncParams; + // For now, temp random the LTK, EDIV and RAND + VOID osal_memset( pEnc->ltk, 0, KEYLEN ); + smGenerateRandBuf( pEnc->ltk, smDetermineKeySize(connectionHandle) ); + pEnc->div = osal_rand(); + smGenerateRandBuf( pEnc->rand, B_RANDOM_NUM_SIZE ); + pEnc->keySize = smDetermineKeySize(connectionHandle); + // Send the Encryption Info + smPairingSendEncInfo( pPairingParams[connectionHandle]->connectionHandle, pEnc->ltk ); + } + + break; + + case SM_PAIRING_STATE_WAIT_SLAVE_MASTER_INFO: + if ( pPairingParams[connectionHandle]->pEncParams ) + { + smPairingSendMasterID( pPairingParams[connectionHandle]->connectionHandle, + pPairingParams[connectionHandle]->pEncParams->div, + pPairingParams[connectionHandle]->pEncParams->rand ); + } + + break; + + case SM_PAIRING_STATE_WAIT_SLAVE_IDENTITY_INFO: + smPairingSendIdentityInfo( pPairingParams[connectionHandle]->connectionHandle, gapGetIRK() ); + break; + + case SM_PAIRING_STATE_WAIT_SLAVE_IDENTITY_ADDR_INFO: + { + uint8 getRealAddr = TRUE; + uint8 addrType = gapGetDevAddressMode(); + + if ( addrType == ADDRTYPE_STATIC ) + { + getRealAddr = FALSE; + } + else + { + addrType = ADDRTYPE_PUBLIC; + } + + smPairingSendIdentityAddrInfo( pPairingParams[connectionHandle]->connectionHandle, + addrType, gapGetDevAddress( getRealAddr ) ); + } + break; + + case SM_PAIRING_STATE_WAIT_SLAVE_SIGNING_INFO: + smPairingSendSingingInfo( pPairingParams[connectionHandle]->connectionHandle, gapGetSRK() ); + break; + + default: + break; + } + + // Determine the state + if ( state == SM_PAIRING_STATE_WAIT_SLAVE_ENCRYPTION_INFO ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_SLAVE_MASTER_INFO; + } + else if ( state == SM_PAIRING_STATE_WAIT_SLAVE_MASTER_INFO ) + { + if ( (pSecReq->keyDist.sIdKey) && (pPairReq->keyDist.sIdKey) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_SLAVE_IDENTITY_INFO; + } + else if ( (pSecReq->keyDist.sSign) && (pPairReq->keyDist.sSign) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_SLAVE_SIGNING_INFO; + } + else if ( (pSecReq->keyDist.mEncKey) && (pPairReq->keyDist.mEncKey) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_ENCRYPTION_INFO; + } + else if ( (pSecReq->keyDist.mIdKey) && (pPairReq->keyDist.mIdKey) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_INFO; + } + else if ( (pSecReq->keyDist.mSign) && (pPairReq->keyDist.mSign) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_SIGNING_INFO; + } + else + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_DONE; + } + } + else if ( state == SM_PAIRING_STATE_WAIT_SLAVE_IDENTITY_INFO ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_SLAVE_IDENTITY_ADDR_INFO; + } + else if ( state == SM_PAIRING_STATE_WAIT_SLAVE_IDENTITY_ADDR_INFO ) + { + if ( (pSecReq->keyDist.sSign) && (pPairReq->keyDist.sSign) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_SLAVE_SIGNING_INFO; + } + else if ( (pSecReq->keyDist.mEncKey) && (pPairReq->keyDist.mEncKey) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_ENCRYPTION_INFO; + } + else if ( (pSecReq->keyDist.mIdKey) && (pPairReq->keyDist.mIdKey) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_INFO; + } + else if ( (pSecReq->keyDist.mSign) && (pPairReq->keyDist.mSign) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_SIGNING_INFO; + } + else + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_DONE; + } + } + else + { + if ( (pSecReq->keyDist.mEncKey) && (pPairReq->keyDist.mEncKey) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_ENCRYPTION_INFO; + } + else if ( (pSecReq->keyDist.mIdKey) && (pPairReq->keyDist.mIdKey) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_IDENTITY_INFO; + } + else if ( (pSecReq->keyDist.mSign) && (pPairReq->keyDist.mSign) ) + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_WAIT_MASTER_SIGNING_INFO; + } + else + { + pPairingParams[connectionHandle]->state = SM_PAIRING_STATE_DONE; + } + } + + if ( (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_SLAVE_ENCRYPTION_INFO) + || (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_SLAVE_MASTER_INFO) + || (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_SLAVE_IDENTITY_INFO) + || (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_SLAVE_IDENTITY_ADDR_INFO) + || (pPairingParams[connectionHandle]->state == SM_PAIRING_STATE_WAIT_SLAVE_SIGNING_INFO) ) + { + linkDBItem_t* pLinkItem; + uint32 timeout; + pLinkItem = linkDB_Find( pPairingParams[connectionHandle]->connectionHandle ); + + if ( pLinkItem != NULL ) + { + // Make the timeout 1.5 * connInterval (connInterval = 1.25 ms) + timeout = pLinkItem->connInterval; + timeout += pLinkItem->connInterval / 2; + } + else + { + timeout = SM_PAIRING_STATE_WAIT; + } + + // Set up the next send +// VOID osal_start_timerEx( smTaskID, SM_PAIRING_STATE_EVT, timeout ); + smState_CBTimer[connectionHandle] = connectionHandle; + osal_CbTimerStart( smState_timerCB, &smState_CBTimer[connectionHandle], + timeout, &pPairingParams[connectionHandle]->stateID ); + } + } +} + + + +/********************************************************************* +*********************************************************************/ diff --git a/src/lib/ble_host/sm_task.c b/src/lib/ble_host/sm_task.c new file mode 100644 index 0000000..c9816a4 --- /dev/null +++ b/src/lib/ble_host/sm_task.c @@ -0,0 +1,330 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: sm_task.c + Revised: + Revision: + + Description: This file contains the SM Task. + + +**************************************************************************************************/ + +#include "bcomdef.h" +#include "hci_tl.h" +#include "osal_bufmgr.h" +#include "gap_internal.h" +#include "linkdb.h" +#include "l2cap.h" +#include "sm.h" +#include "sm_internal.h" +#include "smp.h" +#include "jump_function.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ +uint8 smTaskID; // SM task ID + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +/********************************************************************* + LOCAL FUNCTIONS +*/ +static uint8 smProcessOSALMsg( osal_event_hdr_t* pMsg ); +static uint8 smProcessHCICmdCompleteEvt( hciEvt_CmdComplete_t* pMsg ); +static uint8 smProcessHCIBLEEventCode( hciEvt_CmdComplete_t* pMsg ); + +/********************************************************************* + API FUNCTIONS +*/ + +/********************************************************************* + @fn SM_Init0 + + @brief SM Task initialization function. + + @param taskID - SM task ID. + + @return void +*/ +void SM_Init( uint8 task_id ) +{ + smTaskID = task_id; + // Register to receive all security related HCI events + HCI_SMPTaskRegister( smTaskID ); + // Register with L2CAP SMP channel + VOID L2CAP_RegisterApp( smTaskID, L2CAP_CID_SMP ); + // link database callback + VOID linkDB_Register( smLinkCheck ); +} + +/********************************************************************* + @fn SM_ProcessEvent0 + + @brief SM Task event processing function. + + @param taskID - SM task ID. + @param events - SM events. + + @return events not processed +*/ +uint16 SM_ProcessEvent( uint8 task_id, uint16 events ) +{ + if ( events & SYS_EVENT_MSG ) + { + uint8* pMsg; // pointer to incoming message + + // Process incoming OSAL SM messages + if ( (pMsg = osal_msg_receive( smTaskID )) != NULL ) + { + uint8 dealloc = TRUE; + + if ( !smProcessOSALMsg( (osal_event_hdr_t*)pMsg ) ) + { + // The message wasn't processed by SM + if ( gapUnwantedTaskID != INVALID_TASK_ID ) + { + // send it to the registered application to process + if ( osal_msg_send( gapUnwantedTaskID, pMsg ) == SUCCESS ) + { + dealloc = FALSE; + } + } + } + + if ( dealloc ) + { + // Release the OSAL message + VOID osal_msg_deallocate( pMsg ); + } + } + + // return unprocessed events + return (events ^ SYS_EVENT_MSG); + } + +// if ( events & SM_TIMEOUT_EVT ) +// { +// // Pairing Timeout +// +//// smTimedOut(); +// +// return ( events ^ SM_TIMEOUT_EVT ); +// } +// +// if ( events & SM_PAIRING_STATE_EVT ) +// { +// // Trigger the next Pairing State +// +// +// return ( events ^ SM_PAIRING_STATE_EVT ); +// } + // If reach here, the events are unknown + // Discard or make more handlers + return 0; +} + +/********************************************************************* + @fn smProcessOSALMsg + + @brief Process an incoming task message. + + @param pMsg - message to process + + @return TRUE if processed and safe to deallocate, FALSE if passed + off to another task. +*/ +static uint8 smProcessOSALMsg( osal_event_hdr_t* pMsg ) +{ + uint8 safeToDealloc = TRUE; // Assume that we are expecting the message + + switch ( pMsg->event ) + { + case HCI_SMP_EVENT_EVENT: + { + switch( pMsg->status ) + { + case HCI_COMMAND_COMPLETE_EVENT_CODE: + safeToDealloc = smProcessHCICmdCompleteEvt( (hciEvt_CmdComplete_t*)pMsg ); + break; + + case HCI_LE_EVENT_CODE: + safeToDealloc = smProcessHCIBLEEventCode( (hciEvt_CmdComplete_t*)pMsg ); + break; + + default: + safeToDealloc = FALSE; + break; + } + } + break; + + case L2CAP_DATA_EVENT: + { + l2capDataEvent_t* pPkt = (l2capDataEvent_t*)pMsg; + smProcessDataMsg( pPkt ); + + // Free the buffer - payload + if ( pPkt->pkt.pPayload ) + { + osal_bm_free( pPkt->pkt.pPayload ); + } + } + break; + + default: + safeToDealloc = FALSE; + break; + } + + return ( safeToDealloc ); +} + +/********************************************************************* + @fn smProcessHCICmdCompleteEvt + + @brief Process an incoming OSAL HCI Command Complete Event. + + @param pMsg - message to process + + @return TRUE if processed and safe to deallocate, FALSE if passed + off to another task. +*/ +static uint8 smProcessHCICmdCompleteEvt( hciEvt_CmdComplete_t* pMsg ) +{ + uint8 safeToDealloc; // return value + + switch ( pMsg->cmdOpcode ) + { + case HCI_LE_RAND: + safeToDealloc = smProcessRandComplete( pMsg->pReturnParam[0], &(pMsg->pReturnParam[1]) ); + break; + + default: + safeToDealloc = FALSE; // send this message to the app + break; + } + + return ( safeToDealloc ); +} + +/********************************************************************* + @fn smProcessHCIBLEEventCode + + @brief Process an incoming OSAL HCI BLE Events. + + @param pMsg - message to process + + @return TRUE if processed and safe to deallocate, FALSE if passed + off to another task. +*/ +static uint8 smProcessHCIBLEEventCode( hciEvt_CmdComplete_t* pMsg ) +{ + uint8 safeToDealloc = TRUE; // Assume that the message will be processed by SM + uint8 eventCode = ((hciEvt_BLELTKReq_t*)pMsg)->BLEEventCode; + + switch ( eventCode ) + { + case HCI_BLE_LTK_REQUESTED_EVENT: + + // Are we the responder? + if ( gapProfileRole & GAP_PROFILE_PERIPHERAL ) + { + if ( pfnResponderCBs && pfnResponderCBs->pfnProcessLTKReq ) + { + hciEvt_BLELTKReq_t* pPkt = (hciEvt_BLELTKReq_t*)pMsg; + safeToDealloc = pfnResponderCBs->pfnProcessLTKReq( pPkt->connHandle, + pPkt->random, + pPkt->encryptedDiversifier ); + } + } + + break; + + case HCI_ENCRYPTION_CHANGE_EVENT_CODE: + { + uint8 reason; // Reason field + uint16 connHandle; // Connection handle + hciEvt_EncryptChange_t* pPkt = (hciEvt_EncryptChange_t*)pMsg; + connHandle = pPkt->connHandle; + reason = pPkt->reason; + // pkt->encEnable isn't needed, if pkt->reason == SUCCESS or LL_ENC_KEY_REQ_ACCEPTED + // then the link is encrypted, otherwise it isn't. + safeToDealloc = smProcessEncryptChange( connHandle, reason ); + } + break; + + default: + safeToDealloc = FALSE; // send this message to the app + break; + } + + return ( safeToDealloc ); +} + +void smTo_timerCB( uint8* pData ) +{ + uint16 connHandle = (uint16 )pData[0]; + smTimedOut( connHandle ); +} + +void smState_timerCB( uint8* pData ) +{ + uint16 connHandle = (uint16 )pData[0]; + smNextPairingState( connHandle ); +} + + diff --git a/src/lib/ble_host/smp.c b/src/lib/ble_host/smp.c new file mode 100644 index 0000000..c79b751 --- /dev/null +++ b/src/lib/ble_host/smp.c @@ -0,0 +1,720 @@ +/************************************************************************************************** + + Phyplus Microelectronics Limited confidential and proprietary. + All rights reserved. + + IMPORTANT: All rights of this software belong to Phyplus Microelectronics + Limited ("Phyplus"). Your use of this Software is limited to those + specific rights granted under the terms of the business contract, the + confidential agreement, the non-disclosure agreement and any other forms + of agreements as a customer or a partner of Phyplus. You may not use this + Software unless you agree to abide by the terms of these agreements. + You acknowledge that the Software may not be modified, copied, + distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy + (BLE) integrated circuit, either as a product or is integrated into your + products. Other than for the aforementioned purposes, you may not use, + reproduce, copy, prepare derivative works of, modify, distribute, perform, + display or sell this Software and/or its documentation for any purposes. + + YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT, + NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER + LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES + INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE + OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT + OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES + (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +**************************************************************************************************/ + +/************************************************************************************************* + Filename: smp.c + Revised: + Revision: + + Description: This file contains the Security Manager Protocol. + + +**************************************************************************************************/ + +#include "bcomdef.h" +#include "OSAL.h" +#include "osal_bufmgr.h" +#include "hci.h" +#include "l2cap.h" +#include "gap.h" +#include "sm.h" +#include "sm_internal.h" +#include "smp.h" + +/********************************************************************* + MACROS +*/ + +/********************************************************************* + CONSTANTS +*/ + +// Pairing Request & Response - Key Distribution Field - bit mask +// These are used to break up byte in to keyDist_t +#define SMP_KEYDIST_ENCKEY 0x01 +#define SMP_KEYDIST_IDKEY 0x02 +#define SMP_KEYDIST_SIGN 0x04 + +/********************************************************************* + TYPEDEFS +*/ + +/********************************************************************* + GLOBAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL VARIABLES +*/ + +/********************************************************************* + EXTERNAL FUNCTIONS +*/ + +/********************************************************************* + LOCAL VARIABLES +*/ + +/********************************************************************* + FUNCTIONS +*/ + +/********************************************************************* + @fn smpBuildPairingReq + + @brief Build an SM Pairing Request + + @param pPairingReq - pointer to structure. + @param pBuf - data buffer to build into + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or pairingReq is NULL +*/ +bStatus_t smpBuildPairingReq( smpPairingReq_t* pPairingReq, uint8* pBuf ) +{ + return ( smpBuildPairingReqRsp( SMP_PAIRING_REQ, pPairingReq, pBuf ) ); +} + +/********************************************************************* + @fn smpBuildPairingRsp + + @brief Build an SM Pairing Response + + @param pPairingRsp - pointer to structure. + @param pBuf - data buffer to build into + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or pairingRsp is NULL +*/ +bStatus_t smpBuildPairingRsp( smpPairingReq_t* pPairingRsp, uint8* pBuf ) +{ + return ( smpBuildPairingReqRsp( SMP_PAIRING_RSP, pPairingRsp, pBuf ) ); +} + +/********************************************************************* + @fn smpBuildPairingReqRsp + + @brief Build an SM Pairing Request or Response + + @param code - either SMP_PAIRING_REQ or SMP_PAIRING_RSP + @param pPairingReq - pointer to structure. + @param pBuf - data buffer to build into + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or pairingReq is NULL +*/ +bStatus_t smpBuildPairingReqRsp( uint8 opCode, smpPairingReq_t* pPairingReq, uint8* pBuf ) +{ + // Check pointers + if ( (pBuf == NULL) || (pPairingReq == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + *pBuf++ = opCode; + *pBuf++ = pPairingReq->ioCapability; + *pBuf++ = pPairingReq->oobDataFlag; + *pBuf++ = smAuthReqToUint8( &(pPairingReq->authReq) ); + *pBuf++ = pPairingReq->maxEncKeySize; + *pBuf = (pPairingReq->keyDist.mEncKey) ? (SMP_KEYDIST_ENCKEY) : 0; + *pBuf |= (pPairingReq->keyDist.mIdKey) ? (SMP_KEYDIST_IDKEY) : 0; + *pBuf |= (pPairingReq->keyDist.mSign) ? (SMP_KEYDIST_SIGN) : 0; + *pBuf |= (pPairingReq->keyDist.mReserved) << 3; // HZF: fixed bug 2018-11-27, recover reserved bits(5bits in BLE4.0) + pBuf++; + *pBuf = (pPairingReq->keyDist.sEncKey) ? (SMP_KEYDIST_ENCKEY) : 0; + *pBuf |= (pPairingReq->keyDist.sIdKey) ? (SMP_KEYDIST_IDKEY) : 0; + *pBuf |= (pPairingReq->keyDist.sSign) ? (SMP_KEYDIST_SIGN) : 0; + *pBuf |= (pPairingReq->keyDist.sReserved) << 3; // HZF: fixed bug 2018-11-27, recover reserved bits(5bits in BLE4.0) + return ( SUCCESS ); +} + +/********************************************************************* + @fn smpParsePairingReq + + @brief Parse an SM Pairing Request + + @param pBuf - data buffer to parse + @param pPairingReq - pointer to structure. + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or pairingReq is NULL + bleInvalidRange if a generic field is out of range + bleIncorrectMode if enc key is out of range +*/ +bStatus_t smpParsePairingReq( uint8* pBuf, smpPairingReq_t* pPairingReq ) +{ + uint8 tmp; + + // Check pointers + if ( (pBuf == NULL) || (pPairingReq == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + pBuf++; // Skip code + pPairingReq->ioCapability = *pBuf++; + pPairingReq->oobDataFlag = *pBuf++; + smUint8ToAuthReq( &(pPairingReq->authReq), *pBuf++ ); + pPairingReq->maxEncKeySize = *pBuf++; + tmp = *pBuf++; + pPairingReq->keyDist.mEncKey = (tmp & SMP_KEYDIST_ENCKEY) ? TRUE : FALSE; + pPairingReq->keyDist.mIdKey = (tmp & SMP_KEYDIST_IDKEY) ? TRUE : FALSE; + pPairingReq->keyDist.mSign = (tmp & SMP_KEYDIST_SIGN) ? TRUE : FALSE; + pPairingReq->keyDist.mReserved = (tmp & 0xF8)>>3; // HZF: fixed bug 2018-11-27, saved reserved bits(5bits in BLE4.0) + tmp = *pBuf; + pPairingReq->keyDist.sEncKey = (tmp & SMP_KEYDIST_ENCKEY) ? TRUE : FALSE; + pPairingReq->keyDist.sIdKey = (tmp & SMP_KEYDIST_IDKEY) ? TRUE : FALSE; + pPairingReq->keyDist.sSign = (tmp & SMP_KEYDIST_SIGN) ? TRUE : FALSE; + pPairingReq->keyDist.sReserved = (tmp & 0xF8)>>3; // HZF: fixed bug 2018-11-27, saved reserved bits(5bits in BLE4.0) + + // Check the encryption key size + if ( (pPairingReq->maxEncKeySize < GAP_GetParamValue( TGAP_SM_MIN_KEY_LEN )) + || (pPairingReq->maxEncKeySize > GAP_GetParamValue( TGAP_SM_MAX_KEY_LEN )) ) + { + return ( bleIncorrectMode ); + } + + // Check for range of fields + if ( (pPairingReq->ioCapability > SMP_IO_CAP_KEYBOARD_DISPLAY) + || (pPairingReq->oobDataFlag > SMP_OOB_AUTH_DATA_REMOTE_DEVICE_PRESENT) ) + { + return ( bleInvalidRange ); + } + else + { + return ( SUCCESS ); + } +} + +/********************************************************************* + @fn smpBuildPairingConfirm + + @brief Build an SM Pairing Confirm + + @param pPairingConfirm - pointer to structure. + @param pBuf - data buffer to build into + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or pairingConfirm is NULL +*/ +bStatus_t smpBuildPairingConfirm( smpPairingConfirm_t* pPairingConfirm, + uint8* pBuf ) +{ + // Check pointers + if ( (pBuf == NULL) || (pPairingConfirm == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + *pBuf++ = SMP_PAIRING_CONFIRM; + VOID osal_memcpy( pBuf, pPairingConfirm->confirmValue, SMP_CONFIRM_LEN ); + return ( SUCCESS ); +} + +/********************************************************************* + @fn smpParsePairingConfirm + + @brief Parse an SM Pairing Confirm + + @param pBuf - data buffer to build into + @param pPairingConfirm - pointer to structure. + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or pairingConfirm is NULL +*/ +bStatus_t smpParsePairingConfirm( uint8* pBuf, + smpPairingConfirm_t* pPairingConfirm ) +{ + // Check pointers + if ( (pBuf == NULL) || (pPairingConfirm == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + pBuf++; // Skip code + VOID osal_memcpy( pPairingConfirm->confirmValue, pBuf, SMP_CONFIRM_LEN ); + return ( SUCCESS ); +} + +/********************************************************************* + @fn smpBuildPairingRandom + + @brief Build an SM Pairing Random + + @param pPairingRandom - pointer to structure. + @param pBuf - data buffer to build into + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or pairingRandom is NULL +*/ +bStatus_t smpBuildPairingRandom( smpPairingRandom_t* pPairingRandom, + uint8* pBuf ) +{ + // Check pointers + if ( (pBuf == NULL) || (pPairingRandom == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + *pBuf++ = SMP_PAIRING_RANDOM; + VOID osal_memcpy( pBuf, pPairingRandom->randomValue, SMP_RANDOM_LEN ); + return ( SUCCESS ); +} + +/********************************************************************* + @fn smpParsePairingRandom + + @brief Parse an SM Pairing Random + + @param pBuf - data buffer to build into + @param pPairingRandom - pointer to structure. + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or pairingRandom is NULL +*/ +bStatus_t smpParsePairingRandom( uint8* pBuf, + smpPairingRandom_t* pPairingRandom ) +{ + // Check pointers + if ( (pBuf == NULL) || (pPairingRandom == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + pBuf++; // Skip code + VOID osal_memcpy( pPairingRandom->randomValue, pBuf, SMP_RANDOM_LEN ); + return ( SUCCESS ); +} + +/********************************************************************* + @fn smpBuildPairingFailed + + @brief Build an SM Pairing Failed + + @param pPairingFailed - pointer to structure. + @param pBuf - data buffer to build into + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or pairingFailed is NULL +*/ +bStatus_t smpBuildPairingFailed( smpPairingFailed_t* pPairingFailed, + uint8* pBuf ) +{ + // Check pointers + if ( (pBuf == NULL) || (pPairingFailed == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + *pBuf++ = SMP_PAIRING_FAILED; + *pBuf = pPairingFailed->reason; + return ( SUCCESS ); +} + +/********************************************************************* + @fn smpParsePairingFailed + + @brief Parse an SM Pairing Failed + + @param pBuf - data buffer to build into + @param pPairingFailed - pointer to structure. + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or pairingFailed is NULL + bleInvalidRange if the reason field is out of range +*/ +bStatus_t smpParsePairingFailed( uint8* pBuf, + smpPairingFailed_t* pPairingFailed ) +{ + // Check pointers + if ( (pBuf == NULL) || (pPairingFailed == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + pBuf++; // Skip code + pPairingFailed->reason = *pBuf; + + // Reason range check + if ( pPairingFailed->reason > SMP_PAIRING_FAILED_REPEATED_ATTEMPTS + || (pPairingFailed->reason == 0) ) + { + return ( bleInvalidRange ); + } + else + { + return ( SUCCESS ); + } +} + +/********************************************************************* + @fn smpBuildEncInfo + + @brief Build an SM Encryption Information + + @param pEncInfo - pointer to structure. + @param pBuf - data buffer to build into + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or struct ptr is NULL +*/ +bStatus_t smpBuildEncInfo( smpEncInfo_t* pEncInfo, uint8* pBuf ) +{ + // Check pointers + if ( (pBuf == NULL) || (pEncInfo == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + *pBuf++ = SMP_ENCRYPTION_INFORMATION; + VOID osal_memcpy( pBuf, pEncInfo->ltk, KEYLEN ); + return ( SUCCESS ); +} + +/********************************************************************* + @fn smpParseEncInfo + + @brief Parse an SM Encryption Information + + @param pBuf - data buffer to build into + @param pEncInfo - pointer to structure. + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or struct ptr is NULL +*/ +bStatus_t smpParseEncInfo( uint8* pBuf, smpEncInfo_t* pEncInfo ) +{ + // Check pointers + if ( (pBuf == NULL) || (pEncInfo == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + pBuf++; // Skip code + VOID osal_memcpy( pEncInfo->ltk, pBuf, KEYLEN ); + return ( SUCCESS ); +} + +/********************************************************************* + @fn smpBuildMasterID + + @brief Build an SM Master Identification + + @param pMasterID - pointer to structure. + @param pBuf - data buffer to build into + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or struct ptr is NULL +*/ +bStatus_t smpBuildMasterID( smpMasterID_t* pMasterID, uint8* pBuf ) +{ + // Check pointers + if ( (pBuf == NULL) || (pMasterID == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + *pBuf++ = SMP_MASTER_IDENTIFICATION; + *pBuf++ = LO_UINT16( pMasterID->ediv ); + *pBuf++ = HI_UINT16( pMasterID->ediv ); + VOID osal_memcpy( pBuf, pMasterID->rand, B_RANDOM_NUM_SIZE ); + return ( SUCCESS ); +} + +/********************************************************************* + @fn smpParseMasterID + + @brief Parse an SM Master Identification + + @param pBuf - data buffer to build into + @param pMasterID - pointer to structure. + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or struct ptr is NULL +*/ +bStatus_t smpParseMasterID( uint8* pBuf, smpMasterID_t* pMasterID ) +{ + // Check pointers + if ( (pBuf == NULL) || (pMasterID == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + pBuf++; // Skip code + pMasterID->ediv = BUILD_UINT16( pBuf[0], pBuf[1] ); + VOID osal_memcpy( pMasterID->rand, &pBuf[2], B_RANDOM_NUM_SIZE ); + return ( SUCCESS ); +} + +/********************************************************************* + @fn smpBuildIdentityInfo + + @brief Build an SM Identity Information + + @param pIdInfo - pointer to structure. + @param pBuf - data buffer to build into + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or struct ptr is NULL +*/ +bStatus_t smpBuildIdentityInfo( smpIdentityInfo_t* pIdInfo, uint8* pBuf ) +{ + // Check pointers + if ( (pBuf == NULL) || (pIdInfo == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + *pBuf++ = SMP_IDENTITY_INFORMATION; + VOID osal_memcpy( pBuf, pIdInfo->irk, KEYLEN ); + return ( SUCCESS ); +} + +/********************************************************************* + @fn smpBuildIdentityAddrInfo + + @brief Build an SM Identity Address Information + + @param pIdInfo - pointer to structure. + @param pBuf - data buffer to build into + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or struct ptr is NULL +*/ +bStatus_t smpBuildIdentityAddrInfo( smpIdentityAddrInfo_t* pIdInfo, uint8* pBuf ) +{ + // Check pointers + if ( (pBuf == NULL) || (pIdInfo == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + *pBuf++ = SMP_IDENTITY_ADDR_INFORMATION; + *pBuf++ = pIdInfo->addrType; + VOID osal_memcpy( pBuf, pIdInfo->bdAddr, B_ADDR_LEN ); + return ( SUCCESS ); +} + +/********************************************************************* + @fn smpParseIdentityInfo + + @brief Parse an SM Identity Information + + @param pBuf - data buffer to build into + @param pIdInfo - pointer to structure. + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or struct ptr is NULL +*/ +bStatus_t smpParseIdentityInfo( uint8* pBuf, smpIdentityInfo_t* pIdInfo ) +{ + // Check pointers + if ( (pBuf == NULL) || (pIdInfo == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + pBuf++; // Skip code + VOID osal_memcpy( pIdInfo->irk, pBuf, KEYLEN ); + return ( SUCCESS ); +} + +/********************************************************************* + @fn smpParseIdentityAddrInfo + + @brief Parse an SM Identity Address Information + + @param pBuf - data buffer to build into + @param pIdInfo - pointer to structure. + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or struct ptr is NULL +*/ +bStatus_t smpParseIdentityAddrInfo( uint8* pBuf, smpIdentityAddrInfo_t* pIdInfo ) +{ + // Check pointers + if ( (pBuf == NULL) || (pIdInfo == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + pBuf++; // Skip code + pIdInfo->addrType = *pBuf++; + VOID osal_memcpy( pIdInfo->bdAddr, pBuf, B_ADDR_LEN ); + return ( SUCCESS ); +} + +/********************************************************************* + @fn smpBuildSigningInfo + + @brief Build an SM Signing Information + + @param pSigningInfo - pointer to structure. + @param pBuf - data buffer to build into + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or struct ptr is NULL +*/ +bStatus_t smpBuildSigningInfo( smpSigningInfo_t* pSigningInfo, uint8* pBuf ) +{ + // Check pointers + if ( (pBuf == NULL) || (pSigningInfo == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + *pBuf++ = SMP_SIGNING_INFORMATION; + VOID osal_memcpy( pBuf, pSigningInfo->signature, KEYLEN ); + return ( SUCCESS ); +} + +/********************************************************************* + @fn smpParseSigningInfo + + @brief Parse an SM Signing Information + + @param pBuf - data buffer to build into + @param pSigningInfo - pointer to structure. + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or struct ptr is NULL +*/ +bStatus_t smpParseSigningInfo( uint8* pBuf, smpSigningInfo_t* pSigningInfo ) +{ + // Check pointers + if ( (pBuf == NULL) || (pSigningInfo == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + pBuf++; // Skip code + VOID osal_memcpy( pSigningInfo->signature, pBuf, KEYLEN ); + return ( SUCCESS ); +} + +/********************************************************************* + @fn smpBuildSecurityReq + + @brief Build an SM Slave Security Request + + @param pSecReq - pointer to structure. + @param pBuf - data buffer to build into + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or struct ptr is NULL +*/ +bStatus_t smpBuildSecurityReq( smpSecurityReq_t* pSecReq, uint8* pBuf ) +{ + // Check pointers + if ( (pBuf == NULL) || (pSecReq == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + *pBuf++ = SMP_SECURITY_REQUEST; + *pBuf = smAuthReqToUint8( &(pSecReq->authReq) ); + return ( SUCCESS ); +} + +/********************************************************************* + @fn smpParseSecurityReq + + @brief Parse an SM Slave Security Request + + @param pBuf - data buffer to build into + @param pSecReq - pointer to structure. + + @return SUCCESS if parsed + INVALIDPARAMETER if buf or struct ptr is NULL +*/ +bStatus_t smpParseSecurityReq( uint8* pBuf, smpSecurityReq_t* pSecReq ) +{ + // Check pointers + if ( (pBuf == NULL) || (pSecReq == NULL) ) + { + return ( INVALIDPARAMETER ); + } + + pBuf++; // Skip code + smUint8ToAuthReq( &(pSecReq->authReq), *pBuf ); + return ( SUCCESS ); +} + +/********************************************************************* + @fn smSendSMMsg + + @brief Allocate send buffer, build the SM message and send + the message to L2CAP. + + @param connHandle - Connection to send message + @param bufLen - Length of buffer needed + @param pMsg - message structure + @param buildFn - function pointer to build function + + @return status +*/ +bStatus_t smSendSMMsg( uint16 connHandle, uint8 bufLen, smpMsgs_t* pMsg, pfnSMBuildCmd_t buildFn ) +{ + bStatus_t stat; + l2capPacket_t sendData; + // Allocate a buffer + sendData.CID = L2CAP_CID_SMP; + sendData.len = bufLen; + sendData.pPayload = (uint8*)L2CAP_bm_alloc( sendData.len ); + + if ( sendData.pPayload ) + { + stat = buildFn( pMsg, sendData.pPayload ); + + if ( stat == SUCCESS ) + { + stat = L2CAP_SendData( connHandle, &sendData ); + } + + if ( stat != SUCCESS ) + { + osal_bm_free( sendData.pPayload ); + } + } + else + { + stat = bleMemAllocError; + } + + // TODO : if stat is not success , start sm tsp timer is there any problem ? + // Start the SM Timeout + smStartRspTimer(connHandle); + return ( stat ); +} + + + diff --git a/src/lib/ble_host_multi5.lib b/src/lib/ble_host_multi5.lib new file mode 100644 index 0000000000000000000000000000000000000000..990feb3dceb829e080870365ec31e9aff1812dbc GIT binary patch literal 336432 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 literal 0 HcmV?d00001 diff --git a/src/lib/phy_font.lib b/src/lib/phy_font.lib new file mode 100644 index 0000000000000000000000000000000000000000..d16639b754e92a696b633592b03868d6eb3a3efb GIT binary patch literal 7886 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 F0RWz3Ud;di literal 0 HcmV?d00001 diff --git a/src/lib/rf.lib b/src/lib/rf.lib new file mode 100644 index 0000000000000000000000000000000000000000..1958b3b8d446eeb9f1411e6675c5e898ba335616 GIT binary patch literal 117306 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 +#include + +//#include "common.h" +//#include "uart.h" +//#include "dma.h" +//#include "flash.h" +//#include "gpio_rom.h" +//#include "i2c.h" +//#include "i2s.h" +//#include "spi.h" +//#include "timer.h" + +#include "ll.h" +#include "rf_phy_driver.h" +#include "global_config.h" +#include "jump_function.h" +#include "uart.h" +#include "ll_sleep.h" +#include "ll_debug.h" +#include "ll.h" +#include "bus_dev.h" +#include "ll_hw_drv.h" +#include "gpio.h" +#include "ll_enc.h" +#include "OSAL_Clock.h" +#include "osal_bufmgr.h" +#include "OSAL_Memory.h" +#include "log.h" +#include "hci.h" +#include "hci_tl.h" +#include "version.h" +#include "flash.h" +#include "gatt.h" +#include "att.h" +#include "error.h" +#include "clock.h" +//======================================================== +// build config +//#define __BUILD_RF_LIB_SLA__ (0x1) +//#define __BUILD_RF_LIB_MST__ (0x2) +//#define __BUILD_RF_LIB_MULTI__ ( __BUILD_RF_LIB_MST__ | __BUILD_RF_LIB_SLA__ ) +// +//#ifndef __BUILD_PATCH_CFG__ +// #define __BUILD_PATCH_CFG__ __BUILD_RF_LIB_MST__ +//#endif + + +#define DBG_BUILD_LL_TIMING 0 //0x01 for enable LL timing debug + + + + +// ====================== +//#define DBG_GPIO_WRITE(a,b) gpio_write((a),(b)) +#define DBG_GPIO_WRITE(a,b) +#define DBGIO_LL_TRIG P23 +#define DBGIO_LL_IRQ P24 +#define DBGIO_APP_WAKEUP P18 +#define DBGIO_APP_SLEEP P20 +#define DBGIO_DIS_IRQ P11 +#define DBGIO_EN_IRQ P34 + +#define LL_HW_MODE_STX 0x00 +#define LL_HW_MODE_SRX 0x01 +#define LL_HW_MODE_TRX 0x02 +#define LL_HW_MODE_RTX 0x03 +#define LL_HW_MODE_TRLP 0x04 +#define LL_HW_MODE_RTLP 0x05 + +// =============== add in A2 for simultaneous slave and adv/scan +#define LL_SEC_STATE_IDLE 0x00 +#define LL_SEC_STATE_SCAN 0x01 +#define LL_SEC_STATE_ADV 0x02 +#define LL_SEC_STATE_SCAN_PENDING 0x03 +#define LL_SEC_STATE_ADV_PENDING 0x04 +#define LL_SEC_STATE_IDLE_PENDING 0x05 +#define LL_SEC_STATE_INIT 0x06 +#define LL_SEC_STATE_INIT_PENDING 0x07 + +#define WFI() __WFI() + +#define LL_MODE_INVALID 0xFF +#define LL_MODE_LEGACY 0x00 +#define LL_MODE_EXTENDED 0x01 + +#define LL_COPY_DEV_ADDR_LE( dstPtr, srcPtr ) { \ + (dstPtr)[0] = (srcPtr)[0]; \ + (dstPtr)[1] = (srcPtr)[1]; \ + (dstPtr)[2] = (srcPtr)[2]; \ + (dstPtr)[3] = (srcPtr)[3]; \ + (dstPtr)[4] = (srcPtr)[4]; \ + (dstPtr)[5] = (srcPtr)[5];} + +#define LL_WINDOW_SIZE 2 // 2.5ms in 1.25ms ticks + +#define LL_CALC_NEXT_SCAN_CHN(chan) { chan ++; \ + chan = (chan > LL_SCAN_ADV_CHAN_39) ? LL_SCAN_ADV_CHAN_37 : chan;} + +#define CONN_CSA2_ALLOW 0x00000080 + +//------------------------------------------------------------------------------------ +//extern rom function +// +//extern int gpio_write(gpio_pin_e pin, bit_action_e en); +extern uint8 ll_processExtAdvIRQ(uint32_t irq_status); +extern uint8 ll_processPrdAdvIRQ(uint32_t irq_status); +extern uint8 ll_processExtScanIRQ(uint32_t irq_status); +extern uint8 ll_processExtInitIRQ(uint32_t irq_status); +extern uint8 ll_processPrdScanIRQ(uint32_t irq_status); +extern uint8 ll_processBasicIRQ(uint32_t irq_status); +extern int clear_timer_int(AP_TIM_TypeDef* TIMx); +extern uint8 isTimer1Running(void); +extern uint8 isTimer4Running(void); +extern void clear_timer(AP_TIM_TypeDef* TIMx); + +extern uint8 ll_processMissMasterEvt(uint8 connId); +extern uint8 ll_processMissSlaveEvt(uint8 connId); +extern int gpio_write(GPIO_Pin_e pin, uint8_t en); +extern void ll_hw_tx2rx_timing_config(uint8 pkt); +extern void wakeup_init0(void); +extern void enter_sleep_off_mode0(Sleep_Mode mode); +extern void spif_release_deep_sleep(void); +extern void spif_set_deep_sleep(void); + +extern uint8 ll_hw_get_tr_mode(void); +extern int ll_hw_get_rfifo_depth(void); +extern void move_to_master_function(void); + +extern struct buf_tx_desc g_tx_adv_buf; +extern struct buf_tx_desc g_tx_ext_adv_buf; +extern struct buf_tx_desc tx_scanRsp_desc; + +extern struct buf_rx_desc g_rx_adv_buf; + +extern chipMAddr_t g_chipMAddr; + +extern uint8 g_llAdvMode; +extern uint32_t g_llHdcDirAdvTime; + +extern uint32 g_new_master_delta; +//----------------------------------------------------------------------------------- +//extern rom variable +// +uint32* pGlobal_config = NULL; +void efuse_init(void); + +const unsigned char libRevisionDate[]=__DATE__; +const unsigned char libRevisionTime[]=__TIME__; + +uint8 CreateConn_Flag = FALSE; +uint32_t g_t_llhwgo = 0; +uint16 g_lastSlaveLatency=0; + +extern uint32 hclk_per_us; +extern uint32 hclk_per_us_shift; +extern volatile uint8 g_clk32K_config; +///////////////////////// + +extern uint32 sleep_flag; +extern uint32 osal_sys_tick; +extern uint32 ll_remain_time; + +extern uint32 llWaitingIrq; +extern uint32 ISR_entry_time; + +extern uint32 counter_tracking; + +extern uint32_t __initial_sp; +extern void _start(void) __NO_RETURN; +extern uint32_t g_smartWindowSize; +extern volatile uint8_t g_same_rf_channel_flag; +extern uint32_t g_TIM2_IRQ_TIM3_CurrCount; +extern uint32_t g_TIM2_IRQ_to_Sleep_DeltTick; +extern uint32_t g_TIM2_IRQ_PendingTick; +extern uint32_t g_osal_tick_trim; +extern uint32_t g_osalTickTrim_mod; +extern uint32_t g_TIM2_wakeup_delay; +extern uint32_t rtc_mod_value; +extern uint32_t g_counter_traking_cnt; +extern uint32_t sleep_tick; +extern uint32_t g_wakeup_rtc_tick; +extern int slave_conn_event_recv_delay; +extern uint8 g_llScanMode; +extern uint8 g_currentPeerAddrType; +extern uint8 g_currentPeerRpa[LL_DEVICE_ADDR_LEN]; +extern uint8 ownRandomAddr[]; +extern uint16_t ll_hw_get_tfifo_wrptr(void); +extern uint32_t llCurrentScanChn; +extern uint8 ownPublicAddr[]; +extern uint32_t llScanTime; +extern uint32_t llScanT1; +extern uint8 isPeerRpaStore; +extern uint8 currentPeerRpa[LL_DEVICE_ADDR_LEN]; +extern uint8 storeRpaListIndex; +extern uint8 g_currentLocalAddrType; +extern uint8 g_currentLocalRpa[LL_DEVICE_ADDR_LEN]; +//extern llPduLenManagment_t g_llPduLen; +extern uint8_t llSecondaryState; // secondary state of LL + +void __wdt_init(void) +{ + typedef void (*my_function)(void ); + my_function pFunc = NULL; + pFunc = (my_function)(JUMP_FUNCTION(HAL_WATCHDOG_INIT)); + + if (pFunc != NULL) + pFunc(); +} + +uint8 ll_processBasicIRQ_SRX(uint32_t irq_status) +{ + uint8 ret=0; + typedef uint8 (*my_function)(uint32_t ); + my_function pFunc = NULL; + pFunc = (my_function)(JUMP_FUNCTION(LL_PROCESSBASICIRQ_SRX)); + + if (pFunc != NULL) + ret = pFunc(irq_status); + else + ret = ll_processBasicIRQ(irq_status); + + return ret; +} +uint8 ll_processBasicIRQ_secondaryAdvTRX(uint32_t irq_status) +{ + uint8 ret=0; + typedef uint8 (*my_function)(uint32_t ); + my_function pFunc = NULL; + pFunc = (my_function)(JUMP_FUNCTION(LL_PROCESSBASICIRQ_SECADVTRX)); + + if (pFunc != NULL) + ret = pFunc(irq_status); + else + ret = ll_processBasicIRQ(irq_status); + + return ret; +} + +uint8 ll_processBasicIRQ_ScanTRX(uint32_t irq_status) +{ + uint8 ret=0; + typedef uint8 (*my_function)(uint32_t ); + my_function pFunc = NULL; + pFunc = (my_function)(JUMP_FUNCTION(LL_PROCESSBASICIRQ_SCANTRX)); + + if (pFunc != NULL) + ret = pFunc(irq_status); + else + ret = ll_processBasicIRQ(irq_status); + + return ret; +} + +uint8 ll_processBasicIRQ_secondaryScanSRX(uint32_t irq_status) +{ + uint8 ret=0; + typedef uint8 (*my_function)(uint32_t ); + my_function pFunc = NULL; + pFunc = (my_function)(JUMP_FUNCTION(LL_PROCESSBASICIRQ_SECSCANSRX)); + + if (pFunc != NULL) + ret = pFunc(irq_status); + else + ret = ll_processBasicIRQ(irq_status); + + return ret; +} + +uint8 ll_processBasicIRQ_secondaryInitSRX(uint32_t irq_status) +{ + uint8 ret=0; + typedef uint8 (*my_function)(uint32_t ); + my_function pFunc = NULL; + pFunc = (my_function)(JUMP_FUNCTION(LL_PROCESSBASICIRQ_SECINITSRX)); + + if (pFunc != NULL) + ret = pFunc(irq_status); + else + ret = ll_processBasicIRQ(irq_status); + + return ret; +} + +//---------------------------------------------------------------------------------------------- +//patch + +void ll_hw_go1(void) +{ + //*(volatile uint32_t *)0x4000f0b8 = 0; // pclk_clk_gate_en + //20190115 ZQ recorded ll re-trigger + if(llWaitingIrq==TRUE) + { + g_pmCounters.ll_trigger_err++; + } + + g_t_llhwgo = read_current_fine_time(); + *(volatile uint32_t*)(LL_HW_BASE+ 0x14) = LL_HW_IRQ_MASK; //clr irq status + *(volatile uint32_t*)(LL_HW_BASE+ 0x0c) = 0x0001; //mask irq :only use mode done + *(volatile uint32_t*)(LL_HW_BASE+ 0x00) = 0x0001; //trig + + if(CreateConn_Flag) + { + osal_memcpy((uint8*)&g_tx_adv_buf.data[0], &initInfo.ownAddr[0], 6); + CreateConn_Flag= FALSE; + } + + //2018-05-23 ZQ + //fix negative rfPhyFreqOff bug, when in scan_rsq case, ll_hw_go will be excuted before set_channel() + //so do not change the tx_rx_foff + //next metal change could modified the set_channel() to deal with the tx_rx_foff + uint8_t rfChnIdx = PHY_REG_RD(0x400300b4)&0xff; + + if(!g_same_rf_channel_flag) + { + if(g_rfPhyFreqOffSet>=0) + PHY_REG_WT(0x400300b4, (g_rfPhyFreqOffSet<<16)+(g_rfPhyFreqOffSet<<8)+rfChnIdx); + else + PHY_REG_WT(0x400300b4, ((255+g_rfPhyFreqOffSet)<<16)+((255+g_rfPhyFreqOffSet)<<8)+(rfChnIdx-1) ); + } + + //2018-02-09 ZQ + //considering the ll_trigger timing, Trigger first, then set the tp_cal cap + + if(rfChnIdx<2) + { + rfChnIdx=2; + } + else if(rfChnIdx>80) + { + rfChnIdx=80; + } + + if(g_rfPhyPktFmt==PKT_FMT_BLE2M) + subWriteReg(0x40030094,7,0,RF_PHY_TPCAL_CALC(g_rfPhyTpCal0_2Mbps,g_rfPhyTpCal1_2Mbps,(rfChnIdx-2)>>1)); + else + subWriteReg(0x40030094,7,0,RF_PHY_TPCAL_CALC(g_rfPhyTpCal0,g_rfPhyTpCal1,(rfChnIdx-2)>>1)); + + int llModeLast; + llModeLast = ll_hw_get_tr_mode(); + extern uint8_t rxFifoFlowCtrl; + extern uint8 ctrlToHostEnable; + + if (llModeLast == LL_HW_MODE_RTLP || llModeLast == LL_HW_MODE_TRLP) + { + if (ctrlToHostEnable && rxFifoFlowCtrl) + { + set_max_length(0); + } + + //for codedphy rxtimeout + llConnState_t* connPtr; + connPtr = &conn_param[g_ll_conn_ctx.currentConn]; + + if (connPtr->llRfPhyPktFmt == PKT_FMT_BLR125K || connPtr->llRfPhyPktFmt == PKT_FMT_BLR500K) + { + ll_hw_set_rx_timeout(350); + } + } + + if((llModeLast == LL_HW_MODE_TRX)&&((llState == LL_STATE_ADV_UNDIRECTED ||llState == LL_STATE_ADV_SCAN ||llState == LL_STATE_ADV_DIRECTED)|| llSecondaryState == LL_SEC_STATE_ADV)) + { + ll_hw_set_rx_timeout(108); + } + + // fix slave scan rsp addr type bug + // if (llModeLast == LL_HW_MODE_STX && + // (llState == LL_STATE_ADV_UNDIRECTED || + // llState == LL_STATE_ADV_SCAN ) + // ) + // { + // if(adv_param.ownAddrType == LL_DEV_ADDR_TYPE_PUBLIC) + // { + // SET_BITS(tx_scanRsp_desc.txheader, LL_DEV_ADDR_TYPE_PUBLIC, TX_ADD_SHIFT, TX_ADD_MASK); + // } + // else if(adv_param.ownAddrType == LL_DEV_ADDR_TYPE_RANDOM) + // { + // SET_BITS(tx_scanRsp_desc.txheader, LL_DEV_ADDR_TYPE_RANDOM, TX_ADD_SHIFT, TX_ADD_MASK); + // } + // DBG_GPIO_WRITE(DBGIO_LL_TRIG,1); + // DBG_GPIO_WRITE(DBGIO_LL_TRIG,0); + // } + // + //disable scan backoff + scanInfo.currentBackoff=1; +} + +//for fix uint8 lastSlaveLatency issue +void LL_set_default_conn_params1(llConnState_t* connPtr) +{ + LL_set_default_conn_params0(connPtr); + g_lastSlaveLatency = 0; +} + +uint8 llSetupNextSlaveEvent1( void ) +{ + uint8 stat = llSetupNextSlaveEvent0(); + llConnState_t* connPtr; + // get connection information + connPtr = &conn_param[g_ll_conn_ctx.currentConn]; + g_lastSlaveLatency = connPtr->slaveLatency; + return stat; +} + +void ll_scheduler2(uint32 time) +{ + llConnState_t* connPtr; + connPtr = &conn_param[g_ll_conn_ctx.currentConn]; + + if(g_lastSlaveLatency > connPtr->lastSlaveLatency) + { + uint32 delttime = connPtr->lastTimeToNextEvt * (g_lastSlaveLatency -connPtr->lastSlaveLatency) * 625; + + if((time != LL_INVALID_TIME) &&(time != 200)) + { + time += delttime; + } + } + + ll_scheduler0(time); +} + +extern int slave_conn_event_recv_delay; +void ll_adptive_adj_next_time1(uint32_t next_time) +{ + (void)(next_time); + uint32_t loop_time,anchor_point; + + // read loop timeout counter, system clock may be 16MHz, 32MHz, 64MHz and 48MHz, 96MHz + if (hclk_per_us_shift != 0) + { + loop_time = ll_hw_get_loop_cycle() >> hclk_per_us_shift; // convert to us + } + else + { + loop_time = ll_hw_get_loop_cycle() / hclk_per_us; // convert to us + } + + if (hclk_per_us_shift != 0) + { + anchor_point = ll_hw_get_anchor() >> hclk_per_us_shift; // convert to us + } + else + { + anchor_point = ll_hw_get_anchor() / hclk_per_us; // convert to us + } + + //================================================== + //DO NOT ADD LOG PRINTF In this FUNCTION + //================================================== + llConnState_t* connPtr; + // get connection information + connPtr = &conn_param[g_ll_conn_ctx.currentConn]; + + //no anche point + if (connPtr->rx_timeout) + { + connPtr->pmCounter.ll_tbd_cnt1++; + slave_conn_event_recv_delay = LL_TIME_DELTA(g_t_llhwgo, ISR_entry_time)-370+160;//160:timer1 irq->hwgo trigger + } + else + { + connPtr->pmCounter.ll_tbd_cnt1 = 0; + slave_conn_event_recv_delay = loop_time - anchor_point+pGlobal_config[SLAVE_CONN_DELAY]; + } + + // slave_conn_event_recv_delay -= 370; + //slave_conn_event_recv_delay += (connPtr->curParam.connInterval >> 2); + // slave_conn_event_recv_delay += pGlobal_config[SLAVE_CONN_DELAY]; + + // if( connPtr->firstPacket ) + // { + // slave_conn_event_recv_delay+=500; + // } + + //only adj for the 1st rxtimeout + if (1 == connPtr->pmCounter.ll_tbd_cnt1) + { + slave_conn_event_recv_delay += 500; + } + + //adj for ntrm pkt, each pkt cost 50us in wt tfifo + //if(connPtr->rx_timeout) + //slave_conn_event_recv_delay += ((connPtr->ll_buf.ntrm_cnt) * 50); +} + +void llConnTerminate1( llConnState_t* connPtr, + uint8 reason ) +{ + /* + ZQ:20210622 + process chanmp update passed instant(core 4.2 should term link, since core 5.0 just update the ) + just update chanmap do not trigger ll conn termination + */ + if( reason == LL_CTRL_PKT_INSTANT_PASSED_PEER_TERM + && ((uint16)(connPtr->chanMapUpdateEvent - connPtr->currentEvent) >= LL_MAX_UPDATE_COUNT_RANGE ) + &&((!osal_memcmp(connPtr->chanMap,connPtr->chanMapUpdate.chanMap,5)))) + { + llProcessChanMap(connPtr, connPtr->chanMapUpdate.chanMap); + } + else + { + llConnTerminate0(connPtr,reason); + } +} + +/* + fix secAdv evt rfphyPkt error issue +*/ +//extern uint8 llSetupSecAdvEvt0( void ); +uint8 llSetupSecAdvEvt1( void ) +{ + uint8 ret = FALSE; + + if (llState == LL_STATE_IDLE) + { + if (adv_param.advEvtType == LL_ADV_CONNECTABLE_UNDIRECTED_EVT) + llState = LL_STATE_ADV_UNDIRECTED; + else if (adv_param.advEvtType == LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT) + llState = LL_STATE_ADV_NONCONN; + else if (adv_param.advEvtType == LL_ADV_SCANNABLE_UNDIRECTED_EVT) + llState = LL_STATE_ADV_SCAN; + + llSetupAdv(); + llSecondaryState = LL_SEC_STATE_IDLE; + return TRUE; + } + else + { + llConnState_t* connPtr; + connPtr = &conn_param[g_ll_conn_ctx.currentConn]; + g_rfPhyPktFmt = LE_1M_PHY; + //support rf phy change + rf_phy_change_cfg0(g_rfPhyPktFmt); + + if (adv_param.advEvtType == LL_ADV_CONNECTABLE_UNDIRECTED_EVT) + ret = llSetupSecConnectableAdvEvt(); + else if (adv_param.advEvtType == LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT) + ret = llSetupSecNonConnectableAdvEvt(); + else if (adv_param.advEvtType == LL_ADV_SCANNABLE_UNDIRECTED_EVT) + ret = llSetupSecScannableAdvEvt(); + else + return FALSE; // other type adv should not here + + g_rfPhyPktFmt = connPtr->llRfPhyPktFmt; + } + + return ret; +} + +//fix sec_scan rfphy issue +void llSetupSecScan1( uint8 chan ) +{ + uint32 scanTime; + // Hold off interrupts. + HAL_ENTER_CRITICAL_SECTION( ); + scanTime = scanInfo.scanWindow * 625; + +// if(llWaitingIrq) +// { +// LOG("==== error, mode: %d\n", scanInfo.scanMode); +// } + + if (llState == LL_STATE_IDLE) + { + llState = LL_STATE_SCAN; + llSecondaryState = LL_SEC_STATE_IDLE; + } + else + { + // calculate scan time + scanTime = llCalcMaxScanTime(); + + if (scanTime) // trigger scan + { + llSecondaryState = LL_SEC_STATE_SCAN; + } + else // no enough time to scan, pending + { + llSecondaryState = LL_SEC_STATE_SCAN_PENDING; + g_pmCounters.ll_conn_scan_pending_cnt ++; + HAL_EXIT_CRITICAL_SECTION( ); + return; + } + } + + if (scanTime > scanInfo.scanWindow * 625) + scanTime = scanInfo.scanWindow * 625; + + llConnState_t* connPtr; + connPtr = &conn_param[g_ll_conn_ctx.currentConn]; + g_rfPhyPktFmt = LE_1M_PHY; + //support rf phy change + rf_phy_change_cfg0(g_rfPhyPktFmt); + // reset all FIFOs; all data is forfeit + ll_hw_rst_tfifo(); + ll_hw_rst_rfifo(); + set_crc_seed(ADV_CRC_INIT_VALUE); // crc seed for adv is same for all channels + set_access_address(ADV_SYNCH_WORD); + set_channel(chan); + set_whiten_seed(chan); + set_max_length(0xff); + ll_hw_set_rx_timeout(scanTime); // maximum scan time, note that actual scan time may exceed the limit if timer expiry when LL engine receiving a report + ll_hw_set_srx(); + ll_hw_ign_rfifo(LL_HW_IGN_CRC|LL_HW_IGN_EMP); + ll_hw_go(); + llScanT1 = read_current_fine_time(); + g_rfPhyPktFmt = connPtr->llRfPhyPktFmt; + llWaitingIrq = TRUE; + HAL_EXIT_CRITICAL_SECTION(); +// uint32 remainTime = read_LL_remainder_time(); +// LOG("<%d %d>", scanTime, remainTime); + return; +} + +extern int32 connUpdateTimer; +/******************************************************************************* + GLOBAL VARIABLES +*/ + +extern perStatsByChan_t* p_perStatsByChan; +extern uint8 g_conn_taskID; +extern uint16 g_conn_taskEvent; + + +/******************************************************************************* + Prototypes +*/ +extern uint8 llProcessMasterControlProcedures( llConnState_t* connPtr ); +extern uint8 llSetupNextMasterEvent( void ); +/******************************************************************************* + @fn llMasterEvt_TaskEndOk + + @brief This function is used to handle the PHY task done end cause + TASK_ENDOK that can result from one of three causes. First, a + a packet was successfully received with MD=0 (i.e. no more Slave + data) after having transmitted a packet with MD=0. Second, a + received packet did not fit in the RX FIFO after transmitting + a packet with MD=0. Third, a packet was received from the Slave + while BLE_L_CONF.ENDC is true or after Timer 2 Event 2 occurs. + + Note: The TASK_ENDOK end cause will also handle the TASK_NOSYNC, + TASK_RXERR, and TASK_MAXNACK end causes as well. + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void llMasterEvt_TaskEndOk1( void ) +{ + llConnState_t* connPtr; + uint16 numPkts; + int i; + uint32_t T2, schedule_time; + // get connection information + connPtr = &conn_param[g_ll_conn_ctx.currentConn]; + // advance the connection event count + connPtr->currentEvent = connPtr->nextEvent; + // get the total number of received packets + // Note: Since Auto-Flush is enabled, numRxFifoFull is incremented instead of + // numRxOk when there's no room in the FIFO. When Auto-Flush is + // disabled and there's no room in the FIFO, only numRxFifoFull is + // incremented for any kind of received packet. + numPkts = ( rfCounters.numRxOk + + rfCounters.numRxNotOk + + rfCounters.numRxEmpty + + rfCounters.numRxIgnored + + rfCounters.numRxFifoFull ); + // collect packet error information + connPtr->perInfo.numPkts += numPkts; + connPtr->perInfo.numCrcErr += rfCounters.numRxNotOk; + // + connPtr->perInfo.numEvents++; + +// // check if PER by Channel is enabled +// if ( connPtr->perInfoByChan != NULL ) +// { +// connPtr->perInfoByChan->numPkts[ PHY_GET_DATA_CHAN() ] += numPkts; +// connPtr->perInfoByChan->numCrcErr[ PHY_GET_DATA_CHAN() ] += rfCounters.numRxNotOk; +// } + + // check if any data has been received + // Note: numRxOk includes numRxCtrl + // Note: numRxNotOk removed as 4.5.2 of spec says the timer is reset upon + // receipt of a "valid packet", which is taken to mean no CRC error. + if ( rfCounters.numRxOk || rfCounters.numRxIgnored || + rfCounters.numRxEmpty || rfCounters.numRxFifoFull + || connPtr->rx_crcok != 0) // ever Rx CRC OK packet + { + // yes, so update the supervision expiration count + connPtr->expirationEvent = connPtr->currentEvent + connPtr->expirationValue; + // clear flag that indicates we received first packet + // Note: The first packet only really needs to be signalled when a new + // connection is formed. However, there's no harm in resetting it + // every time in order to simplify the control logic. + // Note: True-Low logic is used here to be consistent with nR's language. + connPtr->firstPacket = 0; + + //20181206 ZQ add phy change nofity + //receiver ack notifty the host + if(connPtr->llPhyModeCtrl.isChanged==TRUE) + { + connPtr->llPhyModeCtrl.isChanged = FALSE; + llPhyModeCtrlUpdateNotify(connPtr,LL_STATUS_SUCCESS); + } + } + else // no data received, or packet received with CRC error + { + // check if we received any packets with a CRC error + if ( rfCounters.numRxNotOk ) + { + // clear flag that indicates we received first packet + // Note: The first packet only really needs to be signalled when a new + // connection is formed. However, there's no harm in resetting it + // every time in order to simplify the control logic. + // Note: True-Low logic is used here to be consistent with nR's language. + connPtr->firstPacket = 0; + } + else // no packet was received + { + // collect packet error information, TI use HCI ext to get this information. No used by PHY+ now + connPtr->perInfo.numMissedEvts++; + } + + // check if we have a Supervision Timeout + if ( connPtr->expirationEvent == connPtr->currentEvent ) // 20201011�� should be "==" + { + // check if the connection has already been established + if ( connPtr->firstPacket == 0 ) + { + // yes, so terminate with LSTO + llConnTerminate( connPtr, LL_SUPERVISION_TIMEOUT_TERM ); + } + else // no, so this is a failure to establish the connection + { + // so terminate immediately with failure to establish connection + llConnTerminate( connPtr, LL_CONN_ESTABLISHMENT_FAILED_TERM ); + } + +//#ifdef MULTI_ROLE + ll_scheduler(LL_INVALID_TIME); // link is terminated, update scheduler info +//#endif + return; + } + } + + /* + ** Process RX Data Packets + */ + // check if there is any data in the Rx FIFO + uint8_t buffer_size; + buffer_size = getRxBufferSize(connPtr); + + for ( i = 0; i < buffer_size; i ++) // note: i < getRxBufferSize() will fail the loop + { + // there is, so process it; check if data was processed + if ( llProcessRxData() == FALSE ) + { + // it wasn't, so we're done +// ll_scheduler(LL_INVALID_TIME); + break; + } + } + + // check if this connection was terminated + if ( !connPtr->active ) + { +//#ifdef MULTI_ROLE + ll_scheduler(LL_INVALID_TIME); +//#endif + return; + } + + /* + ** Check Control Procedure Processing + */ + if ( llProcessMasterControlProcedures( connPtr ) == LL_CTRL_PROC_STATUS_TERMINATE ) + { +//#ifdef MULTI_ROLE + ll_scheduler(LL_INVALID_TIME); // link is termainte, update schedle info +//#endif + return; + } + else if(connPtr->ctrlDataIsPending == 1) + { + uint8 pktLenctrl; + uint8* pBufctrl = connPtr->ctrlData.data; + pktLenctrl = LL_REJECT_EXT_IND_PAYLOAD_LEN; + + if((connPtr->ctrlData .header == (pktLenctrl << 8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT))&&(*pBufctrl == LL_CTRL_REJECT_EXT_IND)) + { + uint8 ctrlerrorcode = *(pBufctrl + 1); + *(pBufctrl + 1) = connPtr->rejectOpCode; + *(pBufctrl + 2) = ctrlerrorcode; + } + } + + /* + ** Process TX Data Packets + */ + // copy any pending data to the TX FIFO + llProcessTxData( connPtr, LL_TX_DATA_CONTEXT_POST_PROCESSING ); + + // if any fragment l2cap pkt, copy to TX FIFO + //l2capPocessFragmentTxData((uint16)connPtr->connId); + + /* + ** Setup Next Slave Event Timing + */ + + // update next event, calculate time to next event, calculate timer drift, + // update anchor points, setup NR T2E1 and T2E2 events + if ( llSetupNextMasterEvent() == LL_SETUP_NEXT_LINK_STATUS_TERMINATE ) // PHY+ always return success here + { + // this connection is terminated, so nothing to schedule +//#ifdef MULTI_ROLE + ll_scheduler(LL_INVALID_TIME); +//#endif + return; + } + + /* + ** Schedule Next Task + */ +//#ifdef MULTI_ROLE +// schedule_time = ll_get_next_timer(g_ll_conn_ctx.currentConn); + schedule_time = (connPtr->curParam.connInterval + connUpdateTimer) * 625; + T2 = read_current_fine_time(); + // TODO: don't know the cause, here need add 32us to gain accurate timing + //2020.11.11,Jie,master conInterval-5us + ll_scheduler(schedule_time - 10 - LL_TIME_DELTA(g_ll_conn_ctx.timerExpiryTick, T2) ); // 10us: rough delay from timer expire to timer ISR +//#endif + return; +} + +uint8_t ll_hw_read_rfifo1(uint8_t* rxPkt, uint16_t* pktLen, uint32_t* pktFoot0, uint32_t* pktFoot1) +{ + int rdPtr, wrPtr, rdDepth, blen, wlen; + uint32_t* p_rxPkt = (uint32_t*)rxPkt; + ll_hw_get_rfifo_info(&rdPtr, &wrPtr, &rdDepth); + + if(rdDepth > 0) + { + *p_rxPkt++ = *(volatile uint32_t*)(LL_HW_RFIFO); + uint8_t sp =0;//BLE_HEAD_WITH_CTE(rxPkt[0]); + blen = rxPkt[1]+sp; //get the byte length for header + wlen = 1+ ( (blen+2+3-1) >>2 ); //+2 for Header, +3 for crc + + //compared the wlen and HW_WTR + //20190115 ZQ + if( (wlen+2) >rdDepth) + { + g_pmCounters.ll_rfifo_read_err++; + rxPkt[0] = 0; + *pktFoot0 = 0; + *pktFoot1 = 0; + *pktLen = 0; + return 0; + } + + while(p_rxPkt < (uint32_t*)rxPkt + wlen) + { + *p_rxPkt++ = *(volatile uint32_t*)(LL_HW_RFIFO); + } + + *pktFoot0 = *(volatile uint32_t*)(LL_HW_RFIFO); + *pktFoot1 = *(volatile uint32_t*)(LL_HW_RFIFO); + *pktLen = blen + 2; + return wlen; + } + else + { + rxPkt[0] = 0; + *pktFoot0 = 0; + *pktFoot1 = 0; + *pktLen = 0; + return 0; + } +} + +/******************************************************************************* + @fn ll_processBasicIRQ_SRX + + @brief Interrupt Request Handler for Link Layer + + input parameters + + @param None. + + output parameters + + @param None. + + @return None +*/ +uint8 ll_processBasicIRQ_SRX0(uint32_t irq_status) +{ + uint8 mode; + uint32_t T2, delay; + llConnState_t* connPtr; + connPtr = &conn_param[0]; // To update + HAL_ENTER_CRITICAL_SECTION(); + mode = ll_hw_get_tr_mode(); + + if (mode == LL_HW_MODE_SRX + && (llState == LL_STATE_SCAN || llState == LL_STATE_INIT)) + { + ll_debug_output(DEBUG_LL_HW_SRX); + uint8_t rpaListIndex = LL_RESOLVINGLIST_ENTRY_NUM; + uint8_t bWlRlCheckOk = TRUE; + uint8_t* peerAddr; + + // ============= scan case + if (llState == LL_STATE_SCAN) + { + uint8 bSendingScanReq = FALSE; + + // check status + if ((irq_status & LIRQ_RD) && (irq_status & LIRQ_COK)) // bug correct 2018-10-15 + { + // rx done + uint8_t packet_len, pdu_type; + uint16_t pktLen; + uint32_t pktFoot0, pktFoot1; + // read packet + // cost 21-26us(measure with GPIO), depneds on the length of ADV + packet_len = ll_hw_read_rfifo1((uint8_t*)(&(g_rx_adv_buf.rxheader)), + &pktLen, + &pktFoot0, + &pktFoot1); + // check receive pdu type + pdu_type = g_rx_adv_buf.rxheader & 0x0f; + + if(ll_hw_get_rfifo_depth()>0) + { + g_pmCounters.ll_rfifo_read_err++; + packet_len=0; + pktLen=0; + } + + if (packet_len != 0 + && ((pdu_type == ADV_IND) + || (pdu_type == ADV_NONCONN_IND) + || (pdu_type == ADV_SCAN_IND) + || (pdu_type == ADV_DIRECT_IND))) + { + uint8 addrType; // peer address type + uint8_t txAdd = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + peerAddr = &g_rx_adv_buf.data[0]; // AdvA + addrType = txAdd; + + // Resolving list checking + // case 1: receive ScanA using RPA + if (txAdd == LL_DEV_ADDR_TYPE_RANDOM && + (g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) + { + bWlRlCheckOk = TRUE; + + if (g_llRlEnable == TRUE) + { + rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]); + + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM) + { + peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; + // refer to HCI LE Advertising Report Event, RPA address type should be + // 0x02: Public Identity Address (Corresponds to Resolved Private Address) + // 0x03: Random (static) Identity Address (Corresponds to Resolved Private Address) + addrType = g_llResolvinglist[rpaListIndex].peerAddrType + 2; + bWlRlCheckOk = TRUE; + } + else + { + bWlRlCheckOk = FALSE; + } + } + } + else // case 2: receive ScanA using device ID, or scan device not using RPA + { + bWlRlCheckOk = TRUE; + + for (int i = 0; i < LL_RESOLVINGLIST_ENTRY_NUM; i++) + { + if ( g_llResolvinglist[i].peerAddr[0] == g_rx_adv_buf.data[0] + && g_llResolvinglist[i].peerAddr[1] == g_rx_adv_buf.data[1] + && g_llResolvinglist[i].peerAddr[2] == g_rx_adv_buf.data[2] + && g_llResolvinglist[i].peerAddr[3] == g_rx_adv_buf.data[3] + && g_llResolvinglist[i].peerAddr[4] == g_rx_adv_buf.data[4] + && g_llResolvinglist[i].peerAddr[5] == g_rx_adv_buf.data[5]) + { + // the device ID in the RPA list + if (g_llResolvinglist[i].privacyMode == DEVICE_PRIVACY_MODE || + ll_isIrkAllZero(g_llResolvinglist[i].peerIrk)) + rpaListIndex = i; + else + bWlRlCheckOk = FALSE; // the device in the RPA list but not using RPA, reject it + + break; + } + } + } + + // check white list + if ((pGlobal_config[LL_SWITCH] & LL_WHITELIST_ALLOW) + && (scanInfo.wlPolicy == LL_SCAN_WL_POLICY_USE_WHITE_LIST) + && (bWlRlCheckOk == TRUE)) + { + // check white list + bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr); + } + + /* 20201218 Jie,direct adv report when no whitelist filter + else if(pdu_type == ADV_DIRECT_IND) // direct adv only report addr & addr type match the whitelist + bWlRlCheckOk = FALSE; + */ + // if valid, trigger osal event to report adv + if (bWlRlCheckOk == TRUE) + { + uint8 advEventType; + int8 rssi; + llCurrentScanChn = scanInfo.nextScanChan; + + // active scan scenario, send scan req + if (scanInfo.scanType == LL_SCAN_ACTIVE + && (pdu_type== ADV_IND + || pdu_type == ADV_SCAN_IND )) + { + // back off process + scanInfo.currentBackoff = (scanInfo.currentBackoff > 0) ? (scanInfo.currentBackoff - 1) : 0; + + if (scanInfo.currentBackoff == 0) // back off value = 0, send scan req + { + g_tx_adv_buf.txheader = 0xC03; + //ZQ 20181012: add AdvFilterCB + uint8_t retAdvFilter = 1; + + if(LL_PLUS_AdvDataFilterCBack) + { + //!!!CATION!!! + //timing critical + //txbuf will be changed + retAdvFilter = LL_PLUS_AdvDataFilterCBack(); + } + + if(retAdvFilter) + { + g_same_rf_channel_flag = TRUE; + ll_hw_set_tx_rx_interval(10); + ll_hw_set_rx_timeout(158); + set_max_length(0xFF); // add 2020-03-10 + T2 = read_current_fine_time(); + delay = (T2 > ISR_entry_time) ? (T2 - ISR_entry_time) : (BASE_TIME_UNITS - ISR_entry_time + T2); + delay = 118 - delay - pGlobal_config[LL_ADV_TO_SCAN_REQ_DELAY]; + ll_hw_set_trx(); // set LL HW as single TRx mode + ll_hw_set_trx_settle(delay, // set BB delay, about 80us in 16MHz HCLK + pGlobal_config[LL_HW_AFE_DELAY], + pGlobal_config[LL_HW_PLL_DELAY]); //RxAFE,PLL + ll_hw_go(); + g_pmCounters.ll_send_scan_req_cnt++; + llWaitingIrq = TRUE; + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + ll_hw_ign_rfifo(LL_HW_IGN_CRC | LL_HW_IGN_EMP); + + // construct SCAN REQ packet + //g_tx_adv_buf.txheader = 0xCC3; + +// //20181012 ZQ: change the txheader according to the adtype +// g_tx_adv_buf.txheader |=(((g_rx_adv_buf.rxheader&0x40)<<1) +// | (scanInfo.ownAddrType<< TX_ADD_SHIFT & TX_ADD_MASK)); + + // fill scanA, using RPA or device ID address // TODO: move below code before ll_hw_go? + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM && + !ll_isIrkAllZero(g_llResolvinglist[rpaListIndex].localIrk) + && (scanInfo.ownAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC + || scanInfo.ownAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM)) + { + // for resolving private address case, calculate the scanA with Local IRK + ll_CalcRandomAddr(g_llResolvinglist[rpaListIndex].localIrk, &g_tx_adv_buf.data[0]); + SET_BITS(g_tx_adv_buf.txheader, LL_DEV_ADDR_TYPE_RANDOM, TX_ADD_SHIFT, TX_ADD_MASK); + } + else + { + //2020.10.26 Jie,TX_ADD update + if (scanInfo.ownAddrType == LL_DEV_ADDR_TYPE_PUBLIC || scanInfo.ownAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC) + { + osal_memcpy((uint8*)&g_tx_adv_buf.data[0], &ownPublicAddr[0], 6); + SET_BITS(g_tx_adv_buf.txheader, LL_DEV_ADDR_TYPE_PUBLIC, TX_ADD_SHIFT, TX_ADD_MASK); + } + else + { + osal_memcpy((uint8*)&g_tx_adv_buf.data[0], &ownRandomAddr[0], 6); + SET_BITS(g_tx_adv_buf.txheader, LL_DEV_ADDR_TYPE_RANDOM, TX_ADD_SHIFT, TX_ADD_MASK); + } + } + + g_tx_adv_buf.txheader |= (txAdd << RX_ADD_SHIFT & RX_ADD_MASK); + // AdvA, for SCAN REQ, it should identical to the ADV_IND/ADV_SCAN_IND + g_tx_adv_buf.data[6] = g_rx_adv_buf.data[0]; + g_tx_adv_buf.data[7] = g_rx_adv_buf.data[1]; + g_tx_adv_buf.data[8] = g_rx_adv_buf.data[2]; + g_tx_adv_buf.data[9] = g_rx_adv_buf.data[3]; + g_tx_adv_buf.data[10] = g_rx_adv_buf.data[4]; + g_tx_adv_buf.data[11] = g_rx_adv_buf.data[5]; + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(g_tx_adv_buf.txheader), + ((g_tx_adv_buf.txheader & 0xff00) >> 8) + 2); // payload length + header length(2) + bSendingScanReq = TRUE; + g_same_rf_channel_flag = FALSE; + } + } + } + + // convert pdu type to GAP enum + switch (pdu_type) + { + case ADV_IND: + advEventType = LL_ADV_RPT_ADV_IND; + break; + + case ADV_SCAN_IND: + advEventType = LL_ADV_RPT_ADV_SCANNABLE_IND; + break; + + case ADV_DIRECT_IND: + advEventType = LL_ADV_RPT_ADV_DIRECT_IND; + break; + + case ADV_NONCONN_IND: + advEventType = LL_ADV_RPT_ADV_NONCONN_IND; + break; + + case ADV_SCAN_RSP: + advEventType = LL_ADV_RPT_INVALID; + break; + + default: + advEventType = LL_ADV_RPT_ADV_IND; + break; + } + + rssi = -(pktFoot1 >> 24); + // below function cost 51us/66us(measure with GPIO) + LL_AdvReportCback( advEventType, // event type + addrType, // Adv address type (TxAdd) + &peerAddr[0], // Adv address (AdvA) + pktLen - 8, // length of rest of the payload, 2 - header, 6 - advA + &g_rx_adv_buf.data[6], // rest of payload + rssi ); // RSSI + g_pmCounters.ll_recv_adv_pkt_cnt ++; + } + } + else + { + // invalid ADV PDU type +// llSetupScan(); + } + } + + // if not waiting for scan rsp, schedule next scan + if (!bSendingScanReq) + { + // not sending SCAN REQ, update scan time + llScanTime += ((ISR_entry_time > llScanT1) ? (ISR_entry_time - llScanT1) : (BASE_TIME_UNITS - llScanT1 + ISR_entry_time)); + + if (llScanTime >= scanInfo.scanWindow * 625) + { + // calculate next scan channel + LL_CALC_NEXT_SCAN_CHN(scanInfo.nextScanChan); + + // schedule next scan event + if (scanInfo.scanWindow == scanInfo.scanInterval) // scanWindow == scanInterval, trigger immediately + LL_evt_schedule(); + else +// set_timer4((scanInfo.scanInterval - scanInfo.scanWindow) * 625); + ll_schedule_next_event((scanInfo.scanInterval - scanInfo.scanWindow) * 625); + + // reset scan total time + llScanTime = 0; + } + else + { +// AT_LOG("%03x %x %d %d %d %d\n",irq_status,*(volatile uint32_t *)(0x40031054),ll_hw_get_anchor(), +// g_rfifo_rst_cnt,(uint32_t)ISR_entry_time,read_current_fine_time()); + llSetupScan(scanInfo.nextScanChan); + } + } + } + // =========== initiator case + else if (llState == LL_STATE_INIT) + { + uint8 bConnecting = FALSE; + uint8 bMatchAdv = FALSE; // RPA checking OK in previous adv event, and new adv event identical to the old one + connPtr = &conn_param[initInfo.connId]; // connId is allocated when create conn + + // check status + if ((irq_status & LIRQ_RD) && (irq_status & LIRQ_COK)) // bug correct 2018-10-15 + { + // rx done + uint8_t packet_len, pdu_type; + uint16_t pktLen; + uint32_t pktFoot0, pktFoot1; + // read packet + // cost 21-26us(measure with GPIO), depneds on the length of ADV + packet_len = ll_hw_read_rfifo1((uint8_t*)(&(g_rx_adv_buf.rxheader)), + &pktLen, + &pktFoot0, + &pktFoot1); + // check receive pdu type + pdu_type = g_rx_adv_buf.rxheader & 0x0f; + + if(ll_hw_get_rfifo_depth() > 0) + { + g_pmCounters.ll_rfifo_read_err++; + packet_len=0; + pktLen=0; + } + + if (packet_len != 0 + && ((pdu_type == ADV_IND) || pdu_type == ADV_DIRECT_IND)) + { + uint8_t txAdd = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + uint8_t chSel = (g_rx_adv_buf.rxheader & CHSEL_MASK) >> CHSEL_SHIFT; + rpaListIndex = LL_RESOLVINGLIST_ENTRY_NUM; + peerAddr = &g_rx_adv_buf.data[0]; // AdvA + g_currentPeerAddrType = txAdd; + + // ================= Resolving list checking + // case 1: receive InitA using RPA + if (txAdd == LL_DEV_ADDR_TYPE_RANDOM && + ((g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR)) + { + bWlRlCheckOk = TRUE; + + if (g_llRlEnable == TRUE) + { + // if the RPA checking is done in previous scan, compare + if (isPeerRpaStore == TRUE && + currentPeerRpa[0] == g_rx_adv_buf.data[0] + && currentPeerRpa[1] == g_rx_adv_buf.data[1] + && currentPeerRpa[2] == g_rx_adv_buf.data[2] + && currentPeerRpa[3] == g_rx_adv_buf.data[3] + && currentPeerRpa[4] == g_rx_adv_buf.data[4] + && currentPeerRpa[5] == g_rx_adv_buf.data[5]) + { + rpaListIndex = storeRpaListIndex; + peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; + g_currentPeerAddrType = g_llResolvinglist[rpaListIndex].peerAddrType + 2; + bWlRlCheckOk = TRUE; + bMatchAdv = TRUE; + } + else // resolve the address + { + rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]); // spend 30us(48MHz) when the 1st item match + + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM) + { + peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; + g_currentPeerAddrType = g_llResolvinglist[rpaListIndex].peerAddrType + 2; + bWlRlCheckOk = TRUE; + } + else + { + bWlRlCheckOk = FALSE; + } + } + } + } + // case 2: receive InitA using device ID, or init device not using RPA + else + { + for (int i = 0; i < LL_RESOLVINGLIST_ENTRY_NUM; i++) + { + if ( g_llResolvinglist[i].peerAddr[0] == g_rx_adv_buf.data[0] + && g_llResolvinglist[i].peerAddr[1] == g_rx_adv_buf.data[1] + && g_llResolvinglist[i].peerAddr[2] == g_rx_adv_buf.data[2] + && g_llResolvinglist[i].peerAddr[3] == g_rx_adv_buf.data[3] + && g_llResolvinglist[i].peerAddr[4] == g_rx_adv_buf.data[4] + && g_llResolvinglist[i].peerAddr[5] == g_rx_adv_buf.data[5]) + { + // the device ID in the RPA list + if (g_llResolvinglist[i].privacyMode == NETWORK_PRIVACY_MODE && + !ll_isIrkAllZero(g_llResolvinglist[i].peerIrk)) + bWlRlCheckOk = FALSE; + else + rpaListIndex = i; + } + } + } + + // ====== for direct adv, also check initA == own addr + if (pdu_type == ADV_DIRECT_IND && bWlRlCheckOk == TRUE && bMatchAdv != TRUE) + { + //20201228,Jie,add RXADD check for direct IND + uint8_t rxAdd = (g_rx_adv_buf.rxheader & RX_ADD_MASK) >> RX_ADD_SHIFT; + + // initA is resolvable address case + if (rxAdd == LL_DEV_ADDR_TYPE_RANDOM &&((g_rx_adv_buf.data[11] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR)) + { + // should not use RPA case + if (initInfo.ownAddrType != LL_DEV_ADDR_TYPE_RPA_PUBLIC && initInfo.ownAddrType != LL_DEV_ADDR_TYPE_RPA_RANDOM) + bWlRlCheckOk = FALSE; + + if (rpaListIndex >= LL_RESOLVINGLIST_ENTRY_NUM + || (ll_isIrkAllZero(g_llResolvinglist[rpaListIndex].localIrk)) // all-0 local IRK + || (ll_ResolveRandomAddrs(g_llResolvinglist[rpaListIndex].localIrk, &g_rx_adv_buf.data[6]) != SUCCESS)) // resolve failed + bWlRlCheckOk = FALSE; + } + else + { + uint8* localAddr; + + // should not use device ID case + if ((initInfo.ownAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC || initInfo.ownAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM ) + && (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM + && !ll_isIrkAllZero(g_llResolvinglist[rpaListIndex].localIrk))) + { + bWlRlCheckOk = FALSE; + } + + if (rxAdd == LL_DEV_ADDR_TYPE_RANDOM) + localAddr = ownRandomAddr; + else + localAddr = ownPublicAddr; + + if (g_rx_adv_buf.data[6] != localAddr[0] + || g_rx_adv_buf.data[7] != localAddr[1] + || g_rx_adv_buf.data[8] != localAddr[2] + || g_rx_adv_buf.data[9] != localAddr[3] + || g_rx_adv_buf.data[10] != localAddr[4] + || g_rx_adv_buf.data[11] != localAddr[5]) + { + bWlRlCheckOk = FALSE; + } + } + } + + // initiator, 2 types of filter process: 1. connect to peer address set by host 2. connect to address in whitelist only + // 1. connect to peer address set by host + if (initInfo.wlPolicy == LL_INIT_WL_POLICY_USE_PEER_ADDR + && bWlRlCheckOk == TRUE) + { + if (peerAddr[0] != peerInfo.peerAddr[0] + || peerAddr[1] != peerInfo.peerAddr[1] + || peerAddr[2] != peerInfo.peerAddr[2] + || peerAddr[3] != peerInfo.peerAddr[3] + || peerAddr[4] != peerInfo.peerAddr[4] + || peerAddr[5] != peerInfo.peerAddr[5]) + { + // not match, not init connect + bWlRlCheckOk = FALSE; + } + } + // 2. connect to address in whitelist only + else if (initInfo.wlPolicy == LL_INIT_WL_POLICY_USE_WHITE_LIST && + bWlRlCheckOk == TRUE) + { + // if advA in whitelist list, connect + // check white list + bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr); + + //2020.10.26,Jie,update peer addr + if (bWlRlCheckOk == TRUE) + { + peerInfo.peerAddrType = txAdd; + peerInfo.peerAddr[0] = peerAddr[0]; + peerInfo.peerAddr[1] = peerAddr[1]; + peerInfo.peerAddr[2] = peerAddr[2]; + peerInfo.peerAddr[3] = peerAddr[3]; + peerInfo.peerAddr[4] = peerAddr[4]; + peerInfo.peerAddr[5] = peerAddr[5]; + } + } + + if (bWlRlCheckOk == TRUE) + { + g_same_rf_channel_flag = TRUE; + + // channel selection algorithm decision + if ((pGlobal_config[LL_SWITCH] & CONN_CSA2_ALLOW) + && chSel == LL_CHN_SEL_ALGORITHM_2) + { + conn_param[initInfo.connId].channel_selection = LL_CHN_SEL_ALGORITHM_2; + SET_BITS(g_tx_adv_buf.txheader, LL_CHN_SEL_ALGORITHM_2, CHSEL_SHIFT, CHSEL_MASK); + } + else + { + conn_param[initInfo.connId].channel_selection = LL_CHN_SEL_ALGORITHM_1; + SET_BITS(g_tx_adv_buf.txheader, LL_CHN_SEL_ALGORITHM_1, CHSEL_SHIFT, CHSEL_MASK); + } + + // calculate initA if using RPA list, otherwise copy the address stored in initInfo + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM && + !ll_isIrkAllZero(g_llResolvinglist[rpaListIndex].localIrk) && + (initInfo.ownAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC || initInfo.ownAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM)) + { + // for resolving private address case, calculate the scanA with Local IRK + ll_CalcRandomAddr(g_llResolvinglist[rpaListIndex].localIrk, &g_tx_adv_buf.data[0]); + SET_BITS(g_tx_adv_buf.txheader, LL_DEV_ADDR_TYPE_RANDOM, TX_ADD_SHIFT, TX_ADD_MASK); +// osal_memcpy( &g_currentLocalRpa[0], &g_tx_adv_buf.data[0], 6); + g_currentLocalAddrType = LL_DEV_ADDR_TYPE_RPA_RANDOM; + } + else + { + if (initInfo.ownAddrType == LL_DEV_ADDR_TYPE_PUBLIC || initInfo.ownAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC) + { + osal_memcpy((uint8*)&g_tx_adv_buf.data[0], &ownPublicAddr[0], 6); + SET_BITS(g_tx_adv_buf.txheader, LL_DEV_ADDR_TYPE_PUBLIC, TX_ADD_SHIFT, TX_ADD_MASK); + } + else + { + osal_memcpy((uint8*)&g_tx_adv_buf.data[0], &ownRandomAddr[0], 6); + SET_BITS(g_tx_adv_buf.txheader, LL_DEV_ADDR_TYPE_RANDOM, TX_ADD_SHIFT, TX_ADD_MASK); + } + + g_currentLocalAddrType = LL_DEV_ADDR_TYPE_RANDOM; // not accute local type, for branch selection in enh conn complete event + } + + // send conn req + T2 = read_current_fine_time(); + delay = (T2 > ISR_entry_time) ? (T2 - ISR_entry_time) : (BASE_TIME_UNITS - ISR_entry_time + T2); + + if (delay > 118 - pGlobal_config[LL_ADV_TO_CONN_REQ_DELAY] - pGlobal_config[LL_HW_PLL_DELAY]) // not enough time + { + // not enough time to send conn req, store the RPA + isPeerRpaStore = TRUE; + storeRpaListIndex = rpaListIndex; + osal_memcpy(¤tPeerRpa[0], &g_rx_adv_buf.data[0], 6); +// LOG("store %d\n", storeRpaListIndex); + g_same_rf_channel_flag = FALSE; + //LOG("<%d>", delay); + } + else + { + delay = 118 - delay - pGlobal_config[LL_ADV_TO_CONN_REQ_DELAY]; + ll_hw_set_trx_settle(delay, // set BB delay, about 80us in 16MHz HCLK + pGlobal_config[LL_HW_AFE_DELAY], + pGlobal_config[LL_HW_PLL_DELAY]); //RxAFE,PLL + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + // send conn req + ll_hw_set_stx(); // set LL HW as single Tx mode + ll_hw_go(); + llWaitingIrq = TRUE; + // AdvA, offset 6 + osal_memcpy((uint8*)&g_tx_adv_buf.data[6], &g_rx_adv_buf.data[0], 6); + //2020.8.11 Jie:add init req header for RxAdd + SET_BITS(g_tx_adv_buf.txheader, txAdd, RX_ADD_SHIFT, RX_ADD_MASK); + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(g_tx_adv_buf.txheader), + ((g_tx_adv_buf.txheader & 0xff00) >> 8) + 2); // payload length + header length(2) + + if (g_currentPeerAddrType >= 0x02) + osal_memcpy(&g_currentPeerRpa[0], &g_rx_adv_buf.data[0], 6); + + if (g_currentLocalAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM) + osal_memcpy( &g_currentLocalRpa[0], &g_tx_adv_buf.data[0], 6); + + move_to_master_function(); + isPeerRpaStore = FALSE; + bConnecting = TRUE; + g_same_rf_channel_flag = FALSE; + } + } + } + else if (packet_len != 0 + && (pdu_type == ADV_DIRECT_IND)) // TODO: add process of direct ADV + { + } + } + + // scan again if not start connect + if (!bConnecting) // if not waiting for scan rsp, schedule next scan + { + if (initInfo.scanMode == LL_SCAN_STOP) + { + // scan has been stopped + llState = LL_STATE_IDLE; // for single connection case, set the LL state idle + // release the associated allocated connection + llReleaseConnId(connPtr); // new for multi-connection + g_ll_conn_ctx.numLLMasterConns --; + (void)osal_set_event( LL_TaskID, LL_EVT_MASTER_CONN_CANCELLED ); // inform high layer + } + else + { + // not sending SCAN REQ, update scan time + llScanTime += ((ISR_entry_time > llScanT1) ? (ISR_entry_time - llScanT1) : (BASE_TIME_UNITS - llScanT1 + ISR_entry_time)); + + if (llScanTime >= initInfo.scanWindow * 625) + { + // calculate next scan channel + LL_CALC_NEXT_SCAN_CHN(initInfo.nextScanChan); + + // schedule next scan event + if (initInfo.scanWindow == initInfo.scanInterval) // scanWindow == scanInterval, trigger immediately + LL_evt_schedule(); + else +// set_timer4((initInfo.scanInterval - initInfo.scanWindow) * 625); + ll_schedule_next_event((initInfo.scanInterval - initInfo.scanWindow) * 625); + + // reset scan total time + llScanTime = 0; + } + else + llSetupScan(initInfo.nextScanChan); + } + } + } + } + + // post ISR process + if (!llWaitingIrq) // bug fixed 2018-05-04, only clear IRQ status when no config new one + ll_hw_clr_irq(); + + HAL_EXIT_CRITICAL_SECTION(); + return TRUE; +} + +uint8 llSetupStartEncRsp( llConnState_t* connPtr ) +{ + uint8 pktLen; + uint8* pBuf = connPtr->ctrlData.data; + // Note: No need to check if there's enough room in the TX FIFO since it was + // forced to empty prior to beginning encryption control procedure. + // write control type as payload + *pBuf = LL_CTRL_START_ENC_RSP; + // encrypt PDU with authentication check + LL_ENC_Encrypt( connPtr, + LL_DATA_PDU_HDR_LLID_CONTROL_PKT, + LL_START_ENC_RSP_PAYLOAD_LEN, + pBuf ); // input no-encrypt data pBuf, output in the same buffer + pktLen = LL_START_ENC_RSP_PAYLOAD_LEN + LL_ENC_MIC_LEN; + connPtr->ctrlDataIsPending = 1; + connPtr->ctrlData .header = pktLen << 8 | LL_DATA_PDU_HDR_LLID_CONTROL_PKT; + + // control procedure timeout value only needed for Master after Start Enc Response +// if ( llState == LL_STATE_CONN_MASTER ) + if( connPtr->llTbd1 != LL_LINK_CONNECT_COMPLETE_MASTER ) + { + // set the control packet timeout for 40s relative to our present time + // Note: This is done in terms of connection events. + // Note: Core Spec V4.0 now indicates that each LL control PDU that is queued + // for transmission resets the procedure response timeout timer. + connPtr->ctrlPktInfo.ctrlTimeout = connPtr->ctrlPktInfo.ctrlTimeoutVal; + } + + return( TRUE ); +} + +uint8 llProcessSlaveControlProcedures1( llConnState_t* connPtr ) +{ + // check if there are any control packets ready for processing + while ( connPtr->ctrlPktInfo.ctrlPktCount > 0 ) + { + // processing based on control packet type at the head of the queue + switch( connPtr->ctrlPktInfo.ctrlPkts[ 0 ] ) + { + case LL_CTRL_TERMINATE_IND: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // we have already place packet on TX FIFO, so check if its been ACK'ed + if ( rfCounters.numTxCtrlAck ) + { + // yes, so process the termination + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_HOST_REQUESTED_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else // no done yet + { + // check if a termination control procedure timeout has occurred + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else // no control procedure timeout yet + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupTermInd( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + // Note: Unreachable statement generates compiler warning! + //break; + + case LL_CTRL_ENC_RSP: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + // done with this control packet, so remove from the processing queue + // Note: By dequeueing here, it is possible to get another control + // packet at the head of the queue. This is techincally not + // supposed to happen if the spec is followed. + // ALT: COULD MAKE MORE BULLET PROOF. SINCE THE REPLACE ROUTINE + // CAN'T BE USED UNTIL THE LTK IS RECEIVED BY THE HOST, A + // DUMMY CONTROL PACKET THAT SITS AT THE HEAD UNTIL IT IS + // REPLACE COULD BE USED INSTEAD. + //llReplaceCtrlPkt( connPtr, LL_CTRL_DUMMY_PLACE_HOLDER ); + llDequeueCtrlPkt( connPtr ); + // notify the Host with RAND and EDIV after sending the RSP + // Note: Need to wait for the Host reply to determine if the LTK + // is available or not. + LL_EncLtkReqCback( connPtr->connId, + connPtr->encInfo.RAND, + connPtr->encInfo.EDIV ); + } + else // not done yet + { + // check if a update param req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupEncRsp( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_START_ENC_REQ: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This only means the packet has been transmitted, not that it + // has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + // enable encryption once start encryption request is sent + // Note: We can not receive data once the encryption control + // procedure has begun, so there is no risk of a race + // condition here. + connPtr->encEnabled = TRUE; + // clear packet counters + connPtr->encInfo.txPktCount = 0; + connPtr->encInfo.rxPktCount = 0; + } + + // not done until the LL_CTRL_START_ENC_RSP is received, so check it + // Note: The following code can not be in the previous "if" statement + // since it is possible that numTxCtrl could be true, yet the + // flag startEncRspRcved isn't. Then on the next event, + // numTxCtrl wouldn't be true, and we would never check the + // startEncRspRcved flag again. Since we can't get the + // LL_START_ENC_RSP until we send the LL_CTRL_START_ENC_REQ, + // this isn't an issue. + if ( connPtr->encInfo.startEncRspRcved == TRUE ) + { + // replace control procedure at head of queue to prevent interleaving + llReplaceCtrlPkt( connPtr, LL_CTRL_START_ENC_RSP ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // first, check if the SK has been calculated + if ( connPtr->encInfo.SKValid == TRUE ) + { + // so try to begin the last step of the encryption procedure + if ( llSetupStartEncReq( connPtr ) == TRUE ) + { + // ready the flag that indicates that we've received the response + connPtr->encInfo.startEncRspRcved = FALSE; + // the control packet is now active + connPtr->ctrlPktInfo.ctrlPktActive = TRUE; + } + + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrl. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrl, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + else // SK isn't valid yet, so see if we've received the LTK yet + { + if ( connPtr->encInfo.LTKValid ) + { + // generate the Session Key (i.e. SK = AES128(LTK, SKD)) + LL_ENC_GenerateSK( connPtr->encInfo.LTK, + connPtr->encInfo.SKD, + connPtr->encInfo.SK ); + // indicate the SK is valid, and drop through + connPtr->encInfo.SKValid = TRUE; + } + else // not done yet + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + + break; + + case LL_CTRL_START_ENC_RSP: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This only means the packet has been transmitted, not that it + // has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + // packet TX'ed, so we are done with the encryption procedure + // re-activate slave latency + connPtr->slaveLatency = connPtr->slaveLatencyValue; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + // set flag to allow outgoing data transmissions + connPtr->txDataEnabled = TRUE; + // okay to receive data again + connPtr->rxDataEnabled = TRUE; + + // notify the Host + if ( connPtr->encInfo.encRestart == TRUE ) + { + // a key change was requested + LL_EncKeyRefreshCback( connPtr->connId, + LL_ENC_KEY_REQ_ACCEPTED ); + } + else + { + // a new encryption was requested + LL_EncChangeCback( connPtr->connId, + LL_ENC_KEY_REQ_ACCEPTED, + LL_ENCRYPTION_ON ); + } + + // clear the restart flag in case of another key change request, + // and all other encryption flags + // Note: But in reality, there isn't a disable encryption in BLE, + // so once encryption is enabled, any call to LL_StartEncrypt + // will result in an encryption key change callback. + connPtr->encInfo.encRestart = FALSE; + connPtr->encInfo.encReqRcved = FALSE; + connPtr->encInfo.pauseEncRspRcved = FALSE; + connPtr->encInfo.startEncRspRcved = FALSE; + } + else // not done yet + { + // check if a update param req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupStartEncRsp( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_PAUSE_ENC_RSP: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // not done until the LL_CTRL_PAUSE_ENC_RSP is received, so check it + if ( connPtr->encInfo.pauseEncRspRcved == TRUE ) + { + // done with this control packet, so remove from the processing + // queue and drop through (so the encrypton response can be + // processed) + // ALT: COULD REPLACE HEAD OF QUEUE WITH DUMMY SO NO OTHER CONTROL + // PROCEDURE CAN INTERLEAVE BEFORE THE ENC_REQ IS RECEIVED. + llDequeueCtrlPkt( connPtr ); + } + else // not received yet, so decrement and check control procedure timeout + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there + // Note: All pending transmissions must also be finished before this + // packet is placed in the TX FIFO. + if ( llSetupPauseEncRsp( connPtr ) == TRUE ) + { + // clear the flag that indicates an Encryption Request has been + // received, which is used by this control procedure to restart the + // control procedure timeout + connPtr->encInfo.pauseEncRspRcved = FALSE; + // disable encryption + // Note: Not really necessary as no data is supposed to be sent + // or received. + connPtr->encEnabled = FALSE; + // the control packet is now active; drop through + connPtr->ctrlPktInfo.ctrlPktActive = TRUE; + } + else // not done yet + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + + break; + + case LL_CTRL_REJECT_IND: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This only means the packet has been transmitted, not that it + // has been ACK'ed or NACK'ed. + // Note: The control procedure does not end until the Reject is ACKed. + // However, if the ACK is a data packet, it will be tossed + // unless data is allowed hereafter. So to avoid this, only + // the confirmed transmission of this will be used to qualify + // the related flags, but a new procedure will not be able to + // begin until this procedure completes, per the spec. + if ( rfCounters.numTxCtrl ) + { + // disable encryption + // Note: Never really enabled so this isn't necessary. + connPtr->encEnabled = FALSE; + // set flag to allow outgoing data transmissions + connPtr->txDataEnabled = TRUE; + // okay to receive data again + connPtr->rxDataEnabled = TRUE; + } + + // we have already place packet on TX FIFO, so check if its been ACK'ed + if ( rfCounters.numTxCtrlAck ) + { + // done with this control packet, so remove from the processing + // queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not ack'ed yet + { + // check if a control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupRejectInd( connPtr,connPtr->encInfo.encRejectErrCode); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + // should be LL_CTRL_SLAVE_FEATURE_REQ +// case LL_CTRL_FEATURE_REQ: // for v4.2, slave may send LL_CTRL_FEATURE_REQ msg. to be test later......... HZF +// // check if the control packet procedure is active +// if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) +// { +// // we have already placed a packet on TX FIFO, so wait now until we +// // get the slave's LL_CTRL_FEATURE_RSP +// if ( connPtr->featureSetInfo.featureRspRcved == TRUE ) +// { +// // notify the Host +// LL_ReadRemoteUsedFeaturesCompleteCback( LL_STATUS_SUCCESS, +// connPtr->connId, +// connPtr->featureSetInfo.featureSet ); + +// // done with this control packet, so remove from the processing queue +// llDequeueCtrlPkt( connPtr ); +// } +// else // no done yet +// { +// // check if a update param req control procedure timeout has occurred +// // Note: No need to cleanup control packet info as we are done. +// if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) +// { +// // indicate a control procedure timeout on this request +// // Note: The parameters are not valid. +// LL_ReadRemoteUsedFeaturesCompleteCback( LL_CTRL_PKT_TIMEOUT_TERM, +// connPtr->connId, +// connPtr->featureSetInfo.featureSet ); +// // we're done waiting, so end it all +// // Note: No need to cleanup control packet info as we are done. +// llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_HOST_TERM ); + +// return( LL_CTRL_PROC_STATUS_TERMINATE ); +// } +// else +// { +// // control packet stays at head of queue, so exit here +// return( LL_CTRL_PROC_STATUS_SUCCESS ); +// } +// } +// } +// else // control packet has not been put on the TX FIFO yet +// { +// // so try to put it there; being active depends on a success +// connPtr->ctrlPktInfo.ctrlPktActive = llSetupFeatureSetReq( connPtr ); + +// // set flag while we wait for response +// // Note: It is okay to repeatedly set this flag in the event the +// // setup routine hasn't completed yet (e.g. if the TX FIFO +// // has not yet become empty). +// connPtr->featureSetInfo.featureRspRcved = FALSE; + +// // Note: Two cases are possible: +// // a) We successfully placed the packet in the TX FIFO. +// // b) We did not. +// // +// // In case (a), it may be possible that a previously just +// // completed control packet happened to complete based on +// // rfCounters.numTxCtrlAck. Since the current control +// // procedure is now active, it could falsely detect +// // rfCounters.numTxCtrlAck, when in fact this was from the +// // previous control procedure. Consequently, return. +// // +// // In case (b), the control packet stays at the head of the +// // queue, and there's nothing more to do. Consequently, return. +// // +// // So, in either case, return. +// return( LL_CTRL_PROC_STATUS_SUCCESS ); +// } + +// break; + + case LL_CTRL_FEATURE_RSP: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + // packet TX'ed, so use this flag on the Slave to indicate that + // the feature response procedure has already taken place on this + // connection + // Note: This is being done to support the HCI extension command + // LL_EXT_SetLocalSupportedFeatures so that the user can + // update the local supported features even after a connection + // is formed. This update will be used as long as a feature + // response feature has not been performed by the Master. Once + // performed, the connection feature set is fixed! + connPtr->featureSetInfo.featureRspRcved = TRUE; + // ALT: COULD RE-ACTIVATE SL (IF ENABLED) RIGHT HERE. + connPtr->slaveLatency = connPtr->slaveLatencyValue; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: There is no control procedure timeout associated with this + // control packet. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupFeatureSetRsp( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + // Version Information Indication + case LL_CTRL_VERSION_IND: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if the peer's version information is valid + if ( connPtr->verExchange.peerInfoValid == TRUE ) + { + // yes, so check if the host has requested this information + if ( connPtr->verExchange.hostRequest == TRUE ) + { + // yes, so provide it + LL_ReadRemoteVersionInfoCback( LL_STATUS_SUCCESS, + connPtr->connId, + connPtr->verInfo.verNum, + connPtr->verInfo.comId, + connPtr->verInfo.subverNum ); + } + + // in any case, dequeue this control procedure + llDequeueCtrlPkt( connPtr ); + } + else // no done yet + { + // check if a update param req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so complete the callback with error + LL_ReadRemoteVersionInfoCback( LL_CTRL_PKT_TIMEOUT_TERM, + connPtr->connId, + connPtr->verInfo.verNum, + connPtr->verInfo.comId, + connPtr->verInfo.subverNum ); + // and end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // since we are in the process of sending the version indication, + // it is okay to set this flag here even if it is set repeatedly + // in the of llSetupVersionIndReq failures + connPtr->verExchange.verInfoSent = TRUE; + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupVersionIndReq( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_LENGTH_REQ: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + connPtr->llPduLen.isWatingRsp=TRUE; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: There is no control procedure timeout associated with this + // control packet. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupDataLenghtReq( connPtr ); + connPtr->llPduLen.isWatingRsp=FALSE; + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_LENGTH_RSP: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + connPtr->llPduLen.isProcessingReq=FALSE; + llPduLengthUpdate((uint16)connPtr->connId); + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: There is no control procedure timeout associated with this + // control packet. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupDataLenghtRsp( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_PHY_REQ: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + connPtr->llPhyModeCtrl.isWatingRsp=TRUE; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: There is no control procedure timeout associated with this + // control packet. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupPhyReq( connPtr ); + connPtr->llPhyModeCtrl.isWatingRsp=FALSE; + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_PHY_RSP: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + connPtr->llPhyModeCtrl.isProcessingReq=FALSE; + connPtr->llPhyModeCtrl.isWatingRsp=TRUE; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: There is no control procedure timeout associated with this + // control packet. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupPhyRsp( connPtr ); + connPtr->llPhyModeCtrl.isWatingRsp=FALSE; + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_CTE_REQ: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + // connPtr->llPhyModeCtrl.isWatingRsp=TRUE; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + osal_memset( &(connPtr->llCTEModeCtrl), 0, sizeof( connPtr->llCTEModeCtrl )); + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + connPtr->ctrlPktInfo.ctrlPktActive = llSetupCTEReq( connPtr ); + connPtr->llCTEModeCtrl.isWatingRsp = TRUE; + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_CTE_RSP: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + connPtr->llCTEModeCtrl.isWatingRsp = FALSE; + connPtr->llCTEModeCtrl.isProcessingReq = FALSE; + // remove control packet from processing queue and drop through + // 2020-02-12 comment:after send CONN CTE RSP , then clear txSupp + ll_hw_set_cte_txSupp( CTE_SUPP_NULL); + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + } + } + else // control packet has not been put on the TX FIFO yet + { + connPtr->ctrlPktInfo.ctrlPktActive = llSetupCTERsp( connPtr ); + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_UNKNOWN_RSP: + + // try to place control packet in the TX FIFO + // Note: Since there are no dependencies for this control packet, we + // do not have to bother with the active flag. + if ( llSetupUnknownRsp( connPtr ) == TRUE ) + { + // all we have to do is put this control packet on the TX FIFO, so + // remove control packet from the processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + // Dummy Place Holder + //case LL_CTRL_DUMMY_PLACE_HOLDER: + // // dummy packet stays at head of queue, so exit here + // Note: Unreachable statement generates compiler warning! + //break; + // return( LL_CTRL_PROC_STATUS_SUCCESS ); + + default: + break; + } + } + + return( LL_CTRL_PROC_STATUS_SUCCESS ); +} + +uint8 llProcessMasterControlProcedures1( llConnState_t* connPtr ) +{ + // check if there are any control packets ready for processing + while ( connPtr->ctrlPktInfo.ctrlPktCount > 0 ) + { + // processing based on control packet type at the head of the queue + switch( connPtr->ctrlPktInfo.ctrlPkts[ 0 ] ) + { + case LL_CTRL_TERMINATE_IND: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // we have already place packet on TX FIFO, so check if its been ACK'ed + if ( rfCounters.numTxCtrlAck ) + { + // done with this control packet, so remove from the processing queue + llDequeueCtrlPkt( connPtr ); + // yes, so process the termination + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_HOST_REQUESTED_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else // no done yet + { + // check if a termination control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupTermInd( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + // Note: Unreachable statement generates compiler warning! + //break; + + /* + ** Connection Update Request + */ + case LL_CTRL_CONNECTION_UPDATE_REQ: + +// LOG("CONN UPD"); + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // we have already placed a packet on TX FIFO, so check if its been ACK'ed + if ( rfCounters.numTxCtrlAck ) + { + // yes, so adjust all time values to units of 625us + connPtr->paramUpdate.winSize <<= 1; + connPtr->paramUpdate.winOffset <<= 1; + connPtr->paramUpdate.connInterval <<= 1; + connPtr->paramUpdate.connTimeout <<= 4; + // and activate the update + connPtr->pendingParamUpdate = TRUE; + // done with this control packet, so remove from the processing queue + llDequeueCtrlPkt( connPtr ); + } + else // no done yet + { + // Core Spec V4.0 now indicates there is no control procedure + // timeout. However, it still seems prudent to monitor for the + // instant while waiting for the slave's ACK. + if ( connPtr->nextEvent == connPtr->paramUpdateEvent ) + { + // this event is the instant, and the control procedure still + // has not been ACK'ed, we the instant has passed + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_INSTANT_PASSED_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else // continue waiting for the slave's ACK + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupUpdateParamReq( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + /* + ** Channel Map Update Request + */ + case LL_CTRL_CHANNEL_MAP_REQ: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // we have already placed a packet on TX FIFO, so check if its been ACK'ed + if ( rfCounters.numTxCtrlAck ) + { + // yes, so activate the update + connPtr->pendingChanUpdate = TRUE; + // done with this control packet, so remove from the processing queue + llDequeueCtrlPkt( connPtr ); + } + else // no done yet + { + // Core Spec V4.0 now indicates there is no control procedure + // timeout. However, it still seems prudent to monitor for the + // instant while waiting for the slave's ACK. + if ( connPtr->nextEvent == connPtr->chanMapUpdateEvent ) + { + // this event is the instant, and the control procedure still + // has not been ACK'ed, we the instant has passed + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_INSTANT_PASSED_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else // continue waiting for the slave's ACK + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupUpdateChanReq( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + /* + ** Encryption Request + */ + case LL_CTRL_ENC_REQ: + +// LOG("1 ENC_REQ->"); + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + // set flag to discard all incoming data transmissions + connPtr->rxDataEnabled = FALSE; + } + + // we have already placed a packet on TX FIFO, so wait now until we + // get the slave's LL_START_ENC_REQ + if ( connPtr->encInfo.startEncReqRcved == TRUE ) + { + // clear packet counters + connPtr->encInfo.txPktCount = 0; + connPtr->encInfo.rxPktCount = 0; + // enable encryption + connPtr->encEnabled = TRUE; + // replace control procedure at head of queue to prevent interleaving + llReplaceCtrlPkt( connPtr, LL_CTRL_START_ENC_RSP ); + } + else if ( connPtr->encInfo.rejectIndRcved == TRUE ) + { + // the slave's Host has failed to provide an LTK, so the encryption + // setup has been rejected; end the start encryption procedure + // done with this control packet, so remove from the processing queue + llDequeueCtrlPkt( connPtr ); + // disable encryption + // Note: Not really necessary as no data is supposed to be sent + // or received. + connPtr->encEnabled = FALSE; + // set flag to allow outgoing transmissions again + connPtr->txDataEnabled = TRUE; + // set flag to allow all incoming data transmissions + connPtr->rxDataEnabled = TRUE; + + // check the rejection indication error code + if ( connPtr->encInfo.encRejectErrCode == LL_STATUS_ERROR_PIN_OR_KEY_MISSING ) + { + // notify the Host + LL_EncChangeCback( connPtr->connId, + LL_ENC_KEY_REQ_REJECTED, + LL_ENCRYPTION_OFF ); + } + else // LL_STATUS_ERROR_UNSUPPORTED_REMOTE_FEATURE + { + // notify the Host + LL_EncChangeCback( connPtr->connId, + LL_ENC_KEY_REQ_UNSUPPORTED_FEATURE, + LL_ENCRYPTION_OFF ); + } + } + else if ( connPtr->termInfo.termIndRcvd == TRUE ) + { + // the slave's Host has failed to provide an LTK, so the encryption + // setup has been rejected; end the start encryption procedure + // done with this control packet, so remove from the processing queue + llDequeueCtrlPkt( connPtr ); + } + else // no done yet + { + // check if a update param req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // notify the Host + if ( connPtr->encInfo.encRestart == TRUE ) + { + // a key change was requested + LL_EncKeyRefreshCback( connPtr->connId, + LL_CTRL_PKT_TIMEOUT_TERM ); + } + else + { + // a new encryption was requested + LL_EncChangeCback( connPtr->connId, + LL_CTRL_PKT_TIMEOUT_TERM, + LL_ENCRYPTION_OFF ); + } + + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupEncReq( connPtr ); + // set a flag to indicate we have received LL_START_ENC_REQ + // Note: The LL_ENC_RSP will be received first, which will result in + // the master calculating its IVm and SKDm, concatenating it + // with the slave's IVs and SKDs, and calculating the SK from + // the LTK and SKD. After that, we will receive the + // LL_START_ENC_REQ from the slave. So, it is okay to stay in + // this control procedure until LL_START_ENC_REQ is received. + // Note: It is okay to repeatedly set this flag in the event the + // setup routine hasn't completed yet (e.g. if the TX FIFO + // has not yet become empty). + connPtr->encInfo.startEncReqRcved = FALSE; + connPtr->encInfo.rejectIndRcved = FALSE; + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + /* + ** Encryption Start Response + */ + case LL_CTRL_START_ENC_RSP: + +// LOG("1 START_ENC_RSP->"); + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // we have already placed a packet on TX FIFO, so wait now until we + // get the slave's LL_START_ENC_RSP + if ( connPtr->encInfo.startEncRspRcved == TRUE ) + { + // done with this control packet, so remove from the processing queue + llDequeueCtrlPkt( connPtr ); + // we're done with encryption procedure, so clear flags + connPtr->encInfo.encReqRcved = FALSE; + connPtr->encInfo.pauseEncRspRcved = FALSE; + connPtr->encInfo.startEncReqRcved = FALSE; + connPtr->encInfo.startEncRspRcved = FALSE; + connPtr->encInfo.rejectIndRcved = FALSE; + } + else // no done yet + { + // check if a update param req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // notify the Host + if ( connPtr->encInfo.encRestart == TRUE ) + { + // a key change was requested + LL_EncKeyRefreshCback( connPtr->connId, + LL_CTRL_PKT_TIMEOUT_TERM ); + } + else + { + // a new encryption was requested + LL_EncChangeCback( connPtr->connId, + LL_CTRL_PKT_TIMEOUT_TERM, + LL_ENCRYPTION_OFF ); + } + + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: The llSetupStartEncRsp routine will *not* reset the control + // timeout value since the entire encryption procedure starts + // with the master sending the LL_ENC_REQ, and ends when the + // master receives the LL_START_ENC_RSP from the slave. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupStartEncRsp( connPtr ); + // set a flag to indicate we have received LL_START_ENC_RSP + // Note: It is okay to repeatedly set this flag in the event the + // setup routine hasn't completed yet (e.g. if the TX FIFO + // has not yet become empty). + connPtr->encInfo.startEncRspRcved = FALSE; + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + /* + ** Encryption Pause Request + */ + case LL_CTRL_PAUSE_ENC_REQ: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // we have already placed a packet on TX FIFO, so wait now until we + // get the slave's LL_PAUSE_ENC_RSP + if ( connPtr->encInfo.pauseEncRspRcved == TRUE ) + { + // disable encryption + connPtr->encEnabled = FALSE; + // replace control procedure at head of queue to prevent interleaving + llReplaceCtrlPkt( connPtr, LL_CTRL_PAUSE_ENC_RSP ); + } + else // no done yet + { + // check if a update param req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // notify the Host + if ( connPtr->encInfo.encRestart == TRUE ) + { + // a key change was requested + LL_EncKeyRefreshCback( connPtr->connId, + LL_CTRL_PKT_TIMEOUT_TERM ); + } + else + { + // a new encryption was requested + LL_EncChangeCback( connPtr->connId, + LL_CTRL_PKT_TIMEOUT_TERM, + LL_ENCRYPTION_OFF ); + } + + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: The llSetupStartEncRsp routine will *not* reset the control + // timeout value since the entire encryption procedure starts + // with the master sending the LL_ENC_REQ, and ends when the + // master receives the LL_START_ENC_RSP from the slave. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupPauseEncReq( connPtr ); + // set a flag to indicate we have received LL_START_ENC_RSP + // Note: It is okay to repeatedly set this flag in the event the + // setup routine hasn't completed yet (e.g. if the TX FIFO + // has not yet become empty). + connPtr->encInfo.pauseEncRspRcved = FALSE; + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + /* + ** Encryption Pause Response + */ + case LL_CTRL_PAUSE_ENC_RSP: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This only means the packet has been transmitted, not that it + // has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + // replace control procedure at head of queue to prevent interleaving + llReplaceCtrlPkt( connPtr, LL_CTRL_ENC_REQ ); + } + else // no done yet + { + // check if a update param req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // notify the Host + if ( connPtr->encInfo.encRestart == TRUE ) + { + // a key change was requested + LL_EncKeyRefreshCback( connPtr->connId, + LL_CTRL_PKT_TIMEOUT_TERM ); + } + else + { + // a new encryption was requested + LL_EncChangeCback( connPtr->connId, + LL_CTRL_PKT_TIMEOUT_TERM, + LL_ENCRYPTION_OFF ); + } + + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupPauseEncRsp( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + /* + ** Feature Set Request + */ + case LL_CTRL_FEATURE_REQ: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // we have already placed a packet on TX FIFO, so wait now until we + // get the slave's LL_CTRL_FEATURE_RSP + if ( connPtr->featureSetInfo.featureRspRcved == TRUE ) + { + // notify the Host + LL_ReadRemoteUsedFeaturesCompleteCback( LL_STATUS_SUCCESS, + connPtr->connId, + connPtr->featureSetInfo.featureSet ); + // done with this control packet, so remove from the processing queue + llDequeueCtrlPkt( connPtr ); + } + else // no done yet + { + // check if a update param req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // indicate a control procedure timeout on this request + // Note: The parameters are not valid. + LL_ReadRemoteUsedFeaturesCompleteCback( LL_CTRL_PKT_TIMEOUT_TERM, + connPtr->connId, + connPtr->featureSetInfo.featureSet ); + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // add by HZF, read device feature set + for (int i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupFeatureSetReq( connPtr ); + // set flag while we wait for response + // Note: It is okay to repeatedly set this flag in the event the + // setup routine hasn't completed yet (e.g. if the TX FIFO + // has not yet become empty). + connPtr->featureSetInfo.featureRspRcved = FALSE; + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_FEATURE_RSP: // new for BLE4.2, feature req could be init by slave + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + // packet TX'ed, so use this flag on the Slave to indicate that + // the feature response procedure has already taken place on this + // connection + // Note: This is being done to support the HCI extension command + // LL_EXT_SetLocalSupportedFeatures so that the user can + // update the local supported features even after a connection + // is formed. This update will be used as long as a feature + // response feature has not been performed by the Master. Once + // performed, the connection feature set is fixed! + connPtr->featureSetInfo.featureRspRcved = TRUE; + // ALT: COULD RE-ACTIVATE SL (IF ENABLED) RIGHT HERE. +// connPtr->slaveLatency = connPtr->slaveLatencyValue; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: There is no control procedure timeout associated with this + // control packet. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupFeatureSetRsp( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + /* + ** Vendor Information Exchange (Request or Reply) + */ + case LL_CTRL_VERSION_IND: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if the peer's version information is valid + if ( connPtr->verExchange.peerInfoValid == TRUE ) + { + // yes, so check if the host has requested this information + if ( connPtr->verExchange.hostRequest == TRUE ) + { + // yes, so provide it + LL_ReadRemoteVersionInfoCback( LL_STATUS_SUCCESS, + connPtr->connId, + connPtr->verInfo.verNum, + connPtr->verInfo.comId, + connPtr->verInfo.subverNum ); + } + + // in any case, dequeue this control procedure + llDequeueCtrlPkt( connPtr ); + } + else // no done yet + { + // check if a update param req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so complete the callback with error + LL_ReadRemoteVersionInfoCback( LL_CTRL_PKT_TIMEOUT_TERM, + connPtr->connId, + connPtr->verInfo.verNum, + connPtr->verInfo.comId, + connPtr->verInfo.subverNum ); + // and end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // since we are in the process of sending the version indication, + // it is okay to set this flag here even if it is set repeatedly + // in the of llSetupVersionIndReq failures + connPtr->verExchange.verInfoSent = TRUE; +// // so try to put it there; being active depends on a success +// connPtr->ctrlPktInfo.ctrlPktActive = llSetupPingReq(connPtr);// llSetupVersionIndReq( connPtr ); + connPtr->ctrlPktInfo.ctrlPktActive = llSetupVersionIndReq( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_LENGTH_REQ: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + connPtr->llPduLen.isWatingRsp=TRUE; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: There is no control procedure timeout associated with this + // control packet. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupDataLenghtReq( connPtr ); + connPtr->llPduLen.isWatingRsp=FALSE; + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_LENGTH_RSP: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + connPtr->llPduLen.isProcessingReq=FALSE; + llPduLengthUpdate((uint16)connPtr->connId); + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: There is no control procedure timeout associated with this + // control packet. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupDataLenghtRsp( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + // LL PHY UPDATE REQ + case LL_CTRL_PHY_REQ: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + connPtr->llPhyModeCtrl.isWatingRsp=TRUE; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + // Note: There is no control procedure timeout associated with this + // control packet. + connPtr->ctrlPktInfo.ctrlPktActive = llSetupPhyReq( connPtr ); + connPtr->llPhyModeCtrl.isWatingRsp=FALSE; + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_PHY_UPDATE_IND: + + // check if the control packet procedure is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // we have already placed a packet on TX FIFO, so check if its been ACK'ed + if ( rfCounters.numTxCtrlAck ) + { + //20181206 ZQ phy update no change case + if( connPtr->phyUpdateInfo.m2sPhy== 0 + && connPtr->phyUpdateInfo.s2mPhy== 0) + { + connPtr->phyUpdateInfo.m2sPhy=connPtr->llPhyModeCtrl.local.txPhy; + connPtr->phyUpdateInfo.s2mPhy=connPtr->llPhyModeCtrl.local.rxPhy; + llPhyModeCtrlUpdateNotify(connPtr,LL_STATUS_SUCCESS); + } + else + { + // yes, so activate the update + connPtr->pendingPhyModeUpdate = TRUE; + } + + connPtr->llPhyModeCtrl.isWatingRsp=FALSE; + connPtr->llPhyModeCtrl.isProcessingReq=FALSE; + // done with this control packet, so remove from the processing queue + llDequeueCtrlPkt( connPtr ); + } + else // no done yet + { + // Core Spec V4.0 now indicates there is no control procedure + // timeout. However, it still seems prudent to monitor for the + // instant while waiting for the slave's ACK. + if ( connPtr->nextEvent == connPtr->phyModeUpdateEvent ) + { + // this event is the instant, and the control procedure still + // has not been ACK'ed, we the instant has passed + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_INSTANT_PASSED_HOST_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else // continue waiting for the slave's ACK + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + // so try to put it there; being active depends on a success + connPtr->ctrlPktInfo.ctrlPktActive = llSetupPhyUpdateInd( connPtr ); + // Note: Two cases are possible: + // a) We successfully placed the packet in the TX FIFO. + // b) We did not. + // + // In case (a), it may be possible that a previously just + // completed control packet happened to complete based on + // rfCounters.numTxCtrlAck. Since the current control + // procedure is now active, it could falsely detect + // rfCounters.numTxCtrlAck, when in fact this was from the + // previous control procedure. Consequently, return. + // + // In case (b), the control packet stays at the head of the + // queue, and there's nothing more to do. Consequently, return. + // + // So, in either case, return. + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + // REJECT EXT IND --> PHY UPDATE COLLSION + case LL_CTRL_REJECT_EXT_IND: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + connPtr->isCollision=TRUE; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // check if a start enc req control procedure timeout has occurred + // Note: No need to cleanup control packet info as we are done. + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + if(connPtr->llPhyModeCtrl.isWatingRsp==TRUE) + { + connPtr->ctrlPktInfo.ctrlPktActive = llSetupRejectExtInd( connPtr,LL_STATUS_ERROR_LL_PROCEDURE_COLLISION); + } + else if(connPtr->pendingChanUpdate==TRUE || + connPtr->pendingParamUpdate==TRUE ) + { + connPtr->ctrlPktInfo.ctrlPktActive = llSetupRejectExtInd( connPtr,LL_STATUS_ERROR_DIFF_TRANSACTION_COLLISION); + } + else if( connPtr->llCTEModeCtrl.isWatingRsp == TRUE) + { + // 2020-01-23 add for CTE + connPtr->ctrlPktInfo.ctrlPktActive = llSetupRejectExtInd( connPtr,connPtr->llCTEModeCtrl.errorCode ); + connPtr->llCTEModeCtrl.errorCode = LL_STATUS_SUCCESS; + } + else + { + //should not be here + } + + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_CTE_REQ: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + // connPtr->llCTEModeCtrl.isWatingRsp = TRUE; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // + if ( --connPtr->ctrlPktInfo.ctrlTimeout == 0 ) + { + osal_memset( &(connPtr->llCTEModeCtrl), 0, sizeof( connPtr->llCTEModeCtrl )); + // we're done waiting, so end it all + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, LL_CTRL_PKT_TIMEOUT_PEER_TERM ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + else + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + } + } + else // control packet has not been put on the TX FIFO yet + { + connPtr->ctrlPktInfo.ctrlPktActive = llSetupCTEReq( connPtr ); + connPtr->llCTEModeCtrl.isWatingRsp = TRUE; + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + case LL_CTRL_CTE_RSP: + + // check if the control packet procedure is is active + if ( connPtr->ctrlPktInfo.ctrlPktActive == TRUE ) + { + // yes, so check if it has been transmitted yet + // Note: This does not mean this packet has been ACK'ed or NACK'ed. + if ( rfCounters.numTxCtrl ) + { + connPtr->llCTEModeCtrl.isProcessingReq = FALSE; + // remove control packet from processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + } + else // control packet has not been put on the TX FIFO yet + { + connPtr->ctrlPktInfo.ctrlPktActive = llSetupCTERsp( connPtr ); + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + /* + ** Unknown Control Type Response + */ + case LL_CTRL_UNKNOWN_RSP: + + // try to place control packet in the TX FIFO + // Note: Since there are no dependencies for this control packet, we + // do not have to bother with the active flag. + if ( llSetupUnknownRsp( connPtr ) == TRUE ) + { + // all we have to do is put this control packet on the TX FIFO, so + // remove control packet from the processing queue and drop through + llDequeueCtrlPkt( connPtr ); + } + else // not done yet + { + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + } + + break; + + /* + ** Control Internal - Wait for Control ACK + */ + case LL_CTRL_TERMINATE_RX_WAIT_FOR_TX_ACK: + + // check if the control packet has been ACK'ed (i.e. is not pending) + // Note: Normally this routine is used for control procedures where + // control packets are sent by this role. This is a special case + // where a terminate indication was received, but we must as a + // master wait for our ACK to be sent before terminating. + if ( rfCounters.numTxCtrlAck == 1) // ctrl packet has been acked + { + // yes, so terminate + // Note: No need to cleanup control packet info as we are done. + llConnTerminate( connPtr, connPtr->termInfo.reason ); + return( LL_CTRL_PROC_STATUS_TERMINATE ); + } + + // control packet stays at head of queue, so exit here + return( LL_CTRL_PROC_STATUS_SUCCESS ); + + // Note: Unreachable statement generates compiler warning! + //break; + + // Dummy Place Holder + //case LL_CTRL_DUMMY_PLACE_HOLDER: + // // dummy packet stays at head of queue, so exit here + // return( LL_CTRL_PROC_STATUS_SUCCESS ); + // Note: Unreachable statement generates compiler warning! + //break; + default: + #ifdef DEBUG + // fatal error - a unknown control procedure value was used + LL_ASSERT( FALSE ); + #endif // DEBUG + break; + } + } + + return( LL_CTRL_PROC_STATUS_SUCCESS ); +} + +static void llAdjBoffUpperLimitFailure1( void ) +{ + // first, since this was a failure, clear the number of consecutive successes + scanInfo.numSuccess = 0; + + // check if we received two failures in a row + if ( ++scanInfo.numFailure == 2 ) + { + // yes, so double backoff upper limit + scanInfo.scanBackoffUL <<= 1; + + // maximum is 256 + if ( scanInfo.scanBackoffUL > 256 ) + { + scanInfo.scanBackoffUL = 256; + } + + // reset consecutive count + scanInfo.numFailure = 0; + } + + g_pmCounters.ll_tbd_cnt4++; + return; +} + +static void llAdjBoffUpperLimitSuccess1( void ) +{ + // first, since this is a success, clear the number of consecutive failures + scanInfo.numFailure = 0; + + // check if we received two successful in a row + if ( ++scanInfo.numSuccess == 2 ) + { + // yes, so half backoff upper limit + scanInfo.scanBackoffUL >>= 1; + + // however, the minimum is 1 + if ( scanInfo.scanBackoffUL == 0 ) + { + scanInfo.scanBackoffUL = 1; + } + + // reset consecutive count + scanInfo.numSuccess = 0; + } + + return; +} + +static void llGenerateNextBackoffCount1( void ) +{ + // determine the new backoff count constrained by upper limit + // Note: Backoff and Upper Limit can be 1..256. + if ( scanInfo.scanBackoffUL == 1 ) + { + scanInfo.currentBackoff = 1; + } + else // backoff count is a random number from 1..UL + { + scanInfo.currentBackoff = ((uint16)LL_ENC_GeneratePseudoRandNum() % scanInfo.scanBackoffUL) + 1; + } + +// hal_uart_tx("scanBackoffUL = "); +// hal_uart_send_int(scanInfo.scanBackoffUL); +// hal_uart_tx(",currentBackoff = "); +// hal_uart_send_int(scanInfo.currentBackoff); +// hal_uart_tx("\r\n"); + return; +} + +uint8 ll_processBasicIRQ_ScanTRX0(uint32_t irq_status ) +{ + HAL_ENTER_CRITICAL_SECTION(); + ll_debug_output(DEBUG_LL_HW_TRX); + llScanTime += ((ISR_entry_time > llScanT1) ? (ISR_entry_time - llScanT1) : (BASE_TIME_UNITS - llScanT1 + ISR_entry_time)); + + // check whether receives SCAN RSP + if (irq_status & LIRQ_COK) // bug correct 2018-10-15 + { + // rx done + uint8_t packet_len, pdu_type; + uint16_t pktLen; + uint32_t pktFoot0, pktFoot1; + // read packet + packet_len = ll_hw_read_rfifo1((uint8_t*)(&(g_rx_adv_buf.rxheader)), + &pktLen, + &pktFoot0, + &pktFoot1); + // check receive pdu type + pdu_type = g_rx_adv_buf.rxheader & 0x0f; + + if(ll_hw_get_rfifo_depth()>0) + { + g_pmCounters.ll_rfifo_read_err++; + packet_len=0; + pktLen=0; + } + + if (packet_len > 0 && pdu_type == ADV_SCAN_RSP) + { + // receives SCAN_RSP + uint8 advEventType; + uint8 rpaListIndex; + uint8* peerAddr; + uint8 addrType = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; + uint8 dataLen = pktLen - 8; + int8 rssi = -(pktFoot1 >> 24); + uint8 bCheckOk = TRUE; + peerAddr = &g_rx_adv_buf.data[0]; + + //=== + // AdvA of SCAN_RSP should also be checked here. Refer to 4.4.3.2 Active Scanning + // After sending a scan request PDU the Link Layer listens for a scan response + //PDU from that advertiser. If the scan response PDU was not received from that + //advertiser, it is considered a failure; otherwise it is considered a success. + + // check AdvA in Scan Rsp is identical to Scan Req + if (g_rx_adv_buf.data[0] != g_tx_adv_buf.data[6] || + g_rx_adv_buf.data[1] != g_tx_adv_buf.data[7] || + g_rx_adv_buf.data[2] != g_tx_adv_buf.data[8] || + g_rx_adv_buf.data[3] != g_tx_adv_buf.data[9] || + g_rx_adv_buf.data[4] != g_tx_adv_buf.data[10] || + g_rx_adv_buf.data[5] != g_tx_adv_buf.data[11] + ) + bCheckOk = FALSE; + + // RPA checking. Note that we do not check whether it is the same RPA index + if (addrType == LL_DEV_ADDR_TYPE_RANDOM && + (g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) + { + if (g_llRlEnable == TRUE) + { + rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]); + + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM) + { + peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; + // refer to HCI LE Advertising Report Event, RPA address type should be + // 0x02: Public Identity Address (Corresponds to Resolved Private Address) + // 0x03: Random (static) Identity Address (Corresponds to Resolved Private Address) + addrType = g_llResolvinglist[rpaListIndex].peerAddrType + 2; + bCheckOk = TRUE; + } + else + bCheckOk = FALSE; + } + } + + //=== + + if (bCheckOk == TRUE) + { + advEventType = LL_ADV_RPT_SCAN_RSP; + // below function cost 51us/66us(measure with GPIO) + LL_AdvReportCback( advEventType, // event type + addrType, // Adv address type (TxAdd) + peerAddr, // Adv address (AdvA) + dataLen, // length of rest of the payload + &g_rx_adv_buf.data[6], // rest of payload + rssi ); // RSSI + g_pmCounters.ll_recv_scan_rsp_cnt ++; + llAdjBoffUpperLimitSuccess1(); + } + } + else + llAdjBoffUpperLimitFailure1(); + } + else + llAdjBoffUpperLimitFailure1(); + + // update back off value according to new backoff upperLimit + llGenerateNextBackoffCount1(); + + if (llScanTime >= scanInfo.scanWindow * 625) + { + // calculate next scan channel + LL_CALC_NEXT_SCAN_CHN(scanInfo.nextScanChan); + + // schedule next scan event + if (scanInfo.scanWindow == scanInfo.scanInterval) // scanWindow == scanInterval, trigger immediately + LL_evt_schedule(); + else +// set_timer4((scanInfo.scanInterval - scanInfo.scanWindow) * 625); + ll_schedule_next_event((scanInfo.scanInterval - scanInfo.scanWindow) * 625); + + // reset scan total time + llScanTime = 0; + } + else + llSetupScan(scanInfo.nextScanChan); + + // post ISR process + if (!llWaitingIrq) // bug fixed 2018-05-04, only clear IRQ status when no config new one + ll_hw_clr_irq(); + + HAL_EXIT_CRITICAL_SECTION(); + return TRUE; +} + +uint8 ll_processBasicIRQ_secondaryAdvTRX0(uint32_t irq_status ) +{ + HAL_ENTER_CRITICAL_SECTION(); + uint32_t T2, delay; +// secondary adv state, connectable adv or scannable adv + uint8_t packet_len, pdu_type, txAdd; + uint16_t pktLen; + uint32_t pktFoot0, pktFoot1; + int calibra_time; // this parameter will be provided by global_config + //int i; + // 2021-02-23 + // bugfix for multi-role secondary advertising + // bug-case : a device in advertising and receive another device's scan request + uint8 adv_sch_flag = TRUE; + // read packet + packet_len = ll_hw_read_rfifo((uint8_t*)(&(g_rx_adv_buf.rxheader)), + &pktLen, + &pktFoot0, + &pktFoot1); + + if(ll_hw_get_rfifo_depth() > 0) + { + g_pmCounters.ll_rfifo_read_err++; + packet_len=0; + pktLen=0; + } + + // check receive pdu type + pdu_type = g_rx_adv_buf.rxheader & PDU_TYPE_MASK; + txAdd = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + + if (packet_len > 0 // any better checking rule for rx anything? + && (irq_status & LIRQ_COK) + && pdu_type == ADV_SCAN_REQ) +// && (llState == LL_STATE_ADV_UNDIRECTED +// || llState == LL_STATE_ADV_SCAN)) + { + // 1. scan req + g_pmCounters.ll_recv_scan_req_cnt ++; + + // check AdvA + if (g_rx_adv_buf.data[6] != adv_param.ownAddr[0] + || g_rx_adv_buf.data[7] != adv_param.ownAddr[1] + || g_rx_adv_buf.data[8] != adv_param.ownAddr[2] + || g_rx_adv_buf.data[9] != adv_param.ownAddr[3] + || g_rx_adv_buf.data[10] != adv_param.ownAddr[4] + || g_rx_adv_buf.data[11] != adv_param.ownAddr[5]) + { + } + else + { +//=== + uint8_t rpaListIndex, bWlRlCheckOk; + uint8_t* peerAddr = &g_rx_adv_buf.data[0]; // ScanA + adv_sch_flag = FALSE; + + // === Resolving list checking + if (txAdd == LL_DEV_ADDR_TYPE_RANDOM + && (g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) + { + bWlRlCheckOk = TRUE; + + // if ScanA is resolvable private address + if (g_llRlEnable == TRUE) + { + bWlRlCheckOk = FALSE; + rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]); + + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM) + { + peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; + bWlRlCheckOk = TRUE; + } + } + } + else // ScanA is device Identity, if the device ID in the RPA list, check whether RPA should be used + { + bWlRlCheckOk = TRUE; + + for (int i = 0; i < LL_RESOLVINGLIST_ENTRY_NUM; i++) + { + if (g_llResolvinglist[i].peerAddr[0] == g_rx_adv_buf.data[0] + && g_llResolvinglist[i].peerAddr[1] == g_rx_adv_buf.data[1] + && g_llResolvinglist[i].peerAddr[2] == g_rx_adv_buf.data[2] + && g_llResolvinglist[i].peerAddr[3] == g_rx_adv_buf.data[3] + && g_llResolvinglist[i].peerAddr[4] == g_rx_adv_buf.data[4] + && g_llResolvinglist[i].peerAddr[5] == g_rx_adv_buf.data[5] + && g_llResolvinglist[i].peerAddrType == txAdd) + { + if (g_llResolvinglist[i].privacyMode == NETWORK_PRIVACY_MODE && + !ll_isIrkAllZero(g_llResolvinglist[i].peerIrk)) + bWlRlCheckOk = FALSE; + + break; + } + } + } + + // === check white list + if ((pGlobal_config[LL_SWITCH] & LL_WHITELIST_ALLOW) + && (adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_SCAN_REQ + || adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_ALL_REQ) + && (bWlRlCheckOk == TRUE)) + { + // check white list + bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr); + } + + if (bWlRlCheckOk == FALSE) // if not in white list, do nothing + { + g_pmCounters.ll_filter_scan_req_cnt ++; + } + else + { + g_pmCounters.ll_rx_peer_cnt++; + uint8 retScanRspFilter=1; + + if(LL_PLUS_ScanRequestFilterCBack) + { + retScanRspFilter = LL_PLUS_ScanRequestFilterCBack(); + } + + if(retScanRspFilter) + { + // send scan rsp + ll_hw_set_stx(); // set LL HW as single Tx mode + g_same_rf_channel_flag = TRUE; + // calculate the delay + T2 = read_current_fine_time(); + delay = (T2 > ISR_entry_time) ? (T2 - ISR_entry_time) : (BASE_TIME_UNITS - ISR_entry_time + T2); + calibra_time = pGlobal_config[SCAN_RSP_DELAY]; // consider rx_done to ISR time, SW delay after read_current_fine_time(), func read_current_fine_time() delay ... + delay = 118 - delay - calibra_time; // IFS = 150us, Tx tail -> Rx done time: about 32us + ll_hw_set_trx_settle(delay, // set BB delay, about 80us in 16MHz HCLK + pGlobal_config[LL_HW_AFE_DELAY], + pGlobal_config[LL_HW_PLL_DELAY]); //RxAFE,PLL + ll_hw_go(); + llWaitingIrq = TRUE; + g_same_rf_channel_flag = FALSE; + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(tx_scanRsp_desc.txheader), + ((tx_scanRsp_desc.txheader & 0xff00) >> 8) + 2); // payload length + header length(2) + ll_debug_output(DEBUG_LL_HW_SET_STX); + g_pmCounters.ll_send_scan_rsp_cnt ++; + } + } + } + } + else if (pdu_type == ADV_CONN_REQ + && (irq_status & LIRQ_COK) ) +// && (llState == LL_STATE_ADV_UNDIRECTED +// || llState == LL_STATE_ADV_DIRECTED)) + { + uint8_t* peerAddr; + uint8_t bWlRlCheckOk = TRUE; + // 2. connect req + g_pmCounters.ll_recv_conn_req_cnt ++; + + // check AdvA + if (g_rx_adv_buf.data[6] != adv_param.ownAddr[0] + || g_rx_adv_buf.data[7] != adv_param.ownAddr[1] + || g_rx_adv_buf.data[8] != adv_param.ownAddr[2] + || g_rx_adv_buf.data[9] != adv_param.ownAddr[3] + || g_rx_adv_buf.data[10] != adv_param.ownAddr[4] + || g_rx_adv_buf.data[11] != adv_param.ownAddr[5]) + { + // nothing to do + } + else + { + uint8_t rpaListIndex = LL_RESOLVINGLIST_ENTRY_NUM; + peerAddr = &g_rx_adv_buf.data[0]; // initA + adv_sch_flag = FALSE; + + // ====== check Resolving list + if (txAdd == LL_DEV_ADDR_TYPE_RANDOM && + (g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) + { + bWlRlCheckOk = TRUE; + + if (g_llRlEnable == TRUE) + { + bWlRlCheckOk = FALSE; + rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]); + + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM) + { + // save resolved peer address + peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; + // if resolved address success, map the peer address type to 0x02 or 0x03 + g_currentPeerAddrType = g_llResolvinglist[rpaListIndex].peerAddrType + 2; + osal_memcpy( &g_currentPeerRpa[0], &g_rx_adv_buf.data[0], 6); // save latest peer RPA + bWlRlCheckOk = TRUE; + } + } + } + else // InitA is device Identity, check whether the device Addr in the RPA list, if it is + { + // in the RPA list and network privacy mode is selected and non all-0 IRK, check failed + bWlRlCheckOk = TRUE; + + for (int i = 0; i < LL_RESOLVINGLIST_ENTRY_NUM; i++) + { + if (g_llResolvinglist[i].peerAddr[0] == g_rx_adv_buf.data[0] + && g_llResolvinglist[i].peerAddr[1] == g_rx_adv_buf.data[1] + && g_llResolvinglist[i].peerAddr[2] == g_rx_adv_buf.data[2] + && g_llResolvinglist[i].peerAddr[3] == g_rx_adv_buf.data[3] + && g_llResolvinglist[i].peerAddr[4] == g_rx_adv_buf.data[4] + && g_llResolvinglist[i].peerAddr[5] == g_rx_adv_buf.data[5] + && g_llResolvinglist[i].peerAddrType == txAdd) + { + if (g_llResolvinglist[i].privacyMode == NETWORK_PRIVACY_MODE && + !ll_isIrkAllZero(g_llResolvinglist[i].peerIrk)) + bWlRlCheckOk = FALSE; + + break; + } + } + } + + // ====== check white list + if ((pGlobal_config[LL_SWITCH] & LL_WHITELIST_ALLOW) + && (llState == LL_STATE_ADV_UNDIRECTED) + && (adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_CONNECT_REQ + || adv_param.wlPolicy == LL_ADV_WL_POLICY_WL_ALL_REQ) + && (bWlRlCheckOk == TRUE)) + { + // check white list + bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr); + } + + // fixed bug 2018-09-25, LL/CON/ADV/BV-04-C, for direct adv, initA should equal peer Addr + if (llState == LL_STATE_ADV_DIRECTED) + { + if (//txAdd != peerInfo.peerAddrType // for (extended) set adv param, peer addr type could only be 0x0 or 0x01 + peerAddr[0] != peerInfo.peerAddr[0] + || peerAddr[1] != peerInfo.peerAddr[1] + || peerAddr[2] != peerInfo.peerAddr[2] + || peerAddr[3] != peerInfo.peerAddr[3] + || peerAddr[4] != peerInfo.peerAddr[4] + || peerAddr[5] != peerInfo.peerAddr[5]) + { + bWlRlCheckOk = FALSE; + } + } + + if (bWlRlCheckOk == FALSE) // if not in white list, do nothing + { + g_pmCounters.ll_filter_conn_req_cnt ++; + } + else + { + // increment statistics counter + g_pmCounters.ll_rx_peer_cnt++; + // bug fixed 2018-01-23, peerAddrType should read TxAdd + peerInfo.peerAddrType = txAdd; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + osal_memcpy(peerInfo.peerAddr, &peerAddr[0], 6); + move_to_slave_function(); // move to slave role for connection state + } + } + } + + //test for fast adv +// else //if(llState == LL_STATE_ADV_UNDIRECTED) + if( adv_sch_flag ) + { + // adv in next channel, or schedule next adv event + uint8 i = 0; + + while (!(adv_param.advChanMap & (1 << i))) i ++; // get the 1st adv channel + + // adv_param.advNextChan stores the next adv channel, when adv the last adv channel, advNextChan should equal 1st adv channel + if (adv_param.advNextChan != (LL_ADV_CHAN_FIRST + i)) // not finish adv the last channel, continue adv + { + llSetupSecAdvEvt(); + } + else + { + if (llSecondaryState == LL_SEC_STATE_IDLE_PENDING) // advertise last channel and transiting to IDLE + llSecondaryState = LL_SEC_STATE_IDLE; + else // otherwise, schedule next adv + osal_start_timerEx(LL_TaskID, LL_EVT_SECONDARY_ADV, (adv_param.advInterval * 5) >> 3); // * 625 / 1000 + } + } + + // post ISR process + if (!llWaitingIrq) // bug fixed 2018-05-04, only clear IRQ status when no config new one + ll_hw_clr_irq(); + + HAL_EXIT_CRITICAL_SECTION(); + return TRUE; +} + +uint8 ll_processBasicIRQ_secondaryScanSRX0(uint32_t irq_status ) +{ + HAL_ENTER_CRITICAL_SECTION(); + + // check status + if ((irq_status & LIRQ_RD) && (irq_status & LIRQ_COK)) // bug correct 2018-10-15 + { + // rx done + uint8_t packet_len, pdu_type; + uint16_t pktLen; + uint32_t pktFoot0, pktFoot1; + // read packet + // cost 21-26us(measure with GPIO), depneds on the length of ADV + packet_len = ll_hw_read_rfifo1((uint8_t*)(&(g_rx_adv_buf.rxheader)), + &pktLen, + &pktFoot0, + &pktFoot1); + // check receive pdu type + pdu_type = g_rx_adv_buf.rxheader & 0x0f; + + if (packet_len != 0 + && ((pdu_type == ADV_IND) + || (pdu_type == ADV_NONCONN_IND) + || (pdu_type == ADV_SCAN_IND))) + { + int i = 0; + uint8_t txAdd = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + + // check white list + if ((pGlobal_config[LL_SWITCH] & LL_WHITELIST_ALLOW) + && (scanInfo.wlPolicy == LL_SCAN_WL_POLICY_USE_WHITE_LIST)) + { + // check white list + for (i = 0; i < LL_WHITELIST_ENTRY_NUM; i++) + { + if (txAdd != g_llWhitelist[i].peerAddrType + || g_rx_adv_buf.data[0] != g_llWhitelist[i].peerAddr[0] + || g_rx_adv_buf.data[1] != g_llWhitelist[i].peerAddr[1] + || g_rx_adv_buf.data[2] != g_llWhitelist[i].peerAddr[2] + || g_rx_adv_buf.data[3] != g_llWhitelist[i].peerAddr[3] + || g_rx_adv_buf.data[4] != g_llWhitelist[i].peerAddr[4] + || g_rx_adv_buf.data[5] != g_llWhitelist[i].peerAddr[5]) + { + // not match, check next + continue; + } + else + break; + } + } + + // if valid, trigger osal event to report adv + if (i < LL_WHITELIST_ENTRY_NUM) + { + uint8 advEventType; + int8 rssi; + llCurrentScanChn = scanInfo.nextScanChan; + + // no active scan scenario + + // convert pdu type to GAP enum + switch (pdu_type) + { + case ADV_IND: + advEventType = LL_ADV_RPT_ADV_IND; + break; + + case ADV_SCAN_IND: + advEventType = LL_ADV_RPT_ADV_SCANNABLE_IND; + break; + + case ADV_DIRECT_IND: + advEventType = LL_ADV_RPT_ADV_DIRECT_IND; + break; + + case ADV_NONCONN_IND: + advEventType = LL_ADV_RPT_ADV_NONCONN_IND; + break; + + case ADV_SCAN_RSP: + advEventType = LL_ADV_RPT_INVALID; + break; + + default: + advEventType = LL_ADV_RPT_ADV_IND; + break; + } + + rssi = -(pktFoot1 >> 24); + // below function cost 51us/66us(measure with GPIO) + LL_AdvReportCback( advEventType, // event type + txAdd, // Adv address type (TxAdd) + &g_rx_adv_buf.data[0], // Adv address (AdvA) + pktLen - 8, // length of rest of the payload, 2 - header, 6 - advA + &g_rx_adv_buf.data[6], // rest of payload + rssi ); // RSSI + g_pmCounters.ll_recv_adv_pkt_cnt ++; + } + } + } + + // update scan time + llScanTime += ((ISR_entry_time > llScanT1) ? (ISR_entry_time - llScanT1) : (BASE_TIME_UNITS - llScanT1 + ISR_entry_time)); + + if (llScanTime >= scanInfo.scanWindow * 625) + { + // switch scan channel, set event instead of trigger immediately + // calculate next scan channel + LL_CALC_NEXT_SCAN_CHN(scanInfo.nextScanChan); + + // schedule next scan event + if (scanInfo.scanWindow == scanInfo.scanInterval) // scanWindow == scanInterval, trigger immediately + osal_set_event(LL_TaskID, LL_EVT_SECONDARY_SCAN); + else + osal_start_timerEx(LL_TaskID, LL_EVT_SECONDARY_SCAN, ((scanInfo.scanInterval - scanInfo.scanWindow) * 5) >> 3 ); + + // reset scan total time + llScanTime = 0; + } + else if (llSecondaryState == LL_SEC_STATE_SCAN) + llSetupSecScan(scanInfo.nextScanChan); + + // post ISR process + if (!llWaitingIrq) // bug fixed 2018-05-04, only clear IRQ status when no config new one + ll_hw_clr_irq(); + + HAL_EXIT_CRITICAL_SECTION(); + return TRUE; +} + +uint8 ll_processBasicIRQ_secondaryInitSRX0(uint32_t irq_status ) +{ + uint32_t T2, delay; + llConnState_t* connPtr; + HAL_ENTER_CRITICAL_SECTION(); + uint8 bConnecting = FALSE; +// hal_gpio_write(GPIO_P18, 0); + connPtr = &conn_param[initInfo.connId]; // connId is allocated when create conn + + // check status + if ((irq_status & LIRQ_RD) && (irq_status & LIRQ_COK)) // bug correct 2018-10-15 + { + // rx done + uint8_t packet_len, pdu_type; + uint16_t pktLen; + uint32_t pktFoot0, pktFoot1; + // read packet + // cost 21-26us(measure with GPIO), depneds on the length of ADV + packet_len = ll_hw_read_rfifo1((uint8_t*)(&(g_rx_adv_buf.rxheader)), + &pktLen, + &pktFoot0, + &pktFoot1); + // check receive pdu type + pdu_type = g_rx_adv_buf.rxheader & 0x0f; + + if(ll_hw_get_rfifo_depth()>0) + { + g_pmCounters.ll_rfifo_read_err++; + packet_len=0; + pktLen=0; + } + + if (packet_len != 0 + && ((pdu_type == ADV_IND))) + { + uint8_t txAdd = (g_rx_adv_buf.rxheader & TX_ADD_MASK) >> TX_ADD_SHIFT; // adv PDU header, bit 6: TxAdd, 0 - public, 1 - random + uint8_t chSel = (g_rx_adv_buf.rxheader & CHSEL_MASK) >> CHSEL_SHIFT; + uint8_t bWlRlCheckOk = TRUE; + uint8_t* peerAddr; + uint8_t rpaListIndex = LL_RESOLVINGLIST_ENTRY_NUM; +//-==== + peerAddr = &g_rx_adv_buf.data[0]; // AdvA + g_currentPeerAddrType = txAdd; + + // Resolving list checking + // case 1: receive InitA using RPA + if (txAdd == LL_DEV_ADDR_TYPE_RANDOM && + (g_rx_adv_buf.data[5] & RANDOM_ADDR_HDR) == PRIVATE_RESOLVE_ADDR_HDR) + { + bWlRlCheckOk = FALSE; + + if (g_llRlEnable == TRUE) + { + rpaListIndex = ll_getRPAListEntry(&g_rx_adv_buf.data[0]); + + if (rpaListIndex < LL_RESOLVINGLIST_ENTRY_NUM) + { + peerAddr = &g_llResolvinglist[rpaListIndex].peerAddr[0]; + g_currentPeerAddrType = g_llResolvinglist[rpaListIndex].peerAddrType + 2; + osal_memcpy(&g_currentPeerRpa[0], &g_rx_adv_buf.data[0], 6); + bWlRlCheckOk = TRUE; + } + } + } + else // case 2: receive InitA using device ID, or init device not using RPA + { + bWlRlCheckOk = TRUE; + + for (int i = 0; i < LL_RESOLVINGLIST_ENTRY_NUM; i++) + { + if ( g_llResolvinglist[i].peerAddr[0] == g_rx_adv_buf.data[0] + && g_llResolvinglist[i].peerAddr[1] == g_rx_adv_buf.data[1] + && g_llResolvinglist[i].peerAddr[2] == g_rx_adv_buf.data[2] + && g_llResolvinglist[i].peerAddr[3] == g_rx_adv_buf.data[3] + && g_llResolvinglist[i].peerAddr[4] == g_rx_adv_buf.data[4] + && g_llResolvinglist[i].peerAddr[5] == g_rx_adv_buf.data[5]) + { + // the device ID in the RPA list + if (g_llResolvinglist[i].privacyMode == DEVICE_PRIVACY_MODE || + ll_isIrkAllZero(g_llResolvinglist[i].peerIrk)) + rpaListIndex = i; + else + bWlRlCheckOk = FALSE; // the device in the RPA list but not using RPA, reject it + + break; + } + } + } + + // initiator, 2 types of filter process: 1. connect to peer address set by host 2. connect to address in whitelist only + // 1. connect to peer address set by host + if (initInfo.wlPolicy == LL_INIT_WL_POLICY_USE_PEER_ADDR + && bWlRlCheckOk == TRUE) + { + if (//txAdd != peerInfo.peerAddrType + peerAddr[0] != peerInfo.peerAddr[0] + || peerAddr[1] != peerInfo.peerAddr[1] + || peerAddr[2] != peerInfo.peerAddr[2] + || peerAddr[3] != peerInfo.peerAddr[3] + || peerAddr[4] != peerInfo.peerAddr[4] + || peerAddr[5] != peerInfo.peerAddr[5]) + { + // not match, not init connect + bWlRlCheckOk = FALSE; + } + } + // 2. connect to address in whitelist only + else if (initInfo.wlPolicy == LL_INIT_WL_POLICY_USE_WHITE_LIST && + bWlRlCheckOk == TRUE) + { + // if advA in whitelist list, connect + // check white list + bWlRlCheckOk = ll_isAddrInWhiteList(txAdd, peerAddr); + } + + if (bWlRlCheckOk == TRUE) + { + g_same_rf_channel_flag = TRUE; + // calculate connPtr->curParam.winOffset and set tx buffer + uint16 win_offset; + uint32 remainder; + + // calculate windows offset in multiconnection case + if (g_ll_conn_ctx.currentConn != LL_INVALID_CONNECTION_ID) + { +//#ifdef MULTI_ROLE + // allocate time slot for new connection + // calculate delta to current connection + // calculate new win_offset + uint32 temp, temp1, temp2; + int i; + + for (i = 0; i < g_maxConnNum; i++ ) + { + if (g_ll_conn_ctx.scheduleInfo[i].linkRole == LL_ROLE_MASTER && conn_param[i].active) + break; + } + + if (i == g_maxConnNum) + { + // case 1: no master connection, schedule new connection after the current slave connection + g_new_master_delta = 12 * 625; // delta time to the current slave event + remainder = read_LL_remainder_time(); + g_new_master_delta += remainder; + remainder = g_new_master_delta - 352; // time of CONN_REQ + remainder = (remainder + (remainder >> 1) + (remainder >> 3) + (remainder >> 7)) >> 10; // rough estimate of (x / 625) = (1/1024 + 1/2048 + 1/8192) + + // winoffset should less then conn interval + if (g_new_master_delta - 2 > (conn_param[initInfo.connId].curParam.connInterval << 1)) // win_offset should less then conn interval + g_new_master_delta -= conn_param[initInfo.connId].curParam.connInterval << 1; + + win_offset = (remainder - 2) >> 1; + } + else + { + // case 2: master connection exist, select the 1st master connection as anchor master connection + + // calculate the delta to the anchor master connection + if (initInfo.connId > i) + g_new_master_delta = (initInfo.connId - i) * g_ll_conn_ctx.per_slot_time; + else + g_new_master_delta = (conn_param[i].curParam.connInterval << 1) - (i - initInfo.connId) * g_ll_conn_ctx.per_slot_time; + + // schedule the new connection after the anchor master connection + g_new_master_delta = g_new_master_delta * 625 + g_ll_conn_ctx.scheduleInfo[i].remainder; + // elapse time since last schedule + temp1 = g_ll_conn_ctx.current_timer - ((AP_TIM1->CurrentCount) >> 2) + 2; + g_new_master_delta -= temp1; + + if (g_new_master_delta - 1250 > (conn_param[initInfo.connId].curParam.connInterval * 1250)) // win_offset should less then conn interval + g_new_master_delta -= conn_param[initInfo.connId].curParam.connInterval * 1250; + + // calculate win_offset + temp = g_new_master_delta - 352; // 352: CONN_REQ time + temp2 = (temp + (temp >> 1) + (temp >> 3) + (temp >> 7)) >> 10; // rough estimate of (x / 625) + win_offset = (temp2 - 2) >> 1; + // calculate remainder time of anchor master connection +// temp1 = (CP_TIM1->LoadCount - CP_TIM1->CurrentCount) >> 2; // get elapse time //read_LL_remainder_time(); +// temp1 = g_ll_conn_ctx.current_timer - ((CP_TIM1->CurrentCount) >> 2) + 2; // 2: rough time from read old timer1 to kick new timer1 +// temp = (g_ll_conn_ctx.scheduleInfo[i].remainder - temp1 - 352);// / 625; +// temp2 = (temp + (temp >> 1) + (temp >> 3) + (temp >> 7)) >> 10; // rough estimate of (x / 625) +// +// // remainder time of new connection = remainder time of anchor master connection + delta +// g_new_master_delta += temp2; +// +// // winoffset should less then conn interval +// if (g_new_master_delta - 2 > (conn_param[initInfo.connId].curParam.connInterval << 1)) // win_offset should less then conn interval +// g_new_master_delta -= conn_param[initInfo.connId].curParam.connInterval << 1; +// +// win_offset = (g_new_master_delta - 2) >> 1; +// g_new_master_delta = win_offset * 1250 + 352; + } + +//#else +// if (initInfo.connId > g_ll_conn_ctx.currentConn) +// g_new_master_delta = (initInfo.connId - g_ll_conn_ctx.currentConn) * g_ll_conn_ctx.per_slot_time; +// else +// g_new_master_delta = (conn_param[initInfo.connId].curParam.connInterval << 1) - (g_ll_conn_ctx.currentConn - initInfo.connId) * g_ll_conn_ctx.per_slot_time; +// +// // there are 2 case for new connection timing : 1. before next current connection slot 2. after next current connection slot. +// // Note: we will send the 1st master packet at time (1.25ms + winoffset) after send CONN REQ msg, +// // the time should align to allocate time slot, i.e. +// // remain time of timer1 + delta tick = 2 + winOffset + CONN REQ msg length(352us) +// remainder = (read_LL_remainder_time() - 352);// / 625; +// remainder = (remainder + (remainder >> 1) + (remainder >> 3) + (remainder >> 7)) >> 10; // rough estimate of (x / 625) = (1/1024 + 1/2048 + 1/8192) +// +// win_offset = (remainder + g_new_master_delta - 2) >> 1; +// if (win_offset > (conn_param[initInfo.connId].curParam.connInterval << 1)) // case 1 +// win_offset -= (conn_param[initInfo.connId].curParam.connInterval << 1); +// +//// g_new_master_delta = win_offset << 1; +// g_new_master_delta = win_offset * 1250 + 352; +//#endif + // WinOffset, Byte 20 ~ 21 + memcpy((uint8*)&g_tx_adv_buf.data[20], (uint8*)&win_offset, 2); + conn_param[initInfo.connId].curParam.winOffset = win_offset; + } + + // channel selection algorithm decision + if ((pGlobal_config[LL_SWITCH] & CONN_CSA2_ALLOW) + && chSel == LL_CHN_SEL_ALGORITHM_2) + { + conn_param[initInfo.connId].channel_selection = LL_CHN_SEL_ALGORITHM_2; + SET_BITS(g_tx_adv_buf.txheader, LL_CHN_SEL_ALGORITHM_2, CHSEL_SHIFT, CHSEL_MASK); + } + else + conn_param[initInfo.connId].channel_selection = LL_CHN_SEL_ALGORITHM_1; + + // send conn req + T2 = read_current_fine_time(); + delay = (T2 > ISR_entry_time) ? (T2 - ISR_entry_time) : (BASE_TIME_UNITS - ISR_entry_time + T2); + delay = 118 - delay - pGlobal_config[LL_ADV_TO_CONN_REQ_DELAY]; + ll_hw_set_trx_settle(delay, // set BB delay, about 80us in 16MHz HCLK + pGlobal_config[LL_HW_AFE_DELAY], + pGlobal_config[LL_HW_PLL_DELAY]); //RxAFE,PLL + // reset Rx/Tx FIFO + ll_hw_rst_rfifo(); + ll_hw_rst_tfifo(); + // send conn req + ll_hw_set_stx(); // set LL HW as single Tx mode + ll_hw_go(); + llWaitingIrq = TRUE; + // AdvA, offset 6 + memcpy((uint8*)&g_tx_adv_buf.data[6], &g_rx_adv_buf.data[0], 6); + //write Tx FIFO + ll_hw_write_tfifo((uint8*)&(g_tx_adv_buf.txheader), + ((g_tx_adv_buf.txheader & 0xff00) >> 8) + 2); // payload length + header length(2) + move_to_master_function(); + //LOG("win_off = %d\n", win_offset); + //LOG("remainder = %d\n", remainder); + bConnecting = TRUE; + g_same_rf_channel_flag = FALSE; + } + } + else if (packet_len != 0 + && (pdu_type == ADV_DIRECT_IND)) // TODO: add process of direct ADV + { + } + } + + // scan again if not start connect + if (!bConnecting) // if not start connect, schedule next scan + { + if (initInfo.scanMode == LL_SCAN_STOP) + { + // scan has been stopped + llSecondaryState = LL_SEC_STATE_IDLE; // bug fixed by Zhufei // set the LL state idle + // release the associated allocated connection + llReleaseConnId(connPtr); // new for multi-connection + g_ll_conn_ctx.numLLMasterConns --; + (void)osal_set_event( LL_TaskID, LL_EVT_MASTER_CONN_CANCELLED ); // inform high layer + } + else + { + // not sending SCAN REQ, update scan time + llScanTime += ((ISR_entry_time > llScanT1) ? (ISR_entry_time - llScanT1) : (BASE_TIME_UNITS - llScanT1 + ISR_entry_time)); + + if (llScanTime >= initInfo.scanWindow * 625) + { + // calculate next scan channel + LL_CALC_NEXT_SCAN_CHN(initInfo.nextScanChan); + + // schedule next scan event + if (initInfo.scanWindow == initInfo.scanInterval) // scanWindow == scanInterval, trigger immediately + osal_set_event(LL_TaskID, LL_EVT_SECONDARY_INIT); + else + osal_start_timerEx(LL_TaskID, LL_EVT_SECONDARY_INIT, ((initInfo.scanInterval - initInfo.scanWindow) * 5) >> 3 ); + + // reset scan total time + llScanTime = 0; + } + else + llSetupSecInit(initInfo.nextScanChan); + } + } + + // post ISR process + if (!llWaitingIrq) // bug fixed 2018-05-04, only clear IRQ status when no config new one + ll_hw_clr_irq(); + + HAL_EXIT_CRITICAL_SECTION(); + return TRUE; +} + +void LL_IRQHandler1(void) +{ +// gpio_write(P32,1); +// gpio_write(P32,0); + uint32 irq_status; + int8 ret; + ISR_entry_time = read_current_fine_time(); + //*(volatile uint32_t *)0x4000f0b8 = 1; // pclk_clk_gate_en + ll_debug_output(DEBUG_ISR_ENTRY); + irq_status = ll_hw_get_irq_status(); + + if (!(irq_status & LIRQ_MD)) // only process IRQ of MODE DONE + { + ll_hw_clr_irq(); // clear irq status + return; + } + + llWaitingIrq = FALSE; + + if (llTaskState == LL_TASK_EXTENDED_ADV) + { + ret = ll_processExtAdvIRQ(irq_status); + + // TODO: consider whether need process secondary adv/scan here + if (ret == TRUE) + return; + } + else if (llTaskState == LL_TASK_EXTENDED_SCAN) + { + ret = ll_processExtScanIRQ(irq_status); + + // TODO: consider whether need process secondary adv/scan here + if (ret == TRUE) + return; + } + else if (llTaskState == LL_TASK_EXTENDED_INIT) + { + ret = ll_processExtInitIRQ(irq_status); + + // TODO: consider whether need process secondary adv/scan here + if (ret == TRUE) + return; + } + else if (llTaskState == LL_TASK_PERIODIC_ADV) + { + ret = ll_processPrdAdvIRQ(irq_status); + + // TODO: consider whether need process secondary adv/scan here + if (ret == TRUE) + return; + } + else if (llTaskState == LL_TASK_PERIODIC_SCAN) + { + ret = ll_processPrdScanIRQ(irq_status); + + // TODO: consider whether need process secondary adv/scan here + if (ret == TRUE) + return; + } + else + { + uint8 mode; + mode = ll_hw_get_tr_mode(); + + if(mode == LL_HW_MODE_SRX && (llState == LL_STATE_SCAN || llState == LL_STATE_INIT)) + { + ret = ll_processBasicIRQ_SRX(irq_status); + } + else if((llSecondaryState == LL_SEC_STATE_ADV || llSecondaryState == LL_SEC_STATE_IDLE_PENDING) + && (mode == LL_HW_MODE_TRX ) + && (adv_param.advEvtType == LL_ADV_CONNECTABLE_UNDIRECTED_EVT || adv_param.advEvtType == LL_ADV_SCANNABLE_UNDIRECTED_EVT)) + { + // JIRA bugfix : BBBSDKREL-294 + ret = ll_processBasicIRQ_secondaryAdvTRX(irq_status); + } + else if (mode == LL_HW_MODE_TRX && + (llState == LL_STATE_SCAN)) + { + ret = ll_processBasicIRQ_ScanTRX(irq_status); + } + else if (mode == LL_HW_MODE_SRX && + (llSecondaryState == LL_SEC_STATE_SCAN)) + { + ret = ll_processBasicIRQ_secondaryScanSRX(irq_status); + } + else if (mode == LL_HW_MODE_SRX && + (llSecondaryState == LL_SEC_STATE_INIT)) + { + ret = ll_processBasicIRQ_secondaryInitSRX(irq_status); + } + else + { + ret = ll_processBasicIRQ(irq_status); + } + + //test for fast adv + if( mode == LL_HW_MODE_TRX + && llState == LL_STATE_ADV_UNDIRECTED + && 0==(irq_status&LIRQ_COK) ) + { + uint8_t firstAdvChan = (adv_param.advChanMap&LL_ADV_CHAN_37) !=0 ? 37 : + (adv_param.advChanMap&LL_ADV_CHAN_38) !=0 ? 38 : 39; + + if(adv_param.advNextChan>firstAdvChan) + { + ll_schedule_next_event(50); //20180623 modified by ZQ + } + } + } + + // ================ Post ISR process: secondary pending state process + // conn-adv case 2: other ISR, there is pending secondary advertise event, make it happen + if (llSecondaryState == LL_SEC_STATE_ADV_PENDING) + { + if (llSecAdvAllow()) // for multi-connection case, it is possible still no enough time for adv + { + llSetupSecAdvEvt(); + ll_hw_set_rx_timeout(88); + llSecondaryState = LL_SEC_STATE_ADV; + } + } + // there is pending scan event, make it happen, note that it may stay pending if there is no enough idle time + else if (llSecondaryState == LL_SEC_STATE_SCAN_PENDING) + { + // trigger scan + llSetupSecScan(scanInfo.nextScanChan); + } + // there is pending init event, make it happen, note that it may stay pending if there is no enough idle time + else if (llSecondaryState == LL_SEC_STATE_INIT_PENDING) + { + // trigger scan + llSetupSecInit(initInfo.nextScanChan); + } + + DBG_GPIO_WRITE(DBGIO_LL_IRQ,0); + ll_debug_output(DEBUG_ISR_EXIT); +} + +//-------------------------------------- +extern uint32 llWaitingIrq; +extern uint32_t g_wakeup_rtc_tick; + +extern uint32 counter_tracking; +extern uint32_t g_counter_traking_avg; +extern uint32_t g_counter_traking_cnt; +extern uint32_t g_TIM2_IRQ_TIM3_CurrCount; +extern uint32_t g_TIM2_IRQ_to_Sleep_DeltTick; +extern uint32 read_ll_adv_remainder_time(void); +#define ROM_SLEEP_TICK *(volatile uint32_t *)(0x1fff0a14) + +__attribute__((weak)) void l2capPocessFragmentTxData(uint16 connHandle) +{ + //do nothing +} + +#if 0 +extern int m_in_critical_region; +int drv_disable_irq1(void) +{ + __disable_irq(); + DBG_GPIO_WRITE(DBGIO_DIS_IRQ,1); + DBG_GPIO_WRITE(DBGIO_DIS_IRQ,0); + m_in_critical_region++; + return m_in_critical_region; +} + +int drv_enable_irq1(void) +{ + m_in_critical_region--; + + if (m_in_critical_region == 0) + { + __enable_irq(); + DBG_GPIO_WRITE(DBGIO_EN_IRQ,1); + DBG_GPIO_WRITE(DBGIO_EN_IRQ,0); + } + + return m_in_critical_region; +} +extern void TIM1_IRQHandler(void); +void TIM1_IRQHandler1(void) +{ + gpio_write(P20,1); + TIM1_IRQHandler(); + gpio_write(P20,0); +} +#endif + +/******************************************************************************* + @fn ll_scheduler + + @brief schedule next task, if current connection will be free, input + parameter should be LL_INVALID_TIME. The function is invoked + after old connection task end, it will not add new task but may + delete exist task + + input parameters + + @param time - schedule time for current connection + + output parameters + + @param None. + + @return None. +*/ +void ll_scheduler1(uint32 time) +{ + uint32 T1, T2, delta, min, prio_adj; + uint8 i, next, temp,conn_temp; + T1 = read_current_fine_time(); + + // timer1 is running, normally it should not occur + if (isTimer1Running()) + { + LOG("=== ASSERT FAIL, timer1 running when invoke ll_scheduler ===\n"); + g_pmCounters.ll_evt_shc_err++; + return; + } + + // if timer1 is not running, calculate the time elapse since last timer expiry + delta = g_ll_conn_ctx.current_timer + LL_TIME_DELTA(g_ll_conn_ctx.timerExpiryTick, T1) + pGlobal_config[TIMER_ISR_ENTRY_TIME]; + // update current context + g_ll_conn_ctx.scheduleInfo[g_ll_conn_ctx.currentConn].remainder = time; // if current conn terminal, the parameter "time" shall be LL_INVALID_TIME + min = time; + + if (time == LL_INVALID_TIME) + { + ll_deleteTask(g_ll_conn_ctx.currentConn); + g_ll_conn_ctx.currentConn = LL_INVALID_CONNECTION_ID; + } + + conn_temp = next = g_ll_conn_ctx.currentConn; + + if (next != LL_INVALID_CONNECTION_ID) + { + // if we want master or slave connection has higher schedule priority, set LL_MASTER_PREEMPHASIS/LL_SLAVE_PREEMPHASIS + if (g_ll_conn_ctx.scheduleInfo[next].linkRole == LL_ROLE_MASTER) + min = (time > pGlobal_config[LL_MULTICONN_MASTER_PREEMP]) ? (time - pGlobal_config[LL_MULTICONN_MASTER_PREEMP]) : 0; + + if (g_ll_conn_ctx.scheduleInfo[next].linkRole == LL_ROLE_SLAVE) + min = (time > pGlobal_config[LL_MULTICONN_SLAVE_PREEMP]) ? (time - pGlobal_config[LL_MULTICONN_SLAVE_PREEMP]) : 0; + } + + // update schedule task list and get the earliest task + for (i = 0; i < g_maxConnNum; i++) + { + if ((i != g_ll_conn_ctx.currentConn) && conn_param[i].active) + { + // task conflict process + // if there is no enough time for new task, invoke relate slave/master conn event process function +// if (g_ll_conn_ctx.scheduleInfo[i].remainder < delta + g_ll_conn_ctx.scheduleInfo[i].task_duration) + if (g_ll_conn_ctx.scheduleInfo[i].remainder < delta + 40) // 40 : margin for process delay, unit: us + { + // no enough time to process the event, regard the event as missed and update the conn context and timer + uint8 ret = LL_PROC_LINK_KEEP; + + if (g_ll_conn_ctx.scheduleInfo[i].linkRole == LL_ROLE_MASTER) + { + // temporary update g_ll_conn_ctx.currentConn to current connection ID because + // ll_processMissMasterEvt will invoke function using global variable g_ll_conn_ctx.currentConn + temp = g_ll_conn_ctx.currentConn; + g_ll_conn_ctx.currentConn = i; + ret = ll_processMissMasterEvt(i); +// if( delta > g_ll_conn_ctx.scheduleInfo[i].remainder) +// { +// llConnState_t *connPtr = &conn_param[i]; +// uint8 missCE = (( delta - g_ll_conn_ctx.scheduleInfo[i].remainder) / ( connPtr->curParam.connInterval*625 )) + 1; +// for(uint8 misI = 0;misI g_ll_conn_ctx.scheduleInfo[i].remainder) + { + llConnState_t* connPtr = &conn_param[i]; + uint8 missCE = (( delta - g_ll_conn_ctx.scheduleInfo[i].remainder) / ( connPtr->curParam.connInterval*625 )) + 1; + + for(uint8 misI = 0; misI prio_adj) ? (g_ll_conn_ctx.scheduleInfo[i].remainder - prio_adj) : 0; + } + } + } + + if (min == LL_INVALID_TIME) // all task may be delete, not start timer + { + return; + } + + T2 = read_current_fine_time(); + // calculate the time elapse since enter this function. + delta = LL_TIME_DELTA(T1, T2); + HAL_ENTER_CRITICAL_SECTION(); + uint8 rem_l_delta_flag = FALSE; + uint8 rem_l_delta_value = 0; + + if (g_ll_conn_ctx.scheduleInfo[next].remainder <= delta) // TODO: should not go here, if this issue detected, root cause should be invest + { +// set_timer1(20); + set_timer(AP_TIM1,20); + g_ll_conn_ctx.current_timer = 20; + rem_l_delta_flag = TRUE; + rem_l_delta_value = next; +// LOG("-T %d:20,",next); + } + else + { +// set_timer1(g_ll_conn_ctx.scheduleInfo[next].remainder - delta); + set_timer(AP_TIM1,g_ll_conn_ctx.scheduleInfo[next].remainder - delta); +// LOG("-S%d,%d,",next,g_ll_conn_ctx.scheduleInfo[next].remainder - delta); + // update connection context & schedule info + g_ll_conn_ctx.current_timer = g_ll_conn_ctx.scheduleInfo[next].remainder - delta; + } + + g_ll_conn_ctx.currentConn = next; + + // set ll state according to current connection LL state + if (g_ll_conn_ctx.scheduleInfo[g_ll_conn_ctx.currentConn].linkRole == LL_ROLE_SLAVE) + llState = LL_STATE_CONN_SLAVE; + else if (g_ll_conn_ctx.scheduleInfo[g_ll_conn_ctx.currentConn].linkRole == LL_ROLE_MASTER) + llState = LL_STATE_CONN_MASTER; + + // the task is scheduled, set the priority as low + g_ll_conn_ctx.scheduleInfo[g_ll_conn_ctx.currentConn].priority = LL_SCH_PRIO_LOW; + + // take into account the time between start timer1 and T1 + for (i = 0; i < g_maxConnNum; i++) + { + if (conn_param[i].active) + { +// if( g_ll_conn_ctx.scheduleInfo[i].remainder >= delta ) +// g_ll_conn_ctx.scheduleInfo[i].remainder -= delta; + if( ( g_ll_conn_ctx.scheduleInfo[i].remainder < delta ) && ( rem_l_delta_flag == FALSE)) + { + if (g_ll_conn_ctx.scheduleInfo[i].linkRole == LL_ROLE_MASTER) + ll_processMissMasterEvt(i); + else + ll_processMissSlaveEvt(i); + } + + if( ( rem_l_delta_value == i ) && ( rem_l_delta_flag == TRUE) ) + g_ll_conn_ctx.scheduleInfo[i].remainder = 0; + else + g_ll_conn_ctx.scheduleInfo[i].remainder -= delta; + + conn_param[i].llTbd2 = g_ll_conn_ctx.scheduleInfo[i].remainder; + /*record if error scheduler time*/ + // if( g_ll_conn_ctx.scheduleInfo[i].remainder > 500000) + // llConnTerminate(&conn_param[i],LL_SUPERVISION_TIMEOUT_TERM); + } + } + + // add for co-master intv bug fix + if( g_ll_conn_ctx.scheduleInfo[conn_temp].linkRole != LL_ROLE_MASTER ) + { + HAL_EXIT_CRITICAL_SECTION(); + return; + } + + int8 k=0; + + for (k = g_maxConnNum-1; k >= 0; k--) + { + if ((conn_param[k].active) && (g_ll_conn_ctx.scheduleInfo[k].linkRole == LL_ROLE_MASTER )) + { + break; + } + } + + i=k; + + if( conn_temp == i ) + { + uint8 jm=i; + uint8 fist_m=0; + // current master --> first master true value + uint32 tv_Masters = 0,tv_diff = 0,first_reminder = 0; + + for (i = 0; i < g_maxConnNum; i++) + { + if ((conn_param[i].active) && (g_ll_conn_ctx.scheduleInfo[i].linkRole == LL_ROLE_MASTER )) + break; + } + + first_reminder = g_ll_conn_ctx.scheduleInfo[i].remainder; + fist_m = i; + + for (i=fist_m+1; i < jm+1 ; i++) + { + if ((conn_param[i].active) && (g_ll_conn_ctx.scheduleInfo[i].linkRole == LL_ROLE_MASTER )) + { + tv_Masters = first_reminder + g_ll_conn_ctx.per_slot_time * 625 * (i - fist_m); + + if( tv_Masters > g_ll_conn_ctx.scheduleInfo[i].remainder) + tv_diff = tv_Masters - g_ll_conn_ctx.scheduleInfo[i].remainder; + else + tv_diff = g_ll_conn_ctx.scheduleInfo[i].remainder - tv_Masters; + + // < 1000 : filter scecondary first create master connection & miss process master event + if(tv_diff < 1000) + { + if( g_ll_conn_ctx.scheduleInfo[i].remainder > tv_Masters ) + { + g_ll_conn_ctx.scheduleInfo[i].remainder -= tv_diff; + } + else if( g_ll_conn_ctx.scheduleInfo[i].remainder < tv_Masters ) + { + g_ll_conn_ctx.scheduleInfo[i].remainder += tv_diff; + } + } + } + } + } + + HAL_EXIT_CRITICAL_SECTION(); +} + +#define CRY32_2_CYCLE_16MHZ_CYCLE_MAX (976 + 98) // tracking value range std +/- 20% +#define CRY32_2_CYCLE_16MHZ_CYCLE_MIN (976 - 98) +#define CRY32_2_CYCLE_DELTA_LMT (19) +#define TRACKING_16M_TICK_MAX (3300) //TRACKING_16M_TICK_MAX*30.5us 3300*30.5 around 100ms +#define TRACKING_MAX_SLEEPTIME (1980000) //MAX sleep time is 60 seconds. + +uint32_t g_xtal16M_tmp=0; +extern void hal_pwrmgr_enter_sleep_rtc_reset(uint32_t sleepRtcTick); +static void check_16MXtal_by_rcTracking(void) +{ + /* + for fiset wakeupini, not do rcCal, just skip the rcTacking + + */ + if(AON_LOAD_RC32K_CALIB_FLG == 0) + { + WaitRTCCount(60); + return; + } + + uint32_t temp,temp1; + uint32_t temp31,temp32,temp33; + uint32_t temp_min,temp_max; + uint32_t tracking_start = rtc_get_counter(); + // ======== enable tracking 32KHz RC timer with 16MHz crystal clock + temp = *(volatile uint32_t*)0x4000f040; + *(volatile uint32_t*)0x4000f040 = temp | BIT(18); + temp = *(volatile uint32_t*)0x4000f05C; + *(volatile uint32_t*)0x4000f05C = (temp & 0xfffefe00) | 0x0028; + WaitRTCCount(3); + temp31 = (*(volatile uint32_t*)0x4000f064 & 0x1ffff); + WaitRTCCount(3); + temp32 = (*(volatile uint32_t*)0x4000f064 & 0x1ffff); + WaitRTCCount(3); + temp33 = (*(volatile uint32_t*)0x4000f064 & 0x1ffff); + + while(1) + { + temp_min = (temp31 >=temp32) ? (temp32):(temp31); + temp_min = (temp_min >=temp33) ? (temp33):(temp_min); + temp_max = (temp31 >=temp32) ? (temp31):(temp32); + temp_max = (temp_max >=temp33) ? (temp_max):(temp33); + + if( temp31>CRY32_2_CYCLE_16MHZ_CYCLE_MIN && + temp31CRY32_2_CYCLE_16MHZ_CYCLE_MIN && + temp32 CRY32_2_CYCLE_16MHZ_CYCLE_MIN && + temp33 =tracking_start) ? (tracking_end-tracking_start) : (0xffffffff-tracking_start+tracking_end); + + if(tracking_16M_tick >= TRACKING_16M_TICK_MAX) + { + //record tracking sleep number + uint32_t tracking_sleep_num =AON_LOAD_XTAL_TRACKING_RST_NUMBER; + AON_SAVE_XTAL_TRACKING_RST_NUMBER(tracking_sleep_num+1); + //set just_enter_sleep_flg + AON_SAVE_XTAL_TRACKING_RST_FLG(1); + set_sleep_flag(0); + + if ((1 << tracking_sleep_num)*33000< TRACKING_MAX_SLEEPTIME) + { + hal_pwrmgr_enter_sleep_rtc_reset((1 << tracking_sleep_num)*33000); + } + else + { + hal_pwrmgr_enter_sleep_rtc_reset(TRACKING_MAX_SLEEPTIME); + } + } + } + + WaitRTCCount(20); + temp1 = (*(volatile uint32_t*)0x4000f064 & 0x1ffff); + //disable tracking + subWriteReg(0x4000f05C,3,3,0); + g_xtal16M_tmp = temp1; +} + +#define TRACKING_96M_16M_MULTI6_DELTA_LIMIT (10*6) //96M:16M*6 +- 1% +#define DLL_ENABLE_MAX (5) + +uint32_t g_xtal96M_temp=0; +uint32_t DLL_enable_num=1; +static void check_96MXtal_by_rcTracking(void) +{ + uint32_t temp,temp1; + + //for first wakeupinit + if(((*(volatile uint32_t*)0x4000f0c4) & 0x80) == 0) + { + //enable DLL + temp = *(volatile uint32_t*)0x4000f044; + *(volatile uint32_t*)0x4000f044 = temp | BIT(7); + WaitRTCCount(3); + return; + } + + DLL_enable_num=0; + // ======== enable tracking 32KHz RC timer with 16MHz crystal clock + temp = *(volatile uint32_t*)0x4000f040; + *(volatile uint32_t*)0x4000f040 = temp | BIT(18); + + while(1) + { + //enable DLL + temp = *(volatile uint32_t*)0x4000f044; + *(volatile uint32_t*)0x4000f044 = temp | BIT(7); + WaitRTCCount(3); + DLL_enable_num++; + // gpio_write(P32,1); + // gpio_write(P32,0); + // //enable digclk 96M + temp = *(volatile uint32_t*)0x4000f044; + *(volatile uint32_t*)0x4000f044 = temp | BIT(16); + + for(uint8 index=0; index<5; index++) + { + temp = *(volatile uint32_t*)0x4000f05C; + *(volatile uint32_t*)0x4000f05C = (temp & 0xfffefe00) | 0x0028 | BIT(16); + WaitRTCCount(3); + temp1 = (*(volatile uint32_t*)0x4000f064 & 0x1ffff); + subWriteReg(0x4000f05C,3,3,0); + + if( (g_xtal16M_tmp*6 >=temp1 ? (g_xtal16M_tmp*6 -temp1):(temp1-g_xtal16M_tmp*6))= DLL_ENABLE_MAX) + { + NVIC_SystemReset(); + } + + //disable DLL + subWriteReg(0x4000f044,7,7,0); + WaitRTCCount(3); + //update g_xtal16M_tmp + temp = *(volatile uint32_t*)0x4000f05C; + *(volatile uint32_t*)0x4000f05C = (temp & 0xfffefe00) | 0x0028 ; + WaitRTCCount(3); + g_xtal16M_tmp = (*(volatile uint32_t*)0x4000f064 & 0x1ffff); + subWriteReg(0x4000f05C,3,3,0); + } +} + +#if 0 + uint32_t rtcCntTemp[10]; +#endif +// now we split the initial fucntion to 3 kinds: +// 1. boot init function: which should be init when system boot. note: not include wakeup init function +// 2. wakeup init function: which should be init when wakeup from system sleep +// 3. parameter which should be init in APP, include: RF, board, ... +// summary: +// - normal boot, need: 1 + 2 + 3 +// - wakeup, need: 2 + 3 + +// init paramaters every time wakeup + +uint32_t tracking_cnt=0; +void wakeup_init1() +{ + efuse_init(); + __wdt_init(); + uint8_t pktFmt = 1; // packet format 1: BLE 1M + uint32 temp; + //int int_state; + // =========== clk gate for low power + //*(volatile uint32_t *) 0x40000008 = 0x01e92190; + // enable rng analog block. RNG analog need > 200us before stable, and it consume few current, so open it at wakeup + //*(volatile uint32_t *) 0x4000f048 |= 1 << 23; + // =========== config PCRM +// *(volatile uint32_t *) 0x4000f040 = 0x501fb000; //enable xtal out +// *(volatile uint32_t *) 0x4000f044 = 0x01ade8b0; //switch rf,adc to doubler,32M +//---by ZQ 2017-10-17 + //*(volatile uint32_t *) 0x4000f040 = 0x501fb820; // enable xtal out + // set the xtal cap to zero for faster settle + // set [16] manually enable ac strigger f 20180613 by ZQ + //*(volatile uint32_t *) 0x4000f044 = 0x01bdf8b0;//0x01bef830; // switch rf,adc to doubler, dll_off, dll_ldo on + // dll will be turn on in rf_ini after xtal settle + //*(volatile uint32_t *) 0x4000f044 = 0x00be0830; //[26:22] 0x02,[21:18]0x0f,[16:12]0x00,[7:4]0x03 + //< 22>:sel_rf_clk_16M; + //< 23>:sel_rf_dbl_clk_32M; + //< 24>:sel_rxadc_dbl_clk_32M; + //< 25>:sel_rxadc_dbl_clk_32M_polarity; + //< 26>:sel_rf_dbl_clk_32M_polarity + // < 18>:en_rf_clk; + // < 19>:en_rxadc_clk_32M; + // < 20>:sel_cp_clk_32M; + // < 21>:sel_dig_dble_clk_32M; + // < 12>:en_cp_dll_clk; + // < 13>:en_dig_clk_32M; + // < 14>:en_dig_clk_48M; + // < 15>:en_dig_clk_64M; + // < 16>:en_dig_clk_96M; + #if (DBG_BUILD_LL_TIMING) + //====== for timing debug============ + gpio_write(DBG_PIN_SYS_CLK_SWITCH, 1); + gpio_write(DBG_PIN_SYS_CLK_SWITCH, 0); + //PHY_REG_WT(AP_IOMUX_BASE+8,1);//en debugMux[0] + #endif + //each rtc count is about 30.5us + //after 15count , xtal will be feedout to dll and doubler + //WaitRTCCount(pGlobal_config[WAKEUP_DELAY]); + #if 0 + volatile uint32_t delay=0; + + for(uint8_t i=0; i<10; i++) + { + delay=500; + rtcCntTemp[i]=rtc_get_counter(); + + while(delay -- > 0) {}; + } + + #endif + + if(g_system_clk == SYS_CLK_XTAL_16M ) + { + WaitRTCCount(pGlobal_config[WAKEUP_DELAY]); + } + else + { + uint32_t tracking_c1,tracking_c2; + tracking_c1 = rtc_get_counter(); + WaitRTCCount(50); + check_16MXtal_by_rcTracking(); + WaitRTCCount(15); + + if(g_system_clk != SYS_CLK_DBL_32M ) + { + check_96MXtal_by_rcTracking(); + } + else + { + /* + for hclk=32M DBL + switch to 32M RC and reset DBL + */ + if((read_reg(0x4000f03c)&0x07)==SYS_CLK_DBL_32M) + { + clk_init(SYS_CLK_RC_32M); + } + + //reset doubler + AP_PCRM->CLKHF_CTL1 &= ~BIT(8); + WaitRTCCount(2); + AP_PCRM->CLKHF_CTL1 |= BIT(8); + } + + tracking_c2 = rtc_get_counter(); + tracking_cnt = (tracking_c2>=tracking_c1) ? (tracking_c2-tracking_c1) : (0xffffffff-tracking_c1+tracking_c2); + pGlobal_config[WAKEUP_ADVANCE] =1650+30*tracking_cnt; + } + + // ============ config BB Top + *(volatile uint32_t*) 0x40030000 = 0x3d068001; // set tx pkt =2 + *(volatile uint32_t*) 0x400300bc = 0x834; //[7:0] pll_tm [11:8] rxafe settle + *(volatile uint32_t*) 0x400300a4 = 0x140; //[6] for tpm_en + clk_init(g_system_clk); + // ================= clock selection + // hclk_sel select hclk source. 0---rc 32m 1----dll 32m 2---xtal 16m 3---dll 48m 4----dll 64m 5----dll 96m +// switch (pGlobal_config[CLOCK_SETTING]) +// { +// case SYS_CLK_XTAL_16M: +//// *(int *) 0x4000f03C = 0x18001; // clock selection +// *(int *) 0x4000f03C = 0x10002; // clock selection +// break; +// case SYS_CLK_DBL_32M: +// case SYS_CLK_DLL_32M: +// *(int *) 0x4000f03C = 0x10001; // clock selection +// break; +// case SYS_CLK_DLL_48M: +// *(int *) 0x4000f03C = 0x10003; // clock selection +// break; +// case SYS_CLK_DLL_64M: +// *(int *) 0x4000f03C = 0x10004; // clock selection +// break; +// case SYS_CLK_DLL_96M: +// *(int *) 0x4000f03C = 0x10005; // clock selection +// break; +// default: +// *(int *) 0x4000f03C = 0x10002; // clock selection +// break; +// } + // ========== init timers + set_timer(AP_TIM2, 625); // OSAL 625us tick + set_timer(AP_TIM3, BASE_TIME_UNITS); // 1s timer + // =========== open interrupt mask + //int_state = 0x14; + //set_int(int_state); + //should use NVIC_EnableIRQn() + NVIC_EnableIRQ(BB_IRQn); + NVIC_EnableIRQ(TIM1_IRQn); + NVIC_EnableIRQ(TIM2_IRQn); + NVIC_EnableIRQ(TIM4_IRQn); + // =========== ll HW setting + set_max_length(0xff); + ll_hw_set_empty_head(0x0001); + //time related setting + ll_hw_set_rx_timeout_1st( 500); + ll_hw_set_rx_timeout( 88); //ZQ 20180606, reduce rx timeout for power saving + //preamble + syncword=40us, sync process = 8us + //timeout should be larger then 48us, + //ll_hw_set_rx_timeout( 268); //for ble shoulde be larger than 80+128. if sync, the timeout timer stop. + // (80 + 128) - BLE 5.0 preamble + access time, 60 for HW process delay + // this time doesn't consider HW startup time, it is set in other regs + ll_hw_set_loop_timeout( 30000); +// ll_hw_set_tx_rx_release (10, 1); +// ll_hw_set_rx_tx_interval( 57); //T_IFS=150us for BLE 1M +// ll_hw_set_tx_rx_interval( 65); //T_IFS=150us for BLE 1M +// ll_hw_set_trx_settle (57, 8, 52); //TxBB,RxAFE,PLL + ll_hw_set_timing(pktFmt); + ll_hw_ign_rfifo(LL_HW_IGN_SSN | LL_HW_IGN_CRC | LL_HW_IGN_EMP); + // ======== enable tracking 32KHz RC timer with 16MHz crystal clock + temp = *(volatile uint32_t*)0x4000f05C; + *(volatile uint32_t*)0x4000f05C = (temp & 0xfffefe00) | 0x0108; //[16] 16M [8:4] cnt [3] track_en_rc32k + //get wakeup tracking counter + // if (pGlobal_config[LL_SWITCH] & RC32_TRACKINK_ALLOW) + // { + // WaitRTCCount(17); + // uint32_t counter_tracking_wakeup = *(volatile uint32_t *)0x4000f064 & 0x1ffff; + // counter_tracking = (counter_tracking_wakeup + counter_tracking)>>1; + // } +} + +void config_RTC1(uint32 time) +{ +// *((volatile uint32_t *)(0xe000e100)) |= INT_BIT_RTC; // remove, we don't use RTC interrupt + //align to rtc clock edge + WaitRTCCount(1); + //update for cal ll next time after wakeup + ll_remain_time = read_LL_remainder_time(); + // comparator configuration + sleep_tick = *(volatile uint32_t*) 0x4000f028; // read current RTC counter + g_TIM2_IRQ_to_Sleep_DeltTick = (g_TIM2_IRQ_TIM3_CurrCount>(AP_TIM3->CurrentCount)) + ? (g_TIM2_IRQ_TIM3_CurrCount-(AP_TIM3->CurrentCount)): 0; + AP_AON->RTCCC0 = sleep_tick + time; //set RTC comparatr0 value +// *(volatile uint32_t *) 0x4000f024 |= 1 << 20; //enable comparator0 envent +// *(volatile uint32_t *) 0x4000f024 |= 1 << 18; //counter overflow interrupt +// *(volatile uint32_t *) 0x4000f024 |= 1 << 15; //enable comparator0 inerrupt + //*(volatile uint32_t *) 0x4000f024 |= 0x148000; // combine above 3 statement to save MCU time + AP_AON->RTCCTL |= BIT(15)|BIT(18)|BIT(20); + + //compensate for cal wakeup next_time + if (llState != LL_STATE_IDLE) + { + if(g_system_clk == SYS_CLK_XTAL_16M) + { + ll_remain_time -= 15; + } + else if(g_system_clk == SYS_CLK_DBL_32M) + { + ll_remain_time -= 8; + } + else if(g_system_clk == SYS_CLK_DLL_48M) + { + ll_remain_time -= 5; + } + else + { + ll_remain_time -= 3; + } + } + + #if 0 + extern uint32 sleep_total; + LOG("%d %d %d\n",conn_param[0].currentEvent,sleep_total,counter_tracking); + #endif +} + +#if 1 +/******************************************************************************* + @fn wakeupProcess1 + + @brief wakeup from system sleep process function. + + + input parameters + + @param None + + output parameters + + @param None. + + @return None. +*/ +uint32 sleep_total; +void wakeupProcess1(void) +{ + uint32 current_RTC_tick; + uint32 wakeup_time, wakeup_time0, next_time; + uint32 dlt_tick; + //restore initial_sp according to the app_initial_sp : 20180706 ZQ + __set_MSP(pGlobal_config[INITIAL_STACK_PTR]); + HAL_CRITICAL_SECTION_INIT(); + + //==== 20180416 commented by ZQ + // to enable flash access after wakeup + // current consumption has been checked. No big different + //rom_set_flash_deep_sleep(); + + //=======fix sram_rent issue 20180323 + //hal_pwrmgr_RAM_retention_clr(); + //subWriteReg(0x4000f01c,21,17,0); + + if (sleep_flag != SLEEP_MAGIC) + { + // enter this branch not in sleep/wakeup scenario + set_sleep_flag(0); + // software reset + *(volatile uint32*)0x40000010 &= ~0x2; // bit 1: M0 cpu reset pulse, bit 0: M0 system reset pulse. + } + + // restore HW registers + wakeup_init1(); + //===20180417 added by ZQ + // could be move into wakeup_init + // add the patch entry for tx2rx/rx2tx interval config + //2018-11-10 by ZQ + //config the tx2rx timing according to the g_rfPhyPktFmt + ll_hw_tx2rx_timing_config(g_rfPhyPktFmt); + // 20200812 ZQ + // DO NOT Turn OFF 32K Xtal + // if (pGlobal_config[LL_SWITCH] & LL_RC32K_SEL) + // { + // subWriteReg(0x4000f01c,16,7,0x3fb); //software control 32k_clk + // subWriteReg(0x4000f01c,6,6 ,0x01); //enable software control + // } + // else + // { + // subWriteReg(0x4000f01c,9,8,0x03); //software control 32k_clk + // subWriteReg(0x4000f01c,6,6,0x00); //disable software control + // } + //20181201 by ZQ + //restart the TIM2 to align the RTC + //---------------------------------------------------------- + //stop the 625 timer + AP_TIM2->ControlReg=0x0; + AP_TIM2->ControlReg=0x2; + AP_TIM2->LoadCount = 2500; + //---------------------------------------------------------- + //wait rtc cnt change + WaitRTCCount(1); + //---------------------------------------------------------- + //restart the 625 timer + AP_TIM2->ControlReg=0x3; + current_RTC_tick = rtc_get_counter(); + //g_TIM2_wakeup_delay= (AP_TIM2->CurrentCount)+12; //12 is used to align the rtc_tick + wakeup_time0 = read_current_fine_time(); + g_wakeup_rtc_tick = rtc_get_counter(); + // rf initial entry, will be set in app + rf_phy_ini(); + + if(current_RTC_tick>sleep_tick) + { + dlt_tick = current_RTC_tick - sleep_tick; + } + else + { + //dlt_tick = current_RTC_tick+0x00ffffff - sleep_tick; + dlt_tick = (0xffffffff - sleep_tick)+current_RTC_tick; + } + + //dlt_tick should not over 24bit + //otherwise, sleep_total will overflow !!! + if(dlt_tick>0x3fffff) + dlt_tick &=0x3fffff; + + if (pGlobal_config[LL_SWITCH] & RC32_TRACKINK_ALLOW) + { + //sleep_total = ((current_RTC_tick - sleep_tick) * counter_tracking) >> 7; // shift 4 for 16MHz -> 1MHz, shift 3 for we count 8 RTC tick + // sleep_total = ((((dlt_tick &0xffff0000)>>16)*counter_tracking)<<9) + // + (((dlt_tick &0xffff)*counter_tracking)>>7); + //counter_tracking default 16 cycle + sleep_total = ((((dlt_tick &0xffff0000)>>16)*counter_tracking)<<8) + + (((dlt_tick &0xffff)*counter_tracking)>>8); + } + else + { + // time = tick * 1000 0000 / f (us). f = 32000Hz for RC, f = 32768Hz for crystal. We also calibrate 32KHz RC to 32768Hz + //sleep_total = ((current_RTC_tick - sleep_tick) * TIMER_TO_32K_CRYSTAL) >> 2; + //fix sleep timing error + sleep_total = ( ( (dlt_tick<<7)-(dlt_tick<<2)-(dlt_tick<<1) +2) >>2 ) /* dlt_tick * (128-4-2)/4 */ + +( ( (dlt_tick<<3)+ dlt_tick +128) >>9 ) ; /* dlt_tick *9/512 */ + //+2,+128 for zero-mean quanization noise + } + + // restore systick + g_osal_tick_trim = (pGlobal_config[OSAL_SYS_TICK_WAKEUP_TRIM]+g_TIM2_IRQ_to_Sleep_DeltTick+2500-g_TIM2_IRQ_PendingTick)>>2; //16 is used to compensate the cal delay + g_osalTickTrim_mod+=(pGlobal_config[OSAL_SYS_TICK_WAKEUP_TRIM]+g_TIM2_IRQ_to_Sleep_DeltTick+2500-g_TIM2_IRQ_PendingTick)&0x03; //16 is used to compensate the cal delay + + if(g_osalTickTrim_mod>4) + { + g_osal_tick_trim+=1; + g_osalTickTrim_mod = g_osalTickTrim_mod%4; + } + + // restore systick + osal_sys_tick += (sleep_total+g_osal_tick_trim) / 625; // convert to 625us systick + rtc_mod_value += ((sleep_total+g_osal_tick_trim)%625); + + if(rtc_mod_value > 625) + { + osal_sys_tick += 1; + rtc_mod_value = rtc_mod_value%625; + } + + osalTimeUpdate(); + + // osal time update, not required. It will be updated when osal_run_system() is called after wakeup + + // TODO: should we consider widen the time drift window ???? + + //20190117 ZQ + if(llState != LL_STATE_IDLE) + { + // SW delay + wakeup_time = read_current_fine_time() - wakeup_time0; + next_time = 0; + + if (ll_remain_time > sleep_total + wakeup_time) + { + next_time = ll_remain_time - sleep_total - wakeup_time; + // restore LL timer + set_timer(AP_TIM1, next_time); + } + else + { + // should not be here + set_timer(AP_TIM1, 1000); + } + } + + if (g_llSleepContext.isTimer4RecoverRequired) + { + // SW delay + wakeup_time = read_current_fine_time() - wakeup_time0; + next_time = 0; + + if (g_llSleepContext.timer4Remainder > sleep_total + wakeup_time) + { + next_time = g_llSleepContext.timer4Remainder - sleep_total - wakeup_time; + // restore LL timer + set_timer(AP_TIM4, next_time); + } + else + { + // should not be here + set_timer(AP_TIM4, 1500); + // next_time = 0xffff; + } + + g_llSleepContext.isTimer4RecoverRequired = FALSE; + } + + // app could add operation after wakeup + app_wakeup_process(); +// uart_tx0(" 111 "); + ll_debug_output(DEBUG_WAKEUP); + set_sleep_flag(0); + // ==== measure value, from RTC counter meet comparator 0 -> here : 260us ~ 270us + // start task loop + osal_start_system(); +} +void enter_sleep_off_mode1(Sleep_Mode mode) +{ + if(mode==SYSTEM_SLEEP_MODE) + spif_set_deep_sleep(); + + enter_sleep_off_mode0(mode); +} +#endif +void LL_ENC_AES128_Encrypt1( uint8* key, + uint8* plaintext, + uint8* ciphertext ) +{ + //only turn on while working + AP_PCR->SW_CLK |= BIT(MOD_AES); + LL_ENC_AES128_Encrypt0(key,plaintext,ciphertext); + AP_PCR->SW_CLK &= ~BIT(MOD_AES); +} + +#define LL_ENC_BASE 0x40040000 // LL HW AES engine Base address + +#define LL_ENC_ENCRYPT_DONE_MASK 0x0001 +#define LL_ENC_DECRYPT_FAIL_MASK 0x0002 +#define LL_ENC_DECRYPT_SUCC_MASK 0x0004 +#define LL_ENC_SINGLE_MODE_DONE_MASK 0x0008 + +extern void LL_ENC_LoadKey( uint8* key ); +void LL_ENC_Encrypt1( llConnState_t* connPtr, uint8 pktHdr, uint8 pktLen, uint8* pBuf ) +{ + AP_PCR->SW_CLK |= BIT(MOD_AES); +// LL_ENC_Encrypt0(connPtr, pktHdr, pktLen, pBuf ); + { + uint8* pByte = NULL; + uint16 index; + int i, len; + uint32_t temp; + // disable AES + *(int*) 0x40040000 = 0x0; + // Load Key + // Note: Normally this would only need to be done once when the SK is derived + // from the LTK and SKD. However, when in sleep, the AES block loses + // this key. Also, when multiple connections are supported, the key + // will be different. + LL_ENC_LoadKey( connPtr->encInfo.SK ); + +// if ( llState == LL_STATE_CONN_MASTER ) + if( connPtr->llTbd1 == LL_LINK_CONNECT_COMPLETE_MASTER ) + { + // generate the nonce based on packet count, IV, and direction + LL_ENC_GenerateNonce( connPtr->encInfo.txPktCount, + LL_ENC_TX_DIRECTION_MASTER, + connPtr->encInfo.nonce ); + } + else // assumed llState == LL_STATE_CONN_SLAVE + { + // generate the nonce based on packet count, IV, and direction + LL_ENC_GenerateNonce( connPtr->encInfo.txPktCount, + LL_ENC_TX_DIRECTION_SLAVE, + connPtr->encInfo.nonce ); + } + + // confiig nounce + pByte = connPtr->encInfo.nonce; + *(volatile uint32_t*)(LL_ENC_BASE + 0x3c) = pByte[0] ; + pByte ++; + *(volatile uint32_t*)(LL_ENC_BASE + 0x38) = pByte[0] << 24 | pByte[1] << 16 | pByte[2] << 8 | pByte[3]; + pByte += 4; + *(volatile uint32_t*)(LL_ENC_BASE + 0x34) = pByte[0] << 24 | pByte[1] << 16 | pByte[2] << 8 | pByte[3]; + pByte += 4; + *(volatile uint32_t*)(LL_ENC_BASE + 0x30) = pByte[0] << 24 | pByte[1] << 16 | pByte[2] << 8 | pByte[3]; + // config plen & aad + *(volatile uint32_t*)(LL_ENC_BASE + 0x0c) = (pktLen << 8) | pktHdr; + // write packet to FIFO + len = pktLen; + index = 0; + + while (len >= 4) + { + *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + index) + = pBuf[index + 3] << 24 | pBuf[index + 2] << 16 | pBuf[index + 1] << 8 | pBuf[index]; + index += 4; + len -= 4; + } + + // to check the byte order + if(len == 3) + { + *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + index) + = pBuf[index + 2] << 16 | pBuf[index + 1] << 8 | pBuf[index]; + index += 4; + } + else if(len == 2) + { + *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + index) + = pBuf[index + 1] << 8 | pBuf[index] ; + index += 4; + } + else if(len == 1) + { + *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + index) + = pBuf[index] ; + index += 4; + } + + // AES FIFO legth is 256 bytes, set other bytes 0 + for (i = index; i < 0x100; i += 4) + { + *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + i) = 0x0; + } + + // set AES ctrl reg + *(int*) 0x40040004 = 0xf00; + // set interrupt enable + *(int*) 0x40040010 = 0xf; + // enable AES + *(int*) 0x40040000 = 0x1; + + // insert delay + // delay = 200; + // while (delay --); + + // query AES interrupt status register + while (*(volatile uint32_t*)(LL_ENC_BASE + 0x0014) == 0) ; + + // disable AES, if not disable AES, there is no output in FIFO + *(int*) 0x40040000 = 0x0; + // read back the encrypt result + index = 0; + len = pktLen + 4; // include 4 bytes MIC + + while (len > 0) + { + temp = *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + index); + pBuf[index ++] = temp & 0xff; + pBuf[index ++] = (temp >> 8) & 0xff; + pBuf[index ++] = (temp >> 16) & 0xff; + pBuf[index ++] = (temp >> 24) & 0xff; + len -= 4; + } + + // up the count for the next TX'ed data packet + // Note: This is supposed to be 39 bit counter, but for now, we don't + // envision receiving 550 billion packets during a connection! + connPtr->encInfo.txPktCount++; +// return; + } + AP_PCR->SW_CLK &= ~BIT(MOD_AES); +} +uint8 LL_ENC_Decrypt1( llConnState_t* connPtr, uint8 pktHdr, uint8 pktLen, uint8* pBuf ) +{ + AP_PCR->SW_CLK |= BIT(MOD_AES); +// uint8 ret = LL_ENC_Decrypt0( connPtr, pktHdr, pktLen, pBuf ); + { + uint8* pByte = NULL; + uint16 index; + int i, len; + uint32_t temp; + // disable AES + *(int*) 0x40040000 = 0x0; + // Load Key + // Note: Normally this would only need to be done once when the SK is derived + // from the LTK and SKD. However, when in sleep, the AES block loses + // this key. Also, when multiple connections are supported, the key + // will be different. + LL_ENC_LoadKey( connPtr->encInfo.SK ); + +// if ( llState == LL_STATE_CONN_MASTER ) + if( connPtr->llTbd1 == LL_LINK_CONNECT_COMPLETE_MASTER ) + { + // generate the nonce based on packet count, IV, and direction + LL_ENC_GenerateNonce( connPtr->encInfo.rxPktCount, + LL_ENC_RX_DIRECTION_MASTER, + connPtr->encInfo.nonce ); + } + else // assumed llState == LL_STATE_CONN_SLAVE + { + // generate the nonce based on packet count, IV, and direction + LL_ENC_GenerateNonce( connPtr->encInfo.rxPktCount, + LL_ENC_RX_DIRECTION_SLAVE, + connPtr->encInfo.nonce ); + } + + // confiig nounce + pByte = connPtr->encInfo.nonce; + *(volatile uint32_t*)(LL_ENC_BASE + 0x3c) = pByte[0]; // << 24 ; + pByte ++; + *(volatile uint32_t*)(LL_ENC_BASE + 0x38) = pByte[0] << 24 | pByte[1] << 16 | pByte[2] << 8 | pByte[3]; + pByte += 4; + *(volatile uint32_t*)(LL_ENC_BASE + 0x34) = pByte[0] << 24 | pByte[1] << 16 | pByte[2] << 8 | pByte[3]; + pByte += 4; + *(volatile uint32_t*)(LL_ENC_BASE + 0x30) = pByte[0] << 24 | pByte[1] << 16 | pByte[2] << 8 | pByte[3]; + // config plen & aad + *(volatile uint32_t*)(LL_ENC_BASE + 0x0c) = (pktLen << 8) | pktHdr; + // write packet to FIFO + len = pktLen + 4; // decrypt, add 4 for MIC field length + index = 0; + + while (len >= 4) + { + *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + index) + = pBuf[index + 3] << 24 | pBuf[index + 2] << 16 | pBuf[index + 1] << 8 | pBuf[index]; + index += 4; + len -= 4; + } + + // fill others bytes < 1 word + if(len == 3) + { + *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + index) + = pBuf[index + 2] << 16 | pBuf[index + 1] << 8 | pBuf[index]; + index += 4; + } + else if(len == 2) + { + *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + index) + = pBuf[index + 1] << 8 | pBuf[index] ; + index += 4; + } + else if(len == 1) + { + *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + index) + = pBuf[index] ; + index += 4; + } + + // AES FIFO legth is 256 bytes, set other bytes 0 + for (i = index; i < 0x100; i += 4) + { + *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + i) = 0x0; + } + + // set AES ctrl reg + *(int*) 0x40040004 = 0xf08; + // set interrupt enable + *(int*) 0x40040010 = 0xf; + // enable AES + *(int*) 0x40040000 = 0x1; + + // insert delay +// delay = 200; +// while (delay --); + + // query AES interrupt status register and wait decrypt finish + while (*(volatile uint32_t*)(LL_ENC_BASE + 0x0014) == 0) ; + + // read interrupt status reg + temp = *(volatile uint32_t*)(LL_ENC_BASE + 0x0014); + + if ((temp & LL_ENC_DECRYPT_FAIL_MASK) + || ((temp & LL_ENC_DECRYPT_SUCC_MASK) == 0)) + { + AP_PCR->SW_CLK &= ~BIT(MOD_AES); + return FALSE; + } + + // disable AES + *(int*) 0x40040000 = 0x0; + // read the decrypt result + index = 0; + len = pktLen; + + while (len > 0) + { + temp = *(volatile uint32_t*)(LL_ENC_BASE + 0x0100 + index); + pBuf[index ++] = temp & 0xff; + pBuf[index ++] = (temp >> 8) & 0xff; + pBuf[index ++] = (temp >> 16) & 0xff; + pBuf[index ++] = (temp >> 24) & 0xff; + len -= 4; + } + + // up the count for the next RX'ed data packet + // Note: This is supposed to be 39 bit counter, but for now, we don't + // envision receiving 550 billion packets during a connection! + connPtr->encInfo.rxPktCount++; + AP_PCR->SW_CLK &= ~BIT(MOD_AES); + return( TRUE ); + } +// AP_PCR->SW_CLK &= ~BIT(MOD_AES); +// return ret; +} + +//20200928 ZQ +//fix ADV_DIR_IND rxAdd setbit +llStatus_t LL_SetAdvParam1( uint16 advIntervalMin, + uint16 advIntervalMax, + uint8 advEvtType, + uint8 ownAddrType, + uint8 peerAddrType, + uint8* peerAddr, + uint8 advChanMap, + uint8 advWlPolicy ) +{ + uint8_t llState_reserve = llState; + llStatus_t ret; + ret=LL_SetAdvParam0( advIntervalMin, + advIntervalMax, + advEvtType, + ownAddrType, + peerAddrType, + peerAddr, + advChanMap, + advWlPolicy ); + llState=llState_reserve; + + if(advEvtType==LL_ADV_CONNECTABLE_HDC_DIRECTED_EVT + || advEvtType==LL_ADV_CONNECTABLE_LDC_DIRECTED_EVT) + { + SET_BITS(g_tx_adv_buf.txheader, peerInfo.peerAddrType, RX_ADD_SHIFT, RX_ADD_MASK); // RxAdd need't set + } + + return ret; +} + +llStatus_t LL_SetAdvControl1( uint8 advMode ) +{ + //if random address isn't defined,can't set ownaddresstype to random + if ((advMode)&&(((adv_param.ownAddrType == LL_DEV_ADDR_TYPE_RANDOM) || + (adv_param.ownAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM)) && + ( (ownRandomAddr[0] == 0xFF) && + (ownRandomAddr[1] == 0xFF) && + (ownRandomAddr[2] == 0xFF) && + (ownRandomAddr[3] == 0xFF) && + (ownRandomAddr[4] == 0xFF) && + (ownRandomAddr[5] == 0xFF) ))) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + if (g_llAdvMode == LL_MODE_EXTENDED ) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llAdvMode = LL_MODE_LEGACY; + + // check if a direct test mode or modem test is in progress + if ( (llState == LL_STATE_DIRECT_TEST_MODE_TX) || + (llState == LL_STATE_DIRECT_TEST_MODE_RX) || + (llState == LL_STATE_MODEM_TEST_TX) || + (llState == LL_STATE_MODEM_TEST_RX) || + (llState == LL_STATE_MODEM_TEST_TX_FREQ_HOPPING) ) + { + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + } + + // 2021-4-19, check init/scan state should not enable/disable adv + if ( (llState == LL_STATE_SCAN) || + (llState == LL_STATE_INIT) ) + { + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + } + + // sanity checks again to be sure we don't start with bad parameters + if ( ( (adv_param.advEvtType != LL_ADV_CONNECTABLE_UNDIRECTED_EVT) && + (adv_param.advEvtType != LL_ADV_CONNECTABLE_HDC_DIRECTED_EVT) && + (adv_param.advEvtType != LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT) && + (adv_param.advEvtType != LL_ADV_SCANNABLE_UNDIRECTED_EVT) && + (adv_param.advEvtType != LL_ADV_CONNECTABLE_LDC_DIRECTED_EVT) ) || + ( (adv_param.ownAddrType != LL_DEV_ADDR_TYPE_PUBLIC) && + (adv_param.ownAddrType != LL_DEV_ADDR_TYPE_RANDOM) && + (adv_param.ownAddrType != LL_DEV_ADDR_TYPE_RPA_PUBLIC) && + (adv_param.ownAddrType != LL_DEV_ADDR_TYPE_RPA_RANDOM)) || + ( ((adv_param.advEvtType == LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT) || + (adv_param.advEvtType == LL_ADV_SCANNABLE_UNDIRECTED_EVT)) && + (adv_param.advInterval < LL_ADV_CONN_INTERVAL_MIN) ) ) // should use LL_ADV_NONCONN_INTERVAL_MIN after update it to 20ms + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + #ifdef DEBUG_LL + LOG("llState = %d\n", llState); + #endif + + // check if we should begin advertising + switch( advMode ) + { + // Advertisment Mode is On + case LL_ADV_MODE_ON: + + // check if command makes sense + if ( adv_param.advMode == LL_ADV_MODE_ON ) + { + // this is unexpected; something is wrong + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + } + + //add llState setting + if((llState == LL_STATE_IDLE)) + { + switch(adv_param .advEvtType) + { + case LL_ADV_CONNECTABLE_UNDIRECTED_EVT: + llState=LL_STATE_ADV_UNDIRECTED; + ll_debug_output(DEBUG_LL_STATE_ADV_UNDIRECTED); + break; + + case LL_ADV_CONNECTABLE_HDC_DIRECTED_EVT: + case LL_ADV_CONNECTABLE_LDC_DIRECTED_EVT: + llState=LL_STATE_ADV_DIRECTED; + ll_debug_output(DEBUG_LL_STATE_ADV_DIRECTED); + break; + + case LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT: + llState=LL_STATE_ADV_NONCONN; + ll_debug_output(DEBUG_LL_STATE_ADV_NONCONN); + break; + + case LL_ADV_SCANNABLE_UNDIRECTED_EVT: + llState=LL_STATE_ADV_SCAN; + ll_debug_output(DEBUG_LL_STATE_ADV_SCAN); + break; + + default: + llState=LL_STATE_IDLE; + ll_debug_output(DEBUG_LL_STATE_IDLE); + break; + } + } + + // llState changed when configure adv parameters + if (llState == LL_STATE_ADV_UNDIRECTED + || llState == LL_STATE_ADV_DIRECTED + || llState == LL_STATE_ADV_NONCONN + || llState == LL_STATE_ADV_SCAN ) // TODO: check this setting + { + g_llHdcDirAdvTime = 0; // for HDC direct adv + adv_param.advNextChan = LL_ADV_CHAN_LAST + 1; // set adv channel invalid + + if ( llSetupAdv() != LL_STATUS_SUCCESS ) + { + // indicate advertising is no longer active + adv_param.advMode = LL_ADV_MODE_OFF; + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + } + } + // add in A2, simultaneous conn event & scan/adv event + else if((llState == LL_STATE_CONN_SLAVE + || llState == LL_STATE_CONN_MASTER) + && (pGlobal_config[LL_SWITCH] & SIMUL_CONN_ADV_ALLOW)) + { + #ifdef DEBUG_LL + LOG("LL_SetAdvControl: start sec adv\r\n"); + #endif + + if (llSecondaryState != LL_SEC_STATE_IDLE) + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + + // adv event check + if (adv_param.advEvtType != LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT + && adv_param.advEvtType != LL_ADV_SCANNABLE_UNDIRECTED_EVT + && adv_param.advEvtType != LL_ADV_CONNECTABLE_UNDIRECTED_EVT) + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + + // Note: we may need maximum slave number check here. If number of slave reach ceil, + // only no-connectable adv is allowed. The checking could be don't in host + llSecondaryState = LL_SEC_STATE_ADV; + adv_param.advNextChan = LL_ADV_CHAN_LAST + 1; // set adv channel invalid + osal_stop_timerEx( LL_TaskID, LL_EVT_SECONDARY_ADV ); + osal_set_event(LL_TaskID, LL_EVT_SECONDARY_ADV); // set adv event + } + else // other state + return (LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE); + + // indicate advertising is no longer active + adv_param.advMode = LL_ADV_MODE_ON; + + if (g_llRlDeviceNum > 0) + osal_start_timerEx( LL_TaskID, LL_EVT_RPA_TIMEOUT, g_llRlTimeout * 1000 ); + + break; + + case LL_ADV_MODE_OFF: + // check if command makes sense +// if ( adv_param.advMode == LL_ADV_MODE_OFF ) +// { +// // this is unexpected; something is wrong +// return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); +// } + HAL_ENTER_CRITICAL_SECTION(); + // free the associated task block + //llFreeTask( &advInfo.llTask ); + // indicate we are no longer actively advertising + adv_param.advMode = LL_ADV_MODE_OFF; + + if (llState != LL_STATE_CONN_SLAVE && + llState != LL_STATE_CONN_MASTER ) // no conn + adv case + { + llState = LL_STATE_IDLE; // if not in connect state, set idle to disable advertise + //ZQ 20190912 + //stop ll timer when idle, considering the scan-adv interleve case + clear_timer(AP_TIM1); + ll_debug_output(DEBUG_LL_STATE_IDLE); + } + + if(llSecondaryState!=LL_SEC_STATE_IDLE) // conn + adv case + { +// uint8 i; +// i = 0; +// while (!(adv_param.advChanMap & (1 << i))) i ++; // get the 1st adv channel in the adv channel map +// if ((llSecondaryState == LL_SEC_STATE_ADV) +// && (adv_param.advNextChan != (LL_ADV_CHAN_FIRST + i))) // last adv event is not finished +// llSecondaryState = LL_SEC_STATE_IDLE_PENDING; +// else + { + llSecondaryState = LL_SEC_STATE_IDLE; + osal_stop_timerEx( LL_TaskID, LL_EVT_SECONDARY_ADV ); // stop timer + } + } + + HAL_EXIT_CRITICAL_SECTION(); + osal_stop_timerEx(LL_TaskID, LL_EVT_RPA_TIMEOUT); + break; + + default: + // we have an invalid value for advertisement mode + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + return( LL_STATUS_SUCCESS ); +} + + +#if 0 +//2020.10.22,Jie,fix phyupdate issue +llStatus_t LL_PhyUpdate1( uint16 connId ) +{ + llStatus_t status; + llConnState_t* connPtr; + uint8 phyMode; + + // make sure connection ID is valid + if ( (status=LL_ConnActive(connId)) != LL_STATUS_SUCCESS ) + { + return( status ); + } + + // get connection info + connPtr = &conn_param[connId ]; + + // check if an update control procedure is already pending + if ( ((connPtr->ctrlPktInfo.ctrlPktCount > 0) && + (connPtr->ctrlPktInfo.ctrlPkts[0] == LL_CTRL_PHY_UPDATE_IND)) || + (connPtr->pendingPhyModeUpdate == TRUE) ) + { + return( LL_STATUS_ERROR_CTRL_PROC_ALREADY_ACTIVE ); + } + + // we only support symmetric connection + // tx rx phy should be same + phyMode = connPtr->llPhyModeCtrl.req.txPhy & connPtr->llPhyModeCtrl.rsp.txPhy; + phyMode &= connPtr->llPhyModeCtrl.req.rxPhy & connPtr->llPhyModeCtrl.rsp.rxPhy; + + //20200727 Jie add for no change case + if((phyMode==0) || (phyMode == connPtr->llPhyModeCtrl.local.txPhy)) + { + //no change case + connPtr->phyUpdateInfo.m2sPhy = 0; + connPtr->phyUpdateInfo.s2mPhy = 0; + } + else if((phyMode&LE_2M_PHY)&&(connPtr->llPhyModeCtrl.local.txPhy != LE_2M_PHY)) + { + connPtr->phyUpdateInfo.m2sPhy = LE_2M_PHY; + connPtr->phyUpdateInfo.s2mPhy = LE_2M_PHY; + } + else if((phyMode&LE_CODED_PHY)&&(connPtr->llPhyModeCtrl.local.txPhy != LE_CODED_PHY)) + { + connPtr->phyUpdateInfo.m2sPhy = LE_CODED_PHY; + connPtr->phyUpdateInfo.s2mPhy = LE_CODED_PHY; + } + else + { + //no perferce can not support the tx/rx same time + connPtr->phyUpdateInfo.m2sPhy = LE_1M_PHY; + connPtr->phyUpdateInfo.s2mPhy = LE_1M_PHY; + } + + if(connPtr->phyUpdateInfo.m2sPhy==0) + { + connPtr->phyModeUpdateEvent = 0; + connPtr->phyUpdateInfo.instant = connPtr->phyModeUpdateEvent; + } + else + { + connPtr->phyModeUpdateEvent = (connPtr->curParam.slaveLatency+1) + + LL_INSTANT_NUMBER_MIN; + connPtr->phyUpdateInfo.instant = connPtr->phyModeUpdateEvent; + } + + // queue control packet for processing + llEnqueueCtrlPkt( connPtr, LL_CTRL_PHY_UPDATE_IND ); + return( LL_STATUS_SUCCESS ); +} +#endif + +//2020.10.22,Jie,fix scanparam ownaddr setting issue +llStatus_t LL_SetScanParam1( uint8 scanType, + uint16 scanInterval, + uint16 scanWindow, + uint8 ownAddrType, + uint8 scanWlPolicy ) +{ + llStatus_t ret; + ret = LL_SetScanParam0(scanType,scanInterval,scanWindow,ownAddrType,scanWlPolicy); +// LOG("%s,ret %d\n",__func__,ret); + + if(ret == LL_STATUS_SUCCESS) + { + scanInfo.ownAddrType = ownAddrType; + + if ( ownAddrType == LL_DEV_ADDR_TYPE_PUBLIC || ownAddrType == LL_DEV_ADDR_TYPE_RPA_PUBLIC) + { + LL_COPY_DEV_ADDR_LE( scanInfo.ownAddr, ownPublicAddr ); + } + else + { + LL_COPY_DEV_ADDR_LE( scanInfo.ownAddr, ownRandomAddr ); + } + } + + return ret; +} + +//2020.10.22,Jie, modify sanity check: +//add ownaddrtype; +//add LL_STATUS_ERROR_BAD_PARAMETER case +llStatus_t LL_SetScanControl1( uint8 scanMode, + uint8 filterReports ) +{ +// LOG("%s,scanMode %d\n",__func__,scanMode); + if (g_llScanMode == LL_MODE_EXTENDED ) + return LL_STATUS_ERROR_COMMAND_DISALLOWED; + + g_llScanMode = LL_MODE_LEGACY; + + // check if a direct test mode or modem test is in progress + if ( (llState == LL_STATE_DIRECT_TEST_MODE_TX) || + (llState == LL_STATE_DIRECT_TEST_MODE_RX) || + (llState == LL_STATE_MODEM_TEST_TX) || + (llState == LL_STATE_MODEM_TEST_RX) || + (llState == LL_STATE_MODEM_TEST_TX_FREQ_HOPPING) ) + { + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + } + + // sanity checks again to be sure we don't start with bad parameters + if ( ( (scanInfo.scanType != LL_SCAN_PASSIVE) && + (scanInfo.scanType != LL_SCAN_ACTIVE)) || + ( (scanInfo.ownAddrType != LL_DEV_ADDR_TYPE_PUBLIC) && + (scanInfo.ownAddrType != LL_DEV_ADDR_TYPE_RANDOM) && + (scanInfo.ownAddrType != LL_DEV_ADDR_TYPE_RPA_PUBLIC) && + (scanInfo.ownAddrType != LL_DEV_ADDR_TYPE_RPA_RANDOM)) || + ( (scanInfo.scanInterval < LL_SCAN_WINDOW_MIN) || + (scanInfo.scanInterval > LL_SCAN_WINDOW_MAX)) || + ( (scanInfo.scanWindow < LL_SCAN_WINDOW_MIN) || + (scanInfo.scanWindow > LL_SCAN_WINDOW_MAX)) || + ( (scanInfo.scanWindow > scanInfo.scanInterval) ) || + ( (filterReports != LL_FILTER_REPORTS_DISABLE) && + (filterReports != LL_FILTER_REPORTS_ENABLE)) ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // check if we should begin scanning + switch( scanMode ) + { + // Scanning Mode is On + case LL_SCAN_START: + +// LOG("LL_SCAN_START\n"); + + // check if command makes sense + if ( scanInfo.scanMode == LL_SCAN_START ) + { + // this is unexpected; something is wrong + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + } + + //20200804 Jie :if random address isn't defined,can't set ownaddresstype to random + if (((scanInfo.ownAddrType == LL_DEV_ADDR_TYPE_RANDOM) || + (scanInfo.ownAddrType == LL_DEV_ADDR_TYPE_RPA_RANDOM)) && + ( (ownRandomAddr[0] == 0xFF) && + (ownRandomAddr[1] == 0xFF) && + (ownRandomAddr[2] == 0xFF) && + (ownRandomAddr[3] == 0xFF) && + (ownRandomAddr[4] == 0xFF) && + (ownRandomAddr[5] == 0xFF) )) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // get a task block for this BLE state/role + // Note: There will always be a valid pointer, so no NULL check required. +// scanInfo.llTask = llAllocTask( LL_TASK_ID_SCANNER ); + + // check if no other tasks are currently active + if ( llState == LL_STATE_IDLE ) + { + // indicate Scan has not already been initalized + scanInfo.initPending = TRUE; + // save the scan filtering flag + scanInfo.filterReports = filterReports; + // add by HZF + scanInfo.nextScanChan = LL_SCAN_ADV_CHAN_37; + // set LL state + llState = LL_STATE_SCAN; + // Note: llState has been changed. + LL_evt_schedule(); + } + else if ((llState == LL_STATE_CONN_SLAVE + || llState == LL_STATE_CONN_MASTER) // HZF: if we should support adv + scan, add more state here + && (pGlobal_config[LL_SWITCH] & SIMUL_CONN_SCAN_ALLOW)) + { + if (llSecondaryState != LL_SEC_STATE_IDLE) + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + + scanInfo.nextScanChan = LL_SCAN_ADV_CHAN_37; + llSecondaryState = LL_SEC_STATE_SCAN; + osal_set_event(LL_TaskID, LL_EVT_SECONDARY_SCAN); + } + else + return( LL_STATUS_ERROR_UNEXPECTED_STATE_ROLE ); + + // indicate we are actively scanning + scanInfo.scanMode = LL_SCAN_START; + break; + + case LL_SCAN_STOP: +// LOG("LL_SCAN_STOP\n"); + HAL_ENTER_CRITICAL_SECTION(); + + if (llState == LL_STATE_SCAN) // no conn + scan case + { + llState = LL_STATE_IDLE; // if not in connect state, set idle to disable scan + //ZQ 20190912 + //stop ll timer when idle, considering the scan-adv interleve case + clear_timer(AP_TIM1); + ll_debug_output(DEBUG_LL_STATE_IDLE); + } + else if (llState == LL_STATE_CONN_SLAVE + || llState == LL_STATE_CONN_MASTER) // conn + scan case + { + llSecondaryState = LL_SEC_STATE_IDLE; + // bugfix for multi-role + osal_stop_timerEx(LL_TaskID, LL_EVT_SECONDARY_SCAN); + } + + // indicate we are no longer actively scanning + scanInfo.scanMode = LL_SCAN_STOP; + // A2 multiconn, should we consider current LL state to avoid change master/slave configuration + // now LL slave/master event use same parameter 88 + ll_hw_set_rx_timeout(88); + // HZF: should we stop scan task immediately, or wait scan IRQ then stop? Now use option 2. + HAL_EXIT_CRITICAL_SECTION(); + + while(read_reg(&llWaitingIrq) == TRUE); + + break; + + default: + // we have an invalid value for advertisement mode + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + return( LL_STATUS_SUCCESS ); +} + +//2020.10.23 Jie,fix g_llPduLen.suggested.MaxTxTime setting error +llStatus_t LL_SetDataLengh1( uint16 connId,uint16 TxOctets,uint16 TxTime ) +{ + if(TxOctets > LL_PDU_LENGTH_SUPPORTED_MAX_TX_OCTECTS + || TxTime > LL_PDU_LENGTH_SUPPORTED_MAX_TX_TIME + || TxOctets < LL_PDU_LENGTH_INITIAL_MAX_TX_OCTECTS + || TxTime < LL_PDU_LENGTH_INITIAL_MAX_TX_TIME) + { + return(LL_STATUS_ERROR_PARAM_OUT_OF_RANGE); + } + else + { + g_llPduLen.suggested.MaxTxOctets= TxOctets; + g_llPduLen.suggested.MaxTxTime = TxTime; + return LL_SetDataLengh0( connId,TxOctets,TxTime ); + } +} + +void llProcessTxData1( llConnState_t* connPtr, uint8 context ) +{ + if(context==LL_TX_DATA_CONTEXT_SEND_DATA) + return; + + llProcessTxData0(connPtr,context); +} +/******************************************************************************* + @fn ll_generateTxBuffer1 + + @brief This function generate Tx data and find in Tx FIFO + there are 4 kinds of data: + 1. control data + 2. last no-ack data + 3. last no-transmit data + 4. new data + in the new RTLP buffer, the data should be in the below sequence: + 2 --> 3 --> 1 --> 4 (changed) + + input parameters + + @param txFifo_vacancy - allow max tx packet number. + + output parameters + + @param None. + + @return the pointer of 1st not transmit packet/new packet. + +*/ +uint16 ll_generateTxBuffer1(int txFifo_vacancy, uint16* pSave_ptr) +{ + int i, new_pkts_num, tx_num = 0; + llConnState_t* connPtr; + connPtr = &conn_param[g_ll_conn_ctx.currentConn]; + + // 0. write empty packet + if(connPtr->llMode == LL_HW_RTLP_EMPT + || connPtr->llMode == LL_HW_TRLP_EMPT) // TRLP case, to be confirmed/test + { + LL_HW_WRT_EMPTY_PKT; + connPtr->ll_buf.tx_not_ack_pkt->valid = 0; // empty mode, tx_not_ack buffer null or empty packet + tx_num ++; + } + // 1. write last not-ACK packet + else if (connPtr->ll_buf.tx_not_ack_pkt->valid != 0) // TODO: if the valid field could omit, move the not-ACK flag to buf. + { + ll_hw_write_tfifo((uint8*)&(connPtr->ll_buf.tx_not_ack_pkt->header), ((connPtr->ll_buf.tx_not_ack_pkt->header & 0xff00) >> 8) + 2); + //txFifo_vacancy --; + tx_num ++; + connPtr->ll_buf.tx_not_ack_pkt->valid = 0; + AT_LOG("write last not-ACK packet \n"); + } + + // 1st RTLP event, no porcess 0/1, it should be 0 because we have reset the TFIFO + // other case, it is 1st not transmit packet/new packet + *pSave_ptr = ll_hw_get_tfifo_wrptr(); + + // 3. write last not transmit packets + if (connPtr->ll_buf.ntrm_cnt > 0 + && txFifo_vacancy >= connPtr->ll_buf.ntrm_cnt) + { + for (i = 0; i < connPtr->ll_buf.ntrm_cnt ; i++) + { + ll_hw_write_tfifo((uint8*)&(connPtr->ll_buf.tx_ntrm_pkts[i]->header), ((connPtr->ll_buf.tx_ntrm_pkts[i]->header & 0xff00) >> 8) + 2); + } + + txFifo_vacancy -= connPtr->ll_buf.ntrm_cnt; + tx_num += connPtr->ll_buf.ntrm_cnt; + AT_LOG("write last not transmit packets\n"); + connPtr->ll_buf.ntrm_cnt = 0; + } + + rfCounters.numTxCtrl = 0; // add on 2017-11-15, set tx control packet number 0 + + // 2. write control packet + if ((connPtr->ll_buf.tx_not_ack_pkt->valid == 0 || // no tx not_ack packet, add on 2017-11-15 + (connPtr->ll_buf.tx_not_ack_pkt->header & 0x3) != LL_DATA_PDU_HDR_LLID_CONTROL_PKT) // last nack packet is not a control packet + && connPtr->ctrlDataIsPending // we only support 1 control procedure per connection + && !connPtr->ctrlDataIsProcess + && txFifo_vacancy > connPtr->ll_buf.ntrm_cnt) // tricky here: if the Tx FIFO is full and nothing is sent in last event, then it can't fill new packet(include ctrl pkt) in new event + { + // not in a control procedure, and there is control packet pending + // fill ctrl packet + ll_hw_write_tfifo((uint8*)&(connPtr->ctrlData .header), ((connPtr->ctrlData .header & 0xff00) >> 8) + 2); + txFifo_vacancy --; + tx_num ++; + // put Ctrl packet in TFIFO, change the control procedure status + connPtr->ctrlDataIsPending = 0; + connPtr->ctrlDataIsProcess = 1; + rfCounters.numTxCtrl = 1; // add 2017-11-15, if put new ctrl packet in FIFO, add the counter + } + + if (connPtr->ll_buf.ntrm_cnt != 0) + { + // should not be here, new packets should not be sent if there is not-transmit packets + return tx_num; + } + + // 4. write new data packets to FIFO + new_pkts_num = getTxBufferSize(connPtr); + + if ((new_pkts_num > 0) + && txFifo_vacancy > 0) + { + // fill the data packet to Tx FIFO + for (i = 0; i < new_pkts_num && i < txFifo_vacancy; i++) + { + uint8_t idx = get_tx_read_ptr(connPtr); + ll_hw_write_tfifo((uint8*)&(connPtr->ll_buf.tx_conn_desc[idx]->header), ((connPtr->ll_buf.tx_conn_desc[idx]->header & 0xff00) >> 8) + 2); + update_tx_read_ptr(connPtr); + tx_num++; + AT_LOG("write new data packets to FIFO\n"); + // update PM counter, add A1 ROM metal change + connPtr->pmCounter.ll_send_data_pkt_cnt ++; + } + } + + // 2020-02-13 periodic cte req & rsp + if( ( connPtr->llConnCTE.enable ) && ( connPtr->llCTE_ReqFlag )) + { + if( connPtr->llConnCTE.CTE_Request_Intv > 0 ) + { + if( connPtr->llConnCTE.CTE_Count_Idx < connPtr->llConnCTE.CTE_Request_Intv ) + connPtr->llConnCTE.CTE_Count_Idx++; + else + { + connPtr->llConnCTE.CTE_Count_Idx = 0; + llEnqueueCtrlPkt(connPtr, LL_CTRL_CTE_REQ ); + } + } + } + + return tx_num; +} + + +#if 0 +//2020.10.23 Jie,fix setphymode issue +llStatus_t LL_SetPhyMode1( uint16 connId,uint8 allPhy,uint8 txPhy, uint8 rxPhy,uint16 phyOptions) +{ + uint8 i; + llStatus_t status; + llConnState_t* connPtr; + + // make sure connection ID is valid + if ( (status=LL_ConnActive(connId)) != LL_STATUS_SUCCESS ) + { + return( status ); + } + + // get connection info + connPtr = &conn_param[connId]; + + // check if a feature response control procedure has taken place + if ( connPtr->featureSetInfo.featureRspRcved == FALSE ) + { + // it hasn't so re-load this device's local Feature Set to the + // connection as it may have been changed by the Host with HCI + // extenstion Set Local Feature Set command + for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + } + + // check if dle is a supported feature set item + if( ( (connPtr->featureSetInfo.featureSet[1] & LL_FEATURE_2M_PHY) != LL_FEATURE_2M_PHY ) + && ( (connPtr->featureSetInfo.featureSet[1] & LL_FEATURE_CODED_PHY) != LL_FEATURE_CODED_PHY ) ) + { + return( LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED ); + } + + // check if an updated parameters control procedure is already what's pending + if ( ((connPtr->ctrlPktInfo.ctrlPktCount > 0) && + (connPtr->ctrlPktInfo.ctrlPkts[0] == LL_CTRL_PHY_REQ)) || + (connPtr->pendingPhyModeUpdate== TRUE) || + (connPtr->llPhyModeCtrl.isWatingRsp == TRUE) || (connPtr->llPhyModeCtrl.isProcessingReq == TRUE) ) + { + return( LL_STATUS_ERROR_CTRL_PROC_ALREADY_ACTIVE ); + } + + //support Symmetric Only + if(allPhy==0 &&(txPhy!=rxPhy)) + { + return( LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED ); + } + + //jie 2020.9.3 check unsupport phy + if ((txPhy > 0x07) || (rxPhy >0x07)) + { + return( LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED ); + } + + uint8 tx_chance = (txPhy ^ connPtr->llPhyModeCtrl.local.txPhy) ^connPtr->llPhyModeCtrl.local.txPhy; + + if(tx_chance & LE_1M_PHY) + { + txPhy = LE_1M_PHY; + } + else if(tx_chance & LE_2M_PHY) + { + txPhy = LE_2M_PHY; + } + else if(tx_chance & LE_CODED_PHY) + { + txPhy = LE_CODED_PHY; + } + else + { + //nothing + } + + uint8 rx_chance = (rxPhy ^ connPtr->llPhyModeCtrl.local.rxPhy)^connPtr->llPhyModeCtrl.local.rxPhy; + + if(rx_chance & LE_1M_PHY) + { + rxPhy = LE_1M_PHY; + } + else if(rx_chance & LE_2M_PHY) + { + rxPhy = LE_2M_PHY; + } + else if(rx_chance & LE_CODED_PHY) + { + rxPhy = LE_CODED_PHY; + } + else + { + //nothing + } + + // how to check the required param? + //LL_TS_5.0.3 Table 4.43: PDU payload contents for each case variation for LE 2M PHY + connPtr->llPhyModeCtrl.req.allPhy = allPhy; + + if(connPtr->llPhyModeCtrl.req.allPhy==0) + { + connPtr->llPhyModeCtrl.req.txPhy = txPhy; + connPtr->llPhyModeCtrl.req.rxPhy = rxPhy; + } + else if(connPtr->llPhyModeCtrl.req.allPhy==1) + { + connPtr->llPhyModeCtrl.req.txPhy = rxPhy;//0; + connPtr->llPhyModeCtrl.req.rxPhy = rxPhy; + } + else if(connPtr->llPhyModeCtrl.req.allPhy==2) + { + connPtr->llPhyModeCtrl.req.txPhy = txPhy; + connPtr->llPhyModeCtrl.req.rxPhy = txPhy;//0; + } + else + { + //no prefer on both phy + connPtr->llPhyModeCtrl.req.txPhy = LE_1M_PHY;//0; + connPtr->llPhyModeCtrl.req.rxPhy = LE_1M_PHY;//0; + } + + connPtr->llPhyModeCtrl.phyOptions = phyOptions; + //update def.phy jie 2020.9.2 + connPtr->llPhyModeCtrl.def.allPhy = allPhy; + // connPtr->llPhyModeCtrl.def.txPhy = connPtr->llPhyModeCtrl.req.txPhy; + // connPtr->llPhyModeCtrl.def.rxPhy = connPtr->llPhyModeCtrl.req.rxPhy; + // setup an LL_CTRL_PHY_REQ + llEnqueueCtrlPkt( connPtr, LL_CTRL_PHY_REQ ); + return(LL_STATUS_SUCCESS); +} +#endif + + +/* 2020.11.11,Jie,fix ownaddr random address source issue +*/ +llStatus_t LL_CreateConn1( uint16 scanInterval, + uint16 scanWindow, + uint8 initWlPolicy, + uint8 peerAddrType, + uint8* peerAddr, + uint8 ownAddrType, + uint16 connIntervalMin, + uint16 connIntervalMax, + uint16 connLatency, + uint16 connTimeout, + uint16 minLength, // minimum length of connection needed for this LE conn, no use now + uint16 maxLength ) // maximum length of connection needed for this LE conn, no use now +{ + CreateConn_Flag = TRUE; + return LL_CreateConn0(scanInterval, + scanWindow, + initWlPolicy, + peerAddrType, + peerAddr, + ownAddrType, + connIntervalMin, + connIntervalMax, + connLatency, + connTimeout, + minLength, + maxLength ); +} + +#if 0 +//2020.11.12, add case LL_REJECT_IND_EXT +void llProcessMasterControlPacket1( llConnState_t* connPtr, + uint8* pBuf ) +{ + uint8 i; + uint8 opcode = *pBuf++; + uint8 iqCnt = 0; + + // check the type of control packet + switch( opcode ) + { + // Encryption Response + case LL_CTRL_ENC_RSP: + // concatenate slave's SKDs with SKDm + // Note: The SKDs MSO is the MSO of the SKD. + //PHY_READ_BYTE( (uint8 *)&connPtr->encInfo.SKD[LL_ENC_SKD_S_OFFSET], LL_ENC_SKD_S_LEN ); + pBuf = llMemCopySrc( (uint8*)&connPtr->encInfo.SKD[LL_ENC_SKD_S_OFFSET], pBuf, LL_ENC_SKD_S_LEN ); + // bytes are received LSO..MSO, but need to be maintained as + // MSO..LSO, per FIPS 197 (AES), so reverse the bytes + LL_ENC_ReverseBytes( &connPtr->encInfo.SKD[LL_ENC_SKD_S_OFFSET], LL_ENC_SKD_S_LEN ); + // concatenate the slave's IVs with IVm + // Note: The IVs MSO is the MSO of the IV. + //PHY_READ_BYTE( (uint8 *)&connPtr->encInfo.IV[LL_ENC_IV_S_OFFSET], LL_ENC_IV_S_LEN ); + pBuf = llMemCopySrc( (uint8*)&connPtr->encInfo.IV[LL_ENC_IV_S_OFFSET], pBuf, LL_ENC_IV_S_LEN ); + // bytes are received LSO..MSO, but need to be maintained as + // MSO..LSO, per FIPS 197 (AES), so reverse the bytes + // ALT: POSSIBLE TO MAINTAIN THE IV IN LSO..MSO ORDER SINCE THE NONCE + // IS FORMED THAT WAY. + LL_ENC_ReverseBytes( &connPtr->encInfo.IV[LL_ENC_IV_S_OFFSET], LL_ENC_IV_S_LEN ); + + // place the IV into the Nonce to be used for this connection + // Note: If a Pause Encryption control procedure is started, the + // old Nonce value will be used until encryption is disabled. + // Note: The IV is sequenced LSO..MSO within the Nonce. + // ALT: POSSIBLE TO MAINTAIN THE IV IN LSO..MSO ORDER SINCE THE NONCE + // IS FORMED THAT WAY. + for (i=0; iencInfo.nonce[ LL_END_NONCE_IV_OFFSET+i ] = + connPtr->encInfo.IV[ (LL_ENC_IV_LEN-i)-1 ]; + } + + // generate the Session Key (i.e. SK = AES128(LTK, SKD)) + LL_ENC_GenerateSK( connPtr->encInfo.LTK, + connPtr->encInfo.SKD, + connPtr->encInfo.SK ); + // LOG("LTK: %x\r\n", connPtr->encInfo.LTK); + // LOG("SKD: %x\r\n", connPtr->encInfo.SKD); + // LOG("SK: %x\r\n", connPtr->encInfo.SK[0], connPtr->encInfo.SK[1], connPtr->encInfo.SK[],connPtr->encInfo.SK[0], + // connPtr->encInfo.SK[0],connPtr->encInfo.SK[0],connPtr->encInfo.SK[0]); + // Note: Done for now; the slave will send LL_CTRL_START_ENC_REQ. + //LOG("ENC_RSP ->"); + break; + + // Start Encryption Request + case LL_CTRL_START_ENC_REQ: + // set a flag to indicate we've received this packet + connPtr->encInfo.startEncReqRcved = TRUE; + break; + + // Start Encryption Response + case LL_CTRL_START_ENC_RSP: + // set flag to allow outgoing data transmissions + connPtr->txDataEnabled = TRUE; + // okay to receive data again + connPtr->rxDataEnabled = TRUE; + // indicate we've received the start encryption response + connPtr->encInfo.startEncRspRcved = TRUE; + + // notify the Host + if ( connPtr->encInfo.encRestart == TRUE ) + { + // a key change was requested + LL_EncKeyRefreshCback( connPtr->connId, + LL_ENC_KEY_REQ_ACCEPTED ); + } + else + { + // a new encryption was requested + LL_EncChangeCback( connPtr->connId, + LL_ENC_KEY_REQ_ACCEPTED, + LL_ENCRYPTION_ON ); + } + + // clear the restart flag in case of another key change request + // Note: But in reality, there isn't a disable encryption in BLE, + // so once encryption is enabled, any call to LL_StartEncrypt + // will result in an encryption key change callback. + connPtr->encInfo.encRestart = FALSE; + //LOG("START_ENC_RSP ->"); + break; + + // Pause Encryption Response + case LL_CTRL_PAUSE_ENC_RSP: + // set a flag to indicate we have received LL_START_ENC_RSP + connPtr->encInfo.pauseEncRspRcved = TRUE; + break; + + // Reject Encryption Indication + /* + case LL_CTRL_REJECT_IND: + // either the slave's Host has failed to provide an LTK, or + // the encryption feature is not supported by the slave, so read + // the rejection indication error code + //connPtr->encInfo.encRejectErrCode = PHY_READ_BYTE_VAL(); + connPtr->encInfo.encRejectErrCode = *pBuf; + + // and end the start encryption procedure + connPtr->encInfo.rejectIndRcved = TRUE; + + break; + */ + + // Controller Feature Setup --> should be LL_CTRL_SLAVE_FEATURE_REQ + // case LL_CTRL_FEATURE_REQ: // new for BLE4.2, to test + + // for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + // } + + // // logical-AND with master's feature set to indicate which of the + // // controller features in the master the slave requests to be used + // for (i=0; ifeatureSetInfo.featureSet[i] = + // *pBuf++ & deviceFeatureSet.featureSet[i]; + // } + + // // schedule the output of the control packet + // // Note: Features to be used will be taken on the next connection + // // event after the response is successfully transmitted. + // llEnqueueCtrlPkt( connPtr, LL_CTRL_FEATURE_RSP ); + + // break; + + case LL_CTRL_FEATURE_RSP: + { + uint8 peerFeatureSet[ LL_MAX_FEATURE_SET_SIZE ]; + // get the peer's device Feature Set + //for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + + // logical-AND with slave's feature set to indicate which of the + // controller features in the master the slave requests to be + // used + // Note: For now, there is only one feature that is supported + // controller-to-controller. + // Note: If the peer supports the feature, then our setting is + // the controller-to-controller setting, so no action + // is required. + if ( !(peerFeatureSet[0] & LL_FEATURE_ENCRYPTION) ) + { + // this feature is not supported by the peer, so it doesn't + // matter if we support it or not, it should not be supported + connPtr->featureSetInfo.featureSet[0] &= ~LL_FEATURE_ENCRYPTION; + } + } + + // set flag to indicate the response has been received + connPtr->featureSetInfo.featureRspRcved = TRUE; + break; + + // Version Information Indication + case LL_CTRL_VERSION_IND: + + // check if the peer's version information has already been obtained + if ( connPtr->verExchange.peerInfoValid == TRUE ) + { + // it has, so something is wrong as the spec indicates that + // only one version indication should be sent for a connection + // unknown data PDU control packet received so save the type + connPtr->unknownCtrlType = opcode; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_UNKNOWN_RSP ); + } + else // the peer version info is invalid, so make it valid + { + // get the peer's version information and save it + //PHY_READ_BYTE( (uint8 *)&peerInfo.verInfo.verNum, 1 ); + connPtr->verInfo.verNum = *pBuf++; + //PHY_READ_BYTE( (uint8 *)&peerInfo.verInfo.comId, 2 ); + pBuf = llMemCopySrc( (uint8*)&connPtr->verInfo.comId, pBuf, 2 ); + //PHY_READ_BYTE( (uint8 *)&peerInfo.verInfo.subverNum, 2 ); + pBuf = llMemCopySrc( (uint8*)&connPtr->verInfo.subverNum, pBuf, 2 ); + // set a flag to indicate it is now valid + connPtr->verExchange.peerInfoValid = TRUE; + + // check if a version indication has been sent + if ( connPtr->verExchange.verInfoSent == FALSE ) + { + // no, so this is a peer's request for our version information + llEnqueueCtrlPkt( connPtr, LL_CTRL_VERSION_IND ); + } + } + + break; + + // Terminate Indication + case LL_CTRL_TERMINATE_IND: + // read the reason code + connPtr->termInfo.reason = *pBuf; + // set flag to indicate a termination indication was received + connPtr->termInfo.termIndRcvd = TRUE; + // received a terminate from peer host, so terminate after + // confirming we have sent an ACK + // Note: For the master, we have to ensure that this control + // packet was ACK'ed. For that, the nR has a new flag that + // is set when the control packet is received, and cleared + // when the control packet received is ACK'ed. + // Note: This is not an issue as a slave because the terminate + // packet will re-transmit until the slave ACK's. + // ALT: COULD REPLACE THIS CONTROL PROCEDURE AT THE HEAD OF THE + // QUEUE SO TERMINATE CAN TAKE PLACE ASAP. + //llReplaceCtrlPkt( connPtr, LL_CTRL_TERMINATE_RX_WAIT_FOR_TX_ACK ); + llEnqueueCtrlPkt( connPtr, LL_CTRL_TERMINATE_RX_WAIT_FOR_TX_ACK ); + break; + + // LL PDU Data Length Req + case LL_CTRL_LENGTH_REQ: + + // check if the feature response procedure has already been performed + // on this connection + if ( connPtr->featureSetInfo.featureRspRcved == FALSE ) + { + // it hasn't so re-load this device's local Feature Set to the + // connection as it may have been changed by the Host with HCI + // extenstion Set Local Feature Set command + for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + } + + // check if supported DLE + if ( (connPtr->featureSetInfo.featureSet[0] & LL_FEATURE_DATA_LENGTH_EXTENSION) + != LL_FEATURE_DATA_LENGTH_EXTENSION ) + { + // unknown data PDU control packet received so save the type + connPtr->unknownCtrlType = opcode; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_UNKNOWN_RSP ); + } + else + { + if(connPtr->llPduLen.isProcessingReq==FALSE) + { + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxRxOctets), pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxRxTime), pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxTxOctets), pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxTxTime), pBuf, 2 ); + connPtr->llPduLen.isProcessingReq=TRUE; + llEnqueueCtrlPkt( connPtr, LL_CTRL_LENGTH_RSP ); + } + } + + break; + + // LL PDU Data Length RSP + case LL_CTRL_LENGTH_RSP: + + // check if supported DLE + if ( (connPtr->featureSetInfo.featureSet[0] & LL_FEATURE_DATA_LENGTH_EXTENSION) + != LL_FEATURE_DATA_LENGTH_EXTENSION ) + { + // unknown data PDU control packet received so save the type + connPtr->unknownCtrlType = opcode; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_UNKNOWN_RSP ); + } + else + { + if(connPtr->llPduLen.isWatingRsp==TRUE ) + { + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxRxOctets), pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxRxTime), pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxTxOctets), pBuf, 2 ); + pBuf = llMemCopySrc( (uint8*)& (connPtr->llPduLen.remote.MaxTxTime), pBuf, 2 ); + llPduLengthUpdate((uint16)connPtr->connId); + connPtr->llPduLen.isWatingRsp=FALSE; + } + } + + break; + + // LL PHY UPDATE REQ + case LL_CTRL_PHY_REQ: + + // check if the feature response procedure has already been performed + // on this connection + if ( connPtr->featureSetInfo.featureRspRcved == FALSE ) + { + // it hasn't so re-load this device's local Feature Set to the + // connection as it may have been changed by the Host with HCI + // extenstion Set Local Feature Set command + for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + } + + // check if supported PHY MODE UPDATE + if ( (connPtr->featureSetInfo.featureSet[1] & LL_FEATURE_2M_PHY) != LL_FEATURE_2M_PHY + && (connPtr->featureSetInfo.featureSet[1] & LL_FEATURE_CODED_PHY) != LL_FEATURE_CODED_PHY) + { + // unknown data PDU control packet received so save the type + connPtr->unknownCtrlType = opcode; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_UNKNOWN_RSP ); + } + else + { + //process for the protocol collision + //2018-11-10 by ZQ + if(connPtr->llPhyModeCtrl.isWatingRsp==TRUE || + connPtr->pendingChanUpdate==TRUE || + connPtr->pendingParamUpdate==TRUE ) + { + connPtr->isCollision=TRUE; + connPtr->rejectOpCode = LL_CTRL_PHY_REQ; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_REJECT_EXT_IND ); + } + else + { + if(connPtr->llPhyModeCtrl.isProcessingReq==FALSE) + { + connPtr->llPhyModeCtrl.req.txPhy=*pBuf++; + connPtr->llPhyModeCtrl.req.rxPhy=*pBuf++; + connPtr->llPhyModeCtrl.req.allPhy=connPtr->llPhyModeCtrl.def.allPhy; + connPtr->llPhyModeCtrl.rsp.txPhy=connPtr->llPhyModeCtrl.def.txPhy; + connPtr->llPhyModeCtrl.rsp.rxPhy=connPtr->llPhyModeCtrl.def.rxPhy; + //rsp and req will be used to determine the next phy mode + LL_PhyUpdate((uint16) connPtr->connId); + connPtr->llPhyModeCtrl.isProcessingReq=TRUE; + } + else + { + //should no be here + } + } + } + + break; + + // LL_CTRL_PHY_RSP + case LL_CTRL_PHY_RSP: + + // check if supported PHY MODE UPDATE + if ( (connPtr->featureSetInfo.featureSet[1] & LL_FEATURE_2M_PHY) != LL_FEATURE_2M_PHY + && (connPtr->featureSetInfo.featureSet[1] & LL_FEATURE_CODED_PHY) != LL_FEATURE_CODED_PHY) + { + // unknown data PDU control packet received so save the type + connPtr->unknownCtrlType = opcode; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_UNKNOWN_RSP ); + } + else + { + if(connPtr->llPhyModeCtrl.isWatingRsp==TRUE) + { + connPtr->llPhyModeCtrl.rsp.txPhy=*pBuf++; + connPtr->llPhyModeCtrl.rsp.rxPhy=*pBuf++; + LL_PhyUpdate((uint16) connPtr->connId); + connPtr->llPhyModeCtrl.isWatingRsp=FALSE; + } + else + { + //should no be here + } + } + + break; + + case LL_CTRL_CTE_REQ: + + // check if the feature response procedure has already been performed + // on this connection + if ( connPtr->featureSetInfo.featureRspRcved == FALSE ) + { + // it hasn't so re-load this device's local Feature Set to the + // connection as it may have been changed by the Host with HCI + // extenstion Set Local Feature Set command + for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + } + + // check if supported CTE Response Feature + // if( connPtr->featureSetInfo.featureSet[LL_CTE_FEATURE_IDX] & LL_CONN_CTE_RSP) + if(( ( connPtr->featureSetInfo.featureSet[LL_CTE_FEATURE_IDX] & LL_CONN_CTE_RSP) != LL_CONN_CTE_RSP) || \ + ( connPtr->llCTE_RspFlag != TRUE )) + { + // unknown data PDU control packet received so save the type + connPtr->unknownCtrlType = opcode; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_UNKNOWN_RSP ); + } + else + { + // process for the protocol collision + // if other ctrl command procedure in processing , then reject + if(connPtr->llCTEModeCtrl.isWatingRsp==TRUE) + { + connPtr->isCollision=TRUE; + connPtr->rejectOpCode = LL_CTRL_CTE_REQ; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_REJECT_EXT_IND ); + } + else + { + if(connPtr->llCTEModeCtrl.isProcessingReq==FALSE) + { + uint8 CTE_tmp; + CTE_tmp = *pBuf++; + connPtr->llConnCTE.CTE_Length = CTE_tmp & 0x1F; + connPtr->llConnCTE.CTE_Type = CTE_tmp & 0xC0; + connPtr->llCTEModeCtrl.isProcessingReq=TRUE; + + if( ( connPtr->llConnCTE.enable ) && ( connPtr->llRfPhyPktFmt < LL_PHY_CODE )) + { + llEnqueueCtrlPkt( connPtr, LL_CTRL_CTE_RSP ); + } + else + { + if( connPtr->llRfPhyPktFmt >= LL_PHY_CODE ) + { + connPtr->llCTEModeCtrl.errorCode = LL_STATUS_ERROR_INVALID_LMP_LL_PARAMETER; + } + else + { + connPtr->llCTEModeCtrl.errorCode = LL_STATUS_ERROR_UNSUPPORT_LMP_LL_PARAMETER; + } + + connPtr->rejectOpCode = LL_CTRL_CTE_REQ; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_REJECT_EXT_IND ); + } + } + } + } + + break; + + case LL_CTRL_CTE_RSP: + if( connPtr->llCTEModeCtrl.isWatingRsp == TRUE ) + { + if( ( g_pLLcteISample != NULL ) && ( g_pLLcteQSample != NULL) ) + iqCnt = ll_hw_get_iq_RawSample( g_pLLcteISample, g_pLLcteQSample ); + + if( iqCnt > 0) + { + LL_ConnectionIQReportCback( connPtr->connId, + connPtr->llRfPhyPktFmt, + connPtr->currentChan, + connPtr->lastRssi, + // before CTE Transmit and sampling , no Antenna change , default 0 + 0, + connPtr->llConnCTE.CTE_Type, + connPtr->llConnCTE.slot_Duration, + // Packet_Status=0, CRC success,cause only CRC Correctly that can run here + 0, + connPtr->currentEvent, + iqCnt, + g_pLLcteISample, + g_pLLcteQSample); + } + else + { + // packet contain LL_CTE_RSP , but did not contain CTE field + // status = 0x0 : LL_CTE_RSP received successful , but without a CTE field + LL_CTE_Report_FailedCback( 0x0,connPtr->connId); + } + + connPtr->llCTEModeCtrl.isWatingRsp = FALSE; + } + + break; + + // Peer Device Received an Unknown Control Type + case LL_CTRL_UNKNOWN_RSP: + + // Note: There doesn't appear to be any action for this message, + // other than to ACK it. + if(connPtr->llPduLen.isWatingRsp) + { + llPduLengthUpdate((uint16)connPtr->connId); + connPtr->llPduLen.isWatingRsp=FALSE;//not support DLE + } + + if(connPtr->llPhyModeCtrl.isWatingRsp) + { + llPhyModeCtrlUpdateNotify(connPtr,LL_STATUS_ERROR_UNSUPPORTED_REMOTE_FEATURE); + connPtr->llPhyModeCtrl.isWatingRsp=FALSE;//not support PHY_UPDATE + } + + // 2020-01-23 add for CTE + if( connPtr->llCTEModeCtrl.isWatingRsp ) + { + connPtr->llCTEModeCtrl.isWatingRsp = FALSE; + } + + break; + + case LL_REJECT_IND: + case LL_REJECT_IND_EXT: + connPtr->rejectOpCode = *pBuf++; + uint8 errorcode = *pBuf++; + + if(connPtr->rejectOpCode == LL_CTRL_ENC_REQ) + { + // either the slave's Host has failed to provide an LTK, or + // the encryption feature is not supported by the slave, so read + // the rejection indication error code + //connPtr->encInfo.encRejectErrCode = PHY_READ_BYTE_VAL(); + connPtr->encInfo.encRejectErrCode = connPtr->rejectOpCode; + // and end the start encryption procedure + connPtr->encInfo.rejectIndRcved = TRUE; + LL_EncChangeCback( connPtr->connId, + errorcode, + LL_ENCRYPTION_OFF ); + } + else + { + //TBD + } + + //connPtr->isCollision=FALSE; + break; + + // Our Device Received an Unknown Control Type + default: + // unknown data PDU control packet received so save the type + connPtr->unknownCtrlType = opcode; + // schedule the output of the control packet + llEnqueueCtrlPkt( connPtr, LL_CTRL_UNKNOWN_RSP ); + break; + } + + return; +} +#endif + +static uint32 read_LL_remainder_time1(void) +{ + uint32 currentCount; + uint32 g_tim1_pass = read_current_fine_time(); + currentCount = AP_TIM1->CurrentCount; + + if((currentCount < 6) || NVIC_GetPendingIRQ(TIM1_IRQn)) + return 0; + else + return (currentCount >> 2); +} + +uint8 llSecAdvAllow1(void) +{ + uint32 advTime, margin; + uint32 remainTime; + uint8 ret = FALSE; + // Hold off interrupts. + HAL_ENTER_CRITICAL_SECTION( ); + // read global config to get advTime and margin + advTime = pGlobal_config[LL_NOCONN_ADV_EST_TIME]; + margin = pGlobal_config[LL_NOCONN_ADV_MARGIN]; + // remain time before trigger LL HW + remainTime = read_LL_remainder_time1(); + + if ((remainTime > advTime + margin) + && !llWaitingIrq) + ret = TRUE; + else + { + llSecondaryState = LL_SEC_STATE_ADV_PENDING; + g_pmCounters.ll_conn_adv_pending_cnt ++; + } + + HAL_EXIT_CRITICAL_SECTION(); + return ret; +} + +uint32 llCalcMaxScanTime1(void) +{ + uint32 margin, scanTime; + uint32 remainTime; + margin = pGlobal_config[LL_SEC_SCAN_MARGIN]; + // Hold off interrupts. + HAL_ENTER_CRITICAL_SECTION( ); + // remain time before trigger LL HW + remainTime = read_LL_remainder_time1(); + scanTime = 0; + + if (remainTime > margin + pGlobal_config[LL_MIN_SCAN_TIME] + && !llWaitingIrq) + scanTime = remainTime - margin; + + HAL_EXIT_CRITICAL_SECTION(); + return (scanTime); +} + + + +llStatus_t LL_StartEncrypt1( uint16 connId, + uint8* rand, + uint8* eDiv, + uint8* ltk ) +{ + uint8 i; + llStatus_t status; + llConnState_t* connPtr; + + // make sure we're in Master role +// if ( llState != LL_STATE_CONN_MASTER ) +// { +// return( LL_STATUS_ERROR_COMMAND_DISALLOWED ); +// } + + // check parameters + if ( (rand == NULL) || (eDiv == NULL) || (ltk == NULL) ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // make sure connection ID is valid + if ( (status=LL_ConnActive(connId)) != LL_STATUS_SUCCESS ) + { + return( status ); + } + + // get connection info + connPtr = &conn_param[connId]; + + // check if a feature response control procedure has taken place + if ( connPtr->featureSetInfo.featureRspRcved == FALSE ) + { + // it hasn't so re-load this device's local Feature Set to the + // connection as it may have been changed by the Host with HCI + // extenstion Set Local Feature Set command + for (i=0; ifeatureSetInfo.featureSet[i] = deviceFeatureSet.featureSet[i]; + } + } + + // check if encryption is a supported feature set item + if ( (connPtr->featureSetInfo.featureSet[0] & LL_FEATURE_ENCRYPTION) != LL_FEATURE_ENCRYPTION ) + { + return( LL_STATUS_ERROR_FEATURE_NOT_SUPPORTED ); + } + + // cache the master's random vector + // Note: The RAND will be left in LSO..MSO order as this is assumed to be the + // order of the bytes that will be returned to the Host. + for (i=0; iencInfo.RAND[i] = rand[i]; + } + + // cache the master's encryption diversifier + // Note: The EDIV will be left in LSO..MSO order as this is assumed to be the + // order of the bytes that will be returned to the Host. + connPtr->encInfo.EDIV[0] = eDiv[0]; + connPtr->encInfo.EDIV[1] = eDiv[1]; + + // cache the master's long term key + // Note: The order of the bytes will be maintained as MSO..LSO + // per FIPS 197 (AES). + for (i=0; iencInfo.LTK[(LL_ENC_LTK_LEN-i)-1] = ltk[i]; + } + + // generate SKDm + // Note: The SKDm LSO is the LSO of the SKD. + // Note: Placement of result forms concatenation of SKDm and SKDs. + // Note: The order of the bytes will be maintained as MSO..LSO + // per FIPS 197 (AES). + LL_ENC_GenDeviceSKD( &connPtr->encInfo.SKD[ LL_ENC_SKD_M_OFFSET ] ); + // generate IVm + // Note: The IVm LSO is the LSO of the IV. + // Note: Placement of result forms concatenation of IVm and IVs. + // Note: The order of the bytes will be maintained as MSO..LSO + // per FIPS 197 (AES). + LL_ENC_GenDeviceIV( &connPtr->encInfo.IV[ LL_ENC_IV_M_OFFSET ] ); + // schedule a cache update of FIPS TRNG values for next SKD/IV usage + // postRfOperations |= LL_POST_RADIO_CACHE_RANDOM_NUM; + (void)LL_ENC_GenerateTrueRandNum( cachedTRNGdata, LL_ENC_TRUE_RAND_BUF_SIZE ); + // set flag to stop all outgoing transmissions + connPtr->txDataEnabled = FALSE; + // invalidate the existing session key, if any + connPtr->encInfo.SKValid = FALSE; + // indicate the LTK is not valid + connPtr->encInfo.LTKValid = FALSE; + + // check if we are already in encryption mode + if ( connPtr->encEnabled == TRUE ) + { + // set a flag to indicate this is a restart (i.e. pause-then-start) + connPtr->encInfo.encRestart = TRUE; + // setup a pause encryption control procedure + llEnqueueCtrlPkt( connPtr, LL_CTRL_PAUSE_ENC_REQ ); + } + else // no, so... + { + // clear flag to indicate this is an encryption setup + connPtr->encInfo.encRestart = FALSE; + // setup an encryption control procedure + llEnqueueCtrlPkt( connPtr, LL_CTRL_ENC_REQ ); + } + + return( LL_STATUS_SUCCESS ); +} + + +// global configuration in SRAM, it could be change by application +// TODO: when integrate, the global_config should be set by APP project +__ATTR_SECTION_XIP__ void init_config(void) +{ + pGlobal_config = (uint32*)(CONFIG_BASE_ADDR); + int i; + + for (i = 0; i < 256; i ++) + pGlobal_config[i] = 0; + + //save the app initial_sp which will be used in wakeupProcess 20180706 by ZQ + pGlobal_config[INITIAL_STACK_PTR] = (uint32_t)&__initial_sp; + // LL switch setting + pGlobal_config[LL_SWITCH] = LL_DEBUG_ALLOW | SLAVE_LATENCY_ALLOW | LL_WHITELIST_ALLOW + | SIMUL_CONN_ADV_ALLOW | SIMUL_CONN_SCAN_ALLOW; //RC32_TRACKINK_ALLOW + + if(g_clk32K_config==CLK_32K_XTAL) + pGlobal_config[LL_SWITCH] &= 0xffffffee; + else + pGlobal_config[LL_SWITCH] |= RC32_TRACKINK_ALLOW | LL_RC32K_SEL; + + // sleep delay + pGlobal_config[MIN_TIME_TO_STABLE_32KHZ_XOSC] = 10; // 10ms, temporary set + // system clock setting + pGlobal_config[CLOCK_SETTING] = g_system_clk;//CLOCK_32MHZ; + //------------------------------------------------------------------------ + // wakeup time cose + // t1. HW_Wakeup->MCU relase 62.5us + // t2. wakeup_process in waitRTCCounter 30.5us*[WAKEUP_DELAY] about 500us + // t3. dll_en -> hclk_sel in hal_system_ini 100us in run as RC32M + // t4. sw prepare cal sleep tick initial rf_ini about 300us @16M this part depends on HCLK + // WAKEUP_ADVANCE should be larger than t1+t2+t3+t4 + //------------------------------------------------------------------------ + // wakeup advance time, in us + pGlobal_config[WAKEUP_ADVANCE] = 1850;//650;//600;//310; + + if(g_system_clk==SYS_CLK_XTAL_16M) + { + pGlobal_config[WAKEUP_DELAY] = 16; + } + else if(g_system_clk==SYS_CLK_DBL_32M) + { + pGlobal_config[WAKEUP_DELAY] = 16; + } + else if(g_system_clk==SYS_CLK_DLL_48M) + { + pGlobal_config[WAKEUP_DELAY] = 16; + } + else if(g_system_clk==SYS_CLK_DLL_64M) + { + pGlobal_config[WAKEUP_DELAY] = 16; + } + + // sleep time, in us + pGlobal_config[MAX_SLEEP_TIME] = 30000000; + pGlobal_config[MIN_SLEEP_TIME] = 1600; + pGlobal_config[ALLOW_TO_SLEEP_TICK_RC32K] = 55;// 30.5 per tick + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + // LL engine settle time + pGlobal_config[LL_HW_BB_DELAY] = 54;//54-8; + pGlobal_config[LL_HW_AFE_DELAY] = 8; + pGlobal_config[LL_HW_PLL_DELAY] = 40;//45;//52; + // Tx2Rx and Rx2Tx interval + //Tx2Rx could be advanced a little + //Rx2Tx should be ensure T_IFS within150us+-2us + pGlobal_config[LL_HW_Rx_TO_TX_INTV] = 62-RF_PHY_EXT_PREAMBLE_US; + pGlobal_config[LL_HW_Tx_TO_RX_INTV] = 50;//65 + //------------------------------------------------2MPHY + // LL engine settle time + pGlobal_config[LL_HW_BB_DELAY_2MPHY] = 59; + pGlobal_config[LL_HW_AFE_DELAY_2MPHY] = 8; + pGlobal_config[LL_HW_PLL_DELAY_2MPHY] = 40;//45;//52; + // Tx2Rx and Rx2Tx interval + //Tx2Rx could be advanced a little + //Rx2Tx should be ensure T_IFS within150us+-2us + pGlobal_config[LL_HW_Rx_TO_TX_INTV_2MPHY] = 73-RF_PHY_EXT_PREAMBLE_US;//20200822 ZQ + pGlobal_config[LL_HW_Tx_TO_RX_INTV_2MPHY] = 57;//72 + //------------------------------------------------CODEPHY 500K + // LL engine settle time CODEPHY 500K + pGlobal_config[LL_HW_BB_DELAY_500KPHY] = 50;//54-8; + pGlobal_config[LL_HW_AFE_DELAY_500KPHY] = 8; + pGlobal_config[LL_HW_PLL_DELAY_500KPHY] = 40;//45;//52; + // Tx2Rx and Rx2Tx interval + //Tx2Rx could be advanced a little + //Rx2Tx should be ensure T_IFS within150us+-2us + pGlobal_config[LL_HW_Rx_TO_TX_INTV_500KPHY] = 2; + pGlobal_config[LL_HW_Tx_TO_RX_INTV_500KPHY] = 66;//72 + //------------------------------------------------CODEPHY 125K + // LL engine settle time CODEPHY 125K + pGlobal_config[LL_HW_BB_DELAY_125KPHY] = 30;//54-8; + pGlobal_config[LL_HW_AFE_DELAY_125KPHY] = 8; + pGlobal_config[LL_HW_PLL_DELAY_125KPHY] = 40;//45;//52; + // Tx2Rx and Rx2Tx interval + //Tx2Rx could be advanced a little + //Rx2Tx should be ensure T_IFS within150us+-2us + pGlobal_config[LL_HW_Rx_TO_TX_INTV_125KPHY] = 5; + pGlobal_config[LL_HW_Tx_TO_RX_INTV_125KPHY] = 66;//72 + // LL engine settle time, for advertisement + pGlobal_config[LL_HW_BB_DELAY_ADV] = 90; + pGlobal_config[LL_HW_AFE_DELAY_ADV] = 8; + pGlobal_config[LL_HW_PLL_DELAY_ADV] = 60; + // adv channel interval + pGlobal_config[ADV_CHANNEL_INTERVAL] = 1400;//6250; + pGlobal_config[NON_ADV_CHANNEL_INTERVAL] = 666;//6250; + + //20201207 Jie modify + if(g_system_clk==SYS_CLK_XTAL_16M) + { + // scan req -> scan rsp timing + pGlobal_config[SCAN_RSP_DELAY] = 13+RF_PHY_EXT_PREAMBLE_US;//23; + } + else if(g_system_clk==SYS_CLK_DBL_32M) + { + pGlobal_config[SCAN_RSP_DELAY] = 8+RF_PHY_EXT_PREAMBLE_US;//23; + } + else if(g_system_clk==SYS_CLK_DLL_48M) + { + // scan req -> scan rsp timing + pGlobal_config[SCAN_RSP_DELAY] = 6+RF_PHY_EXT_PREAMBLE_US;//20201207 set //4; // 12 // 2019/3/19 A2: 12 --> 9 + } + else if(g_system_clk == SYS_CLK_DLL_64M) // 2019/3/26 add + { + pGlobal_config[SCAN_RSP_DELAY] = 4+RF_PHY_EXT_PREAMBLE_US;//2020.12.07 set //3; + } + + // conn_req -> slave connection event calibration time, will advance the receive window + pGlobal_config[CONN_REQ_TO_SLAVE_DELAY] = 300;//192;//500;//192; + // calibration time for 2 connection event, will advance the next conn event receive window + // SLAVE_CONN_DELAY for sync catch, SLAVE_CONN_DELAY_BEFORE_SYNC for sync not catch + pGlobal_config[SLAVE_CONN_DELAY] = 300;//0;//1500;//0;//3000;//0; ---> update 11-20 + pGlobal_config[SLAVE_CONN_DELAY_BEFORE_SYNC] = 500;//160 NG//500 OK + // RTLP timeout + pGlobal_config[LL_HW_RTLP_LOOP_TIMEOUT] = 50000; + pGlobal_config[LL_HW_RTLP_TO_GAP] = 1000; + pGlobal_config[LL_HW_RTLP_1ST_TIMEOUT] = 2000 + pGlobal_config[SLAVE_CONN_DELAY] * 2;//500; + // direct adv interval configuration + pGlobal_config[HDC_DIRECT_ADV_INTERVAL] = 1000; + pGlobal_config[LDC_DIRECT_ADV_INTERVAL] = 6250; + // A1 ROM metal change for HDC direct adv, + pGlobal_config[DIR_ADV_DELAY] = 115; // in us, consider both direct adv broadcast time & SW delay, ... etc. + // A1 ROM metal change + pGlobal_config[LL_TX_PKTS_PER_CONN_EVT] = 6;//8; + pGlobal_config[LL_RX_PKTS_PER_CONN_EVT] = 6;//8; + pGlobal_config[LL_TRX_NUM_ADAPTIVE_CONFIG] = 8; //0: disable adaptive + //other: adaptive max limitation +// pGlobal_config[LL_TX_PWR_TO_REG_BIAS] = 0x15; // assume when g_rfPhyTxPower = 0x1f, tx power = 10dBm + //smart window configuration + pGlobal_config[LL_SMART_WINDOW_COEF_ALPHA] = 2; + pGlobal_config[LL_SMART_WINDOW_TARGET] = 600; + pGlobal_config[LL_SMART_WINDOW_INCREMENT] = 9; + pGlobal_config[LL_SMART_WINDOW_LIMIT] = 20000; + pGlobal_config[LL_SMART_WINDOW_ACTIVE_THD] = 8; + pGlobal_config[LL_SMART_WINDOW_ACTIVE_RANGE] = 0;//300 + pGlobal_config[LL_SMART_WINDOW_FIRST_WINDOW] = 5000; + g_smartWindowSize = pGlobal_config[LL_HW_RTLP_1ST_TIMEOUT] ; + + //====== A2 metal change add, for scanner & initiator + if(g_system_clk==SYS_CLK_XTAL_16M) + { + pGlobal_config[LL_ADV_TO_SCAN_REQ_DELAY] = 18+RF_PHY_EXT_PREAMBLE_US;//20; // 2019/3/19 A2: 20 --> 18 + pGlobal_config[LL_ADV_TO_CONN_REQ_DELAY] = 25+RF_PHY_EXT_PREAMBLE_US;//27; // 2019/3/19 A2: 27 --> 25 + } + else if(g_system_clk==SYS_CLK_DBL_32M) + { + pGlobal_config[LL_ADV_TO_SCAN_REQ_DELAY] = 12+RF_PHY_EXT_PREAMBLE_US; // 2019/3/26 add + pGlobal_config[LL_ADV_TO_CONN_REQ_DELAY] = 16+RF_PHY_EXT_PREAMBLE_US; + } + else if(g_system_clk==SYS_CLK_DLL_48M) + { + pGlobal_config[LL_ADV_TO_SCAN_REQ_DELAY] = 8+RF_PHY_EXT_PREAMBLE_US;//12; // 2019/3/19 A2: 12 --> 10 + pGlobal_config[LL_ADV_TO_CONN_REQ_DELAY] = 11+RF_PHY_EXT_PREAMBLE_US; + } + else if(g_system_clk==SYS_CLK_DLL_64M) + { + pGlobal_config[LL_ADV_TO_SCAN_REQ_DELAY] = 6+RF_PHY_EXT_PREAMBLE_US; // 2019/3/26 add + pGlobal_config[LL_ADV_TO_CONN_REQ_DELAY] = 8+RF_PHY_EXT_PREAMBLE_US; + } + + // TRLP timeout + pGlobal_config[LL_HW_TRLP_LOOP_TIMEOUT] = 50000; // enough for 8Tx + 8Rx : (41 * 8 + 150) * 16 - 150 = 7498us + pGlobal_config[LL_HW_TRLP_TO_GAP] = 1000; + pGlobal_config[LL_MOVE_TO_MASTER_DELAY] = 100; + pGlobal_config[LL_CONN_REQ_WIN_SIZE] = 5; + pGlobal_config[LL_CONN_REQ_WIN_OFFSET] = 2; + pGlobal_config[LL_MASTER_PROCESS_TARGET] = 200; // reserve time for preparing master conn event, delay should be insert if needn't so long time + pGlobal_config[LL_MASTER_TIRQ_DELAY] = 0; // timer IRQ -> timer ISR delay + pGlobal_config[OSAL_SYS_TICK_WAKEUP_TRIM] = 56; // 0.125us + pGlobal_config[MAC_ADDRESS_LOC] = 0x11004000; + // for simultaneous conn & adv/scan + pGlobal_config[LL_NOCONN_ADV_EST_TIME] = 1400*3; + pGlobal_config[LL_NOCONN_ADV_MARGIN] = 600; + pGlobal_config[LL_SEC_SCAN_MARGIN] = 2500;//1400; to avoid mesh proxy llTrigErr 0x15 + pGlobal_config[LL_MIN_SCAN_TIME] = 2000; + // BBB new + pGlobal_config[TIMER_ISR_ENTRY_TIME] = 30;//15; + pGlobal_config[LL_MULTICONN_MASTER_PREEMP] = 0; + pGlobal_config[LL_MULTICONN_SLAVE_PREEMP] = 0; + pGlobal_config[LL_EXT_ADV_TASK_DURATION] = 20000; + pGlobal_config[LL_PRD_ADV_TASK_DURATION] = 20000; + pGlobal_config[LL_CONN_TASK_DURATION] = 5000; + pGlobal_config[LL_EXT_ADV_INTER_PRI_CHN_INT] = 5000; + pGlobal_config[LL_EXT_ADV_INTER_SEC_CHN_INT] = 5000; + pGlobal_config[LL_EXT_ADV_PRI_2_SEC_CHN_INT] = 1500; + pGlobal_config[LL_EXT_ADV_RSC_PERIOD] = 1000000; + pGlobal_config[LL_EXT_ADV_RSC_SLOT_DURATION] = 10000; + pGlobal_config[LL_PRD_ADV_RSC_PERIOD] = 1000000; + pGlobal_config[LL_PRD_ADV_RSC_SLOT_DURATION] = 10000; + pGlobal_config[LL_EXT_ADV_PROCESS_TARGET] = 500; + pGlobal_config[LL_PRD_ADV_PROCESS_TARGET] = 500; + //------------------------------------------------------------------- + // patch function register + //-------------------------------------------------------------------- + JUMP_FUNCTION(LL_HW_GO) = (uint32_t)&ll_hw_go1; + JUMP_FUNCTION(V4_IRQ_HANDLER) = (uint32_t)&LL_IRQHandler1; + //JUMP_FUNCTION(V11_IRQ_HANDLER) = (uint32_t)&hal_UART0_IRQHandler; + extern void rf_calibrate1(void); + JUMP_FUNCTION(RF_CALIBRATTE) = (uint32_t)&rf_calibrate1; + JUMP_FUNCTION(RF_PHY_CHANGE) = (uint32_t)&rf_phy_change_cfg0; + //JUMP_FUNCTION(LL_GEN_TRUE_RANDOM) = (uint32_t)&LL_ENC_GenerateTrueRandNum1; + JUMP_FUNCTION(LL_AES128_ENCRYPT) = (uint32_t)&LL_ENC_AES128_Encrypt1; + JUMP_FUNCTION(LL_ENC_ENCRYPT) = (uint32_t)&LL_ENC_Encrypt1; + JUMP_FUNCTION(LL_ENC_DECRYPT) = (uint32_t)&LL_ENC_Decrypt1; + //JUMP_FUNCTION(LL_PROCESS_SLAVE_CTRL_PROC) = (uint32_t)&llProcessSlaveControlProcedures1; + //JUMP_FUNCTION(LL_PROCESS_TX_DATA) = (uint32_t)&llProcessTxData1; + //JUMP_FUNCTION(OSAL_POWER_CONSERVE) = (uint32_t)&osal_pwrmgr_powerconserve1; + //JUMP_FUNCTION(ENTER_SLEEP_OFF_MODE) = (uint32_t)&enter_sleep_off_mode1; + //JUMP_FUNCTION(ENTER_SLEEP_PROCESS) = (uint32_t)&enterSleepProcess1; + JUMP_FUNCTION(CONFIG_RTC) = (uint32_t)&config_RTC1; + //JUMP_FUNCTION(V20_IRQ_HANDLER) = (uint32_t)&TIM1_IRQHandler1; +// JUMP_FUNCTION(LL_SCHEDULER) = (uint32_t)&ll_scheduler1; + //JUMP_FUNCTION(HAL_DRV_IRQ_ENABLE) = (uint32_t)&drv_enable_irq1; + //JUMP_FUNCTION(HAL_DRV_IRQ_DISABLE) = (uint32_t)&drv_disable_irq1; + JUMP_FUNCTION(WAKEUP_INIT) = (uint32_t)&wakeup_init1; + JUMP_FUNCTION(WAKEUP_PROCESS) = (uint32_t)&wakeupProcess1; + extern void l2capPocessFragmentTxData(uint16 connHandle); + JUMP_FUNCTION(L2CAP_PROCESS_FREGMENT_TX_DATA) = (uint32_t)&l2capPocessFragmentTxData; + //BQB bug fix,2020.11.17 + //JUMP_FUNCTION(LL_PHY_MODE_UPDATE) = (uint32_t)&LL_PhyUpdate1; + JUMP_FUNCTION(LL_SET_DATA_LENGTH) = (uint32_t)&LL_SetDataLengh1; + //JUMP_FUNCTION(LL_SET_PHY_MODE) = (uint32_t)&LL_SetPhyMode1; + JUMP_FUNCTION(LL_PROCESS_TX_DATA) = (uint32_t)&llProcessTxData1; + JUMP_FUNCTION(LL_GENERATE_TX_BUFFER) = (uint32_t)&ll_generateTxBuffer1; + JUMP_FUNCTION(LL_ADP_ADJ_NEXT_TIME) = (uint32_t)&ll_adptive_adj_next_time1; + JUMP_FUNCTION(LL_CONN_TERMINATE) = (uint32_t)&llConnTerminate1; + JUMP_FUNCTION(LL_SET_DEFAULT_CONN_PARAM) = (uint32_t)&LL_set_default_conn_params1; +// ==================== + //disableSleep(); + //setSleepMode(MCU_SLEEP_MODE);//SYSTEM_SLEEP_MODE + enableSleep(); + setSleepMode(SYSTEM_SLEEP_MODE); +} + +void ll_patch_slave(void) +{ + JUMP_FUNCTION(LL_SET_ADV_PARAM) = (uint32_t)&LL_SetAdvParam1; + JUMP_FUNCTION(LL_CALC_MAX_SCAN_TIME) = (uint32_t)&llCalcMaxScanTime1; + JUMP_FUNCTION(LL_SEC_ADV_ALLOW) = (uint32_t)&llSecAdvAllow1; + JUMP_FUNCTION(LL_SET_ADV_CONTROL) = (uint32_t)&LL_SetAdvControl1; + JUMP_FUNCTION(LL_SETUP_SEC_ADV_ENTRY) = (uint32_t)&llSetupSecAdvEvt1; + JUMP_FUNCTION(LL_SCHEDULER) = (uint32_t)&ll_scheduler2; + JUMP_FUNCTION(LL_SETUP_NEXT_SLAVE_EVT) = (uint32_t)&llSetupNextSlaveEvent1; +} + +void ll_patch_master(void) +{ + JUMP_FUNCTION(LL_SET_ADV_PARAM) = (uint32_t)&LL_SetAdvParam1; + JUMP_FUNCTION(LL_SET_ADV_CONTROL) = (uint32_t)&LL_SetAdvControl1; + JUMP_FUNCTION(LL_MASTER_EVT_ENDOK) = (uint32_t)&llMasterEvt_TaskEndOk1; + JUMP_FUNCTION(LL_SET_SCAN_PARAM) = (uint32_t)&LL_SetScanParam1; + JUMP_FUNCTION(LL_SET_SCAN_CTRL) = (uint32_t)&LL_SetScanControl1; + //JUMP_FUNCTION(LL_PROCESS_MASTER_CTRL_PKT) = (uint32_t)&llProcessMasterControlPacket1; + JUMP_FUNCTION(LL_CREATE_CONN) = (uint32_t)&LL_CreateConn1; + JUMP_FUNCTION(LL_START_ENCRYPT) = (uint32_t)&LL_StartEncrypt1; + JUMP_FUNCTION(LL_ENC_DECRYPT) = (uint32_t)&LL_ENC_Decrypt1; + JUMP_FUNCTION(LL_PROCESS_MASTER_CTRL_PROC) = (uint32_t)&llProcessMasterControlProcedures1; + JUMP_FUNCTION(LL_PROCESS_SLAVE_CTRL_PROC) = (uint32_t)&llProcessSlaveControlProcedures1; + JUMP_FUNCTION(LL_PROCESSBASICIRQ_SRX) = (uint32_t )&ll_processBasicIRQ_SRX0; + JUMP_FUNCTION(LL_PROCESSBASICIRQ_SCANTRX) = (uint32_t )&ll_processBasicIRQ_ScanTRX0; + JUMP_FUNCTION(LL_SETUP_SEC_SCAN) = (uint32_t )&llSetupSecScan1; +} + +void ll_patch_multi(void) +{ + ll_patch_slave(); + ll_patch_master(); + JUMP_FUNCTION(LL_SCHEDULER) = (uint32_t)&ll_scheduler1; + JUMP_FUNCTION(LL_PROCESSBASICIRQ_SECADVTRX) = (uint32_t )&ll_processBasicIRQ_secondaryAdvTRX0; + JUMP_FUNCTION(LL_PROCESSBASICIRQ_SECSCANSRX) = (uint32_t )&ll_processBasicIRQ_secondaryScanSRX0; + JUMP_FUNCTION(LL_PROCESSBASICIRQ_SECINITSRX) = (uint32_t )&ll_processBasicIRQ_secondaryInitSRX0; +} + +void hal_rom_boot_init(void) +{ + extern void _rom_sec_boot_init(); + _rom_sec_boot_init(); +} +//----------------------------------------------------------------------- +// Patch for V105/V103 LL_ChanMapUpdate +// Copy chanMap to connPtr->chanMapUpdate.chaMap +hciStatus_t HCI_LE_SetHostChanClassificationCmd(uint8* chanMap) +{ + hciStatus_t status; + status = LL_ChanMapUpdate(chanMap); + + //patch for LL_ChanMapUpdate + if (status == LL_STATUS_SUCCESS) + { + // need to issue an update on all active connections, if any + for (uint8_t i = 0; i < g_maxConnNum; i++) + { + if (conn_param[i].active) + { + llConnState_t* connPtr = &conn_param[i]; + osal_memcpy((uint8_t*)&(connPtr->chanMapUpdate.chanMap[0]), chanMap, LL_NUM_BYTES_FOR_CHAN_MAP); + } + } + } + + //AT_LOG("ChanMap Patch %d \n", status); + HCI_CommandCompleteEvent(HCI_LE_SET_HOST_CHANNEL_CLASSIFICATION, sizeof(status), &status); + return (HCI_SUCCESS); +} + +/******************************************************************************* + @fn pplus_enter_programming_mode + + @brief force deive enter to programing mode. + + input parameters + + @param none. + + output parameters + + @param none. + + @return none. +*/ +void pplus_enter_programming_mode(void) +{ + typedef void (*uart_init_t)(int baud, GPIO_Pin_e tx_pin, GPIO_Pin_e rx_pin,uint32_t cb_addr); + typedef void (*uart_tx_t)(unsigned char* str); + typedef void (*uart_cmd_t)(void); + uart_init_t p_uart_init = (uart_init_t)0x0000b379; + uart_tx_t p_uart_tx = (uart_tx_t)0x0000b4f5; + uart_cmd_t p_uart_cmd = (uart_cmd_t)0x00015c51; + uint32_t _cb_addr = 0x00015c8d; + *(volatile unsigned int*) 0xe000e180 = 0xffffffff; + HAL_ENTER_CRITICAL_SECTION(); + osal_memset((void*)0x1fff0000, 0, 256*4); + HAL_EXIT_CRITICAL_SECTION(); + AP_CACHE->CTRL0 = 0x02; + AP_PCR->CACHE_RST = 0x02; + AP_PCR->CACHE_BYPASS = 1; + *(volatile unsigned int*) 0xe000e100 |= BIT(11); + p_uart_init(115200,P9, P10,_cb_addr); + *(volatile unsigned int*) 0x40004004 |= BIT(0); + p_uart_tx("cmd:"); + __set_MSP(0x1fff1830); + p_uart_cmd(); +} + + +int8 LL_PLUS_GetCurrentRSSI(void) +{ + uint8 rssi; + uint16 foff; + uint8 carrSens; + rf_phy_get_pktFoot(&rssi,&foff,&carrSens); + return -rssi; +} + +void LL_PLUS_GetCurrentPduDle(uint8_t connId, ll_pdu_length_ctrl_t* ppdu) +{ + if(LL_INVALID_CONNECTION_ID!=connId && ppdu!=NULL) + { + ppdu->MaxRxOctets = conn_param[connId].llPduLen.local.MaxRxOctets; + ppdu->MaxTxOctets = conn_param[connId].llPduLen.local.MaxTxOctets; + ppdu->MaxRxTime = conn_param[connId].llPduLen.local.MaxRxTime; + ppdu->MaxTxTime = conn_param[connId].llPduLen.local.MaxTxTime; + } +} + + +void LOG_PATCH_DATA_TIME(void) +{ + LOG("\n"); + LOG("PATCH_LIB:"); +// for(int i=0;i<12;i++) +// { +// LOG("%s",libRevisionDate[i]); +// } + LOG("%s",libRevisionDate); + LOG(" "); + LOG("%s",libRevisionTime); +// for(int i=0;i<12;i++) +// { +// LOG("%s",libRevisionTime[i]); +// } + LOG("\n"); +} + + + +extern inline uint32_t __psr(void) +{ + uint32_t i; + __asm volatile("MRS %0, psr": "=r"(i)); + return i; +} + +void rflib_vesion(uint8_t* major, uint8_t* minor, uint8_t* revision, char* test_build) +{ + *major = SDK_VER_MAJOR; + *minor = SDK_VER_MINOR; + *revision = SDK_VER_REVISION; + *test_build = '\0'; + #ifdef SDK_VER_TEST_BUILD + *test_build = SDK_VER_TEST_BUILD; + #endif +} + + +#define OSALMEM_BIGBLK_IDX 157 +// =========================================================== +// ptr: the header of osal heap +//uint32 osal_memory_statics(void *ptr) +extern uint8 g_largeHeap[]; +uint32 osal_memory_statics(void) +{ + osalMemHdr_t* header, *current; + void* ptr; + uint32 sum_alloc = 0; + uint32 sum_free = 0; + uint32 max_block = 0; +// halIntState_t intState; + ptr = (void*)g_largeHeap; + header = (osalMemHdr_t*)ptr; + current = (osalMemHdr_t*)ptr; + +// HAL_ENTER_CRITICAL_SECTION1( intState ); // Hold off interrupts. + + do + { + if ((uint32)ptr > (uint32)header + 4096) + { + LOG("==========error: memory audit failed===============\r\n"); + break; + } + + // seek to the last block, return + if ( current->val == 0 ) /// val = 0, so len = 0 + { + break; + } + + if (current->hdr.inUse) + sum_alloc += current->hdr.len; + else + { + sum_free += current->hdr.len; + + if (current->hdr.len > max_block && (void*)(¤t->hdr) > (void*)(header + OSALMEM_BIGBLK_IDX)) + max_block = current->hdr.len; + } + + current = (osalMemHdr_t*)((uint8*)current + current->hdr.len); + } + while (1); + +// HAL_EXIT_CRITICAL_SECTION1( intState ); // Re-enable interrupts. +// printf("sum_alloc = %d, sum_free = %d, max_free_block = %d\r\n", sum_alloc, sum_free, max_block); + LOG("sum_alloc = %d, max_free_block = %d ", sum_alloc, max_block); + return sum_alloc; +} + +llStatus_t LL_ConnUpdate1( uint16 connId, + uint16 connIntervalMin, + uint16 connIntervalMax, + uint16 connLatency, + uint16 connTimeout, + uint16 minLength, + uint16 maxLength ) +{ + llStatus_t status; + llConnState_t* connPtr; + // unused input parameter; PC-Lint error 715. + (void)minLength; + (void)maxLength; + + // make sure we're in Master role +// if ( llState != LL_STATE_CONN_MASTER ) +// { +// return( LL_STATUS_ERROR_COMMAND_DISALLOWED ); +// } + if (g_ll_conn_ctx.scheduleInfo[connId].linkRole != LL_ROLE_MASTER ) + return( LL_STATUS_ERROR_COMMAND_DISALLOWED ); + + // sanity checks again to be sure we don't start with bad parameters + if ( LL_INVALID_CONN_TIME_PARAM( connIntervalMin, + connIntervalMax, + connLatency, + connTimeout ) ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // make sure connection ID is valid + if ( (status=LL_ConnActive(connId)) != LL_STATUS_SUCCESS ) + { + return( status ); + } + + // get connection info + connPtr = &conn_param[connId]; + + // check if an updated parameters control procedure is already what's pending + if ( ((connPtr->ctrlPktInfo.ctrlPktCount > 0) && + (connPtr->ctrlPktInfo.ctrlPkts[0] == LL_CTRL_CONNECTION_UPDATE_REQ)) || + (connPtr->pendingParamUpdate == TRUE) ) + { + return( LL_STATUS_ERROR_CTRL_PROC_ALREADY_ACTIVE ); + } + + // check if CI/SL/LSTO is valid (i.e. meets the requirements) + // Note: LSTO > (1 + Slave Latency) * (Connection Interval * 2) + // Note: The CI * 2 requirement based on ESR05 V1.0, Erratum 3904. + // Note: LSTO time is normalized to units of 1.25ms (i.e. 10ms = 8 * 1.25ms). + if ( LL_INVALID_CONN_TIME_PARAM_COMBO(connIntervalMax, connLatency, connTimeout) ) + { + return( LL_STATUS_ERROR_ILLEGAL_PARAM_COMBINATION ); + } + + // if there is at least one connection, make sure this connection interval + // is a multiple/divisor of all other active connection intervals; also make + // sure that this connection's interval is not less than the allowed maximum + // connection interval as determined by the maximum number of allowed + // connections times the number of slots per connection. + if ( g_ll_conn_ctx.numLLMasterConns > 1 ) // if ( g_ll_conn_ctx.numLLConns > 0 ) + { + uint16 connInterval = (connIntervalMax << 1); // convert to 625us ticks + uint16 minCI = g_ll_conn_ctx.connInterval; + + // // first check if this connection interval is even legal + // // Note: The number of active connections is limited by the minCI. + // if ( (minCI / NUM_SLOTS_PER_MASTER) < llConns.numActiveConns ) + // { + // return( LL_STATUS_ERROR_UNACCEPTABLE_CONN_INTERVAL ); + // } + + // // does the CI need to be checked as a multiple of the minCI? + if ( connInterval >= minCI ) + { + // check if this connection's CI is valid (i.e. a multiple of minCI) + if ( connInterval % minCI ) + { + return( LL_STATUS_ERROR_UNACCEPTABLE_CONN_INTERVAL ); + } + } + else + return( LL_STATUS_ERROR_UNACCEPTABLE_CONN_INTERVAL ); + } + else + { + // only 1 master connection + g_ll_conn_ctx.connInterval = connIntervalMax; + g_ll_conn_ctx.per_slot_time = connPtr->curParam.connInterval * 2 / g_maxConnNum; // unit: 625us + } + + // no control procedure currently active, so set this one up + // set the window size (units of 1.25ms) + connPtr->paramUpdate.winSize = LL_WINDOW_SIZE; + // set the window offset (units of 1.25ms) +// connPtr->paramUpdate.winOffset = LL_WINDOW_OFFSET; + connPtr->paramUpdate.winOffset = 0; // multiconnection, this value could be 0 or x * old conn interval and should be less than new conn interval + // set the relative offset of the number of events for the parameter update + // Note: The absolute event number will be determined at the time the packet + // is placed in the TX FIFO. + // Note: The master should allow a minimum of 6 connection events that the + // slave will be listening for before the instant occurs. + connPtr->paramUpdateEvent = (connPtr->curParam.slaveLatency+1) + + LL_INSTANT_NUMBER_MIN; + // determine the connection interval based on min and max values + // Note: Range not used, so assume max value. + // Note: minLength and maxLength are informational. + connPtr->paramUpdate.connInterval = connIntervalMax; + // save the new connection slave latency to be used by the peer + connPtr->paramUpdate.slaveLatency = connLatency; + // save the new connection supervisor timeout + connPtr->paramUpdate.connTimeout = connTimeout; + // queue control packet for processing + llEnqueueCtrlPkt( connPtr, LL_CTRL_CONNECTION_UPDATE_REQ ); + return( LL_STATUS_SUCCESS ); +} + +hciStatus_t HCI_LE_ConnUpdateCmd( uint16 connHandle, + uint16 connIntervalMin, + uint16 connIntervalMax, + uint16 connLatency, + uint16 connTimeout, + uint16 minLen, + uint16 maxLen ) +{ + hciStatus_t status; + status = LL_ConnUpdate1( connHandle, + connIntervalMin, + connIntervalMax, + connLatency, + connTimeout, + minLen, + maxLen ); + HCI_CommandStatusEvent( status, HCI_LE_CONNECTION_UPDATE ); + return( HCI_SUCCESS ); +} + +CHIP_ID_STATUS_e chip_id_one_bit_hot_convter(uint8_t* b,uint32_t w) +{ + uint16 dh = w>>16; + uint16 dl = w&0xffff; + uint16 h1,h0,l1,l0; + h0=l0=0xff; + h1=l1=0; + + for(int i=0; i<16; i++) + { + l1+=((dl&(1<>i); + + if(l0==0xff && l1==1) + { + l0=i; + } + + h1+=((dh&(1<>i); + + if(h0==0xff && h1==1) + { + h0=i; + } + } + + if(l1==1 && h1==1) + { + *b=((h0<<4)+l0); + return CHIP_ID_VALID; + } + else if(l1==16 && h1==16) + { + return CHIP_ID_EMPTY; + } + else + { + return CHIP_ID_INVALID; + } +} + +/******************************************************************************* + @fn LL_PLUS_LoadMACFromFlash + + @brief Used to load MAC Address from Flash + + input parameters + + @param None. + + output parameters + + @param None. + + @return None. +*/ +void LL_PLUS_LoadMACFromFlash(uint32_t addr) +{ + volatile uint8_t* p_ownPublicAddr = (volatile uint8_t*)0x1fff0965; + uint32_t macAddr[2]; + macAddr[0]=*(volatile uint32_t*) (0x11000000+addr); + macAddr[1]=*(volatile uint32_t*) (0x11000000+addr+4); + *(p_ownPublicAddr++) = BREAK_UINT32(macAddr[0],3); + *(p_ownPublicAddr++) = BREAK_UINT32(macAddr[0],2); + *(p_ownPublicAddr++) = BREAK_UINT32(macAddr[0],1); + *(p_ownPublicAddr++) = BREAK_UINT32(macAddr[0],0); + *(p_ownPublicAddr++) = BREAK_UINT32(macAddr[1],1); + *(p_ownPublicAddr++) = BREAK_UINT32(macAddr[1],0); +} + + +/******************************************************************************* + @fn pplus_LoadMACFromChipMAddr + + @brief Used to load MAC Address from chip Maddr + + input parameters + + @param None. + + output parameters + + @param None. + + @return CHIP_ID_STATUS_e. +*/ +CHIP_ID_STATUS_e LL_PLUS_LoadMACFromChipMAddr(void) +{ + check_chip_mAddr(); + volatile uint8_t* p_ownPublicAddr = (volatile uint8_t*)0x1fff0965; + + if(g_chipMAddr.chipMAddrStatus==CHIP_ID_VALID) + { + for(uint8_t i =0; i 16) + { + return PPlus_ERR_FATAL; + } + + TRNG_INIT(); + + for(i=0; i<16; i++) + t0+=s_trng_seed[i]; + + if(t0==0) + return PPlus_ERR_NULL; + + if(len>16) + return PPlus_ERR_DATA_SIZE; + + for(i=0; i<16; i++) + cryIn[i] =s_trng_iv[i]^s_company_id[i]; + + LL_ENC_AES128_Encrypt(s_trng_seed,cryIn,cryOut); + rand_len = len > 16 ? 16 : len; + osal_memcpy(buf,cryOut,rand_len); + TRNG_IV_Updata(); + return PPlus_SUCCESS; +} + + +// bugfix for multi-Role +/******************************************************************************* + @fn LL_EncLtkReply API + + @brief This API is called by the HCI to provide the controller with + the Long Term Key (LTK) for encryption. This command is + actually a reply to the link layer's LL_EncLtkReqCback, which + provided the random number and encryption diversifier received + from the Master during an encryption setup. + + Note: The key parameter is byte ordered LSO to MSO. + + input parameters + + @param connId - The LL connection ID on which to send this data. + @param *key - A 128 bit key to be used to calculate the session key. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS +*/ +llStatus_t LL_EncLtkReply( uint16 connId, + uint8* key ) +{ + uint8 i; + llStatus_t status; + llConnState_t* connPtr; + // get connection info + connPtr = &conn_param[ connId ]; + + // make sure we're in Master role +// if ( llState != LL_STATE_CONN_SLAVE ) + /* asynchronous send msg can not make sure llState = LL_STATE_CONN_SLAVE in multi-role */ + if( connPtr->llTbd1 != LL_LINK_CONNECT_COMPLETE_SLAVE ) + { + return( LL_STATUS_ERROR_COMMAND_DISALLOWED ); + } + + // check parameters + if ( key == NULL ) + { + return( LL_STATUS_ERROR_BAD_PARAMETER ); + } + + // make sure connection ID is valid + if ( (status=LL_ConnActive(connId)) != LL_STATUS_SUCCESS ) + { + return( status ); + } + + // ALT: COULD MAKE THIS PER CONNECTION. + + // save LTK + for (i=0; iencInfo.LTK[(LL_ENC_LTK_LEN-i)-1] = key[i]; + } + + // indicate the host has provided the key + connPtr->encInfo.LTKValid = TRUE; + // got the LTK, so schedule the start of encryption + // ALT: COULD MAKE THIS A REPLACE IF A DUMMY IS SITTING AT THE HEAD OF + // THE QUEUE. + llEnqueueCtrlPkt( connPtr, LL_CTRL_START_ENC_REQ ); + return( LL_STATUS_SUCCESS ); +} + +/******************************************************************************* + @fn LL_EncLtkNegReply API + + @brief This API is called by the HCI to indicate to the controller + that the Long Term Key (LTK) for encryption can not be provided. + This command is actually a reply to the link layer's + LL_EncLtkReqCback, which provided the random number and + encryption diversifier received from the Master during an + encryption setup. How the LL responds to the negative reply + depends on whether this is part of a start encryption or a + re-start encryption after a pause. For the former, an + encryption request rejection is sent to the peer device. For + the latter, the connection is terminated. + + input parameters + + @param connId - The LL connection ID on which to send this data. + + output parameters + + @param None. + + @return LL_STATUS_SUCCESS +*/ +llStatus_t LL_EncLtkNegReply( uint16 connId ) +{ + llStatus_t status; + llConnState_t* connPtr; + // get connection info + connPtr = &conn_param[ connId ]; + +// // make sure we're in Master role +// if ( llState != LL_STATE_CONN_SLAVE ) + /* asynchronous send msg can not make sure llState = LL_STATE_CONN_SLAVE in multi-role */ + if( connPtr->llTbd1 != LL_LINK_CONNECT_COMPLETE_SLAVE ) + { + return( LL_STATUS_ERROR_COMMAND_DISALLOWED ); + } + + // make sure connection ID is valid + if ( (status=LL_ConnActive(connId)) != LL_STATUS_SUCCESS ) + { + return( status ); + } + + // check if this is during a start or a re-start encryption procedure + if ( connPtr->encInfo.encRestart == TRUE ) + { + // indicate the peer requested this termination + connPtr->termInfo.reason = LL_ENC_KEY_REQ_REJECTED; + // queue control packet for processing + // ALT: COULD MAKE THIS A REPLACE IF A DUMMY IS SITTING AT THE HEAD OF + // THE QUEUE. + //llReplaceCtrlPkt( connPtr, LL_CTRL_TERMINATE_IND ); + llEnqueueCtrlPkt( connPtr, LL_CTRL_TERMINATE_IND ); + } + else // during a start encryption + { + // set the encryption rejection error code + connPtr->encInfo.encRejectErrCode = LL_STATUS_ERROR_PIN_OR_KEY_MISSING; // same as LL_ENC_KEY_REQ_REJECTED + // and reject the encryption request + // ALT: COULD MAKE THIS A REPLACE IF A DUMMY IS SITTING AT THE HEAD OF + // THE QUEUE. + //llReplaceCtrlPkt( connPtr, LL_CTRL_REJECT_IND ); + llEnqueueCtrlPkt( connPtr, LL_CTRL_REJECT_IND ); + } + + return( LL_STATUS_SUCCESS ); +} + +hciStatus_t HCI_LE_LtkReqReplyCmd( uint16 connHandle, + uint8* ltk ) +{ + // 0: Status + // 1: Connection Handle (LSB) + // 2: Connection Handle (MSB) + uint8 rtnParam[3]; + rtnParam[0] = LL_EncLtkReply( connHandle, ltk ); + rtnParam[1] = LO_UINT16( connHandle ); + rtnParam[2] = HI_UINT16( connHandle ); + HCI_CommandCompleteEvent( HCI_LE_LTK_REQ_REPLY, sizeof(rtnParam), rtnParam ); + return ( HCI_SUCCESS ); +} + + +/******************************************************************************* + This LE API is used by the Host to send to the Controller a negative LTK + reply. + + Public function defined in hci.h. +*/ +hciStatus_t HCI_LE_LtkReqNegReplyCmd( uint16 connHandle ) +{ + // 0: Status + // 1: Connection Handle (LSB) + // 2: Connection Handle (MSB) + uint8 rtnParam[3]; + rtnParam[0] = LL_EncLtkNegReply( connHandle ); + rtnParam[1] = LO_UINT16( connHandle ); + rtnParam[2] = HI_UINT16( connHandle ); + HCI_CommandCompleteEvent( HCI_LE_LTK_REQ_NEG_REPLY, sizeof(rtnParam), rtnParam ); + return( HCI_SUCCESS ); +} + + +#define EFUSE_PROG_FIX_FOR_CHIP +#ifdef EFUSE_PROG_FIX_FOR_CHIP + +typedef enum +{ + EFUSE_BLOCK_0 = 0, + EFUSE_BLOCK_1 = 1, + EFUSE_BLOCK_2 = 2, + EFUSE_BLOCK_3 = 3, + +} EFUSE_block_t; + +extern int efuse_read(EFUSE_block_t block,uint32_t* buf); + +static bool efuse_get_lock_state(EFUSE_block_t block); +static uint8_t get_even(volatile uint32_t* data); + +int efuse_write_x(EFUSE_block_t block,uint32_t* buf,uint32_t us) +{ + uint8_t even_bit; + uint32_t temp_wr[2]; + uint32_t temp_rd[2]; + volatile uint32_t temp; + int ret; + + if(*(buf+1) > 0x3FFFFFFF) + return PPlus_ERR_INVALID_PARAM; + + if(efuse_get_lock_state(block) == TRUE) + return PPlus_ERR_ACCESS_REJECTED; + + if(efuse_read(block,temp_rd) != PPlus_ERR_UNINITIALIZED) + return PPlus_ERR_ACCESS_REJECTED; + + even_bit = get_even(buf); + temp_wr[0] = ((*buf)<<1)|(even_bit); + temp_wr[1] = ((*(buf+1))<<1) | (((*buf) & 0x80000000)?1:0); + AP_PCRM->EFUSE_PROG[0] = temp_wr[0]; + AP_PCRM->EFUSE_PROG[1] = temp_wr[1]; + temp = (BIT((28 + block)) | 0x8000);//enable o_sclk_prog_hcyc,sclk high duty during time, unit:1/32M clk.prog en + AP_PCRM->efuse_cfg = temp; + WaitRTCCount(((us<<15)/1000000)+1);//at least 400us + { + AP_PCRM->efuse_cfg = 0x00;//disable o_sclk_prog_hcyc and clear prog data + AP_PCRM->EFUSE_PROG[0] = 0; + AP_PCRM->EFUSE_PROG[1] = 0; + } + ret = efuse_read(block,temp_rd); + + if(ret == PPlus_SUCCESS) + { + if((temp_rd[1] != buf[1]) || (temp_rd[0] != buf[0])) + return PPlus_ERR_INVALID_DATA; + } + + return ret; +} + +static bool efuse_get_lock_state(EFUSE_block_t block) +{ + return (AP_PCRM->SECURTY_STATE & BIT(block))?FALSE:TRUE; +} + +static uint8_t get_even(volatile uint32_t* data) +{ + uint32_t x; + x = *(data+1) ^ (*data); + x = ( x >> 16 ) ^ x; + x = ( x >> 8 ) ^ x; + x = ( x >> 4 ) ^ x; + x = ( x >> 2 ) ^ x; + x = ( x >> 1) ^ x; + return (x & 1); +} + +#endif diff --git a/src/lib/rf_mst.lib b/src/lib/rf_mst.lib new file mode 100644 index 0000000000000000000000000000000000000000..f6a6f1a68dcf6a889e2f934990f1dab5fc7d5ae1 GIT binary patch literal 77514 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 +} + + +unsigned char getByte(int* b) +{ + unsigned char out=0; + + for(int i=0; i<8; i++) + out=out+(b[i]<>i)&0x01) + { + res ^= bw[i]; + } + } + + return res; +} + + +void ShiftRows(unsigned char state[][4],int mode) +{ + unsigned char t[4]; + int r,c; + + for(r=1; r<4; r++) + { + for(c=0; c<4; c++) + { + if(mode==0) + t[c] = state[r][(c+r)%4];// --> 1 2 3 + else + t[c] = state[r][(c+4-r)%4];//<--1 2 3 + } + + for(c=0; c<4; c++) + { + state[r][c] = t[c]; + } + } +} + +void MixColumns(unsigned char state[][4],int mode) +{ + unsigned char t[4]; + int c; + + for(c=0; c< 4; c++) + { + t[0]=state[0][c]; + t[1]=state[1][c]; + t[2]=state[2][c]; + t[3]=state[3][c]; + state[0][c]= xtime(t[0]^t[1],1) ^ (t[2]^t[3]) ^ t[1]; + state[1][c]= xtime(t[1]^t[2],1) ^ (t[0]^t[3]) ^ t[2]; + state[2][c]= xtime(t[2]^t[3],1) ^ (t[0]^t[1]) ^ t[3]; + state[3][c]= xtime(t[0]^t[3],1) ^ (t[1]^t[2]) ^ t[0]; + + if(mode==1) + { + state[0][c]= state[0][c] ^ xtime(t[0]^t[2],2) ^ xtime( (t[0]^t[2]) ^ (t[1]^t[3]),3); + state[1][c]= state[1][c] ^ xtime(t[1]^t[3],2) ^ xtime( (t[0]^t[2]) ^ (t[1]^t[3]),3); + state[2][c]= state[2][c] ^ xtime(t[0]^t[2],2) ^ xtime( (t[0]^t[2]) ^ (t[1]^t[3]),3); + state[3][c]= state[3][c] ^ xtime(t[1]^t[3],2) ^ xtime( (t[0]^t[2]) ^ (t[1]^t[3]),3); + } + } +} + +void AddRoundKey(unsigned char state[][4], unsigned char k[][4]) +{ + int r,c; + + for(c=0; c<4; c++) + { + for(r=0; r<4; r++) + { + state[r][c] ^= k[r][c]; + } + } +} + +void printfStats(unsigned char state[][4],int mode) +{ + #if(AES_DEBUG) + int c,r; + + if(mode==1) + { + for(r=0; r<4; r++) + { + for(c=0; c<4; c++) + { + printf("%2x ",state[r][c]); + } + + printf("\n"); + } + + printf("\n"); + } + + #endif +} + + + + +void xor128bit(unsigned char* x,unsigned char* y,unsigned char* z) +{ + for(int i=0; i<16; i++) + { + z[i]=x[i]^y[i]; + } +} + + +extern int phy_sec_decrypt(const uint8_t* key, const uint8_t* iv, + uint8_t* din, uint32_t len, uint8_t* mic_in, uint8_t* dout); +extern int phy_sec_encrypt(const uint8_t* key, const uint8_t* iv, + uint8_t* din, uint32_t len, uint8_t* mic_out, uint8_t* dout); + +extern uint32_t g_ota_sec_key[4]; + +typedef enum +{ + EFUSE_BLOCK_0 = 0, + EFUSE_BLOCK_1 = 1, + EFUSE_BLOCK_2 = 2, + EFUSE_BLOCK_3 = 3, + +} EFUSE_block_t; +//extern int efuse_lock(EFUSE_block_t block); + +/**************************************************************************** + Function Name : aes_ccm_phyplus_dec + Description : decrypt by phyplus defined aes ccm mode + Input : + : *iv, 13 byte + : *din, dLen byte + : dLen, input data length, exclude mic + : *mic, 4 byte, Message Identify Code + Output : (dout,dLen byte + Return : bool, according to the MIC check result +****************************************************************************/ +#if 0 +bool aes_ccm_phyplus_dec(const unsigned char* key,const unsigned char* iv, unsigned char* din,int dLen, unsigned char* micIn, + unsigned char* dout) +{ + //unsigned char key_o[16]; + int i = 0, j = 0; + unsigned char ax[16]; + unsigned char bx[16]; + unsigned char y[16]; + unsigned char s[16]; + unsigned char ti[16]; + unsigned char to[16]; + unsigned char dummy_out[16]; + int loopNum = (dLen+15)/16; + int resLen = dLen-(loopNum-1)*16; + unsigned short cnt=0; + ax[0]=0x02; + bx[0]=0x62; + + for(i =0; i<13; i++) + { + ax[i+1]=iv[i]; + bx[i+1]=iv[i]; + } + + bx[14]=((dLen/16)&0xff00)>>8; + bx[15]=(dLen/16)&0xff; + + for(i=0; i>8; + ax[15]=cnt&0x00ff; + //aes((const unsigned char*)s_company_id,key_o,ax,s,AES_ENC); + LL_ENC_AES128_Encrypt_X((unsigned char*)key,ax,s); + + if(i>16; + uint16 dl = w&0xffff; + uint16 h1,h0,l1,l0; + h0=l0=0xff; + h1=l1=0; + + for(int i=0; i<16; i++) + { + l1+=((dl&(1<>i); + + if(l0==0xff && l1==1) + { + l0=i; + } + + h1+=((dh&(1<>i); + + if(h0==0xff && h1==1) + { + h0=i; + } + } + + if(l1==1 && h1==1) + { + *b=((h0<<4)+l0); + return CHIP_ID_VALID; + } + else if(l1==16 && h1==16) + { + return CHIP_ID_EMPTY; + } + else + { + return CHIP_ID_INVALID; + } +} + +CHIP_ID_STATUS_e read_chip_id(void) +{ + CHIP_ID_STATUS_e ret = CHIP_ID_UNCHECK; + uint8_t b; + + for(int i=0; i0 && ret==CHIP_ID_EMPTY) + { + ret =CHIP_ID_INVALID; + } + + return ret; + } + } + + return ret; +} + +void check_chip_id(void) +{ + //============================================================ + //chip id check + for(int i=0; i0 && ret==CHIP_ID_EMPTY) + { + ret =CHIP_ID_INVALID; + } + + return ret; + } + } + + return ret; +} + +void check_chip_mAddr(void) +{ + //============================================================ + //chip id check + for(int i=0; i> 14) ^ (a >> 13)) & 1); + a = ((a << 1) | b) & 0x7fff; + c = c + 1 + (((a >> 8) ^ a) & 0x3f); + tmp = read_reg(0x11002308 + (c&0xfffc)); + v[i] = (unsigned char)(tmp >> ((c&3)*8)); + } + } + + return TRUE; +} +#endif +/**************************************************************************** + Function Name : finidv + Description : + Output : + : *iv, 13 byte + Return : bool, if has crypto,return true +****************************************************************************/ +bool finidv() +{ + int ret,i; + uint32_t temp_sec_key[4]; + uint32_t cyr_out[4]; //phase1: validate phy_sec_mic, phase2: generate p_phy_sec_key + uint32_t efuse[2] = {0, 0}; + + if(g_ota_sec_key_valid == OTA_SEC_KEY_CCM) + { + return TRUE; + } + + ret = efuse_read(EFUSE_BLOCK_1, efuse); + + if(ret!=0) + { + return FALSE; + } + + temp_sec_key[0] = efuse[0]; + temp_sec_key[1] = efuse[1]; + temp_sec_key[2] = CHIP_SECURE_KEY_L; + temp_sec_key[3] = CHIP_SECURE_KEY_H; + //validate phy_sec_mic + LL_ENC_AES128_Encrypt_X((uint8_t* )temp_sec_key, (uint8_t* ) pCHIP_SECURE_PLAINTEXT, (uint8_t* ) cyr_out); + + if(osal_memcmp((uint8_t*) cyr_out, (const void*)pCHIP_SECURE_MIC, 128/8) == 0) + { + //g_phy_sec_key_valid = PHY_SEC_KEY_FAIL; + g_ota_sec_key_valid = OTA_SEC_KEY_FAIL; + return FALSE; + } + + //generate g_phy_sec_key + g_ota_sec_key_valid = OTA_SEC_KEY_CCM; + LL_ENC_AES128_Encrypt_X((uint8_t* )temp_sec_key, (uint8_t* ) pCHIP_SECURE_MIC, (uint8_t* ) g_ota_sec_key); + efuse[0] = 0; + efuse[1] = 0; + + for(i=0; i<4; i++) + { + temp_sec_key[i] = 0; + } + + return TRUE; +} +bool verify_mic(unsigned char* buf, int size) +{ + //unsigned char key[16]; + bool is_encrypt = FALSE; + is_encrypt = finidv(); + + if(is_encrypt == FALSE) + { + return TRUE; + } + + flash_load_parition(buf,size-4, buf+ size-4, NULL); + return TRUE; + //return aes_ccm_phyplus_dec(iv, buf,size-4,buf+ size-4,NULL); +} + + + +#if 0 +void LOG_CHIP_ID(void) +{ + LOG("\n"); + + if(g_chipId.chipIdStatus==CHIP_ID_EMPTY) + { + LOG("[CHIP_ID EMPTY]\n"); + } + else if(g_chipId.chipIdStatus==CHIP_ID_INVALID) + { + LOG("[CHIP_ID INVALID]\n"); + } + else if(g_chipId.chipIdStatus==CHIP_ID_VALID) + { + LOG("[CHIP_ID VALID]\n"); + volatile uint8_t chipIdStr[CHIP_ID_LENGTH+1]; + + for(int i=0; i + + +int utf8_to_unicode(const char* utf8, uint16_t* unicode); +int ui_font_unicode(void* font, uint16_t unicode,uint8_t* bitmap); +void* ui_font_load(uint32_t flash_addr); +const char* ui_font_version(void); + +#endif + diff --git a/src/misc/bb_rom_sym_m0.gcc b/src/misc/bb_rom_sym_m0.gcc new file mode 100644 index 0000000..dbb183e --- /dev/null +++ b/src/misc/bb_rom_sym_m0.gcc @@ -0,0 +1,1022 @@ +bx_to_application = 0x000000d5; +P256_mul64 = 0x000001f9; +P256_mul128 = 0x0000029d; +P256_mulmod = 0x0000032d; +P256_sqr64 = 0x00000567; +P256_sqr128 = 0x000005c5; +P256_sqrmod = 0x00000641; +P256_addmod = 0x00000735; +P256_submod = 0x00000791; +P256_load_1 = 0x000007c3; +P256_to_montgomery = 0x000007d7; +P256_from_montgomery = 0x00000801; +P256_point_is_on_curve = 0x0000081b; +P256_greater_or_equal_than = 0x0000086d; +P256_negate_mod_m_if = 0x00000887; +P256_copy32 = 0x000008a9; +P256_copy32_unaligned = 0x000008b5; +P256_select = 0x000008c7; +P256_double_j = 0x00000927; +P256_add_j = 0x0000092b; +P256_div2mod = 0x00000983; +P256_interpreter = 0x000009e9; +P256_sqrmod_many_and_mulmod = 0x00000a4d; +P256_modinv = 0x00000a6d; +P256_jacobian_to_affine = 0x00000af7; +P256_abs_int = 0x00000b33; +P256_pointmult = 0x00000b41; +P256_ecdh_keygen = 0x00000d03; +P256_ecdh_shared_secret = 0x00000d0b; +__aeabi_uidiv = 0x00000e09; +__aeabi_uidivmod = 0x00000e09; +__aeabi_idiv = 0x00000e35; +__aeabi_idivmod = 0x00000e35; +__aeabi_memcpy = 0x00000e81; +__aeabi_memcpy4 = 0x00000e81; +__aeabi_memcpy8 = 0x00000e81; +__aeabi_memset = 0x00000ea5; +__aeabi_memset4 = 0x00000ea5; +__aeabi_memset8 = 0x00000ea5; +__aeabi_memclr = 0x00000eb3; +__aeabi_memclr4 = 0x00000eb3; +__aeabi_memclr8 = 0x00000eb3; +memset = 0x00000eb7; +strlen = 0x00000ec9; +strcmp = 0x00000ed7; +memcmp = 0x00000ef3; +strncmp = 0x00000f0d; +strtok = 0x00000f2d; +__aeabi_uread4 = 0x00000f75; +__rt_uread4 = 0x00000f75; +_uread4 = 0x00000f75; +strtoul = 0x00000f89; +__rt_ctype_table = 0x00001001; +_strtoul = 0x00001009; +GPIO_IRQHandler = 0x0000112d; +HCI_CommandCompleteEvent = 0x00001175; +HCI_CommandStatusEvent = 0x000011fd; +HCI_DataBufferOverflowEvent = 0x00001251; +HCI_DisconnectCmd = 0x0000128d; +HCI_EXT_AdvEventNoticeCmd = 0x000012a1; +HCI_EXT_BuildRevisionCmd = 0x000012a9; +HCI_EXT_ClkDivOnHaltCmd = 0x000012e5; +HCI_EXT_ConnEventNoticeCmd = 0x0000130d; +HCI_EXT_DeclareNvUsageCmd = 0x00001315; +HCI_EXT_DecryptCmd = 0x00001339; +HCI_EXT_DelaySleepCmd = 0x0000137d; +HCI_EXT_DisconnectImmedCmd = 0x000013a5; +HCI_EXT_EnablePTMCmd = 0x000013cd; +HCI_EXT_EndModemTestCmd = 0x000013e1; +HCI_EXT_HaltDuringRfCmd = 0x00001409; +HCI_EXT_ModemHopTestTxCmd = 0x00001431; +HCI_EXT_ModemTestRxCmd = 0x00001459; +HCI_EXT_ModemTestTxCmd = 0x00001481; +HCI_EXT_NumComplPktsLimitCmd = 0x000014a5; +HCI_EXT_OnePktPerEvtCmd = 0x000014c9; +HCI_EXT_OverlappedProcessingCmd = 0x000014f5; +HCI_EXT_PERbyChanCmd = 0x0000151d; +HCI_EXT_PacketErrorRateCmd = 0x00001541; +HCI_EXT_ResetSystemCmd = 0x00001575; +HCI_EXT_SaveFreqTuneCmd = 0x0000159d; +HCI_EXT_SetBDADDRCmd = 0x000015c5; +HCI_EXT_SetFastTxResponseTimeCmd = 0x00001601; +HCI_EXT_SetFreqTuneCmd = 0x00001629; +HCI_EXT_SetLocalSupportedFeaturesCmd = 0x00001651; +HCI_EXT_SetMaxDtmTxPowerCmd = 0x00001679; +HCI_EXT_SetRxGainCmd = 0x000016a1; +HCI_EXT_SetSCACmd = 0x000016d1; +HCI_EXT_SetSlaveLatencyOverrideCmd = 0x000016f9; +HCI_EXT_SetTxPowerCmd = 0x00001721; +HCI_ExtTaskRegister = 0x00001751; +HCI_GAPTaskRegister = 0x0000175d; +HCI_HardwareErrorEvent = 0x00001769; +HCI_HostBufferSizeCmd = 0x000017b1; +HCI_HostNumCompletedPktCmd = 0x000017e1; +HCI_Init = 0x0000183d; +HCI_L2CAPTaskRegister = 0x00001879; +HCI_LE_AddDevToResolvingListCmd = 0x000018a1; +HCI_LE_AddWhiteListCmd = 0x000018bd; +HCI_LE_ClearAdvSetsCmd = 0x000018e1; +HCI_LE_ClearResolvingListCmd = 0x00001919; +HCI_LE_ClearWhiteListCmd = 0x00001935; +HCI_LE_Connection_CTE_Request_EnableCmd = 0x0000196d; +HCI_LE_Connection_CTE_Response_EnableCmd = 0x00001999; +HCI_LE_ConnectionlessCTE_TransmitEnableCmd = 0x000019c1; +HCI_LE_ConnectionlessCTE_TransmitParamCmd = 0x000019dd; +HCI_LE_ConnectionlessIQ_SampleEnableCmd = 0x00001a01; +HCI_LE_CreateConnCancelCmd = 0x00001a31; +HCI_LE_CreateConnCmd = 0x00001a4d; +HCI_LE_EncryptCmd = 0x00001a89; +HCI_LE_ExtendedCreateConnectionCmd = 0x00001ac1; +HCI_LE_LtkReqNegReplyCmd = 0x00001b09; +HCI_LE_LtkReqReplyCmd = 0x00001b31; +HCI_LE_PeriodicAdvertisingCreateSyncCancelCmd = 0x00001b59; +HCI_LE_PeriodicAdvertisingCreateSyncCmd = 0x00001b75; +HCI_LE_PeriodicAdvertisingTerminateSyncCmd = 0x00001b9d; +HCI_LE_READ_Anatenna_InfoCmd = 0x00001bb9; +HCI_LE_RandCmd = 0x00001bd9; +HCI_LE_ReadAdvChanTxPowerCmd = 0x00001c09; +HCI_LE_ReadBufSizeCmd = 0x00001c29; +HCI_LE_ReadChannelMapCmd = 0x00001c4d; +HCI_LE_ReadLocalSupportedFeaturesCmd = 0x00001c99; +HCI_LE_ReadMaxDataLengthCmd = 0x00001cb9; +HCI_LE_ReadMaximumAdvDataLengthCmd = 0x00001ce9; +HCI_LE_ReadNumberOfSupportAdvSetCmd = 0x00001d11; +HCI_LE_ReadPhyMode = 0x00001d71; +HCI_LE_ReadRemoteUsedFeaturesCmd = 0x00001db1; +HCI_LE_ReadResolvingListSizeCmd = 0x00001dc5; +HCI_LE_ReadSuggestedDefaultDataLengthCmd = 0x00001de5; +HCI_LE_ReadSupportedStatesCmd = 0x00001e15; +HCI_LE_ReadWhiteListSizeCmd = 0x00001e3d; +HCI_LE_ReceiverTestCmd = 0x00001e9d; +HCI_LE_RemoveAdvSetCmd = 0x00001eb1; +HCI_LE_RemoveResolvingListCmd = 0x00001ee9; +HCI_LE_RemoveWhiteListCmd = 0x00001f0d; +HCI_LE_SetAddressResolutionEnableCmd = 0x00001f31; +HCI_LE_SetAdvDataCmd = 0x00001f4d; +HCI_LE_SetAdvEnableCmd = 0x00001f69; +HCI_LE_SetAdvParamCmd = 0x00001f85; +HCI_LE_SetDataLengthCmd = 0x00001fb1; +HCI_LE_SetDefaultPhyMode = 0x00001fd9; +HCI_LE_SetEventMaskCmd = 0x00001ff5; +HCI_LE_SetExtAdvDataCmd = 0x0000202d; +HCI_LE_SetExtAdvEnableCmd = 0x0000204d; +HCI_LE_SetExtAdvParamCmd = 0x0000206d; +HCI_LE_SetExtAdvSetRandomAddressCmd = 0x000020c1; +HCI_LE_SetExtScanRspDataCmd = 0x000020dd; +HCI_LE_SetExtendedScanEnableCmd = 0x000020fd; +HCI_LE_SetExtendedScanParametersCmd = 0x00002119; +HCI_LE_SetHostChanClassificationCmd = 0x0000213d; +HCI_LE_SetPeriodicAdvDataCmd = 0x00002159; +HCI_LE_SetPeriodicAdvEnableCmd = 0x00002175; +HCI_LE_SetPeriodicAdvParameterCmd = 0x00002191; +HCI_LE_SetPhyMode = 0x000021ad; +HCI_LE_SetRandomAddressCmd = 0x000021c5; +HCI_LE_SetResolvablePrivateAddressTimeoutCmd = 0x000021e9; +HCI_LE_SetScanEnableCmd = 0x00002219; +HCI_LE_SetScanParamCmd = 0x00002235; +HCI_LE_SetScanRspDataCmd = 0x00002255; +HCI_LE_Set_ConnectionCTE_ReceiveParamCmd = 0x00002271; +HCI_LE_Set_ConnectionCTE_TransmitParamCmd = 0x0000229d; +HCI_LE_StartEncyptCmd = 0x000022e1; +HCI_LE_TestEndCmd = 0x000022f5; +HCI_LE_TransmitterTestCmd = 0x0000231d; +HCI_LE_WriteSuggestedDefaultDataLengthCmd = 0x00002339; +HCI_NumOfCompletedPacketsEvent = 0x00002371; +HCI_PPLUS_AdvEventDoneNoticeCmd = 0x00002401; +HCI_PPLUS_ConnEventDoneNoticeCmd = 0x00002421; +HCI_PPLUS_DateLengthChangedNoticeCmd = 0x00002461; +HCI_PPLUS_ExtendTRXCmd = 0x000024a1; +HCI_PPLUS_PhyUpdateNoticeCmd = 0x000024bd; +HCI_ProcessEvent = 0x000024fd; +HCI_ReadBDADDRCmd = 0x00002551; +HCI_ReadLocalSupportedCommandsCmd = 0x00002571; +HCI_ReadLocalSupportedFeaturesCmd = 0x00002589; +HCI_ReadLocalVersionInfoCmd = 0x000025ad; +HCI_ReadRemoteVersionInfoCmd = 0x000025f5; +HCI_ReadRssiCmd = 0x00002625; +HCI_ReadTransmitPowerLevelCmd = 0x00002651; +HCI_ResetCmd = 0x0000267d; +HCI_ReverseBytes = 0x000026a9; +HCI_SMPTaskRegister = 0x000026c9; +HCI_SendCommandCompleteEvent = 0x000026d5; +HCI_SendCommandStatusEvent = 0x0000277d; +HCI_SendControllerToHostEvent = 0x0000279d; +HCI_SendDataPkt = 0x000027e9; +HCI_SetControllerToHostFlowCtrlCmd = 0x00002819; +HCI_SetEventMaskCmd = 0x0000285d; +HCI_TestAppTaskRegister = 0x0000288d; +HCI_ValidConnTimeParams = 0x00002899; +HCI_VendorSpecifcCommandCompleteEvent = 0x000028d9; +HCI_bm_alloc = 0x000028e9; +HardFault_Handler = 0x000028f1; +HardFault_IRQHandler = 0x00002909; +LL_AddResolvingListLDevice = 0x000029dd; +LL_AddWhiteListDevice = 0x00002a95; +LL_AdvReportCback = 0x00002b11; +LL_CTE_Report_FailedCback = 0x00002ca1; +LL_ChanMapUpdate = 0x00002d0d; +LL_ClearAdvSets = 0x00002e2d; +LL_ClearResolvingList = 0x00002f41; +LL_ClearWhiteList = 0x00002fbd; +LL_ConnActive = 0x00003011; +LL_ConnParamUpdateCback = 0x00003039; +LL_ConnUpdate = 0x000030e5; +LL_ConnectionCompleteCback = 0x000031b9; +LL_ConnectionIQReportCback = 0x000032d5; +LL_Connection_CTE_Request_Enable = 0x000033e5; +LL_Connection_CTE_Response_Enable = 0x00003499; +LL_ConnectionlessCTE_TransmitEnable = 0x00003505; +LL_ConnectionlessCTE_TransmitParam = 0x000035e5; +LL_ConnectionlessIQReportCback = 0x000036c1; +LL_ConnectionlessIQ_SampleEnable = 0x000037c5; +LL_CreateConn = 0x00003901; +LL_CreateConn0 = 0x00003949; +LL_CreateConnCancel = 0x00003c91; +LL_CtrlToHostFlowControl = 0x00003d59; +LL_DataLengthChangeCback = 0x00003d71; +LL_DirectTestEnd = 0x00003e3d; +LL_DirectTestTxTest = 0x00003e95; +LL_Disconnect = 0x00003eb1; +LL_DisconnectCback = 0x00003f41; +LL_ENC_AES128_Encrypt = 0x00003fc5; +LL_ENC_AES128_Encrypt0 = 0x00003fdd; +LL_ENC_Decrypt = 0x000040ed; +LL_ENC_Decrypt0 = 0x00004105; +LL_ENC_Encrypt = 0x00004261; +LL_ENC_Encrypt0 = 0x00004278; +LL_ENC_GenDeviceIV = 0x000043c1; +LL_ENC_GenDeviceSKD = 0x000043f1; +LL_ENC_GenerateNonce = 0x00004421; +LL_ENC_GeneratePseudoRandNum = 0x00004459; +LL_ENC_GenerateTrueRandNum = 0x00004469; +LL_ENC_LoadKey = 0x00004489; +LL_ENC_ReverseBytes = 0x000044e1; +LL_ENC_sm_ah = 0x00004501; +LL_EXT_AdvEventNotice = 0x00004543; +LL_EXT_BuildRevision = 0x00004547; +LL_EXT_ClkDivOnHalt = 0x0000454b; +LL_EXT_ConnEventNotice = 0x0000454f; +LL_EXT_DeclareNvUsage = 0x00004553; +LL_EXT_Decrypt = 0x00004557; +LL_EXT_DelaySleep = 0x0000455b; +LL_EXT_DisconnectImmed = 0x0000455f; +LL_EXT_EndModemTest = 0x00004563; +LL_EXT_HaltDuringRf = 0x00004567; +LL_EXT_Init_IQ_pBuff = 0x0000456d; +LL_EXT_MapPmIoPort = 0x00004581; +LL_EXT_ModemHopTestTx = 0x00004585; +LL_EXT_ModemTestRx = 0x00004589; +LL_EXT_ModemTestTx = 0x0000458d; +LL_EXT_NumComplPktsLimit = 0x00004591; +LL_EXT_OnePacketPerEvent = 0x000045ad; +LL_EXT_OverlappedProcessing = 0x000045b1; +LL_EXT_PERbyChan = 0x000045b5; +LL_EXT_PacketErrorRate = 0x000045b9; +LL_EXT_PacketErrorRateCback = 0x000045bd; +LL_EXT_ResetSystem = 0x000045f9; +LL_EXT_SaveFreqTune = 0x000045fd; +LL_EXT_SetBDADDR = 0x00004601; +LL_EXT_SetFastTxResponseTime = 0x00004605; +LL_EXT_SetFreqTune = 0x00004609; +LL_EXT_SetLocalSupportedFeatures = 0x0000460d; +LL_EXT_SetMaxDtmTxPower = 0x00004611; +LL_EXT_SetRxGain = 0x00004615; +LL_EXT_SetRxGainCback = 0x00004619; +LL_EXT_SetSCA = 0x00004635; +LL_EXT_SetSlaveLatencyOverride = 0x00004639; +LL_EXT_SetTxPower = 0x0000463d; +LL_EXT_SetTxPowerCback = 0x00004679; +LL_EncChangeCback = 0x00004699; +LL_EncKeyRefreshCback = 0x00004715; +LL_EncLtkNegReply = 0x0000478d; +LL_EncLtkReply = 0x000047d9; +LL_EncLtkReqCback = 0x00004831; +LL_Encrypt = 0x000048e5; +LL_ExtAdvReportCback = 0x00004a8d; +LL_ExtendedCreateConnection = 0x00004bfd; +LL_IRQHandler = 0x00004e25; +LL_Init = 0x00004eb1; +LL_InitConnectContext = 0x00005045; +LL_InitExtendedAdv = 0x0000511d; +LL_InitExtendedScan = 0x000051b5; +LL_InitPeriodicAdv = 0x000051c5; +LL_NumEmptyWlEntries = 0x00005291; +LL_PLUS_DisableSlaveLatency = 0x000052a5; +LL_PLUS_EnableSlaveLatency = 0x00005435; +LL_PLUS_GetAdvDataExtendData = 0x0000548d; +LL_PLUS_GetScanRequestExtendData = 0x00005495; +LL_PLUS_GetScanerAddr = 0x000054bd; +LL_PLUS_PerStasReadByChn = 0x000054d5; +LL_PLUS_PerStatsReset = 0x00005519; +LL_PLUS_PerStats_Init = 0x00005535; +LL_PLUS_SetAdvDataFilterCB = 0x00005545; +LL_PLUS_SetScanRequestData = 0x00005551; +LL_PLUS_SetScanRequestFilterCB = 0x00005579; +LL_PLUS_SetScanRsqData = 0x00005585; +LL_PLUS_SetScanRsqDataByIndex = 0x000055b1; +LL_PeriodicAdvertisingCreateSync = 0x000055bd; +LL_PeriodicAdvertisingCreateSyncCancel = 0x0000560d; +LL_PeriodicAdvertisingTerminateSync = 0x00005635; +LL_PhyUpdate = 0x00005655; +LL_PhyUpdate0 = 0x0000566d; +LL_PhyUpdateCompleteCback = 0x00005725; +LL_PrdAdvReportCback = 0x000057c9; +LL_PrdAdvSyncEstablishedCback = 0x000058b5; +LL_PrdAdvSyncLostCback = 0x00005989; +LL_ProcessEvent = 0x000059f1; +LL_PseudoRand = 0x00005dd9; +LL_READ_Anatenna_Info = 0x00005ddd; +LL_RX_bm_alloc = 0x00005df1; +LL_Rand = 0x00005e05; +LL_RandCback = 0x00005e65; +LL_ReadAdvChanTxPower = 0x00005e89; +LL_ReadBDADDR = 0x00005eb9; +LL_ReadCarrSens = 0x00005edd; +LL_ReadChanMap = 0x00005ef9; +LL_ReadFoff = 0x00005f31; +LL_ReadLocalSupportedFeatures = 0x00005f71; +LL_ReadLocalVersionInfo = 0x00005f8d; +LL_ReadMaximumAdvDataLength = 0x00005fa5; +LL_ReadNumberOfSupportAdvSet = 0x00005fc5; +LL_ReadRemoteUsedFeatures = 0x00006021; +LL_ReadRemoteUsedFeaturesCompleteCback = 0x00006061; +LL_ReadRemoteVersionInfo = 0x000060d5; +LL_ReadRemoteVersionInfoCback = 0x00006131; +LL_ReadResolvingListSize = 0x000061a9; +LL_ReadRssi = 0x000061b1; +LL_ReadSupportedStates = 0x000061e5; +LL_ReadTxPowerLevel = 0x00006269; +LL_ReadWlSize = 0x000062e5; +LL_RemoveAdvSet = 0x00006335; +LL_RemoveResolvingListDevice = 0x000064a5; +LL_RemoveWhiteListDevice = 0x00006561; +LL_Reset = 0x000065f1; +LL_RxDataCompleteCback = 0x00006791; +LL_SetAddressResolutionEnable = 0x00006831; +LL_SetAdvControl = 0x00006881; +LL_SetAdvControl0 = 0x00006899; +LL_SetAdvData = 0x00006a05; +LL_SetAdvParam = 0x00006a6d; +LL_SetAdvParam0 = 0x00006a9d; +LL_SetDataLengh = 0x00006df9; +LL_SetDataLengh0 = 0x00006e11; +LL_SetDefaultPhyMode = 0x00006ead; +LL_SetExtAdvData = 0x00006edd; +LL_SetExtAdvEnable = 0x00006fc5; +LL_SetExtAdvParam = 0x00007205; +LL_SetExtAdvSetRandomAddress = 0x000073a9; +LL_SetExtScanRspData = 0x000073f5; +LL_SetExtendedScanEnable = 0x00007471; +LL_SetExtendedScanParameters = 0x000074b5; +LL_SetPeriodicAdvData = 0x0000751d; +LL_SetPeriodicAdvEnable = 0x000075cd; +LL_SetPeriodicAdvParameter = 0x00007715; +LL_SetPhyMode = 0x000077e1; +LL_SetPhyMode0 = 0x000077fd; +LL_SetRandomAddress = 0x000078c9; +LL_SetResolvablePrivateAddressTimeout = 0x00007929; +LL_SetScanControl = 0x00007935; +LL_SetScanControl0 = 0x0000794d; +LL_SetScanParam = 0x00007a59; +LL_SetScanParam0 = 0x00007a75; +LL_SetScanRspData = 0x00007b15; +LL_SetTxPowerLevel = 0x00007b65; +LL_Set_ConnectionCTE_ReceiveParam = 0x00007b91; +LL_Set_ConnectionCTE_TransmitParam = 0x00007c99; +LL_StartEncrypt = 0x00007e01; +LL_TX_bm_alloc = 0x00007f01; +LL_TxData = 0x00007f1d; +LL_WriteSuggestedDefaultDataLength = 0x00007fb9; +LL_evt_schedule = 0x00007ff9; +LL_extAdvTimerExpProcess = 0x000080b5; +LL_extInitTimerExpProcess = 0x000080b9; +LL_extScanTimerExpProcess = 0x000080bb; +LL_master_conn_event = 0x000080bd; +LL_prdAdvTimerExpProcess = 0x0000826d; +LL_prdScanTimerExpProcess = 0x00008271; +LL_set_default_conn_params = 0x00008275; +LL_set_default_conn_params0 = 0x0000828d; +LL_slave_conn_event = 0x000082b9; +NMI_Handler = 0x00008481; +PendSV_Handler = 0x000084cd; +TIM1_IRQHandler = 0x00008545; +WaitRTCCount = 0x00008901; +__ARM_common_switch8 = 0x00008961; +_spif_read_status_reg = 0x0000961d; +_spif_wait_nobusy = 0x00009645; +app_sleep_process = 0x00009769; +app_wakeup_process = 0x00009779; +ate_fun_test = 0x00009789; +ate_sleep_process = 0x00009d11; +ate_wakeup_process = 0x0000a121; +bit_to_byte = 0x0000a1e9; +ble_crc24_gen = 0x0000a201; +boot_init = 0x0000a361; +boot_init0 = 0x0000a379; +boot_m0 = 0x0000a3c1; +byte_to_bit = 0x0000a535; +calculate_whiten_seed = 0x0000a549; +clear_timer = 0x0000a5c1; +clear_timer_int = 0x0000a5cb; +clk_get_pclk = 0x0000a5d1; +clk_init = 0x0000a5ed; +clk_set_pclk_div = 0x0000a681; +clk_spif_ref_clk = 0x0000a6a1; +config_RTC = 0x0000a6f9; +config_RTC0 = 0x0000a711; +rom_crc16 = 0x0000a755; +debug_print = 0x0000a791; +disableSleep = 0x0000a921; +drv_disable_irq = 0x0000a975; +drv_enable_irq = 0x0000a99d; +drv_irq_init = 0x0000a9c9; +dwc_connect = 0x0000a9fd; +dwc_data_process = 0x0000aa35; +dwc_loop = 0x0000abd1; +efuse_read = 0x0000ace1; +enableSleep = 0x0000aead; +enterSleepProcess = 0x0000aeb9; +enterSleepProcess0 = 0x0000aed1; +enter_sleep_off_mode = 0x0000afa1; +enter_sleep_off_mode0 = 0x0000afb9; +getMcuPrecisionCount = 0x0000afe9; +getPN23RandNumber = 0x0000aff5; +getRxBufferFree = 0x0000b01d; +getRxBufferSize = 0x0000b031; +getSleepMode = 0x0000b051; +getTxBufferFree = 0x0000b05d; +getTxBufferSize = 0x0000b071; +get_rx_read_ptr = 0x0000b0b1; +get_rx_write_ptr = 0x0000b0b9; +get_sleep_flag = 0x0000b0c1; +get_timer_count = 0x0000b0cd; +get_timer_int = 0x0000b0d1; +get_tx_read_ptr = 0x0000b0d9; +get_tx_write_ptr = 0x0000b0e1; +gpio_cfg_analog_io = 0x0000b0e9; +gpio_dir = 0x0000b119; +gpio_fmux_control = 0x0000b15d; +gpio_fmux_set = 0x0000b179; +gpio_in_trigger = 0x0000b1b1; +gpio_init = 0x0000b219; +gpio_interrupt_set = 0x0000b22d; +gpio_pull_set = 0x0000b249; +gpio_read = 0x0000b291; +gpio_wakeup_set = 0x0000b2b5; +gpio_write = 0x0000b319; +hciInitEventMasks = 0x0000b52d; +isSleepAllow = 0x0000b555; +isTimer1Running = 0x0000b561; +isTimer4Running = 0x0000b571; +jump_area_init = 0x0000b581; +ll24BitTimeCompare = 0x0000b5a9; +llAdjSlaveLatencyValue = 0x0000b609; +llAllocConnId = 0x0000b629; +llAllocateSyncHandle = 0x0000b679; +llAtLeastTwoChans = 0x0000b6a9; +llCalcMaxScanTime = 0x0000b6ed; +llCalcScaFactor = 0x0000b745; +llCalcTimerDrift = 0x0000b76d; +llCheckForLstoDuringSL = 0x0000b7b1; +llCheckWhiteListUsage = 0x0000b7ed; +llConnCleanup = 0x0000b809; +llConnTerminate = 0x0000b839; +llConnTerminate0 = 0x0000b851; +llConvertCtrlProcTimeoutToEvent = 0x0000b87d; +llConvertLstoToEvent = 0x0000b899; +llDeleteSyncHandle = 0x0000b8bd; +llDequeueCtrlPkt = 0x0000b8ed; +llDequeueDataQ = 0x0000b929; +llEnqueueCtrlPkt = 0x0000b953; +llEnqueueDataQ = 0x0000b98b; +llEqAlreadyValidAddr = 0x0000b9b1; +llEqSynchWord = 0x0000b9b5; +llEqualBytes = 0x0000b9c9; +llEventDelta = 0x0000b9e9; +llEventInRange = 0x0000b9fd; +llGenerateCRC = 0x0000ba1b; +llGenerateValidAccessAddr = 0x0000ba3d; +llGetNextAdvChn = 0x0000ba6d; +llGetNextAuxAdvChn = 0x0000bac1; +llGetNextDataChan = 0x0000bae5; +llGetNextDataChanCSA2 = 0x0000bb23; +llGtSixConsecZerosOrOnes = 0x0000bb81; +llGtTwentyFourTransitions = 0x0000bbb3; +llInitFeatureSet = 0x0000bbe5; +llInitFeatureSet2MPHY = 0x0000bc1d; +llInitFeatureSetCodedPHY = 0x0000bc45; +llInitFeatureSetDLE = 0x0000bc6d; +llLtTwoChangesInLastSixBits = 0x0000bc89; +llMasterEvt_TaskEndOk = 0x0000bcb9; +llMemCopyDst = 0x0000be05; +llMemCopySrc = 0x0000be1b; +llOneBitSynchWordDiffer = 0x0000be35; +llPduLengthManagmentReset = 0x0000be4d; +llPduLengthUpdate = 0x0000bf01; +llPendingUpdateParam = 0x0000c00d; +llPhyModeCtrlReset = 0x0000c051; +llPhyModeCtrlUpdateNotify = 0x0000c0b9; +llProcessChanMap = 0x0000c185; +llProcessMasterControlPacket = 0x0000c1d1; +llProcessMasterControlProcedures = 0x0000c5b9; +llProcessRxData = 0x0000ca85; +llProcessSlaveControlPacket = 0x0000cc31; +llProcessSlaveControlProcedures = 0x0000d169; +llProcessTxData = 0x0000d4d1; +llProcessTxData0 = 0x0000d4e9; +llReleaseAllConnId = 0x0000d55d; +llReleaseConnId = 0x0000d561; +llReplaceCtrlPkt = 0x0000d5f5; +llResetConnId = 0x0000d60d; +llResetRfCounters = 0x0000d6ed; +llSecAdvAllow = 0x0000d701; +llSetNextDataChan = 0x0000d769; +llSetNextPhyMode = 0x0000d839; +llSetupAdv = 0x0000d8a9; +llSetupAdvExtIndPDU = 0x0000d949; +llSetupAuxAdvIndPDU = 0x0000db4d; +llSetupAuxChainIndPDU = 0x0000dda1; +llSetupAuxConnectReqPDU = 0x0000df91; +llSetupAuxConnectRspPDU = 0x0000e025; +llSetupAuxScanRspPDU = 0x0000e09d; +llSetupAuxSyncIndPDU = 0x0000e109; +llSetupCTEReq = 0x0000e2c1; +llSetupCTERsp = 0x0000e38d; +llSetupConn = 0x0000e457; +llSetupDataLenghtReq = 0x0000e459; +llSetupDataLenghtRsp = 0x0000e4d5; +llSetupDirectedAdvEvt = 0x0000e551; +llSetupEncReq = 0x0000e6a1; +llSetupEncRsp = 0x0000e725; +llSetupExtAdvEvent = 0x0000e7b1; +llSetupExtInit = 0x0000eb09; +llSetupExtScan = 0x0000eb81; +llSetupFeatureSetReq = 0x0000ec01; +llSetupFeatureSetRsp = 0x0000ec63; +llSetupInit = 0x0000ecc1; +llSetupNextMasterEvent = 0x0000ed39; +llSetupNextSlaveEvent = 0x0000ede1; +llSetupNextSlaveEvent0 = 0x0000edf9; +llSetupNonConnectableAdvEvt = 0x0000ef65; +llSetupPauseEncReq = 0x0000f075; +llSetupPauseEncRsp = 0x0000f0c5; +llSetupPhyReq = 0x0000f121; +llSetupPhyRsp = 0x0000f177; +llSetupPhyUpdateInd = 0x0000f1cd; +llSetupPrdAdvEvent = 0x0000f239; +llSetupPrdScan = 0x0000f3b9; +llSetupRejectExtInd = 0x0000f44d; +llSetupRejectInd = 0x0000f479; +llSetupScan = 0x0000f4a5; +llSetupScanInit = 0x0000f54d; +llSetupScannableAdvEvt = 0x0000f55d; +llSetupSecAdvEvt = 0x0000f66d; +llSetupSecConnectableAdvEvt = 0x0000f6e9; +llSetupSecInit = 0x0000f7c1; +llSetupSecNonConnectableAdvEvt = 0x0000f875; +llSetupSecScan = 0x0000f94d; +llSetupSecScannableAdvEvt = 0x0000fa19; +llSetupStartEncReq = 0x0000faf1; +llSetupStartEncRsp = 0x0000fb15; +llSetupSyncInfo = 0x0000fb59; +llSetupTermInd = 0x0000fc2d; +llSetupUndirectedAdvEvt = 0x0000fc91; +llSetupUnknownRsp = 0x0000fda5; +llSetupUpdateChanReq = 0x0000fdf9; +llSetupUpdateParamReq = 0x0000fe6d; +llSetupVersionIndReq = 0x0000ff05; +llSlaveEvt_TaskAbort = 0x0000ff79; +llSlaveEvt_TaskEndOk = 0x0000ff95; +llTrxNumAdaptiveConfig = 0x00010181; +llValidAccessAddr = 0x0001019b; +llWaitUs = 0x000101e1; +llWriteTxData = 0x00010209; +ll_CalcRandomAddr = 0x0001028f; +ll_ResolveRandomAddrs = 0x000102cd; +ll_addTask = 0x00010315; +ll_add_adv_task = 0x00010445; +ll_add_adv_task_periodic = 0x00010461; +ll_adptive_adj_next_time = 0x0001047d; +ll_adptive_smart_window = 0x000104fd; +ll_adv_scheduler = 0x000105ad; +ll_adv_scheduler_periodic = 0x000105c9; +ll_allocAuxAdvTimeSlot = 0x000105e5; +ll_allocAuxAdvTimeSlot_prd = 0x00010679; +ll_debug_output = 0x00010719; +ll_deleteTask = 0x00010731; +ll_delete_adv_task = 0x00010765; +ll_delete_adv_task_periodic = 0x00010781; +ll_ext_adv_schedule_next_event = 0x0001079d; +ll_ext_init_schedule_next_event = 0x000107c1; +ll_ext_scan_schedule_next_event = 0x000107dd; +ll_generateExtAdvDid = 0x000107f9; +ll_generateTxBuffer = 0x00010801; +ll_getFirstAdvChn = 0x000109c1; +ll_getRPAListEntry = 0x000109cd; +ll_get_next_active_conn = 0x00010a39; +ll_get_next_timer = 0x00010aa1; +ll_hw_clr_irq = 0x00010add; +ll_hw_config = 0x00010aed; +ll_hw_get_anchor = 0x00010b6d; +ll_hw_get_fsm_status = 0x00010b79; +ll_hw_get_iq_RawSample = 0x00010b89; +ll_hw_get_irq_status = 0x00010bbd; +ll_hw_get_last_ack = 0x00010bcd; +ll_hw_get_loop_cycle = 0x00010be9; +ll_hw_get_loop_time = 0x00010bf5; +ll_hw_get_nAck = 0x00010c01; +ll_hw_get_rfifo_depth = 0x00010c11; +ll_hw_get_rfifo_info = 0x00010c25; +ll_hw_get_rxPkt_CrcErr_num = 0x00010c45; +ll_hw_get_rxPkt_CrcOk_num = 0x00010c55; +ll_hw_get_rxPkt_Total_num = 0x00010c69; +ll_hw_get_rxPkt_num = 0x00010c79; +ll_hw_get_rxPkt_stats = 0x00010c85; +ll_hw_get_snNesn = 0x00010c9d; +ll_hw_get_tfifo_info = 0x00010cad; +ll_hw_get_tfifo_wrptr = 0x00010ccd; +ll_hw_get_tr_mode = 0x00010cdd; +ll_hw_get_txAck = 0x00010ced; +ll_hw_go = 0x00010cf9; +ll_hw_ign_rfifo = 0x00010df9; +ll_hw_process_RTO = 0x00010e05; +ll_hw_read_rfifo = 0x00010e6d; +ll_hw_read_rfifo_pplus = 0x00010ee9; +ll_hw_read_rfifo_zb = 0x00010f51; +ll_hw_read_tfifo_packet = 0x00010fad; +ll_hw_read_tfifo_rtlp = 0x00010ff5; +ll_hw_rst_rfifo = 0x000110b1; +ll_hw_rst_tfifo = 0x000110e9; +ll_hw_set_ant_pattern = 0x000110f5; +ll_hw_set_ant_switch_mode = 0x00011101; +ll_hw_set_ant_switch_timing = 0x00011115; +ll_hw_set_crc_fmt = 0x0001112d; +ll_hw_set_cte_rxSupp = 0x0001113d; +ll_hw_set_cte_txSupp = 0x00011155; +ll_hw_set_empty_head = 0x00011169; +ll_hw_set_irq = 0x00011175; +ll_hw_set_loop_nack_num = 0x00011181; +ll_hw_set_loop_timeout = 0x0001118d; +ll_hw_set_pplus_pktfmt = 0x000111a1; +ll_hw_set_rtlp = 0x000111cd; +ll_hw_set_rtlp_1st = 0x0001121d; +ll_hw_set_rtx = 0x00011265; +ll_hw_set_rx_timeout = 0x00011279; +ll_hw_set_rx_timeout_1st = 0x00011285; +ll_hw_set_rx_tx_interval = 0x00011291; +ll_hw_set_srx = 0x000112a5; +ll_hw_set_stx = 0x000112b9; +ll_hw_set_tfifo_space = 0x000112cd; +ll_hw_set_timing = 0x000112e5; +ll_hw_set_trlp = 0x00011381; +ll_hw_set_trx = 0x000113c9; +ll_hw_set_trx_settle = 0x000113dd; +ll_hw_set_tx_rx_interval = 0x000113f1; +ll_hw_set_tx_rx_release = 0x00011405; +ll_hw_trigger = 0x00011421; +ll_hw_trx_settle_config = 0x00011445; +ll_hw_tx2rx_timing_config = 0x00011489; +ll_hw_update = 0x000114dd; +ll_hw_update_rtlp_mode = 0x00011539; +ll_hw_update_trlp_mode = 0x00011579; +ll_hw_write_tfifo = 0x000115c1; +ll_isAddrInWhiteList = 0x00011649; +ll_isFirstAdvChn = 0x000116a9; +ll_isIrkAllZero = 0x000116c7; +ll_isLegacyAdv = 0x000116dd; +ll_parseExtHeader = 0x000116ed; +ll_prd_adv_schedule_next_event = 0x000117a9; +ll_prd_scan_schedule_next_event = 0x000117cd; +ll_processBasicIRQ = 0x000117e9; +ll_processExtAdvIRQ = 0x00013401; +ll_processExtInitIRQ = 0x00013405; +ll_processExtScanIRQ = 0x00013409; +ll_processMissMasterEvt = 0x0001340d; +ll_processMissSlaveEvt = 0x000134ed; +ll_processPrdAdvIRQ = 0x000135f5; +ll_processPrdScanIRQ = 0x000135f9; +ll_readLocalIRK = 0x000135fd; +ll_read_rxfifo = 0x000136c5; +ll_schedule_next_event = 0x00013761; +ll_scheduler = 0x00013771; +ll_scheduler0 = 0x00013789; +ll_updateAuxAdvTimeSlot = 0x00013a11; +ll_updateExtAdvRemainderTime = 0x00013a39; +log_clr_putc = 0x00013ab9; +log_debug_level = 0x00013ac5; +log_get_debug_level = 0x00013ad9; +log_printf = 0x00013ae5; +log_set_putc = 0x00013b05; +log_vsprintf = 0x00013b11; +move_to_master_function = 0x00013f09; +move_to_slave_function = 0x0001406d; +osalAddTimer = 0x00014439; +osalDeleteTimer = 0x000144a9; +osalFindTimer = 0x000144b5; +osalTimeUpdate = 0x000144d5; +osalTimeUpdate1 = 0x00014541; +osalTimerInit = 0x0001457d; +osalTimerUpdate = 0x00014589; +osal_CbTimerInit = 0x00014621; +osal_CbTimerProcessEvent = 0x00014641; +osal_CbTimerStart = 0x000146a9; +osal_CbTimerStop = 0x00014711; +osal_CbTimerUpdate = 0x00014751; +osal_ConvertUTCSecs = 0x000147a1; +osal_ConvertUTCTime = 0x00014841; +osal_GetSystemClock = 0x00014949; +osal_bm_adjust_header = 0x00014955; +osal_bm_adjust_tail = 0x0001497d; +osal_bm_alloc = 0x000149a9; +osal_bm_free = 0x000149d9; +osal_buffer_uint24 = 0x00014a21; +osal_buffer_uint32 = 0x00014a2f; +osal_build_uint16 = 0x00014a41; +osal_build_uint32 = 0x00014a4d; +osal_clear_event = 0x00014a89; +osal_getClock = 0x00014abd; +osal_get_timeoutEx = 0x00014ac9; +osal_init_system = 0x00014aed; +osal_isbufset = 0x00014b1d; +osal_mem_alloc = 0x00014b3d; +osal_mem_free = 0x00014c01; +osal_mem_init = 0x00014c25; +osal_mem_kick = 0x00014c8d; +osal_mem_set_heap = 0x00014cb5; +osal_memcmp = 0x00014ccd; +osal_memcpy = 0x00014ce9; +osal_memdup = 0x00014cf9; +osal_memset = 0x00014d15; +osal_msg_allocate = 0x00014d1d; +osal_msg_deallocate = 0x00014d43; +osal_msg_dequeue = 0x00014d65; +osal_msg_enqueue = 0x00014d91; +osal_msg_enqueue_max = 0x00014dc3; +osal_msg_extract = 0x00014e6d; +osal_msg_find = 0x00014e9d; +osal_msg_push = 0x00014ed1; +osal_msg_push_front = 0x00014eeb; +osal_msg_receive = 0x00014ef5; +osal_msg_send = 0x00014f59; +osal_next_timeout = 0x00014f7d; +osal_pwrmgr_device = 0x00014fa5; +osal_pwrmgr_init = 0x00014fb1; +osal_pwrmgr_powerconserve = 0x00014fc1; +osal_pwrmgr_powerconserve0 = 0x00014fd9; +osal_pwrmgr_task_state = 0x000150f9; +osal_rand = 0x00015129; +osal_revmemcpy = 0x00015145; +osal_run_system = 0x00015159; +osal_self = 0x000151f5; +osal_setClock = 0x00015201; +osal_set_event = 0x0001520d; +osal_start_reload_timer = 0x00015259; +osal_start_system = 0x00015285; +osal_start_timerEx = 0x0001528b; +osal_stop_timerEx = 0x000152b3; +osal_strlen = 0x000152dd; +osal_timer_num_active = 0x000152e5; +phy_sec_app_key = 0x00015315; +phy_sec_decrypt = 0x0001531d; +phy_sec_efuse_lock = 0x0001532d; +phy_sec_encrypt = 0x00015339; +phy_sec_init = 0x00015349; +phy_sec_key_valid = 0x0001540d; +prog_process_data = 0x00015b19; +prog_uart_command = 0x00015c51; +prog_uart_fct_command = 0x00015c71; +prog_uart_handle = 0x00015c8d; +read_LL_remainder_time = 0x00015cbd; +read_current_fine_time = 0x00015cc9; +read_ll_adv_remainder_time = 0x00015cf1; +reset_conn_buf = 0x00015cfd; +rf_calibrate = 0x00015d75; +rf_init = 0x00015ded; +rf_phy_ana_cfg = 0x00015dfd; +rf_phy_bb_cfg = 0x00015f0d; +rf_phy_change_cfg = 0x00016085; +rf_phy_direct_test_ate = 0x00016129; +rf_phy_get_pktFoot = 0x00016669; +rf_phy_ini = 0x000166c1; +rf_phy_set_txPower = 0x000166dd; +rf_rxDcoc_cfg = 0x00016701; +rf_tpCal_cfg = 0x00016811; +rf_tpCal_cfg_avg = 0x0001683d; +rf_tpCal_gen_cap_arrary = 0x000168ed; +rf_tp_cal = 0x00016929; +rom_board_init = 0x00016a09; +rtc_clear = 0x00016ab5; +rtc_config_prescale = 0x00016ad1; +rtc_get_counter = 0x00016b15; +rtc_start = 0x00016b25; +rtc_stop = 0x00016b35; +setSleepMode = 0x00016b45; +set_access_address = 0x00016b51; +set_channel = 0x00016b5d; +set_crc_seed = 0x00016b9d; +set_gpio_pull_down_ate = 0x00016bb5; +set_gpio_pull_up_ate = 0x00016bcb; +set_int = 0x00016be1; +set_max_length = 0x00016bed; +set_sleep_flag = 0x00016c01; +set_timer = 0x00016c2d; +set_whiten_seed = 0x00016cc9; +spif_cmd = 0x00016d49; +spif_config = 0x00016dc5; +spif_erase_all = 0x00016ea1; +spif_erase_block64 = 0x00016ed1; +spif_erase_chip = 0x00016f55; +spif_erase_sector = 0x00016fa9; +spif_flash_size = 0x00017029; +spif_flash_status_reg_0 = 0x0001703d; +spif_flash_status_reg_1 = 0x00017047; +spif_init = 0x00017051; +spif_rddata = 0x0001713d; +spif_read = 0x00017165; +spif_read_dma = 0x0001717d; +spif_release_deep_sleep = 0x000172cd; +spif_set_deep_sleep = 0x00017349; +spif_wrdata = 0x0001736d; +spif_write = 0x00017395; +spif_write_dma = 0x0001744d; +spif_write_protect = 0x000174f9; +sram_ret_patch = 0x00017591; +update_rx_read_ptr = 0x00017609; +update_rx_write_ptr = 0x00017635; +update_tx_read_ptr = 0x00017659; +update_tx_write_ptr = 0x00017685; +wakeupProcess = 0x000176a9; +wakeupProcess0 = 0x000176c5; +wakeup_init = 0x000178a5; +wakeup_init0 = 0x000178bd; +zigbee_crc16_gen = 0x0001798d; +supportedCmdsTable = 0x00017c00; +hciCmdTable = 0x00017c44; +SCA = 0x00017c4c; +hclk_per_us = 0x1fff0818; +hclk_per_us_shift = 0x1fff081c; +s_prog_time_save = 0x1fff0828; +s_prog_timeout = 0x1fff082c; +DFL_ENTRY_BASE = 0x1fff0830; +receive_timeout_flag = 0x1fff0850; +osal_sys_tick = 0x1fff0860; +g_timer4_irq_pending_time = 0x1fff0864; +g_hclk = 0x1fff0874; +m_in_critical_region = 0x1fff0878; +s_rom_debug_level = 0x1fff0888; +s_spif_ctx = 0x1fff0894; +osal_qHead = 0x1fff08b8; +baseTaskID = 0x1fff08c0; +OSAL_timeSeconds = 0x1fff08cc; +ll_remain_time = 0x1fff08e4; +pwrmgr_attribute = 0x1fff08e8; +timerHead = 0x1fff08f0; +hciPTMenabled = 0x1fff08f8; +ctrlToHostEnable = 0x1fff08f9; +numHostBufs = 0x1fff08fa; +hciCtrlCmdToken = 0x1fff08fc; +bleEvtMask = 0x1fff0900; +pHciEvtMask = 0x1fff0904; +hciTaskID = 0x1fff090c; +hciTestTaskID = 0x1fff090d; +hciGapTaskID = 0x1fff090e; +hciL2capTaskID = 0x1fff090f; +hciSmpTaskID = 0x1fff0910; +hciExtTaskID = 0x1fff0911; +g_maxConnNum = 0x1fff0914; +g_maxPktPerEventTx = 0x1fff0915; +g_maxPktPerEventRx = 0x1fff0916; +g_blePktVersion = 0x1fff0917; +g_llRlEnable = 0x1fff0918; +g_llScanMode = 0x1fff0919; +g_llAdvMode = 0x1fff091a; +LL_TaskID = 0x1fff091b; +llState = 0x1fff091c; +numComplPkts = 0x1fff091d; +numComplPktsLimit = 0x1fff091e; +fastTxRespTime = 0x1fff091f; +g_llWlDeviceNum = 0x1fff0920; +g_llRlDeviceNum = 0x1fff0921; +rxFifoFlowCtrl = 0x1fff0922; +llSecondaryState = 0x1fff0923; +g_extAdvNumber = 0x1fff0924; +g_perioAdvNumber = 0x1fff0925; +g_schExtAdvNum = 0x1fff0926; +g_currentExtAdv = 0x1fff0927; +g_schExtAdvNum_periodic = 0x1fff0928; +g_currentExtAdv_periodic = 0x1fff0929; +g_llRlTimeout = 0x1fff092c; +g_advSetMaximumLen = 0x1fff0930; +conn_param = 0x1fff0934; +g_pExtendedAdvInfo = 0x1fff0938; +g_pPeriodicAdvInfo = 0x1fff093c; +g_pLLcteISample = 0x1fff0940; +g_pLLcteQSample = 0x1fff0944; +g_llHdcDirAdvTime = 0x1fff0948; +g_pAdvSchInfo = 0x1fff094c; +g_advPerSlotTick = 0x1fff0950; +g_advSlotPeriodic = 0x1fff0954; +g_pAdvSchInfo_periodic = 0x1fff0958; +g_timerExpiryTick = 0x1fff095c; +chanMapUpdate = 0x1fff0960; +ownPublicAddr = 0x1fff0965; +ownRandomAddr = 0x1fff096b; +verInfo = 0x1fff0972; +peerInfo = 0x1fff0978; +g_currentAdvTimer = 0x1fff0980; +g_currentTimerTask = 0x1fff0984; +g_adv_taskID = 0x1fff0988; +g_conn_taskID = 0x1fff0989; +g_smartWindowRTOCnt = 0x1fff098a; +isPeerRpaStore = 0x1fff098b; +g_same_rf_channel_flag = 0x1fff098c; +g_currentPeerAddrType = 0x1fff098d; +g_currentLocalAddrType = 0x1fff098e; +storeRpaListIndex = 0x1fff098f; +llTaskState = 0x1fff0990; +g_adv_taskEvent = 0x1fff0992; +g_conn_taskEvent = 0x1fff0994; +llWaitingIrq = 0x1fff0998; +ISR_entry_time = 0x1fff099c; +slave_conn_event_recv_delay = 0x1fff09a0; +g_smartWindowLater = 0x1fff09a4; +g_smartWindowActiveCnt = 0x1fff09a8; +g_smartWindowPreAnchPoint = 0x1fff09ac; +g_getPn23_cnt = 0x1fff09b0; +g_getPn23_seed = 0x1fff09b4; +llScanTime = 0x1fff09b8; +p_perStatsByChan = 0x1fff09bc; +LL_PLUS_AdvDataFilterCBack = 0x1fff09c0; +LL_PLUS_ScanRequestFilterCBack = 0x1fff09c4; +g_new_master_delta = 0x1fff09c8; +llScanT1 = 0x1fff09cc; +llCurrentScanChn = 0x1fff09d0; +g_currentLocalRpa = 0x1fff09d4; +g_currentPeerRpa = 0x1fff09da; +currentPeerRpa = 0x1fff09e0; +g_dle_taskID = 0x1fff09e6; +g_dle_taskEvent = 0x1fff09e8; +g_phyChg_taskID = 0x1fff09ea; +g_phyChg_taskEvent = 0x1fff09ec; +g_smartWindowSize = 0x1fff09f0; +g_smartWindowSizeNew = 0x1fff09f4; +g_smartWindowActive = 0x1fff09f8; +g_interAuxPduDuration = 0x1fff09fc; +connUpdateTimer = 0x1fff0a04; +sleep_flag = 0x1fff0a0c; +g_wakeup_rtc_tick = 0x1fff0a10; +g_counter_traking_avg = 0x1fff0a14; +g_TIM2_IRQ_TIM3_CurrCount = 0x1fff0a18; +g_TIM2_IRQ_to_Sleep_DeltTick = 0x1fff0a1c; +g_TIM2_IRQ_PendingTick = 0x1fff0a20; +g_osal_tick_trim = 0x1fff0a24; +g_osalTickTrim_mod = 0x1fff0a28; +rtc_mod_value = 0x1fff0a2c; +g_counter_traking_cnt = 0x1fff0a30; +sleep_tick = 0x1fff0a34; +counter_tracking = 0x1fff0a38; +forever_write = 0x1fff0a3c; +g_TIM2_wakeup_delay = 0x1fff0a40; +g_rfPhyTpCal0 = 0x1fff0a44; +g_rfPhyTpCal1 = 0x1fff0a45; +g_rfPhyTpCal0_2Mbps = 0x1fff0a46; +g_rfPhyTpCal1_2Mbps = 0x1fff0a47; +g_rfPhyTxPower = 0x1fff0a48; +g_rfPhyPktFmt = 0x1fff0a49; +g_system_clk = 0x1fff0a4a; +g_rfPhyClkSel = 0x1fff0a4b; +g_rxAdcClkSel = 0x1fff0a4c; +g_dtmModeType = 0x1fff0a4d; +g_dtmLength = 0x1fff0a4e; +g_dtmExtLen = 0x1fff0a4f; +g_dtmPKT = 0x1fff0a50; +g_dtmTxPower = 0x1fff0a51; +g_dtmRssi = 0x1fff0a52; +g_dtmCarrSens = 0x1fff0a53; +g_dtmPktIntv = 0x1fff0a54; +g_dtmPktCount = 0x1fff0a56; +g_dtmRxCrcNum = 0x1fff0a58; +g_dtmRxTONum = 0x1fff0a5a; +g_dtmRsp = 0x1fff0a5c; +g_dtmFoff = 0x1fff0a5e; +g_rfPhyRxDcIQ = 0x1fff0a60; +g_dtmTick = 0x1fff0a64; +g_rfPhyFreqOffSet = 0x1fff0a68; +g_rfPhyDtmCmd = 0x1fff0a69; +g_rfPhyDtmEvt = 0x1fff0a6b; +g_dtmCmd = 0x1fff0a6d; +g_dtmFreq = 0x1fff0a6e; +g_dtmCtrl = 0x1fff0a6f; +g_dtmPara = 0x1fff0a70; +g_dtmEvt = 0x1fff0a71; +g_dtmStatus = 0x1fff0a72; +g_dtmTpCalEnable = 0x1fff0a73; +g_dtmPerAutoIntv = 0x1fff0a74; +g_dtmAccessCode = 0x1fff0a78; +g_system_reset_cause = 0x1fff0a80; +cbTimers = 0x1fff0afc; +g_llSleepContext = 0x1fff0b74; +syncInfo = 0x1fff0b84; +scanSyncInfo = 0x1fff0b96; +adv_param = 0x1fff0ba6; +scanInfo = 0x1fff0bbc; +initInfo = 0x1fff0bd4; +extScanInfo = 0x1fff0be8; +extInitInfo = 0x1fff0c10; +g_llPeriodAdvSyncInfo = 0x1fff0c50; +g_ll_conn_ctx = 0x1fff0d30; +deviceFeatureSet = 0x1fff0e48; +g_llWhitelist = 0x1fff0e51; +g_llResolvinglist = 0x1fff0e89; +g_pmCounters = 0x1fff0ffc; +g_llPduLen = 0x1fff1084; +rfCounters = 0x1fff10e0; +ext_adv_hdr = 0x1fff10ec; +dataPkt = 0x1fff1118; +cachedTRNGdata = 0x1fff1138; +whiten_seed = 0x1fff1144; +g_tx_adv_buf = 0x1fff116c; +g_tx_ext_adv_buf = 0x1fff1278; +tx_scanRsp_desc = 0x1fff1384; +g_rx_adv_buf = 0x1fff1490; diff --git a/src/misc/bb_rom_sym_m0.txt b/src/misc/bb_rom_sym_m0.txt new file mode 100644 index 0000000..a9d4768 --- /dev/null +++ b/src/misc/bb_rom_sym_m0.txt @@ -0,0 +1,1023 @@ +## ARM Linker, 5050041: Last Updated: Tue Jun 16 11:44:23 2020 +0x000000d5 T bx_to_application +0x000001f9 T P256_mul64 +0x0000029d T P256_mul128 +0x0000032d T P256_mulmod +0x00000567 T P256_sqr64 +0x000005c5 T P256_sqr128 +0x00000641 T P256_sqrmod +0x00000735 T P256_addmod +0x00000791 T P256_submod +0x000007c3 T P256_load_1 +0x000007d7 T P256_to_montgomery +0x00000801 T P256_from_montgomery +0x0000081b T P256_point_is_on_curve +0x0000086d T P256_greater_or_equal_than +0x00000887 T P256_negate_mod_m_if +0x000008a9 T P256_copy32 +0x000008b5 T P256_copy32_unaligned +0x000008c7 T P256_select +0x00000927 T P256_double_j +0x0000092b T P256_add_j +0x00000983 T P256_div2mod +0x000009e9 T P256_interpreter +0x00000a4d T P256_sqrmod_many_and_mulmod +0x00000a6d T P256_modinv +0x00000af7 T P256_jacobian_to_affine +0x00000b33 T P256_abs_int +0x00000b41 T P256_pointmult +0x00000d03 T P256_ecdh_keygen +0x00000d0b T P256_ecdh_shared_secret +0x00000e09 T __aeabi_uidiv +0x00000e09 T __aeabi_uidivmod +0x00000e35 T __aeabi_idiv +0x00000e35 T __aeabi_idivmod +0x00000e81 T __aeabi_memcpy +0x00000e81 T __aeabi_memcpy4 +0x00000e81 T __aeabi_memcpy8 +0x00000ea5 T __aeabi_memset +0x00000ea5 T __aeabi_memset4 +0x00000ea5 T __aeabi_memset8 +0x00000eb3 T __aeabi_memclr +0x00000eb3 T __aeabi_memclr4 +0x00000eb3 T __aeabi_memclr8 +0x00000eb7 T memset +0x00000ec9 T strlen +0x00000ed7 T strcmp +0x00000ef3 T memcmp +0x00000f0d T strncmp +0x00000f2d T strtok +0x00000f75 T __aeabi_uread4 +0x00000f75 T __rt_uread4 +0x00000f75 T _uread4 +0x00000f89 T strtoul +0x00001001 T __rt_ctype_table +0x00001009 T _strtoul +0x0000112d T GPIO_IRQHandler +0x00001175 T HCI_CommandCompleteEvent +0x000011fd T HCI_CommandStatusEvent +0x00001251 T HCI_DataBufferOverflowEvent +0x0000128d T HCI_DisconnectCmd +0x000012a1 T HCI_EXT_AdvEventNoticeCmd +0x000012a9 T HCI_EXT_BuildRevisionCmd +0x000012e5 T HCI_EXT_ClkDivOnHaltCmd +0x0000130d T HCI_EXT_ConnEventNoticeCmd +0x00001315 T HCI_EXT_DeclareNvUsageCmd +0x00001339 T HCI_EXT_DecryptCmd +0x0000137d T HCI_EXT_DelaySleepCmd +0x000013a5 T HCI_EXT_DisconnectImmedCmd +0x000013cd T HCI_EXT_EnablePTMCmd +0x000013e1 T HCI_EXT_EndModemTestCmd +0x00001409 T HCI_EXT_HaltDuringRfCmd +0x00001431 T HCI_EXT_ModemHopTestTxCmd +0x00001459 T HCI_EXT_ModemTestRxCmd +0x00001481 T HCI_EXT_ModemTestTxCmd +0x000014a5 T HCI_EXT_NumComplPktsLimitCmd +0x000014c9 T HCI_EXT_OnePktPerEvtCmd +0x000014f5 T HCI_EXT_OverlappedProcessingCmd +0x0000151d T HCI_EXT_PERbyChanCmd +0x00001541 T HCI_EXT_PacketErrorRateCmd +0x00001575 T HCI_EXT_ResetSystemCmd +0x0000159d T HCI_EXT_SaveFreqTuneCmd +0x000015c5 T HCI_EXT_SetBDADDRCmd +0x00001601 T HCI_EXT_SetFastTxResponseTimeCmd +0x00001629 T HCI_EXT_SetFreqTuneCmd +0x00001651 T HCI_EXT_SetLocalSupportedFeaturesCmd +0x00001679 T HCI_EXT_SetMaxDtmTxPowerCmd +0x000016a1 T HCI_EXT_SetRxGainCmd +0x000016d1 T HCI_EXT_SetSCACmd +0x000016f9 T HCI_EXT_SetSlaveLatencyOverrideCmd +0x00001721 T HCI_EXT_SetTxPowerCmd +0x00001751 T HCI_ExtTaskRegister +0x0000175d T HCI_GAPTaskRegister +0x00001769 T HCI_HardwareErrorEvent +0x000017b1 T HCI_HostBufferSizeCmd +0x000017e1 T HCI_HostNumCompletedPktCmd +0x0000183d T HCI_Init +0x00001879 T HCI_L2CAPTaskRegister +0x000018a1 T HCI_LE_AddDevToResolvingListCmd +0x000018bd T HCI_LE_AddWhiteListCmd +0x000018e1 T HCI_LE_ClearAdvSetsCmd +0x00001919 T HCI_LE_ClearResolvingListCmd +0x00001935 T HCI_LE_ClearWhiteListCmd +0x0000196d T HCI_LE_Connection_CTE_Request_EnableCmd +0x00001999 T HCI_LE_Connection_CTE_Response_EnableCmd +0x000019c1 T HCI_LE_ConnectionlessCTE_TransmitEnableCmd +0x000019dd T HCI_LE_ConnectionlessCTE_TransmitParamCmd +0x00001a01 T HCI_LE_ConnectionlessIQ_SampleEnableCmd +0x00001a31 T HCI_LE_CreateConnCancelCmd +0x00001a4d T HCI_LE_CreateConnCmd +0x00001a89 T HCI_LE_EncryptCmd +0x00001ac1 T HCI_LE_ExtendedCreateConnectionCmd +;0x00001b09 T HCI_LE_LtkReqNegReplyCmd +;0x00001b31 T HCI_LE_LtkReqReplyCmd +0x00001b59 T HCI_LE_PeriodicAdvertisingCreateSyncCancelCmd +0x00001b75 T HCI_LE_PeriodicAdvertisingCreateSyncCmd +0x00001b9d T HCI_LE_PeriodicAdvertisingTerminateSyncCmd +0x00001bb9 T HCI_LE_READ_Anatenna_InfoCmd +0x00001bd9 T HCI_LE_RandCmd +0x00001c09 T HCI_LE_ReadAdvChanTxPowerCmd +0x00001c29 T HCI_LE_ReadBufSizeCmd +0x00001c4d T HCI_LE_ReadChannelMapCmd +0x00001c99 T HCI_LE_ReadLocalSupportedFeaturesCmd +0x00001cb9 T HCI_LE_ReadMaxDataLengthCmd +0x00001ce9 T HCI_LE_ReadMaximumAdvDataLengthCmd +0x00001d11 T HCI_LE_ReadNumberOfSupportAdvSetCmd +0x00001d71 T HCI_LE_ReadPhyMode +0x00001db1 T HCI_LE_ReadRemoteUsedFeaturesCmd +0x00001dc5 T HCI_LE_ReadResolvingListSizeCmd +0x00001de5 T HCI_LE_ReadSuggestedDefaultDataLengthCmd +0x00001e15 T HCI_LE_ReadSupportedStatesCmd +0x00001e3d T HCI_LE_ReadWhiteListSizeCmd +0x00001e9d T HCI_LE_ReceiverTestCmd +0x00001eb1 T HCI_LE_RemoveAdvSetCmd +0x00001ee9 T HCI_LE_RemoveResolvingListCmd +0x00001f0d T HCI_LE_RemoveWhiteListCmd +0x00001f31 T HCI_LE_SetAddressResolutionEnableCmd +0x00001f4d T HCI_LE_SetAdvDataCmd +0x00001f69 T HCI_LE_SetAdvEnableCmd +0x00001f85 T HCI_LE_SetAdvParamCmd +0x00001fb1 T HCI_LE_SetDataLengthCmd +0x00001fd9 T HCI_LE_SetDefaultPhyMode +0x00001ff5 T HCI_LE_SetEventMaskCmd +0x0000202d T HCI_LE_SetExtAdvDataCmd +0x0000204d T HCI_LE_SetExtAdvEnableCmd +0x0000206d T HCI_LE_SetExtAdvParamCmd +0x000020c1 T HCI_LE_SetExtAdvSetRandomAddressCmd +0x000020dd T HCI_LE_SetExtScanRspDataCmd +0x000020fd T HCI_LE_SetExtendedScanEnableCmd +0x00002119 T HCI_LE_SetExtendedScanParametersCmd +;0x0000213d T HCI_LE_SetHostChanClassificationCmd +0x00002159 T HCI_LE_SetPeriodicAdvDataCmd +0x00002175 T HCI_LE_SetPeriodicAdvEnableCmd +0x00002191 T HCI_LE_SetPeriodicAdvParameterCmd +0x000021ad T HCI_LE_SetPhyMode +0x000021c5 T HCI_LE_SetRandomAddressCmd +0x000021e9 T HCI_LE_SetResolvablePrivateAddressTimeoutCmd +0x00002219 T HCI_LE_SetScanEnableCmd +0x00002235 T HCI_LE_SetScanParamCmd +0x00002255 T HCI_LE_SetScanRspDataCmd +0x00002271 T HCI_LE_Set_ConnectionCTE_ReceiveParamCmd +0x0000229d T HCI_LE_Set_ConnectionCTE_TransmitParamCmd +0x000022e1 T HCI_LE_StartEncyptCmd +0x000022f5 T HCI_LE_TestEndCmd +0x0000231d T HCI_LE_TransmitterTestCmd +0x00002339 T HCI_LE_WriteSuggestedDefaultDataLengthCmd +0x00002371 T HCI_NumOfCompletedPacketsEvent +0x00002401 T HCI_PPLUS_AdvEventDoneNoticeCmd +0x00002421 T HCI_PPLUS_ConnEventDoneNoticeCmd +0x00002461 T HCI_PPLUS_DateLengthChangedNoticeCmd +0x000024a1 T HCI_PPLUS_ExtendTRXCmd +0x000024bd T HCI_PPLUS_PhyUpdateNoticeCmd +0x000024fd T HCI_ProcessEvent +0x00002551 T HCI_ReadBDADDRCmd +0x00002571 T HCI_ReadLocalSupportedCommandsCmd +0x00002589 T HCI_ReadLocalSupportedFeaturesCmd +0x000025ad T HCI_ReadLocalVersionInfoCmd +0x000025f5 T HCI_ReadRemoteVersionInfoCmd +0x00002625 T HCI_ReadRssiCmd +0x00002651 T HCI_ReadTransmitPowerLevelCmd +0x0000267d T HCI_ResetCmd +0x000026a9 T HCI_ReverseBytes +0x000026c9 T HCI_SMPTaskRegister +0x000026d5 T HCI_SendCommandCompleteEvent +0x0000277d T HCI_SendCommandStatusEvent +0x0000279d T HCI_SendControllerToHostEvent +0x000027e9 T HCI_SendDataPkt +0x00002819 T HCI_SetControllerToHostFlowCtrlCmd +0x0000285d T HCI_SetEventMaskCmd +0x0000288d T HCI_TestAppTaskRegister +0x00002899 T HCI_ValidConnTimeParams +0x000028d9 T HCI_VendorSpecifcCommandCompleteEvent +0x000028e9 T HCI_bm_alloc +0x000028f1 T HardFault_Handler +0x00002909 T HardFault_IRQHandler +0x000029dd T LL_AddResolvingListLDevice +0x00002a95 T LL_AddWhiteListDevice +0x00002b11 T LL_AdvReportCback +0x00002ca1 T LL_CTE_Report_FailedCback +0x00002d0d T LL_ChanMapUpdate +0x00002e2d T LL_ClearAdvSets +0x00002f41 T LL_ClearResolvingList +0x00002fbd T LL_ClearWhiteList +0x00003011 T LL_ConnActive +0x00003039 T LL_ConnParamUpdateCback +0x000030e5 T LL_ConnUpdate +0x000031b9 T LL_ConnectionCompleteCback +0x000032d5 T LL_ConnectionIQReportCback +0x000033e5 T LL_Connection_CTE_Request_Enable +0x00003499 T LL_Connection_CTE_Response_Enable +0x00003505 T LL_ConnectionlessCTE_TransmitEnable +0x000035e5 T LL_ConnectionlessCTE_TransmitParam +0x000036c1 T LL_ConnectionlessIQReportCback +0x000037c5 T LL_ConnectionlessIQ_SampleEnable +0x00003901 T LL_CreateConn +0x00003949 T LL_CreateConn0 +0x00003c91 T LL_CreateConnCancel +0x00003d59 T LL_CtrlToHostFlowControl +0x00003d71 T LL_DataLengthChangeCback +0x00003e3d T LL_DirectTestEnd +0x00003e95 T LL_DirectTestTxTest +0x00003eb1 T LL_Disconnect +0x00003f41 T LL_DisconnectCback +0x00003fc5 T LL_ENC_AES128_Encrypt +0x00003fdd T LL_ENC_AES128_Encrypt0 +0x000040ed T LL_ENC_Decrypt +0x00004105 T LL_ENC_Decrypt0 +0x00004261 T LL_ENC_Encrypt +0x00004278 T LL_ENC_Encrypt0 +0x000043c1 T LL_ENC_GenDeviceIV +0x000043f1 T LL_ENC_GenDeviceSKD +0x00004421 T LL_ENC_GenerateNonce +0x00004459 T LL_ENC_GeneratePseudoRandNum +0x00004469 T LL_ENC_GenerateTrueRandNum +0x00004489 T LL_ENC_LoadKey +0x000044e1 T LL_ENC_ReverseBytes +0x00004501 T LL_ENC_sm_ah +0x00004543 T LL_EXT_AdvEventNotice +0x00004547 T LL_EXT_BuildRevision +0x0000454b T LL_EXT_ClkDivOnHalt +0x0000454f T LL_EXT_ConnEventNotice +0x00004553 T LL_EXT_DeclareNvUsage +0x00004557 T LL_EXT_Decrypt +0x0000455b T LL_EXT_DelaySleep +0x0000455f T LL_EXT_DisconnectImmed +0x00004563 T LL_EXT_EndModemTest +0x00004567 T LL_EXT_HaltDuringRf +0x0000456d T LL_EXT_Init_IQ_pBuff +0x00004581 T LL_EXT_MapPmIoPort +0x00004585 T LL_EXT_ModemHopTestTx +0x00004589 T LL_EXT_ModemTestRx +0x0000458d T LL_EXT_ModemTestTx +0x00004591 T LL_EXT_NumComplPktsLimit +0x000045ad T LL_EXT_OnePacketPerEvent +0x000045b1 T LL_EXT_OverlappedProcessing +0x000045b5 T LL_EXT_PERbyChan +0x000045b9 T LL_EXT_PacketErrorRate +0x000045bd T LL_EXT_PacketErrorRateCback +0x000045f9 T LL_EXT_ResetSystem +0x000045fd T LL_EXT_SaveFreqTune +0x00004601 T LL_EXT_SetBDADDR +0x00004605 T LL_EXT_SetFastTxResponseTime +0x00004609 T LL_EXT_SetFreqTune +0x0000460d T LL_EXT_SetLocalSupportedFeatures +0x00004611 T LL_EXT_SetMaxDtmTxPower +0x00004615 T LL_EXT_SetRxGain +0x00004619 T LL_EXT_SetRxGainCback +0x00004635 T LL_EXT_SetSCA +0x00004639 T LL_EXT_SetSlaveLatencyOverride +0x0000463d T LL_EXT_SetTxPower +0x00004679 T LL_EXT_SetTxPowerCback +0x00004699 T LL_EncChangeCback +0x00004715 T LL_EncKeyRefreshCback +;0x0000478d T LL_EncLtkNegReply +;0x000047d9 T LL_EncLtkReply +0x00004831 T LL_EncLtkReqCback +0x000048e5 T LL_Encrypt +0x00004a8d T LL_ExtAdvReportCback +0x00004bfd T LL_ExtendedCreateConnection +0x00004e25 T LL_IRQHandler +0x00004eb1 T LL_Init +0x00005045 T LL_InitConnectContext +0x0000511d T LL_InitExtendedAdv +0x000051b5 T LL_InitExtendedScan +0x000051c5 T LL_InitPeriodicAdv +0x00005291 T LL_NumEmptyWlEntries +0x000052a5 T LL_PLUS_DisableSlaveLatency +0x00005435 T LL_PLUS_EnableSlaveLatency +0x0000548d T LL_PLUS_GetAdvDataExtendData +0x00005495 T LL_PLUS_GetScanRequestExtendData +0x000054bd T LL_PLUS_GetScanerAddr +0x000054d5 T LL_PLUS_PerStasReadByChn +0x00005519 T LL_PLUS_PerStatsReset +0x00005535 T LL_PLUS_PerStats_Init +0x00005545 T LL_PLUS_SetAdvDataFilterCB +0x00005551 T LL_PLUS_SetScanRequestData +0x00005579 T LL_PLUS_SetScanRequestFilterCB +0x00005585 T LL_PLUS_SetScanRsqData +0x000055b1 T LL_PLUS_SetScanRsqDataByIndex +0x000055bd T LL_PeriodicAdvertisingCreateSync +0x0000560d T LL_PeriodicAdvertisingCreateSyncCancel +0x00005635 T LL_PeriodicAdvertisingTerminateSync +0x00005655 T LL_PhyUpdate +0x0000566d T LL_PhyUpdate0 +0x00005725 T LL_PhyUpdateCompleteCback +0x000057c9 T LL_PrdAdvReportCback +0x000058b5 T LL_PrdAdvSyncEstablishedCback +0x00005989 T LL_PrdAdvSyncLostCback +0x000059f1 T LL_ProcessEvent +0x00005dd9 T LL_PseudoRand +0x00005ddd T LL_READ_Anatenna_Info +0x00005df1 T LL_RX_bm_alloc +0x00005e05 T LL_Rand +0x00005e65 T LL_RandCback +0x00005e89 T LL_ReadAdvChanTxPower +0x00005eb9 T LL_ReadBDADDR +0x00005edd T LL_ReadCarrSens +0x00005ef9 T LL_ReadChanMap +0x00005f31 T LL_ReadFoff +0x00005f71 T LL_ReadLocalSupportedFeatures +0x00005f8d T LL_ReadLocalVersionInfo +0x00005fa5 T LL_ReadMaximumAdvDataLength +0x00005fc5 T LL_ReadNumberOfSupportAdvSet +0x00006021 T LL_ReadRemoteUsedFeatures +0x00006061 T LL_ReadRemoteUsedFeaturesCompleteCback +0x000060d5 T LL_ReadRemoteVersionInfo +0x00006131 T LL_ReadRemoteVersionInfoCback +0x000061a9 T LL_ReadResolvingListSize +0x000061b1 T LL_ReadRssi +0x000061e5 T LL_ReadSupportedStates +0x00006269 T LL_ReadTxPowerLevel +0x000062e5 T LL_ReadWlSize +0x00006335 T LL_RemoveAdvSet +0x000064a5 T LL_RemoveResolvingListDevice +0x00006561 T LL_RemoveWhiteListDevice +0x000065f1 T LL_Reset +0x00006791 T LL_RxDataCompleteCback +0x00006831 T LL_SetAddressResolutionEnable +0x00006881 T LL_SetAdvControl +0x00006899 T LL_SetAdvControl0 +0x00006a05 T LL_SetAdvData +0x00006a6d T LL_SetAdvParam +0x00006a9d T LL_SetAdvParam0 +0x00006df9 T LL_SetDataLengh +0x00006e11 T LL_SetDataLengh0 +0x00006ead T LL_SetDefaultPhyMode +0x00006edd T LL_SetExtAdvData +0x00006fc5 T LL_SetExtAdvEnable +0x00007205 T LL_SetExtAdvParam +0x000073a9 T LL_SetExtAdvSetRandomAddress +0x000073f5 T LL_SetExtScanRspData +0x00007471 T LL_SetExtendedScanEnable +0x000074b5 T LL_SetExtendedScanParameters +0x0000751d T LL_SetPeriodicAdvData +0x000075cd T LL_SetPeriodicAdvEnable +0x00007715 T LL_SetPeriodicAdvParameter +0x000077e1 T LL_SetPhyMode +0x000077fd T LL_SetPhyMode0 +0x000078c9 T LL_SetRandomAddress +0x00007929 T LL_SetResolvablePrivateAddressTimeout +0x00007935 T LL_SetScanControl +0x0000794d T LL_SetScanControl0 +0x00007a59 T LL_SetScanParam +0x00007a75 T LL_SetScanParam0 +0x00007b15 T LL_SetScanRspData +0x00007b65 T LL_SetTxPowerLevel +0x00007b91 T LL_Set_ConnectionCTE_ReceiveParam +0x00007c99 T LL_Set_ConnectionCTE_TransmitParam +0x00007e01 T LL_StartEncrypt +0x00007f01 T LL_TX_bm_alloc +0x00007f1d T LL_TxData +0x00007fb9 T LL_WriteSuggestedDefaultDataLength +0x00007ff9 T LL_evt_schedule +0x000080b5 T LL_extAdvTimerExpProcess +0x000080b9 T LL_extInitTimerExpProcess +0x000080bb T LL_extScanTimerExpProcess +0x000080bd T LL_master_conn_event +0x0000826d T LL_prdAdvTimerExpProcess +0x00008271 T LL_prdScanTimerExpProcess +0x00008275 T LL_set_default_conn_params +0x0000828d T LL_set_default_conn_params0 +0x000082b9 T LL_slave_conn_event +0x00008481 T NMI_Handler +0x000084cd T PendSV_Handler +0x00008545 T TIM1_IRQHandler +0x00008901 T WaitRTCCount +0x00008961 T __ARM_common_switch8 +0x0000961d T _spif_read_status_reg +0x00009645 T _spif_wait_nobusy +0x00009769 T app_sleep_process +0x00009779 T app_wakeup_process +0x00009789 T ate_fun_test +0x00009d11 T ate_sleep_process +0x0000a121 T ate_wakeup_process +0x0000a1e9 T bit_to_byte +0x0000a201 T ble_crc24_gen +0x0000a361 T boot_init +0x0000a379 T boot_init0 +0x0000a3c1 T boot_m0 +0x0000a535 T byte_to_bit +0x0000a549 T calculate_whiten_seed +0x0000a5c1 T clear_timer +0x0000a5cb T clear_timer_int +0x0000a5d1 T clk_get_pclk +0x0000a5ed T clk_init +0x0000a681 T clk_set_pclk_div +0x0000a6a1 T clk_spif_ref_clk +0x0000a6f9 T config_RTC +0x0000a711 T config_RTC0 +0x0000a755 T rom_crc16 +0x0000a791 T debug_print +0x0000a921 T disableSleep +0x0000a975 T drv_disable_irq +0x0000a99d T drv_enable_irq +0x0000a9c9 T drv_irq_init +0x0000a9fd T dwc_connect +0x0000aa35 T dwc_data_process +0x0000abd1 T dwc_loop +0x0000ace1 T efuse_read +0x0000aead T enableSleep +0x0000aeb9 T enterSleepProcess +0x0000aed1 T enterSleepProcess0 +0x0000afa1 T enter_sleep_off_mode +0x0000afb9 T enter_sleep_off_mode0 +0x0000afe9 T getMcuPrecisionCount +0x0000aff5 T getPN23RandNumber +0x0000b01d T getRxBufferFree +0x0000b031 T getRxBufferSize +0x0000b051 T getSleepMode +0x0000b05d T getTxBufferFree +0x0000b071 T getTxBufferSize +0x0000b0b1 T get_rx_read_ptr +0x0000b0b9 T get_rx_write_ptr +0x0000b0c1 T get_sleep_flag +0x0000b0cd T get_timer_count +0x0000b0d1 T get_timer_int +0x0000b0d9 T get_tx_read_ptr +0x0000b0e1 T get_tx_write_ptr +0x0000b0e9 T gpio_cfg_analog_io +0x0000b119 T gpio_dir +0x0000b15d T gpio_fmux_control +0x0000b179 T gpio_fmux_set +0x0000b1b1 T gpio_in_trigger +0x0000b219 T gpio_init +0x0000b22d T gpio_interrupt_set +0x0000b249 T gpio_pull_set +0x0000b291 T gpio_read +0x0000b2b5 T gpio_wakeup_set +0x0000b319 T gpio_write +0x0000b52d T hciInitEventMasks +0x0000b555 T isSleepAllow +0x0000b561 T isTimer1Running +0x0000b571 T isTimer4Running +0x0000b581 T jump_area_init +0x0000b5a9 T ll24BitTimeCompare +0x0000b609 T llAdjSlaveLatencyValue +0x0000b629 T llAllocConnId +0x0000b679 T llAllocateSyncHandle +0x0000b6a9 T llAtLeastTwoChans +0x0000b6ed T llCalcMaxScanTime +0x0000b745 T llCalcScaFactor +0x0000b76d T llCalcTimerDrift +0x0000b7b1 T llCheckForLstoDuringSL +0x0000b7ed T llCheckWhiteListUsage +0x0000b809 T llConnCleanup +0x0000b839 T llConnTerminate +0x0000b851 T llConnTerminate0 +0x0000b87d T llConvertCtrlProcTimeoutToEvent +0x0000b899 T llConvertLstoToEvent +0x0000b8bd T llDeleteSyncHandle +0x0000b8ed T llDequeueCtrlPkt +0x0000b929 T llDequeueDataQ +0x0000b953 T llEnqueueCtrlPkt +0x0000b98b T llEnqueueDataQ +0x0000b9b1 T llEqAlreadyValidAddr +0x0000b9b5 T llEqSynchWord +0x0000b9c9 T llEqualBytes +0x0000b9e9 T llEventDelta +0x0000b9fd T llEventInRange +0x0000ba1b T llGenerateCRC +0x0000ba3d T llGenerateValidAccessAddr +0x0000ba6d T llGetNextAdvChn +0x0000bac1 T llGetNextAuxAdvChn +0x0000bae5 T llGetNextDataChan +0x0000bb23 T llGetNextDataChanCSA2 +0x0000bb81 T llGtSixConsecZerosOrOnes +0x0000bbb3 T llGtTwentyFourTransitions +0x0000bbe5 T llInitFeatureSet +0x0000bc1d T llInitFeatureSet2MPHY +0x0000bc45 T llInitFeatureSetCodedPHY +0x0000bc6d T llInitFeatureSetDLE +0x0000bc89 T llLtTwoChangesInLastSixBits +0x0000bcb9 T llMasterEvt_TaskEndOk +0x0000be05 T llMemCopyDst +0x0000be1b T llMemCopySrc +0x0000be35 T llOneBitSynchWordDiffer +0x0000be4d T llPduLengthManagmentReset +0x0000bf01 T llPduLengthUpdate +0x0000c00d T llPendingUpdateParam +0x0000c051 T llPhyModeCtrlReset +0x0000c0b9 T llPhyModeCtrlUpdateNotify +0x0000c185 T llProcessChanMap +0x0000c1d1 T llProcessMasterControlPacket +0x0000c5b9 T llProcessMasterControlProcedures +0x0000ca85 T llProcessRxData +0x0000cc31 T llProcessSlaveControlPacket +0x0000d169 T llProcessSlaveControlProcedures +0x0000d4d1 T llProcessTxData +0x0000d4e9 T llProcessTxData0 +0x0000d55d T llReleaseAllConnId +0x0000d561 T llReleaseConnId +0x0000d5f5 T llReplaceCtrlPkt +0x0000d60d T llResetConnId +0x0000d6ed T llResetRfCounters +0x0000d701 T llSecAdvAllow +0x0000d769 T llSetNextDataChan +0x0000d839 T llSetNextPhyMode +0x0000d8a9 T llSetupAdv +0x0000d949 T llSetupAdvExtIndPDU +0x0000db4d T llSetupAuxAdvIndPDU +0x0000dda1 T llSetupAuxChainIndPDU +0x0000df91 T llSetupAuxConnectReqPDU +0x0000e025 T llSetupAuxConnectRspPDU +0x0000e09d T llSetupAuxScanRspPDU +0x0000e109 T llSetupAuxSyncIndPDU +0x0000e2c1 T llSetupCTEReq +0x0000e38d T llSetupCTERsp +0x0000e457 T llSetupConn +0x0000e459 T llSetupDataLenghtReq +0x0000e4d5 T llSetupDataLenghtRsp +0x0000e551 T llSetupDirectedAdvEvt +0x0000e6a1 T llSetupEncReq +0x0000e725 T llSetupEncRsp +0x0000e7b1 T llSetupExtAdvEvent +0x0000eb09 T llSetupExtInit +0x0000eb81 T llSetupExtScan +0x0000ec01 T llSetupFeatureSetReq +0x0000ec63 T llSetupFeatureSetRsp +0x0000ecc1 T llSetupInit +0x0000ed39 T llSetupNextMasterEvent +0x0000ede1 T llSetupNextSlaveEvent +0x0000edf9 T llSetupNextSlaveEvent0 +0x0000ef65 T llSetupNonConnectableAdvEvt +0x0000f075 T llSetupPauseEncReq +0x0000f0c5 T llSetupPauseEncRsp +0x0000f121 T llSetupPhyReq +0x0000f177 T llSetupPhyRsp +0x0000f1cd T llSetupPhyUpdateInd +0x0000f239 T llSetupPrdAdvEvent +0x0000f3b9 T llSetupPrdScan +0x0000f44d T llSetupRejectExtInd +0x0000f479 T llSetupRejectInd +0x0000f4a5 T llSetupScan +0x0000f54d T llSetupScanInit +0x0000f55d T llSetupScannableAdvEvt +0x0000f66d T llSetupSecAdvEvt +0x0000f6e9 T llSetupSecConnectableAdvEvt +0x0000f7c1 T llSetupSecInit +0x0000f875 T llSetupSecNonConnectableAdvEvt +0x0000f94d T llSetupSecScan +0x0000fa19 T llSetupSecScannableAdvEvt +0x0000faf1 T llSetupStartEncReq +;0x0000fb15 T llSetupStartEncRsp +0x0000fb59 T llSetupSyncInfo +0x0000fc2d T llSetupTermInd +0x0000fc91 T llSetupUndirectedAdvEvt +0x0000fda5 T llSetupUnknownRsp +0x0000fdf9 T llSetupUpdateChanReq +0x0000fe6d T llSetupUpdateParamReq +0x0000ff05 T llSetupVersionIndReq +0x0000ff79 T llSlaveEvt_TaskAbort +0x0000ff95 T llSlaveEvt_TaskEndOk +0x00010181 T llTrxNumAdaptiveConfig +0x0001019b T llValidAccessAddr +0x000101e1 T llWaitUs +0x00010209 T llWriteTxData +0x0001028f T ll_CalcRandomAddr +0x000102cd T ll_ResolveRandomAddrs +0x00010315 T ll_addTask +0x00010445 T ll_add_adv_task +0x00010461 T ll_add_adv_task_periodic +0x0001047d T ll_adptive_adj_next_time +0x000104fd T ll_adptive_smart_window +0x000105ad T ll_adv_scheduler +0x000105c9 T ll_adv_scheduler_periodic +0x000105e5 T ll_allocAuxAdvTimeSlot +0x00010679 T ll_allocAuxAdvTimeSlot_prd +0x00010719 T ll_debug_output +0x00010731 T ll_deleteTask +0x00010765 T ll_delete_adv_task +0x00010781 T ll_delete_adv_task_periodic +0x0001079d T ll_ext_adv_schedule_next_event +0x000107c1 T ll_ext_init_schedule_next_event +0x000107dd T ll_ext_scan_schedule_next_event +0x000107f9 T ll_generateExtAdvDid +0x00010801 T ll_generateTxBuffer +0x000109c1 T ll_getFirstAdvChn +0x000109cd T ll_getRPAListEntry +0x00010a39 T ll_get_next_active_conn +0x00010aa1 T ll_get_next_timer +0x00010add T ll_hw_clr_irq +0x00010aed T ll_hw_config +0x00010b6d T ll_hw_get_anchor +0x00010b79 T ll_hw_get_fsm_status +0x00010b89 T ll_hw_get_iq_RawSample +0x00010bbd T ll_hw_get_irq_status +0x00010bcd T ll_hw_get_last_ack +0x00010be9 T ll_hw_get_loop_cycle +0x00010bf5 T ll_hw_get_loop_time +0x00010c01 T ll_hw_get_nAck +0x00010c11 T ll_hw_get_rfifo_depth +0x00010c25 T ll_hw_get_rfifo_info +0x00010c45 T ll_hw_get_rxPkt_CrcErr_num +0x00010c55 T ll_hw_get_rxPkt_CrcOk_num +0x00010c69 T ll_hw_get_rxPkt_Total_num +0x00010c79 T ll_hw_get_rxPkt_num +0x00010c85 T ll_hw_get_rxPkt_stats +0x00010c9d T ll_hw_get_snNesn +0x00010cad T ll_hw_get_tfifo_info +0x00010ccd T ll_hw_get_tfifo_wrptr +0x00010cdd T ll_hw_get_tr_mode +0x00010ced T ll_hw_get_txAck +0x00010cf9 T ll_hw_go +0x00010df9 T ll_hw_ign_rfifo +0x00010e05 T ll_hw_process_RTO +0x00010e6d T ll_hw_read_rfifo +0x00010ee9 T ll_hw_read_rfifo_pplus +0x00010f51 T ll_hw_read_rfifo_zb +0x00010fad T ll_hw_read_tfifo_packet +0x00010ff5 T ll_hw_read_tfifo_rtlp +0x000110b1 T ll_hw_rst_rfifo +0x000110e9 T ll_hw_rst_tfifo +0x000110f5 T ll_hw_set_ant_pattern +0x00011101 T ll_hw_set_ant_switch_mode +0x00011115 T ll_hw_set_ant_switch_timing +0x0001112d T ll_hw_set_crc_fmt +0x0001113d T ll_hw_set_cte_rxSupp +0x00011155 T ll_hw_set_cte_txSupp +0x00011169 T ll_hw_set_empty_head +0x00011175 T ll_hw_set_irq +0x00011181 T ll_hw_set_loop_nack_num +0x0001118d T ll_hw_set_loop_timeout +0x000111a1 T ll_hw_set_pplus_pktfmt +0x000111cd T ll_hw_set_rtlp +0x0001121d T ll_hw_set_rtlp_1st +0x00011265 T ll_hw_set_rtx +0x00011279 T ll_hw_set_rx_timeout +0x00011285 T ll_hw_set_rx_timeout_1st +0x00011291 T ll_hw_set_rx_tx_interval +0x000112a5 T ll_hw_set_srx +0x000112b9 T ll_hw_set_stx +0x000112cd T ll_hw_set_tfifo_space +0x000112e5 T ll_hw_set_timing +0x00011381 T ll_hw_set_trlp +0x000113c9 T ll_hw_set_trx +0x000113dd T ll_hw_set_trx_settle +0x000113f1 T ll_hw_set_tx_rx_interval +0x00011405 T ll_hw_set_tx_rx_release +0x00011421 T ll_hw_trigger +0x00011445 T ll_hw_trx_settle_config +0x00011489 T ll_hw_tx2rx_timing_config +0x000114dd T ll_hw_update +0x00011539 T ll_hw_update_rtlp_mode +0x00011579 T ll_hw_update_trlp_mode +0x000115c1 T ll_hw_write_tfifo +0x00011649 T ll_isAddrInWhiteList +0x000116a9 T ll_isFirstAdvChn +0x000116c7 T ll_isIrkAllZero +0x000116dd T ll_isLegacyAdv +0x000116ed T ll_parseExtHeader +0x000117a9 T ll_prd_adv_schedule_next_event +0x000117cd T ll_prd_scan_schedule_next_event +0x000117e9 T ll_processBasicIRQ +0x00013401 T ll_processExtAdvIRQ +0x00013405 T ll_processExtInitIRQ +0x00013409 T ll_processExtScanIRQ +0x0001340d T ll_processMissMasterEvt +0x000134ed T ll_processMissSlaveEvt +0x000135f5 T ll_processPrdAdvIRQ +0x000135f9 T ll_processPrdScanIRQ +0x000135fd T ll_readLocalIRK +0x000136c5 T ll_read_rxfifo +0x00013761 T ll_schedule_next_event +0x00013771 T ll_scheduler +0x00013789 T ll_scheduler0 +0x00013a11 T ll_updateAuxAdvTimeSlot +0x00013a39 T ll_updateExtAdvRemainderTime +0x00013ab9 T log_clr_putc +0x00013ac5 T log_debug_level +0x00013ad9 T log_get_debug_level +0x00013ae5 T log_printf +0x00013b05 T log_set_putc +0x00013b11 T log_vsprintf +0x00013f09 T move_to_master_function +0x0001406d T move_to_slave_function +0x00014439 T osalAddTimer +0x000144a9 T osalDeleteTimer +0x000144b5 T osalFindTimer +0x000144d5 T osalTimeUpdate +0x00014541 T osalTimeUpdate1 +0x0001457d T osalTimerInit +0x00014589 T osalTimerUpdate +0x00014621 T osal_CbTimerInit +0x00014641 T osal_CbTimerProcessEvent +0x000146a9 T osal_CbTimerStart +0x00014711 T osal_CbTimerStop +0x00014751 T osal_CbTimerUpdate +0x000147a1 T osal_ConvertUTCSecs +0x00014841 T osal_ConvertUTCTime +0x00014949 T osal_GetSystemClock +0x00014955 T osal_bm_adjust_header +0x0001497d T osal_bm_adjust_tail +0x000149a9 T osal_bm_alloc +0x000149d9 T osal_bm_free +0x00014a21 T osal_buffer_uint24 +0x00014a2f T osal_buffer_uint32 +0x00014a41 T osal_build_uint16 +0x00014a4d T osal_build_uint32 +0x00014a89 T osal_clear_event +0x00014abd T osal_getClock +0x00014ac9 T osal_get_timeoutEx +0x00014aed T osal_init_system +0x00014b1d T osal_isbufset +0x00014b3d T osal_mem_alloc +0x00014c01 T osal_mem_free +0x00014c25 T osal_mem_init +0x00014c8d T osal_mem_kick +0x00014cb5 T osal_mem_set_heap +0x00014ccd T osal_memcmp +0x00014ce9 T osal_memcpy +0x00014cf9 T osal_memdup +0x00014d15 T osal_memset +0x00014d1d T osal_msg_allocate +0x00014d43 T osal_msg_deallocate +0x00014d65 T osal_msg_dequeue +0x00014d91 T osal_msg_enqueue +0x00014dc3 T osal_msg_enqueue_max +0x00014e6d T osal_msg_extract +0x00014e9d T osal_msg_find +0x00014ed1 T osal_msg_push +0x00014eeb T osal_msg_push_front +0x00014ef5 T osal_msg_receive +0x00014f59 T osal_msg_send +0x00014f7d T osal_next_timeout +0x00014fa5 T osal_pwrmgr_device +0x00014fb1 T osal_pwrmgr_init +0x00014fc1 T osal_pwrmgr_powerconserve +0x00014fd9 T osal_pwrmgr_powerconserve0 +0x000150f9 T osal_pwrmgr_task_state +0x00015129 T osal_rand +0x00015145 T osal_revmemcpy +0x00015159 T osal_run_system +0x000151f5 T osal_self +0x00015201 T osal_setClock +0x0001520d T osal_set_event +0x00015259 T osal_start_reload_timer +0x00015285 T osal_start_system +0x0001528b T osal_start_timerEx +0x000152b3 T osal_stop_timerEx +0x000152dd T osal_strlen +0x000152e5 T osal_timer_num_active +0x00015315 T phy_sec_app_key +0x0001531d T phy_sec_decrypt +0x0001532d T phy_sec_efuse_lock +0x00015339 T phy_sec_encrypt +0x00015349 T phy_sec_init +0x0001540d T phy_sec_key_valid +0x00015b19 T prog_process_data +0x00015c51 T prog_uart_command +0x00015c71 T prog_uart_fct_command +0x00015c8d T prog_uart_handle +0x00015cbd T read_LL_remainder_time +0x00015cc9 T read_current_fine_time +0x00015cf1 T read_ll_adv_remainder_time +0x00015cfd T reset_conn_buf +;0x00015d75 T rf_calibrate +;0x00015ded T rf_init +;0x00015dfd T rf_phy_ana_cfg +;0x00015f0d T rf_phy_bb_cfg +;0x00016085 T rf_phy_change_cfg +;0x00016129 T rf_phy_direct_test_ate +;0x00016669 T rf_phy_get_pktFoot +;0x000166c1 T rf_phy_ini +;0x000166dd T rf_phy_set_txPower +;0x00016701 T rf_rxDcoc_cfg +;0x00016811 T rf_tpCal_cfg +;0x0001683d T rf_tpCal_cfg_avg +;0x000168ed T rf_tpCal_gen_cap_arrary +;0x00016929 T rf_tp_cal +0x00016a09 T rom_board_init +0x00016ab5 T rtc_clear +0x00016ad1 T rtc_config_prescale +0x00016b15 T rtc_get_counter +0x00016b25 T rtc_start +0x00016b35 T rtc_stop +0x00016b45 T setSleepMode +0x00016b51 T set_access_address +0x00016b5d T set_channel +0x00016b9d T set_crc_seed +0x00016bb5 T set_gpio_pull_down_ate +0x00016bcb T set_gpio_pull_up_ate +0x00016be1 T set_int +0x00016bed T set_max_length +0x00016c01 T set_sleep_flag +0x00016c2d T set_timer +0x00016cc9 T set_whiten_seed +0x00016d49 T spif_cmd +0x00016dc5 T spif_config +0x00016ea1 T spif_erase_all +0x00016ed1 T spif_erase_block64 +0x00016f55 T spif_erase_chip +0x00016fa9 T spif_erase_sector +0x00017029 T spif_flash_size +0x0001703d T spif_flash_status_reg_0 +0x00017047 T spif_flash_status_reg_1 +0x00017051 T spif_init +0x0001713d T spif_rddata +0x00017165 T spif_read +;0x0001717d T spif_read_dma +0x000172cd T spif_release_deep_sleep +0x00017349 T spif_set_deep_sleep +0x0001736d T spif_wrdata +0x00017395 T spif_write +0x0001744d T spif_write_dma +0x000174f9 T spif_write_protect +0x00017591 T sram_ret_patch +0x00017609 T update_rx_read_ptr +0x00017635 T update_rx_write_ptr +0x00017659 T update_tx_read_ptr +0x00017685 T update_tx_write_ptr +0x000176a9 T wakeupProcess +0x000176c5 T wakeupProcess0 +0x000178a5 T wakeup_init +0x000178bd T wakeup_init0 +0x0001798d T zigbee_crc16_gen +0x00017c00 D supportedCmdsTable +0x00017c44 D hciCmdTable +0x00017c4c D SCA +0x1fff0818 D hclk_per_us +0x1fff081c D hclk_per_us_shift +0x1fff0828 D s_prog_time_save +0x1fff082c D s_prog_timeout +0x1fff0830 D DFL_ENTRY_BASE +0x1fff0850 D receive_timeout_flag +0x1fff0860 D osal_sys_tick +0x1fff0864 D g_timer4_irq_pending_time +0x1fff0874 D g_hclk +0x1fff0878 D m_in_critical_region +0x1fff0888 D s_rom_debug_level +0x1fff0894 D s_spif_ctx +0x1fff08b8 D osal_qHead +0x1fff08c0 D baseTaskID +0x1fff08cc D OSAL_timeSeconds +0x1fff08e4 D ll_remain_time +0x1fff08e8 D pwrmgr_attribute +0x1fff08f0 D timerHead +0x1fff08f8 D hciPTMenabled +0x1fff08f9 D ctrlToHostEnable +0x1fff08fa D numHostBufs +0x1fff08fc D hciCtrlCmdToken +0x1fff0900 D bleEvtMask +0x1fff0904 D pHciEvtMask +0x1fff090c D hciTaskID +0x1fff090d D hciTestTaskID +0x1fff090e D hciGapTaskID +0x1fff090f D hciL2capTaskID +0x1fff0910 D hciSmpTaskID +0x1fff0911 D hciExtTaskID +0x1fff0914 D g_maxConnNum +0x1fff0915 D g_maxPktPerEventTx +0x1fff0916 D g_maxPktPerEventRx +0x1fff0917 D g_blePktVersion +0x1fff0918 D g_llRlEnable +0x1fff0919 D g_llScanMode +0x1fff091a D g_llAdvMode +0x1fff091b D LL_TaskID +0x1fff091c D llState +0x1fff091d D numComplPkts +0x1fff091e D numComplPktsLimit +0x1fff091f D fastTxRespTime +0x1fff0920 D g_llWlDeviceNum +0x1fff0921 D g_llRlDeviceNum +0x1fff0922 D rxFifoFlowCtrl +0x1fff0923 D llSecondaryState +0x1fff0924 D g_extAdvNumber +0x1fff0925 D g_perioAdvNumber +0x1fff0926 D g_schExtAdvNum +0x1fff0927 D g_currentExtAdv +0x1fff0928 D g_schExtAdvNum_periodic +0x1fff0929 D g_currentExtAdv_periodic +0x1fff092c D g_llRlTimeout +0x1fff0930 D g_advSetMaximumLen +0x1fff0934 D conn_param +0x1fff0938 D g_pExtendedAdvInfo +0x1fff093c D g_pPeriodicAdvInfo +0x1fff0940 D g_pLLcteISample +0x1fff0944 D g_pLLcteQSample +0x1fff0948 D g_llHdcDirAdvTime +0x1fff094c D g_pAdvSchInfo +0x1fff0950 D g_advPerSlotTick +0x1fff0954 D g_advSlotPeriodic +0x1fff0958 D g_pAdvSchInfo_periodic +0x1fff095c D g_timerExpiryTick +0x1fff0960 D chanMapUpdate +0x1fff0965 D ownPublicAddr +0x1fff096b D ownRandomAddr +0x1fff0972 D verInfo +0x1fff0978 D peerInfo +0x1fff0980 D g_currentAdvTimer +0x1fff0984 D g_currentTimerTask +0x1fff0988 D g_adv_taskID +0x1fff0989 D g_conn_taskID +0x1fff098a D g_smartWindowRTOCnt +0x1fff098b D isPeerRpaStore +0x1fff098c D g_same_rf_channel_flag +0x1fff098d D g_currentPeerAddrType +0x1fff098e D g_currentLocalAddrType +0x1fff098f D storeRpaListIndex +0x1fff0990 D llTaskState +0x1fff0992 D g_adv_taskEvent +0x1fff0994 D g_conn_taskEvent +0x1fff0998 D llWaitingIrq +0x1fff099c D ISR_entry_time +0x1fff09a0 D slave_conn_event_recv_delay +0x1fff09a4 D g_smartWindowLater +0x1fff09a8 D g_smartWindowActiveCnt +0x1fff09ac D g_smartWindowPreAnchPoint +0x1fff09b0 D g_getPn23_cnt +0x1fff09b4 D g_getPn23_seed +0x1fff09b8 D llScanTime +0x1fff09bc D p_perStatsByChan +0x1fff09c0 D LL_PLUS_AdvDataFilterCBack +0x1fff09c4 D LL_PLUS_ScanRequestFilterCBack +0x1fff09c8 D g_new_master_delta +0x1fff09cc D llScanT1 +0x1fff09d0 D llCurrentScanChn +0x1fff09d4 D g_currentLocalRpa +0x1fff09da D g_currentPeerRpa +0x1fff09e0 D currentPeerRpa +0x1fff09e6 D g_dle_taskID +0x1fff09e8 D g_dle_taskEvent +0x1fff09ea D g_phyChg_taskID +0x1fff09ec D g_phyChg_taskEvent +0x1fff09f0 D g_smartWindowSize +0x1fff09f4 D g_smartWindowSizeNew +0x1fff09f8 D g_smartWindowActive +0x1fff09fc D g_interAuxPduDuration +0x1fff0a04 D connUpdateTimer +0x1fff0a0c D sleep_flag +0x1fff0a10 D g_wakeup_rtc_tick +0x1fff0a14 D g_counter_traking_avg +0x1fff0a18 D g_TIM2_IRQ_TIM3_CurrCount +0x1fff0a1c D g_TIM2_IRQ_to_Sleep_DeltTick +0x1fff0a20 D g_TIM2_IRQ_PendingTick +0x1fff0a24 D g_osal_tick_trim +0x1fff0a28 D g_osalTickTrim_mod +0x1fff0a2c D rtc_mod_value +0x1fff0a30 D g_counter_traking_cnt +0x1fff0a34 D sleep_tick +0x1fff0a38 D counter_tracking +0x1fff0a3c D forever_write +0x1fff0a40 D g_TIM2_wakeup_delay +0x1fff0a44 D g_rfPhyTpCal0 +0x1fff0a45 D g_rfPhyTpCal1 +0x1fff0a46 D g_rfPhyTpCal0_2Mbps +0x1fff0a47 D g_rfPhyTpCal1_2Mbps +0x1fff0a48 D g_rfPhyTxPower +0x1fff0a49 D g_rfPhyPktFmt +0x1fff0a4a D g_system_clk +0x1fff0a4b D g_rfPhyClkSel +0x1fff0a4c D g_rxAdcClkSel +0x1fff0a4d D g_dtmModeType +0x1fff0a4e D g_dtmLength +0x1fff0a4f D g_dtmExtLen +0x1fff0a50 D g_dtmPKT +0x1fff0a51 D g_dtmTxPower +0x1fff0a52 D g_dtmRssi +0x1fff0a53 D g_dtmCarrSens +0x1fff0a54 D g_dtmPktIntv +0x1fff0a56 D g_dtmPktCount +0x1fff0a58 D g_dtmRxCrcNum +0x1fff0a5a D g_dtmRxTONum +0x1fff0a5c D g_dtmRsp +0x1fff0a5e D g_dtmFoff +0x1fff0a60 D g_rfPhyRxDcIQ +0x1fff0a64 D g_dtmTick +0x1fff0a68 D g_rfPhyFreqOffSet +0x1fff0a69 D g_rfPhyDtmCmd +0x1fff0a6b D g_rfPhyDtmEvt +0x1fff0a6d D g_dtmCmd +0x1fff0a6e D g_dtmFreq +0x1fff0a6f D g_dtmCtrl +0x1fff0a70 D g_dtmPara +0x1fff0a71 D g_dtmEvt +0x1fff0a72 D g_dtmStatus +0x1fff0a73 D g_dtmTpCalEnable +0x1fff0a74 D g_dtmPerAutoIntv +0x1fff0a78 D g_dtmAccessCode +0x1fff0a80 D g_system_reset_cause +0x1fff0afc D cbTimers +0x1fff0b74 D g_llSleepContext +0x1fff0b84 D syncInfo +0x1fff0b96 D scanSyncInfo +0x1fff0ba6 D adv_param +0x1fff0bbc D scanInfo +0x1fff0bd4 D initInfo +0x1fff0be8 D extScanInfo +0x1fff0c10 D extInitInfo +0x1fff0c50 D g_llPeriodAdvSyncInfo +0x1fff0d30 D g_ll_conn_ctx +0x1fff0e48 D deviceFeatureSet +0x1fff0e51 D g_llWhitelist +0x1fff0e89 D g_llResolvinglist +0x1fff0ffc D g_pmCounters +0x1fff1084 D g_llPduLen +0x1fff10e0 D rfCounters +0x1fff10ec D ext_adv_hdr +0x1fff1118 D dataPkt +0x1fff1138 D cachedTRNGdata +0x1fff1144 D whiten_seed +0x1fff116c D g_tx_adv_buf +0x1fff1278 D g_tx_ext_adv_buf +0x1fff1384 D tx_scanRsp_desc +0x1fff1490 D g_rx_adv_buf diff --git a/src/misc/generate_gccsymfile.py b/src/misc/generate_gccsymfile.py new file mode 100644 index 0000000..0a49327 --- /dev/null +++ b/src/misc/generate_gccsymfile.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 +with open('bb_rom_sym_m0.txt') as symfile: + for line in symfile: + if line[0] == '#': continue + sym = line.split() + if line[0] == ';': sym = line[1:].split() + print(f'{sym[2]} = {sym[0]};') diff --git a/src/misc/jump_function.h b/src/misc/jump_function.h new file mode 100644 index 0000000..bdf219d --- /dev/null +++ b/src/misc/jump_function.h @@ -0,0 +1,594 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + +/** + **************************************************************************************** + + @file jump_fucntion.h + + @brief This file contains the definitions of the macros and functions that are + architecture dependent. The implementation of those is implemented in the + appropriate architecture directory. + + + $Rev: $ + + **************************************************************************************** +*/ + + +#ifndef _JUMP_FUNC_H_ +#define _JUMP_FUNC_H_ +#include +#include "types.h" +#include "ll_def.h" +#include "ll_sleep.h" + +#include "hci.h" +#include "l2cap.h" + +// ===================== MACROS ======================= +#define JUMP_BASE_ADDR 0x1fff0000 +#define JUMP_FUNCTION(x) (*(uint32 *)(JUMP_BASE_ADDR + (x << 2))) + +// ROM function entries + + +// 0 - 10 for common +#define OSAL_INIT_TASKS 1 +#define TASKS_ARRAY 2 +#define TASK_COUNT 3 +#define TASK_EVENTS 4 +#define OSAL_MEM_INIT 5 + +#define LL_INIT 11 +#define LL_PROCESS_EVENT 12 +#define LL_RESET 13 +#define LL_TXDATA 14 +#define LL_DISCONNECT 15 +#define LL_SET_ADV_PARAM 16 +#define LL_SET_ADV_DATA 17 +#define LL_SET_ADV_CONTROL 18 +#define LL_SET_DEFAULT_CONN_PARAM 19 + +#define LL_EXT_SET_TX_POWER 20 + +#define LL_CLEAR_WHITE_LIST 21 +#define LL_ADD_WHITE_LIST_DEV 22 +#define LL_REMOVE_WHITE_LIST_DEV 23 +#define LL_READ_WHITE_LIST_SIZE 24 +#define LL_NUM_EMPTY_WL_ENTRIES 25 + +#define LL_SLAVE_EVT_ENDOK 26 +#define LL_SETUP_NEXT_SLAVE_EVT 27 +#define LL_CHK_LSTO_DURING_SL 28 +#define LL_PROCESS_SLAVE_CTRL_PROC 29 + +#define LL_PROCESS_SLAVE_CTRL_PKT 30 +#define LL_SLAVE_EVT_ABORT 31 +#define LL_PROCESS_RX_DATA 32 +#define LL_PROCESS_TX_DATA 33 +#define LL_CONN_TERMINATE 34 +#define LL_WRITE_TX_DATA 35 + +#define LL_EVT_SCHEDULE 36 +#define LL_MOVE_TO_SLAVE_FUNCTION 37 +#define LL_SLAVE_CONN_EVENT 38 + +#define LL_SETUP_ADV 39 + +#define LL_SETUP_UNDIRECT_ADV 40 +#define LL_SETUP_NOCONN_ADV 41 + +#define LL_SETUP_SCAN_ADV 42 +#define LL_SETUP_DIRECT_ADV 43 + +#define LL_CALC_TIMER_DRIFT 44 +#define LL_GENERATE_TX_BUFFER 45 +#define LL_READ_RX_FIFO 46 +#define LL_READ_TX_FIFO_RTLP 47 +#define LL_READ_TX_FIFO_PKT 48 + +#define LL_HW_PROCESS_RTO 49 + +#define LL_HW_SET_TIMING 50 +#define LL_RELEASE_CONN_ID 51 + +#define LL_READ_TX_PWR_LVL 52 // A1 ROM metal change add +#define LL_READ_ADV_TX_PWR_LVL 53 // A1 ROM metal change add +#define LL_READ_RSSI 54 // A1 ROM metal change add +#define LL_READ_REMOTE_USE_FEATURES 55 // A1 ROM metal change add +#define LL_ENCRYPT 56 // A1 ROM metal change add + +#define LL_DIRECT_TEST_END 57 // A1 ROM metal change add +#define LL_DIRECT_TEST_TX_TEST 58 // A1 ROM metal change add +#define LL_DIRECT_TEST_RX_TEST 59 // A1 ROM metal change add + +#define OSAL_POWER_CONSERVE 60 +#define ENTER_SLEEP_PROCESS 61 +#define WAKEUP_PROCESS 62 +#define CONFIG_RTC 63 +#define ENTER_SLEEP_OFF_MODE 64 // A1 ROM metal change add + +#define HAL_PROCESS_POLL 65 // A1 ROM metal change add +#define LL_HW_GO 66 // A1 ROM metal change add +#define LL_HW_TRIGGER 67 // A1 ROM metal change add +#define LL_SET_TX_PWR_LVL 68 // A1 ROM metal change add + +// LL AES +#define LL_AES128_ENCRYPT 70 // A1 ROM metal change add +#define LL_GEN_TRUE_RANDOM 71 // A1 ROM metal change add +#define LL_GEN_DEVICE_SKD 72 // A1 ROM metal change add +#define LL_GEN_DEVICE_IV 73 // A1 ROM metal change add +#define LL_GENERATE_NOUNCE 74 // A1 ROM metal change add +#define LL_ENC_ENCRYPT 75 // A1 ROM metal change add +#define LL_ENC_DECRYPT 76 // A1 ROM metal change add + +// host entries +#define SMP_INIT 80 +#define SMP_PROCESS_EVENT 81 + +// l2cap entries +#define L2CAP_PARSE_PACKET 82 +#define L2CAP_ENCAP_PACKET 83 +#define L2CAP_PKT_TO_SEGBUFF 84 +#define L2CAP_SEGBUFF_TO_LINKLAYER 85 +#define L2CAP_PROCESS_FREGMENT_TX_DATA 86 + +//gap linkmgr entries +#define GAP_LINK_MGR_PROCESS_CONNECT_EVT 87 +#define GAP_LINK_MGR_PROCESS_DISCONNECT_EVT 88 + +// hci tl +#define HCI_INIT 90 // A1 ROM metal change add +#define HCI_PROCESS_EVENT 91 // A1 ROM metal change add + + + +// app entries +#define APP_SLEEP_PROCESS 100 +#define APP_WAKEUP_PROCESS 101 +#define RF_INIT 102 +#define WAKEUP_INIT 103 +#define BOOT_INIT 104 +#define DEBUG_PRINT 105 +#define RF_CALIBRATTE 106 // A1 ROM metal change add +#define RF_PHY_CHANGE 107 // A1 ROM metal change add + +// LL master, A2 ROM metal change add +#define LL_MASTER_EVT_ENDOK 110 +#define LL_SETUP_NEXT_MASTER_EVT 111 +#define LL_PROCESS_MASTER_CTRL_PROC 112 +#define LL_PROCESS_MASTER_CTRL_PKT 113 +#define LL_MOVE_TO_MASTER_FUNCTION 114 +#define LL_MASTER_CONN_EVENT 115 + +#define LL_SET_SCAN_CTRL 116 +#define LL_SET_SCAN_PARAM 117 + +#define LL_CREATE_CONN 118 +#define LL_CREATE_CONN_CANCEL 119 + +#define LL_START_ENCRYPT 120 + +#define LL_SETUP_SCAN 121 + +#define LL_SETUP_SEC_NOCONN_ADV 122 +#define LL_SETUP_SEC_SCAN 123 +#define LL_SEC_ADV_ALLOW 124 +#define LL_CALC_MAX_SCAN_TIME 125 + +// A2 multi-connection +#define LL_SETUP_SEC_ADV_ENTRY 126 +#define LL_SETUP_SEC_CONN_ADV 127 +#define LL_SETUP_SEC_SCANNABLE_ADV 128 + + + + +//DLE +#define LL_SET_DATA_LENGTH 130 +#define LL_PDU_LENGTH_UPDATE 131 +#define LL_TRX_NUM_ADJUST 132 +//PHY UPDATE +#define LL_SET_PHY_MODE 133 +#define LL_PHY_MODE_UPDATE 134 +#define LL_SET_NEXT_PHY_MODE 135 + +#define LL_ADP_ADJ_NEXT_TIME 136 +#define LL_ADP_SMART_WINDOW 137 +#define LL_SET_NEXT_DATA_CHN 138 +#define LL_PLUS_DISABLE_LATENCY 139 +#define LL_PLUS_ENABLE_LATENCY 140 + +#define LL_SETUP_EXT_ADV_EVENT 141 +#define LL_SETUP_PRD_ADV_EVENT 142 +#define LL_SETUP_ADV_EXT_IND_PDU 143 +#define LL_SETUP_AUX_ADV_IND_PDU 144 +#define LL_SETUP_AUX_SYNC_IND_PDU 145 +#define LL_SETUP_AUX_CHAIN_IND_PDU 146 +#define LL_SETUP_AUX_CONN_REQ_PDU 147 +#define LL_SETUP_AUX_CONN_RSP_PDU 148 + +#define LL_SCHEDULER 149 +#define LL_ADD_TASK 150 +#define LL_DEL_TASK 151 + +#define LL_ADV_SCHEDULER 152 +#define LL_ADV_ADD_TASK 153 +#define LL_ADV_DEL_TASK 154 + +#define LL_ADV_SCHEDULER_PRD 155 +#define LL_ADV_ADD_TASK_PRD 156 +#define LL_ADV_DEL_TASK_PRD 157 + +#define LL_GET_NEXT_AUX_CHN 158 +#define LL_SETUP_AUX_SCAN_RSP_PDU 159 + +#define LL_PROCESSBASICIRQ_SRX 160 +#define LL_PROCESSBASICIRQ_SECADVTRX 161 +#define LL_PROCESSBASICIRQ_SCANTRX 162 +#define LL_PROCESSBASICIRQ_SECSCANSRX 163 +#define LL_PROCESSBASICIRQ_SECINITSRX 164 + +// 2020-02-13 Add for CTE +#define LL_CONNLESS_CTE_TX_PARAM 203 +#define LL_CONNLESS_CTE_TX_ENABLE 204 +#define LL_CONNLESS_IQ_SAMPLE_ENABLE 205 +#define LL_CONN_CTE_RECV_PARAM 206 +#define LL_CONN_CTE_REQ_EN 207 +#define LL_CONN_CTE_TX_PARAM 208 +#define LL_CONN_CTE_RSP_EN 209 + +//OSAL +#define OSAL_SET_EVENT 210 +#define OSAL_MSG_SEND 211 +#define HAL_DRV_IRQ_INIT 212 +#define HAL_DRV_IRQ_ENABLE 213 +#define HAL_DRV_IRQ_DISABLE 214 + +#define HAL_WATCHDOG_INIT 215 + +// interrupt request handler +#define NMI_HANDLER 219 +#define HARDFAULT_HANDLER 220 +#define SVC_HANDLER 221 +#define PENDSV_HANDLER 222 +#define SYSTICK_HANDLER 223 + +#define V0_IRQ_HANDLER 224 +#define V1_IRQ_HANDLER 225 +#define V2_IRQ_HANDLER 226 +#define V3_IRQ_HANDLER 227 +#define V4_IRQ_HANDLER 228 +#define V5_IRQ_HANDLER 229 +#define V6_IRQ_HANDLER 230 +#define V7_IRQ_HANDLER 231 +#define V8_IRQ_HANDLER 232 +#define V9_IRQ_HANDLER 233 +#define V10_IRQ_HANDLER 234 +#define V11_IRQ_HANDLER 235 +#define V12_IRQ_HANDLER 236 +#define V13_IRQ_HANDLER 237 +#define V14_IRQ_HANDLER 238 +#define V15_IRQ_HANDLER 239 +#define V16_IRQ_HANDLER 240 +#define V17_IRQ_HANDLER 241 +#define V18_IRQ_HANDLER 242 +#define V19_IRQ_HANDLER 243 +#define V20_IRQ_HANDLER 244 +#define V21_IRQ_HANDLER 245 +#define V22_IRQ_HANDLER 246 +#define V23_IRQ_HANDLER 247 +#define V24_IRQ_HANDLER 248 +#define V25_IRQ_HANDLER 249 +#define V26_IRQ_HANDLER 250 +#define V27_IRQ_HANDLER 251 +#define V28_IRQ_HANDLER 252 +#define V29_IRQ_HANDLER 253 +#define V30_IRQ_HANDLER 254 +#define V31_IRQ_HANDLER 255 + +// ================== FUNCTIONS ================================== +void move_to_slave_function0(void); +void LL_slave_conn_event0(void); +llStatus_t llSetupAdv0(void); +void llSetupUndirectedAdvEvt0(void); +void llSetupNonConnectableAdvEvt0( void ); +void llSetupScannableAdvEvt0( void ); +void llSetupDirectedAdvEvt0( void ); +void LL_evt_schedule0(void); + +void llCalcTimerDrift0( uint32 connInterval, + uint16 slaveLatency, + uint8 sleepClkAccuracy, + uint32* timerDrift ) ; + +uint16 ll_generateTxBuffer0(int txFifo_vacancy, uint16* pSave_ptr); + +void ll_hw_read_tfifo_rtlp0(void); + +void ll_read_rxfifo0(void); + +int ll_hw_read_tfifo_packet0(uint8* pkt); + +void ll_hw_process_RTO0(uint32 ack_num); + +void LL_set_default_conn_params0(llConnState_t* connPtr); + +// ===== +void enterSleepProcess0(uint32 time); + +void wakeupProcess0(void); + +void config_RTC0(uint32 time); + +void enter_sleep_off_mode0(Sleep_Mode mode); + +void llSlaveEvt_TaskEndOk0( void ); + +uint8 llSetupNextSlaveEvent0( void ); + +uint8 llCheckForLstoDuringSL0( llConnState_t* connPtr ); + +uint8 llProcessSlaveControlProcedures0( llConnState_t* connPtr ); + +void llProcessSlaveControlPacket0( llConnState_t* connPtr, + uint8* pBuf ); + +void llSlaveEvt_TaskAbort0(void ); + +// ------ +void llMasterEvt_TaskEndOk0( void ); +void llProcessMasterControlPacket0( llConnState_t* connPtr, + uint8* pBuf ); +uint8 llProcessMasterControlProcedures0( llConnState_t* connPtr ); +uint8 llSetupNextMasterEvent0( void ); + +void move_to_master_function0(void); +void LL_master_conn_event0(void); + +llStatus_t LL_SetScanControl0( uint8 scanMode, + uint8 filterReports ); +llStatus_t LL_SetScanParam0( uint8 scanType, + uint16 scanInterval, + uint16 scanWindow, + uint8 ownAddrType, + uint8 scanWlPolicy ); + +llStatus_t LL_CreateConn0( uint16 scanInterval, + uint16 scanWindow, + uint8 initWlPolicy, + uint8 peerAddrType, + uint8* peerAddr, + uint8 ownAddrType, + uint16 connIntervalMin, + uint16 connIntervalMax, + uint16 connLatency, + uint16 connTimeout, + uint16 minLength, + uint16 maxLength ); +llStatus_t LL_CreateConnCancel0( void ); + +llStatus_t LL_StartEncrypt0( uint16 connId, + uint8* rand, + uint8* eDiv, + uint8* ltk ); + +void llSetupScan0( uint8 chan ); + +// ================== ll.c +void LL_Init0( uint8 taskId ); +uint16 LL_ProcessEvent0( uint8 task_id, uint16 events ); +llStatus_t LL_Reset0( void ); +llStatus_t LL_TxData0( uint16 connId, uint8* pBuf, uint8 pktLen, uint8 fragFlag ); +llStatus_t LL_Disconnect0( uint16 connId, uint8 reason ); +llStatus_t LL_SetAdvParam0( uint16 advIntervalMin, + uint16 advIntervalMax, + uint8 advEvtType, + uint8 ownAddrType, + uint8 directAddrType, + uint8* directAddr, + uint8 advChanMap, + uint8 advWlPolicy ); +llStatus_t LL_SetAdvData0( uint8 advDataLen, uint8* advData ); +llStatus_t LL_SetAdvControl0( uint8 advMode ); + +llStatus_t LL_EXT_SetTxPower0( uint8 txPower, uint8* cmdComplete ); + +llStatus_t LL_ClearWhiteList0( void ); +llStatus_t LL_AddWhiteListDevice0( uint8* devAddr, uint8 addrType ); +llStatus_t LL_RemoveWhiteListDevice0( uint8* devAddr, uint8 addrType ); +llStatus_t LL_ReadWlSize0( uint8* numEntries ); +llStatus_t LL_ReadTxPowerLevel0( uint8 connId, uint8 type, int8* txPower ); +llStatus_t LL_SetTxPowerLevel0( int8 txPower ); +llStatus_t LL_ReadAdvChanTxPower0( int8* txPower ); +llStatus_t LL_ReadRssi0( uint16 connId, int8* lastRssi ); +llStatus_t LL_ReadRemoteUsedFeatures0( uint16 connId ); +llStatus_t LL_Encrypt0( uint8* key, uint8* plaintextData, uint8* encryptedData ); + +llStatus_t LL_DirectTestEnd0( void ); +llStatus_t LL_DirectTestTxTest0( uint8 txFreq, uint8 payloadLen, uint8 payloadType ); +llStatus_t LL_DirectTestRxTest0( uint8 rxFreq ); + +// ================ ll_common.c +void llProcessTxData0( llConnState_t* connPtr, uint8 context ); +uint8 llProcessRxData0( void ); +uint8 llWriteTxData0( llConnState_t* connPtr, + uint8 pktHdr, + uint8 pktLen, + uint8* pBuf ); +void llConnTerminate0( llConnState_t* connPtr, uint8 reason ); +void llReleaseConnId0( llConnState_t* connPtr ); + +// ================ ll_enc.c +void LL_ENC_AES128_Encrypt0( uint8* key, + uint8* plaintext, + uint8* ciphertext ); +uint8 LL_ENC_GenerateTrueRandNum0( uint8* buf, + uint8 len ); +void LL_ENC_GenDeviceSKD0( uint8* SKD ); +void LL_ENC_GenDeviceIV0( uint8* IV ); +void LL_ENC_GenerateNonce0( uint32 pktCnt, + uint8 direction, + uint8* nonce ); +void LL_ENC_Encrypt0( llConnState_t* connPtr, + uint8 pktHdr, + uint8 pktLen, + uint8* pBuf ); +uint8 LL_ENC_Decrypt0( llConnState_t* connPtr, + uint8 pktHdr, + uint8 pktLen, + uint8* pBuf ); + +// =================== osal +void osal_pwrmgr_powerconserve0( void ) ; + +// =================== ll_hw_drv.c +void ll_hw_set_timing0(uint8 pktFmt); +void ll_hw_go0(void); +void ll_hw_trigger0(void); + +// ================== SMP functions +void SM_Init0( uint8 task_id ); +uint16 SM_ProcessEvent0( uint8 task_id, uint16 events ); + +// ================== HCI_TL functions +void HCI_Init0( uint8 task_id ); +uint16 HCI_ProcessEvent0( uint8 task_id, uint16 events ); + + +// ======= OSAL memory +void osal_mem_init0(void); + +// =========== ROM -> APP function +void app_sleep_process(void); + +void app_wakeup_process(void); + +void rf_init(void); + +void boot_init0(void); + +void wakeup_init0(void); + +void debug_print(uint32 state); + +void rf_calibrate0(void); + +void rf_phy_change_cfg(uint8 pktFmt); + +// ========== A2, for conn-adv, conn-scan +uint8 llSetupSecNonConnectableAdvEvt0( void ); +uint8 llSecAdvAllow0(void); +uint32 llCalcMaxScanTime0(void); +void llSetupSecScan0( uint8 chan ); + +uint8 llSetupSecAdvEvt0( void ); +uint8 llSetupSecConnectableAdvEvt0( void ); +uint8 llSetupSecScannableAdvEvt0( void ); + + + +//=============== gap_linkmgr.c +void gapProcessDisconnectCompleteEvt0( hciEvt_DisconnComplete_t* pPkt ); +void gapProcessConnectionCompleteEvt0( hciEvt_BLEConnComplete_t* pPkt ); + + +//=============== l2cap_util.c +uint8 l2capParsePacket0( l2capPacket_t* pPkt, hciDataEvent_t* pHciMsg ); +uint8 l2capEncapSendData0( uint16 connHandle, l2capPacket_t* pPkt ); +uint8 l2capPktToSegmentBuff0(uint16 connHandle, l2capSegmentBuff_t* pSegBuf, uint8 blen,uint8* pBuf); +void l2capPocessFragmentTxData0(uint16 connHandle); +uint8 l2capSegmentBuffToLinkLayer0(uint16 connHandle, l2capSegmentBuff_t* pSegBuf); +void l2capPocessFragmentTxData0(uint16 connHandle); + +//=============== DLE +llStatus_t LL_SetDataLengh0( uint16 connId,uint16 TxOctets,uint16 TxTime ); +void llPduLengthUpdate0(uint16 connHandle); +void llTrxNumAdaptiveConfig0(void); + +//===============LL ADJ WINDOW +void ll_adptive_adj_next_time0(uint32 nextTime); +void ll_adptive_smart_window0(uint32 irq_status,uint32 anchor_point); +void llSetNextDataChan0( llConnState_t* connPtr ); + +//=============== PHY UPDATE +llStatus_t LL_SetPhyMode0( uint16 connId,uint8 allPhy,uint8 txPhy, uint8 rxPhy,uint16 phyOptions); +llStatus_t LL_PhyUpdate0( uint16 connId ); +void llSetNextPhyMode0( llConnState_t* connPtr ); + +llStatus_t LL_PLUS_DisableSlaveLatency0(uint8 connId); +llStatus_t LL_PLUS_EnableSlaveLatency0(uint8 connId); + +// ================= BBB +void ll_scheduler0(uint32 time); +void ll_addTask0(uint8 connId, uint32 time); +void ll_deleteTask0(uint8 connId); + +void ll_adv_scheduler0(void); +void ll_add_adv_task0(extAdvInfo_t* pExtAdv); +void ll_delete_adv_task0(uint8 index); + +void ll_adv_scheduler_periodic0(void); +void ll_add_adv_task_periodic0(periodicAdvInfo_t* pPrdAdv, extAdvInfo_t* pExtAdv); +void ll_delete_adv_task_periodic0(uint8 index); +uint8 llSetupExtAdvEvent0(extAdvInfo_t* pAdvInfo); +uint8 llSetupPrdAdvEvent0(periodicAdvInfo_t* pPrdAdv, extAdvInfo_t* pExtAdv); + +void llSetupAdvExtIndPDU0(extAdvInfo_t* pAdvInfo, periodicAdvInfo_t* pPrdAdv); +void llSetupAuxAdvIndPDU0(extAdvInfo_t* pAdvInfo, periodicAdvInfo_t* pPrdAdv); +void llSetupAuxChainIndPDU0(extAdvInfo_t* pAdvInfo, periodicAdvInfo_t* pPrdAdv); +void llSetupAuxSyncIndPDU0(extAdvInfo_t* pAdvInfo, periodicAdvInfo_t* pPrdAdv); +void llSetupAuxConnectReqPDU0(void); +void llSetupAuxScanRspPDU0(extAdvInfo_t* pAdvInfo); +void llSetupAuxConnectRspPDU0(extAdvInfo_t* pAdvInfo); + +uint8 llGetNextAuxAdvChn0(uint8 current); + + +//=============== OSAL +uint8 osal_set_event0( uint8 task_id, uint16 event_flag ); +uint8 osal_msg_send0( uint8 destination_task, uint8* msg_ptr ); + +//=============== _HAL_IRQ_ +void drv_irq_init0(void); +int drv_enable_irq0(void); +int drv_disable_irq0(void); + +// 2020-02-13 cte jumpfunction +llStatus_t LL_ConnectionlessCTE_TransmitParam0( uint8 advertising_handle, + uint8 len, + uint8 type, + uint8 count, + uint8 Pattern_LEN, + uint8* AnaIDs); + +llStatus_t LL_ConnectionlessCTE_TransmitEnable0( uint8 advertising_handle,uint8 enable); +llStatus_t LL_ConnectionlessIQ_SampleEnable0( uint16 sync_handle, + uint8 enable, + uint8 slot_Duration, + uint8 MaxSampledCTEs, + uint8 pattern_len, + uint8* AnaIDs); +llStatus_t LL_Set_ConnectionCTE_ReceiveParam0( uint16 connHandle, + uint8 enable, + uint8 slot_Duration, + uint8 pattern_len, + uint8* AnaIDs); +llStatus_t LL_Connection_CTE_Request_Enable0( uint16 connHandle, + uint8 enable, + uint16 Interval, + uint8 len, + uint8 type); + +llStatus_t LL_Set_ConnectionCTE_TransmitParam0( uint16 connHandle, + uint8 type, + uint8 pattern_len, + uint8* AnaIDs); + +llStatus_t LL_Connection_CTE_Response_Enable0( uint16 connHandle,uint8 enable); + + +#endif // _JUMP_FUNC_H_ diff --git a/src/misc/jump_table.c b/src/misc/jump_table.c new file mode 100644 index 0000000..18e427e --- /dev/null +++ b/src/misc/jump_table.c @@ -0,0 +1,149 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +/************************************************************************************************** + Filename: jump_table.c + Revised: + Revision: + + Description: Jump table that holds function pointers and veriables used in ROM code. + + +**************************************************************************************************/ + +/******************************************************************************* + INCLUDES +*/ +#include "jump_function.h" +#include "global_config.h" +#include "OSAL_Tasks.h" +#include "rf_phy_driver.h" +#include "pwrmgr.h" +#include "gpio.h" +#include "timer.h" +#include "uart.h" +#include "log.h" + +/******************************************************************************* + MACROS +*/ +void (*trap_c_callback)(void); + +extern void log_printf(const char* format, ...); +void _hard_fault(uint32_t* arg) +{ + uint32_t* stk = (uint32_t*)((uint32_t)arg); + log_printf("[Hard fault handler]\n"); +// log_printf("R0 = 0x%08x\n", stk[9]); +// log_printf("R1 = 0x%08x\n", stk[10]); +// log_printf("R2 = 0x%08x\n", stk[11]); +// log_printf("R3 = 0x%08x\n", stk[12]); +// log_printf("R4 = 0x%08x\n", stk[1]); +// log_printf("R5 = 0x%08x\n", stk[2]); +// log_printf("R6 = 0x%08x\n", stk[3]); +// log_printf("R7 = 0x%08x\n", stk[4]); +// log_printf("R8 = 0x%08x\n", stk[5]); +// log_printf("R9 = 0x%08x\n", stk[6]); +// log_printf("R10 = 0x%08x\n", stk[7]); +// log_printf("R11 = 0x%08x\n", stk[8]); +// log_printf("R12 = 0x%08x\n", stk[13]); +// log_printf("SP = 0x%08x\n", stk[0]); + log_printf("LR = 0x%08x\n", stk[14]); + log_printf("PC = 0x%08x\n", stk[15]); + log_printf("PSR = 0x%08x\n", stk[16]); + log_printf("ICSR = 0x%08x\n", *(volatile uint32_t*)0xE000ED04); + + if (trap_c_callback) + { + trap_c_callback(); + } + + while (1); +} +// *INDENT-OFF* +void hard_fault(void) +{ + uint32_t arg = 0; + _hard_fault(&arg); +} +// *INDENT-ON* + +/******************************************************************************* + CONSTANTS +*/ +// jump table, this table save the function entry which will be called by ROM code +// item 1 - 4 for OSAL task entry +// item 224 - 255 for ISR(Interrupt Service Routine) entry +// others are reserved by ROM code +const uint32_t* const jump_table_base[256] __attribute__((section("jump_table_mem_area"))) = +{ + (const uint32_t*)0, // 0. write Log + (const uint32_t*)osalInitTasks, // 1. init entry of app + (const uint32_t*)tasksArr, // 2. task list + (const uint32_t*)& tasksCnt, // 3. task count + (const uint32_t*)& tasksEvents, // 4. task events + 0, 0, 0, 0, 0, // 5 - 9, reserved for rom patch + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 10 - 19, reserved for rom patch + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 - 29, reserved for rom patch + 0, 0, 0, 0, 0, 0, 0, 0, // <30 - - 37> + 0, 0, + 0, 0, 0, 0, 0, 0, //40 - 45 + 0, 0, 0, 0, //46 - 49 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 50 - 59, reserved for rom patch + 0, // < 60 - + 0, + 0, + 0, + 0, 0, 0, 0, 0, 0, // -69>, reserved for rom patch + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 70 -79, reserved for rom patch + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80 - 89, reserved for rom patch + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 90 - 99, reserved for rom patch + (const uint32_t*)hal_pwrmgr_sleep_process, // <100 - + (const uint32_t*)hal_pwrmgr_wakeup_process, + (const uint32_t*)rf_phy_ini, + 0, + 0, + 0, + 0, 0, 0, 0, // - 109, reserved for rom patch + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 110 -119, reserved for rom patch + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 120 -129, reserved for rom patch + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 130 -139, reserved for rom patch + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 140 -149, reserved for rom patch + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 150 -159, reserved for rom patch + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160 -169, reserved for rom patch + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 170 -179, reserved for rom patch + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 180 -189, reserved for rom patch + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 190 -199, reserved for rom patch + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 200 - 209, reserved for rom patch + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 210 - 219, reserved for rom patch + (const uint32_t*)hard_fault, 0, 0, 0, 0, 0, 0, 0, // 220 - 227 + 0, 0, // 228 - 229 + 0, 0, 0, 0, 0, // 230 - 234 + (const uint32_t*)hal_UART0_IRQHandler, // 235 uart irq handler + 0, 0, 0, 0, 0, // 236 - 240 + 0, 0, 0, 0, 0, 0, 0, 0, 0, // 241 - 249, for ISR entry + 0, 0, 0, 0, 0, 0 // 250 - 255, for ISR entry +}; + + + +/******************************************************************************* + Prototypes +*/ + + +/******************************************************************************* + LOCAL VARIABLES +*/ + + +/********************************************************************* + EXTERNAL VARIABLES +*/ +uint32 global_config[SOFT_PARAMETER_NUM] __attribute__((section("global_config_area"))); + + + + diff --git a/src/misc/rom_sym_def.h b/src/misc/rom_sym_def.h new file mode 100644 index 0000000..ccc9208 --- /dev/null +++ b/src/misc/rom_sym_def.h @@ -0,0 +1,901 @@ + + +#ifndef __ROM_SYM_H__ +#define __ROM_SYM_H__ +#ifdef USE_ROMSYM_ALIAS + + #define m_in_critical_region _symrom_m_in_critical_region + #define _spif_read_status_reg _symrom__spif_read_status_reg + #define _spif_wait_nobusy _symrom__spif_wait_nobusy + #define adv_param _symrom_adv_param + #define app_sleep_process _symrom_app_sleep_process + #define app_wakeup_process _symrom_app_wakeup_process + #define ate_fun_test _symrom_ate_fun_test + #define ate_sleep_process _symrom_ate_sleep_process + #define ate_wakeup_process _symrom_ate_wakeup_process + #define baseTaskID _symrom_baseTaskID + #define bit_to_byte _symrom_bit_to_byte + #define ble_crc24_gen _symrom_ble_crc24_gen + #define bleEvtMask _symrom_bleEvtMask + #define boot_init _symrom_boot_init + #define boot_init0 _symrom_boot_init0 + #define boot_m0 _symrom_boot_m0 + #define bx_to_application _symrom_bx_to_application + #define byte_to_bit _symrom_byte_to_bit + #define cachedTRNGdata _symrom_cachedTRNGdata + #define calculate_whiten_seed _symrom_calculate_whiten_seed + #define cbTimers _symrom_cbTimers + #define chanMapUpdate _symrom_chanMapUpdate + #define clear_timer _symrom_clear_timer + #define clear_timer_int _symrom_clear_timer_int + #define clk_get_pclk _symrom_clk_get_pclk + #define clk_init _symrom_clk_init + #define clk_set_pclk_div _symrom_clk_set_pclk_div + #define clk_spif_ref_clk _symrom_clk_spif_ref_clk + #define config_RTC _symrom_config_RTC + #define conn_param _symrom_conn_param + #define connUpdateTimer _symrom_connUpdateTimer + #define counter_tracking _symrom_counter_tracking + #define rom_crc16 _symrom_crc16 + #define ctrlToHostEnable _symrom_ctrlToHostEnable + #define dataPkt _symrom_dataPkt + #define debug_print _symrom_debug_print + #define deviceFeatureSet _symrom_deviceFeatureSet + #define disableSleep _symrom_disableSleep + #define drv_disable_irq _symrom_drv_disable_irq + #define drv_enable_irq _symrom_drv_enable_irq + #define drv_irq_init _symrom_drv_irq_init + #define dwc_connect _symrom_dwc_connect + #define dwc_data_process _symrom_dwc_data_process + #define dwc_loop _symrom_dwc_loop + #define efuse_read _symrom_efuse_read + #define enableSleep _symrom_enableSleep + #define enter_sleep_off_mode _symrom_enter_sleep_off_mode + #define enterSleepProcess _symrom_enterSleepProcess + #define ext_adv_hdr _symrom_ext_adv_hdr + #define extInitInfo _symrom_extInitInfo + #define extScanInfo _symrom_extScanInfo + #define fastTxRespTime _symrom_fastTxRespTime + #define forever_write _symrom_forever_write + #define g_adv_taskEvent _symrom_g_adv_taskEvent + #define g_adv_taskID _symrom_g_adv_taskID + #define g_advPerSlotTick _symrom_g_advPerSlotTick + #define g_advSetMaximumLen _symrom_g_advSetMaximumLen + #define g_advSlotPeriodic _symrom_g_advSlotPeriodic + #define g_blePktVersion _symrom_g_blePktVersion + #define g_conn_taskEvent _symrom_g_conn_taskEvent + #define g_conn_taskID _symrom_g_conn_taskID + #define g_counter_traking_avg _symrom_g_counter_traking_avg + #define g_counter_traking_cnt _symrom_g_counter_traking_cnt + #define g_currentAdvTimer _symrom_g_currentAdvTimer + #define g_currentExtAdv _symrom_g_currentExtAdv + #define g_currentExtAdv_periodic _symrom_g_currentExtAdv_periodic + #define g_currentTimerTask _symrom_g_currentTimerTask + #define g_dle_taskEvent _symrom_g_dle_taskEvent + #define g_dle_taskID _symrom_g_dle_taskID + //#define g_dtmAccessCode _symrom_g_dtmAccessCode + //#define g_dtmCarrSens _symrom_g_dtmCarrSens + //#define g_dtmCmd _symrom_g_dtmCmd + //#define g_dtmCtrl _symrom_g_dtmCtrl + //#define g_dtmEvt _symrom_g_dtmEvt + //#define g_dtmExtLen _symrom_g_dtmExtLen + //#define g_dtmFoff _symrom_g_dtmFoff + //#define g_dtmFreq _symrom_g_dtmFreq + //#define g_dtmLength _symrom_g_dtmLength + //#define g_dtmModeType _symrom_g_dtmModeType + //#define g_dtmPara _symrom_g_dtmPara + //#define g_dtmPerAutoIntv _symrom_g_dtmPerAutoIntv + //#define g_dtmPKT _symrom_g_dtmPKT + //#define g_dtmPktCount _symrom_g_dtmPktCount + //#define g_dtmPktIntv _symrom_g_dtmPktIntv + //#define g_dtmRsp _symrom_g_dtmRsp + //#define g_dtmRssi _symrom_g_dtmRssi + //#define g_dtmRxCrcNum _symrom_g_dtmRxCrcNum + //#define g_dtmRxTONum _symrom_g_dtmRxTONum + //#define g_dtmStatus _symrom_g_dtmStatus + //#define g_dtmTick _symrom_g_dtmTick + //#define g_dtmTpCalEnable _symrom_g_dtmTpCalEnable + //#define g_dtmTxPower _symrom_g_dtmTxPower + #define g_extAdvNumber _symrom_g_extAdvNumber + #define g_getPn23_cnt _symrom_g_getPn23_cnt + #define g_getPn23_seed _symrom_g_getPn23_seed + #define g_hclk _symrom_g_hclk + #define g_interAuxPduDuration _symrom_g_interAuxPduDuration + #define g_ll_conn_ctx _symrom_g_ll_conn_ctx + #define g_llHdcDirAdvTime _symrom_g_llHdcDirAdvTime + #define g_llPduLen _symrom_g_llPduLen + #define g_llPeriodAdvSyncInfo _symrom_g_llPeriodAdvSyncInfo + #define g_llResolvinglist _symrom_g_llResolvinglist + #define g_llRlDeviceNum _symrom_g_llRlDeviceNum + #define g_llRlEnable _symrom_g_llRlEnable + #define g_llRlTimeout _symrom_g_llRlTimeout + #define g_llSleepContext _symrom_g_llSleepContext + #define g_llWhitelist _symrom_g_llWhitelist + #define g_llWlDeviceNum _symrom_g_llWlDeviceNum + #define g_maxConnNum _symrom_g_maxConnNum + #define g_maxPktPerEventRx _symrom_g_maxPktPerEventRx + #define g_maxPktPerEventTx _symrom_g_maxPktPerEventTx + #define g_new_master_delta _symrom_g_new_master_delta + #define g_osal_tick_trim _symrom_g_osal_tick_trim + #define g_osalTickTrim_mod _symrom_g_osalTickTrim_mod + #define g_pAdvSchInfo _symrom_g_pAdvSchInfo + #define g_pAdvSchInfo_periodic _symrom_g_pAdvSchInfo_periodic + #define g_perioAdvNumber _symrom_g_perioAdvNumber + #define g_pExtendedAdvInfo _symrom_g_pExtendedAdvInfo + #define g_phyChg_taskEvent _symrom_g_phyChg_taskEvent + #define g_phyChg_taskID _symrom_g_phyChg_taskID + #define g_pLLcteISample _symrom_g_pLLcteISample + #define g_pLLcteQSample _symrom_g_pLLcteQSample + #define g_pmCounters _symrom_g_pmCounters + #define g_pPeriodicAdvInfo _symrom_g_pPeriodicAdvInfo + //#define g_rfPhyClkSel _symrom_g_rfPhyClkSel + //#define g_rfPhyDtmCmd _symrom_g_rfPhyDtmCmd + //#define g_rfPhyDtmEvt _symrom_g_rfPhyDtmEvt + //#define g_rfPhyFreqOffSet _symrom_g_rfPhyFreqOffSet + //#define g_rfPhyPktFmt _symrom_g_rfPhyPktFmt + //#define g_rfPhyRxDcIQ _symrom_g_rfPhyRxDcIQ + //#define g_rfPhyTpCal0 _symrom_g_rfPhyTpCal0 + //#define g_rfPhyTpCal0_2Mbps _symrom_g_rfPhyTpCal0_2Mbps + //#define g_rfPhyTpCal1 _symrom_g_rfPhyTpCal1 + //#define g_rfPhyTpCal1_2Mbps _symrom_g_rfPhyTpCal1_2Mbps + //#define g_rfPhyTxPower _symrom_g_rfPhyTxPower + #define g_rx_adv_buf _symrom_g_rx_adv_buf + //#define g_rxAdcClkSel _symrom_g_rxAdcClkSel + #define g_same_rf_channel_flag _symrom_g_same_rf_channel_flag + #define g_schExtAdvNum _symrom_g_schExtAdvNum + #define g_schExtAdvNum_periodic _symrom_g_schExtAdvNum_periodic + #define g_smartWindowActive _symrom_g_smartWindowActive + #define g_smartWindowActiveCnt _symrom_g_smartWindowActiveCnt + #define g_smartWindowLater _symrom_g_smartWindowLater + #define g_smartWindowPreAnchPoint _symrom_g_smartWindowPreAnchPoint + #define g_smartWindowRTOCnt _symrom_g_smartWindowRTOCnt + #define g_smartWindowSize _symrom_g_smartWindowSize + #define g_smartWindowSizeNew _symrom_g_smartWindowSizeNew + #define g_system_clk _symrom_g_system_clk + #define g_TIM2_IRQ_PendingTick _symrom_g_TIM2_IRQ_PendingTick + #define g_TIM2_IRQ_TIM3_CurrCount _symrom_g_TIM2_IRQ_TIM3_CurrCount + #define g_TIM2_IRQ_to_Sleep_DeltTick _symrom_g_TIM2_IRQ_to_Sleep_DeltTick + #define g_TIM2_wakeup_delay _symrom_g_TIM2_wakeup_delay + #define g_timerExpiryTick _symrom_g_timerExpiryTick + #define g_tx_adv_buf _symrom_g_tx_adv_buf + #define g_tx_ext_adv_buf _symrom_g_tx_ext_adv_buf + #define g_wakeup_rtc_tick _symrom_g_wakeup_rtc_tick + #define get_rx_read_ptr _symrom_get_rx_read_ptr + #define get_rx_write_ptr _symrom_get_rx_write_ptr + #define get_sleep_flag _symrom_get_sleep_flag + #define get_timer_count _symrom_get_timer_count + #define get_timer_int _symrom_get_timer_int + #define get_tx_read_ptr _symrom_get_tx_read_ptr + #define get_tx_write_ptr _symrom_get_tx_write_ptr + #define getMcuPrecisionCount _symrom_getMcuPrecisionCount + #define getPN23RandNumber _symrom_getPN23RandNumber + #define getRxBufferFree _symrom_getRxBufferFree + #define getRxBufferSize _symrom_getRxBufferSize + #define getSleepMode _symrom_getSleepMode + #define getTxBufferFree _symrom_getTxBufferFree + #define getTxBufferSize _symrom_getTxBufferSize + #define gpio_cfg_analog_io _symrom_gpio_cfg_analog_io + #define gpio_dir _symrom_gpio_dir + #define gpio_fmux_control _symrom_gpio_fmux_control + #define gpio_fmux_set _symrom_gpio_fmux_set + #define gpio_in_trigger _symrom_gpio_in_trigger + #define gpio_init _symrom_gpio_init + #define gpio_interrupt_set _symrom_gpio_interrupt_set + #define GPIO_IRQHandler _symrom_GPIO_IRQHandler + #define gpio_pull_set _symrom_gpio_pull_set + #define gpio_read _symrom_gpio_read + #define gpio_wakeup_set _symrom_gpio_wakeup_set + #define gpio_write _symrom_gpio_write + #define HardFault_Handler _symrom_HardFault_Handler + #define HardFault_IRQHandler _symrom_HardFault_IRQHandler + #define HCI_bm_alloc _symrom_HCI_bm_alloc + #define HCI_CommandCompleteEvent _symrom_HCI_CommandCompleteEvent + #define HCI_CommandStatusEvent _symrom_HCI_CommandStatusEvent + #define HCI_DataBufferOverflowEvent _symrom_HCI_DataBufferOverflowEvent + #define HCI_DisconnectCmd _symrom_HCI_DisconnectCmd + #define HCI_ExtTaskRegister _symrom_HCI_ExtTaskRegister + #define HCI_GAPTaskRegister _symrom_HCI_GAPTaskRegister + #define HCI_HardwareErrorEvent _symrom_HCI_HardwareErrorEvent + #define HCI_HostBufferSizeCmd _symrom_HCI_HostBufferSizeCmd + #define HCI_HostNumCompletedPktCmd _symrom_HCI_HostNumCompletedPktCmd + #define HCI_Init _symrom_HCI_Init + #define HCI_L2CAPTaskRegister _symrom_HCI_L2CAPTaskRegister + #define HCI_LE_AddDevToResolvingListCmd _symrom_HCI_LE_AddDevToResolvingListCmd + #define HCI_LE_AddWhiteListCmd _symrom_HCI_LE_AddWhiteListCmd + #define HCI_LE_ClearAdvSetsCmd _symrom_HCI_LE_ClearAdvSetsCmd + #define HCI_LE_ClearResolvingListCmd _symrom_HCI_LE_ClearResolvingListCmd + #define HCI_LE_ClearWhiteListCmd _symrom_HCI_LE_ClearWhiteListCmd + #define HCI_LE_Connection_CTE_Request_EnableCmd _symrom_HCI_LE_Connection_CTE_Request_EnableCmd + #define HCI_LE_Connection_CTE_Response_EnableCmd _symrom_HCI_LE_Connection_CTE_Response_EnableCmd + #define HCI_LE_ConnectionlessCTE_TransmitEnableCmd _symrom_HCI_LE_ConnectionlessCTE_TransmitEnableCmd + #define HCI_LE_ConnectionlessCTE_TransmitParamCmd _symrom_HCI_LE_ConnectionlessCTE_TransmitParamCmd + #define HCI_LE_ConnectionlessIQ_SampleEnableCmd _symrom_HCI_LE_ConnectionlessIQ_SampleEnableCmd + #define HCI_LE_ConnUpdateCmd _symrom_HCI_LE_ConnUpdateCmd + #define HCI_LE_CreateConnCancelCmd _symrom_HCI_LE_CreateConnCancelCmd + #define HCI_LE_CreateConnCmd _symrom_HCI_LE_CreateConnCmd + #define HCI_LE_EncryptCmd _symrom_HCI_LE_EncryptCmd + #define HCI_LE_ExtendedCreateConnectionCmd _symrom_HCI_LE_ExtendedCreateConnectionCmd + #define HCI_LE_LtkReqNegReplyCmd _symrom_HCI_LE_LtkReqNegReplyCmd + #define HCI_LE_LtkReqReplyCmd _symrom_HCI_LE_LtkReqReplyCmd + #define HCI_LE_PeriodicAdvertisingCreateSyncCancelCmd _symrom_HCI_LE_PeriodicAdvertisingCreateSyncCancelCmd + #define HCI_LE_PeriodicAdvertisingCreateSyncCmd _symrom_HCI_LE_PeriodicAdvertisingCreateSyncCmd + #define HCI_LE_PeriodicAdvertisingTerminateSyncCmd _symrom_HCI_LE_PeriodicAdvertisingTerminateSyncCmd + #define HCI_LE_RandCmd _symrom_HCI_LE_RandCmd + #define HCI_LE_READ_Anatenna_InfoCmd _symrom_HCI_LE_READ_Anatenna_InfoCmd + #define HCI_LE_ReadAdvChanTxPowerCmd _symrom_HCI_LE_ReadAdvChanTxPowerCmd + #define HCI_LE_ReadBufSizeCmd _symrom_HCI_LE_ReadBufSizeCmd + #define HCI_LE_ReadChannelMapCmd _symrom_HCI_LE_ReadChannelMapCmd + #define HCI_LE_ReadLocalSupportedFeaturesCmd _symrom_HCI_LE_ReadLocalSupportedFeaturesCmd + #define HCI_LE_ReadMaxDataLengthCmd _symrom_HCI_LE_ReadMaxDataLengthCmd + #define HCI_LE_ReadMaximumAdvDataLengthCmd _symrom_HCI_LE_ReadMaximumAdvDataLengthCmd + #define HCI_LE_ReadNumberOfSupportAdvSetCmd _symrom_HCI_LE_ReadNumberOfSupportAdvSetCmd + #define HCI_LE_ReadPhyMode _symrom_HCI_LE_ReadPhyMode + #define HCI_LE_ReadRemoteUsedFeaturesCmd _symrom_HCI_LE_ReadRemoteUsedFeaturesCmd + #define HCI_LE_ReadResolvingListSizeCmd _symrom_HCI_LE_ReadResolvingListSizeCmd + #define HCI_LE_ReadSuggestedDefaultDataLengthCmd _symrom_HCI_LE_ReadSuggestedDefaultDataLengthCmd + #define HCI_LE_ReadSupportedStatesCmd _symrom_HCI_LE_ReadSupportedStatesCmd + #define HCI_LE_ReadWhiteListSizeCmd _symrom_HCI_LE_ReadWhiteListSizeCmd + #define HCI_LE_ReceiverTestCmd _symrom_HCI_LE_ReceiverTestCmd + #define HCI_LE_RemoveAdvSetCmd _symrom_HCI_LE_RemoveAdvSetCmd + #define HCI_LE_RemoveResolvingListCmd _symrom_HCI_LE_RemoveResolvingListCmd + #define HCI_LE_RemoveWhiteListCmd _symrom_HCI_LE_RemoveWhiteListCmd + #define HCI_LE_Set_ConnectionCTE_ReceiveParamCmd _symrom_HCI_LE_Set_ConnectionCTE_ReceiveParamCmd + #define HCI_LE_Set_ConnectionCTE_TransmitParamCmd _symrom_HCI_LE_Set_ConnectionCTE_TransmitParamCmd + #define HCI_LE_SetAddressResolutionEnableCmd _symrom_HCI_LE_SetAddressResolutionEnableCmd + #define HCI_LE_SetAdvDataCmd _symrom_HCI_LE_SetAdvDataCmd + #define HCI_LE_SetAdvEnableCmd _symrom_HCI_LE_SetAdvEnableCmd + #define HCI_LE_SetAdvParamCmd _symrom_HCI_LE_SetAdvParamCmd + #define HCI_LE_SetDataLengthCmd _symrom_HCI_LE_SetDataLengthCmd + #define HCI_LE_SetDefaultPhyMode _symrom_HCI_LE_SetDefaultPhyMode + #define HCI_LE_SetEventMaskCmd _symrom_HCI_LE_SetEventMaskCmd + #define HCI_LE_SetExtAdvDataCmd _symrom_HCI_LE_SetExtAdvDataCmd + #define HCI_LE_SetExtAdvEnableCmd _symrom_HCI_LE_SetExtAdvEnableCmd + #define HCI_LE_SetExtAdvParamCmd _symrom_HCI_LE_SetExtAdvParamCmd + #define HCI_LE_SetExtAdvSetRandomAddressCmd _symrom_HCI_LE_SetExtAdvSetRandomAddressCmd + #define HCI_LE_SetExtendedScanEnableCmd _symrom_HCI_LE_SetExtendedScanEnableCmd + #define HCI_LE_SetExtendedScanParametersCmd _symrom_HCI_LE_SetExtendedScanParametersCmd + #define HCI_LE_SetExtScanRspDataCmd _symrom_HCI_LE_SetExtScanRspDataCmd + #define HCI_LE_SetHostChanClassificationCmd _symrom_HCI_LE_SetHostChanClassificationCmd + #define HCI_LE_SetPeriodicAdvDataCmd _symrom_HCI_LE_SetPeriodicAdvDataCmd + #define HCI_LE_SetPeriodicAdvEnableCmd _symrom_HCI_LE_SetPeriodicAdvEnableCmd + #define HCI_LE_SetPeriodicAdvParameterCmd _symrom_HCI_LE_SetPeriodicAdvParameterCmd + #define HCI_LE_SetPhyMode _symrom_HCI_LE_SetPhyMode + #define HCI_LE_SetRandomAddressCmd _symrom_HCI_LE_SetRandomAddressCmd + #define HCI_LE_SetResolvablePrivateAddressTimeoutCmd _symrom_HCI_LE_SetResolvablePrivateAddressTimeoutCmd + #define HCI_LE_SetScanEnableCmd _symrom_HCI_LE_SetScanEnableCmd + #define HCI_LE_SetScanParamCmd _symrom_HCI_LE_SetScanParamCmd + #define HCI_LE_SetScanRspDataCmd _symrom_HCI_LE_SetScanRspDataCmd + #define HCI_LE_StartEncyptCmd _symrom_HCI_LE_StartEncyptCmd + #define HCI_LE_TestEndCmd _symrom_HCI_LE_TestEndCmd + #define HCI_LE_TransmitterTestCmd _symrom_HCI_LE_TransmitterTestCmd + #define HCI_LE_WriteSuggestedDefaultDataLengthCmd _symrom_HCI_LE_WriteSuggestedDefaultDataLengthCmd + #define HCI_NumOfCompletedPacketsEvent _symrom_HCI_NumOfCompletedPacketsEvent + #define HCI_ProcessEvent _symrom_HCI_ProcessEvent + #define HCI_ReadBDADDRCmd _symrom_HCI_ReadBDADDRCmd + #define HCI_ReadLocalSupportedCommandsCmd _symrom_HCI_ReadLocalSupportedCommandsCmd + #define HCI_ReadLocalSupportedFeaturesCmd _symrom_HCI_ReadLocalSupportedFeaturesCmd + #define HCI_ReadLocalVersionInfoCmd _symrom_HCI_ReadLocalVersionInfoCmd + #define HCI_ReadRemoteVersionInfoCmd _symrom_HCI_ReadRemoteVersionInfoCmd + #define HCI_ReadRssiCmd _symrom_HCI_ReadRssiCmd + #define HCI_ReadTransmitPowerLevelCmd _symrom_HCI_ReadTransmitPowerLevelCmd + #define HCI_ResetCmd _symrom_HCI_ResetCmd + #define HCI_ReverseBytes _symrom_HCI_ReverseBytes + #define HCI_SendCommandCompleteEvent _symrom_HCI_SendCommandCompleteEvent + #define HCI_SendCommandStatusEvent _symrom_HCI_SendCommandStatusEvent + #define HCI_SendControllerToHostEvent _symrom_HCI_SendControllerToHostEvent + #define HCI_SendDataPkt _symrom_HCI_SendDataPkt + #define HCI_SetControllerToHostFlowCtrlCmd _symrom_HCI_SetControllerToHostFlowCtrlCmd + #define HCI_SetEventMaskCmd _symrom_HCI_SetEventMaskCmd + #define HCI_SMPTaskRegister _symrom_HCI_SMPTaskRegister + #define HCI_TestAppTaskRegister _symrom_HCI_TestAppTaskRegister + #define HCI_ValidConnTimeParams _symrom_HCI_ValidConnTimeParams + #define HCI_VendorSpecifcCommandCompleteEvent _symrom_HCI_VendorSpecifcCommandCompleteEvent + #define hciCmdTable _symrom_hciCmdTable + #define hciCtrlCmdToken _symrom_hciCtrlCmdToken + #define hciExtTaskID _symrom_hciExtTaskID + #define hciGapTaskID _symrom_hciGapTaskID + #define hciInitEventMasks _symrom_hciInitEventMasks + #define hciL2capTaskID _symrom_hciL2capTaskID + #define hciPTMenabled _symrom_hciPTMenabled + #define hciSmpTaskID _symrom_hciSmpTaskID + #define hciTaskID _symrom_hciTaskID + #define hciTestTaskID _symrom_hciTestTaskID + #define hclk_per_us _symrom_hclk_per_us + #define hclk_per_us_shift _symrom_hclk_per_us_shift + #define initInfo _symrom_initInfo + #define ISR_entry_time _symrom_ISR_entry_time + #define isSleepAllow _symrom_isSleepAllow + #define isTimer1Running _symrom_isTimer1Running + #define isTimer4Running _symrom_isTimer4Running + #define jump_area_init _symrom_jump_area_init + #define ll_add_adv_task _symrom_ll_add_adv_task + #define ll_add_adv_task_periodic _symrom_ll_add_adv_task_periodic + #define LL_AddResolvingListLDevice _symrom_LL_AddResolvingListLDevice + #define ll_addTask _symrom_ll_addTask + #define LL_AddWhiteListDevice _symrom_LL_AddWhiteListDevice + #define ll_adptive_adj_next_time _symrom_ll_adptive_adj_next_time + #define ll_adptive_smart_window _symrom_ll_adptive_smart_window + #define ll_adv_scheduler _symrom_ll_adv_scheduler + #define ll_adv_scheduler_periodic _symrom_ll_adv_scheduler_periodic + #define LL_AdvReportCback _symrom_LL_AdvReportCback + #define ll_allocAuxAdvTimeSlot _symrom_ll_allocAuxAdvTimeSlot + #define ll_allocAuxAdvTimeSlot_prd _symrom_ll_allocAuxAdvTimeSlot_prd + #define ll_CalcRandomAddr _symrom_ll_CalcRandomAddr + #define LL_ChanMapUpdate _symrom_LL_ChanMapUpdate + #define LL_ClearAdvSets _symrom_LL_ClearAdvSets + #define LL_ClearResolvingList _symrom_LL_ClearResolvingList + #define LL_ClearWhiteList _symrom_LL_ClearWhiteList + #define LL_ConnActive _symrom_LL_ConnActive + #define LL_Connection_CTE_Request_Enable _symrom_LL_Connection_CTE_Request_Enable + #define LL_Connection_CTE_Response_Enable _symrom_LL_Connection_CTE_Response_Enable + #define LL_ConnectionCompleteCback _symrom_LL_ConnectionCompleteCback + #define LL_ConnectionIQReportCback _symrom_LL_ConnectionIQReportCback + #define LL_ConnectionlessCTE_TransmitEnable _symrom_LL_ConnectionlessCTE_TransmitEnable + #define LL_ConnectionlessCTE_TransmitParam _symrom_LL_ConnectionlessCTE_TransmitParam + #define LL_ConnectionlessIQ_SampleEnable _symrom_LL_ConnectionlessIQ_SampleEnable + #define LL_ConnectionlessIQReportCback _symrom_LL_ConnectionlessIQReportCback + #define LL_ConnParamUpdateCback _symrom_LL_ConnParamUpdateCback + #define LL_ConnUpdate _symrom_LL_ConnUpdate + #define LL_CreateConn _symrom_LL_CreateConn + #define LL_CreateConnCancel _symrom_LL_CreateConnCancel + #define LL_CTE_Report_FailedCback _symrom_LL_CTE_Report_FailedCback + #define LL_CtrlToHostFlowControl _symrom_LL_CtrlToHostFlowControl + #define LL_DataLengthChangeCback _symrom_LL_DataLengthChangeCback + #define ll_debug_output _symrom_ll_debug_output + #define ll_delete_adv_task _symrom_ll_delete_adv_task + #define ll_delete_adv_task_periodic _symrom_ll_delete_adv_task_periodic + #define ll_deleteTask _symrom_ll_deleteTask + #define LL_DirectTestEnd _symrom_LL_DirectTestEnd + #define LL_DirectTestTxTest _symrom_LL_DirectTestTxTest + #define LL_Disconnect _symrom_LL_Disconnect + #define LL_DisconnectCback _symrom_LL_DisconnectCback + #define LL_ENC_AES128_Encrypt _symrom_LL_ENC_AES128_Encrypt + #define LL_ENC_Decrypt _symrom_LL_ENC_Decrypt + #define LL_ENC_Encrypt _symrom_LL_ENC_Encrypt + #define LL_ENC_GenDeviceIV _symrom_LL_ENC_GenDeviceIV + #define LL_ENC_GenDeviceSKD _symrom_LL_ENC_GenDeviceSKD + #define LL_ENC_GenerateNonce _symrom_LL_ENC_GenerateNonce + #define LL_ENC_GeneratePseudoRandNum _symrom_LL_ENC_GeneratePseudoRandNum + #define LL_ENC_GenerateTrueRandNum _symrom_LL_ENC_GenerateTrueRandNum + #define LL_ENC_LoadKey _symrom_LL_ENC_LoadKey + #define LL_ENC_ReverseBytes _symrom_LL_ENC_ReverseBytes + #define LL_ENC_sm_ah _symrom_LL_ENC_sm_ah + #define LL_EncChangeCback _symrom_LL_EncChangeCback + #define LL_EncKeyRefreshCback _symrom_LL_EncKeyRefreshCback + #define LL_EncLtkNegReply _symrom_LL_EncLtkNegReply + #define LL_EncLtkReply _symrom_LL_EncLtkReply + #define LL_EncLtkReqCback _symrom_LL_EncLtkReqCback + #define LL_Encrypt _symrom_LL_Encrypt + #define LL_evt_schedule _symrom_LL_evt_schedule + #define ll_ext_adv_schedule_next_event _symrom_ll_ext_adv_schedule_next_event + #define LL_EXT_AdvEventNotice _symrom_LL_EXT_AdvEventNotice + #define LL_EXT_BuildRevision _symrom_LL_EXT_BuildRevision + #define LL_EXT_ClkDivOnHalt _symrom_LL_EXT_ClkDivOnHalt + #define LL_EXT_ConnEventNotice _symrom_LL_EXT_ConnEventNotice + #define LL_EXT_DeclareNvUsage _symrom_LL_EXT_DeclareNvUsage + #define LL_EXT_Decrypt _symrom_LL_EXT_Decrypt + #define LL_EXT_DelaySleep _symrom_LL_EXT_DelaySleep + #define LL_EXT_DisconnectImmed _symrom_LL_EXT_DisconnectImmed + #define LL_EXT_EndModemTest _symrom_LL_EXT_EndModemTest + #define LL_EXT_HaltDuringRf _symrom_LL_EXT_HaltDuringRf + #define LL_EXT_Init_IQ_pBuff _symrom_LL_EXT_Init_IQ_pBuff + #define ll_ext_init_schedule_next_event _symrom_ll_ext_init_schedule_next_event + #define LL_EXT_MapPmIoPort _symrom_LL_EXT_MapPmIoPort + #define LL_EXT_ModemHopTestTx _symrom_LL_EXT_ModemHopTestTx + #define LL_EXT_ModemTestRx _symrom_LL_EXT_ModemTestRx + #define LL_EXT_ModemTestTx _symrom_LL_EXT_ModemTestTx + #define LL_EXT_NumComplPktsLimit _symrom_LL_EXT_NumComplPktsLimit + #define LL_EXT_OnePacketPerEvent _symrom_LL_EXT_OnePacketPerEvent + #define LL_EXT_OverlappedProcessing _symrom_LL_EXT_OverlappedProcessing + #define LL_EXT_PacketErrorRate _symrom_LL_EXT_PacketErrorRate + #define LL_EXT_PERbyChan _symrom_LL_EXT_PERbyChan + #define LL_EXT_ResetSystem _symrom_LL_EXT_ResetSystem + #define LL_EXT_SaveFreqTune _symrom_LL_EXT_SaveFreqTune + #define ll_ext_scan_schedule_next_event _symrom_ll_ext_scan_schedule_next_event + #define LL_EXT_SetBDADDR _symrom_LL_EXT_SetBDADDR + #define LL_EXT_SetFastTxResponseTime _symrom_LL_EXT_SetFastTxResponseTime + #define LL_EXT_SetFreqTune _symrom_LL_EXT_SetFreqTune + #define LL_EXT_SetLocalSupportedFeatures _symrom_LL_EXT_SetLocalSupportedFeatures + #define LL_EXT_SetMaxDtmTxPower _symrom_LL_EXT_SetMaxDtmTxPower + #define LL_EXT_SetRxGain _symrom_LL_EXT_SetRxGain + #define LL_EXT_SetSCA _symrom_LL_EXT_SetSCA + #define LL_EXT_SetSlaveLatencyOverride _symrom_LL_EXT_SetSlaveLatencyOverride + #define LL_EXT_SetTxPower _symrom_LL_EXT_SetTxPower + #define LL_ExtAdvReportCback _symrom_LL_ExtAdvReportCback + #define LL_extAdvTimerExpProcess _symrom_LL_extAdvTimerExpProcess + #define LL_ExtendedCreateConnection _symrom_LL_ExtendedCreateConnection + #define LL_extInitTimerExpProcess _symrom_LL_extInitTimerExpProcess + #define LL_extScanTimerExpProcess _symrom_LL_extScanTimerExpProcess + #define ll_generateExtAdvDid _symrom_ll_generateExtAdvDid + #define ll_generateTxBuffer _symrom_ll_generateTxBuffer + #define ll_get_next_active_conn _symrom_ll_get_next_active_conn + #define ll_get_next_timer _symrom_ll_get_next_timer + #define ll_getFirstAdvChn _symrom_ll_getFirstAdvChn + #define ll_getRPAListEntry _symrom_ll_getRPAListEntry + #define ll_hw_clr_irq _symrom_ll_hw_clr_irq + #define ll_hw_config _symrom_ll_hw_config + #define ll_hw_get_anchor _symrom_ll_hw_get_anchor + #define ll_hw_get_fsm_status _symrom_ll_hw_get_fsm_status + #define ll_hw_get_iq_RawSample _symrom_ll_hw_get_iq_RawSample + #define ll_hw_get_irq_status _symrom_ll_hw_get_irq_status + #define ll_hw_get_last_ack _symrom_ll_hw_get_last_ack + #define ll_hw_get_loop_cycle _symrom_ll_hw_get_loop_cycle + #define ll_hw_get_loop_time _symrom_ll_hw_get_loop_time + #define ll_hw_get_nAck _symrom_ll_hw_get_nAck + #define ll_hw_get_rfifo_depth _symrom_ll_hw_get_rfifo_depth + #define ll_hw_get_rfifo_info _symrom_ll_hw_get_rfifo_info + #define ll_hw_get_rxPkt_CrcErr_num _symrom_ll_hw_get_rxPkt_CrcErr_num + #define ll_hw_get_rxPkt_CrcOk_num _symrom_ll_hw_get_rxPkt_CrcOk_num + #define ll_hw_get_rxPkt_num _symrom_ll_hw_get_rxPkt_num + #define ll_hw_get_rxPkt_stats _symrom_ll_hw_get_rxPkt_stats + #define ll_hw_get_rxPkt_Total_num _symrom_ll_hw_get_rxPkt_Total_num + #define ll_hw_get_snNesn _symrom_ll_hw_get_snNesn + #define ll_hw_get_tfifo_info _symrom_ll_hw_get_tfifo_info + #define ll_hw_get_tfifo_wrptr _symrom_ll_hw_get_tfifo_wrptr + #define ll_hw_get_tr_mode _symrom_ll_hw_get_tr_mode + #define ll_hw_get_txAck _symrom_ll_hw_get_txAck + #define ll_hw_go _symrom_ll_hw_go + #define ll_hw_ign_rfifo _symrom_ll_hw_ign_rfifo + #define ll_hw_process_RTO _symrom_ll_hw_process_RTO + #define ll_hw_read_rfifo _symrom_ll_hw_read_rfifo + #define ll_hw_read_rfifo_pplus _symrom_ll_hw_read_rfifo_pplus + #define ll_hw_read_rfifo_zb _symrom_ll_hw_read_rfifo_zb + #define ll_hw_read_tfifo_packet _symrom_ll_hw_read_tfifo_packet + #define ll_hw_read_tfifo_rtlp _symrom_ll_hw_read_tfifo_rtlp + #define ll_hw_rst_rfifo _symrom_ll_hw_rst_rfifo + #define ll_hw_rst_tfifo _symrom_ll_hw_rst_tfifo + #define ll_hw_set_ant_pattern _symrom_ll_hw_set_ant_pattern + #define ll_hw_set_ant_switch_mode _symrom_ll_hw_set_ant_switch_mode + #define ll_hw_set_ant_switch_timing _symrom_ll_hw_set_ant_switch_timing + #define ll_hw_set_crc_fmt _symrom_ll_hw_set_crc_fmt + #define ll_hw_set_cte_rxSupp _symrom_ll_hw_set_cte_rxSupp + #define ll_hw_set_cte_txSupp _symrom_ll_hw_set_cte_txSupp + #define ll_hw_set_empty_head _symrom_ll_hw_set_empty_head + #define ll_hw_set_irq _symrom_ll_hw_set_irq + #define ll_hw_set_loop_nack_num _symrom_ll_hw_set_loop_nack_num + #define ll_hw_set_loop_timeout _symrom_ll_hw_set_loop_timeout + #define ll_hw_set_pplus_pktfmt _symrom_ll_hw_set_pplus_pktfmt + #define ll_hw_set_rtlp _symrom_ll_hw_set_rtlp + #define ll_hw_set_rtlp_1st _symrom_ll_hw_set_rtlp_1st + #define ll_hw_set_rtx _symrom_ll_hw_set_rtx + #define ll_hw_set_rx_timeout _symrom_ll_hw_set_rx_timeout + #define ll_hw_set_rx_timeout_1st _symrom_ll_hw_set_rx_timeout_1st + #define ll_hw_set_rx_tx_interval _symrom_ll_hw_set_rx_tx_interval + #define ll_hw_set_srx _symrom_ll_hw_set_srx + #define ll_hw_set_stx _symrom_ll_hw_set_stx + #define ll_hw_set_tfifo_space _symrom_ll_hw_set_tfifo_space + #define ll_hw_set_timing _symrom_ll_hw_set_timing + #define ll_hw_set_trlp _symrom_ll_hw_set_trlp + #define ll_hw_set_trx _symrom_ll_hw_set_trx + #define ll_hw_set_trx_settle _symrom_ll_hw_set_trx_settle + #define ll_hw_set_tx_rx_interval _symrom_ll_hw_set_tx_rx_interval + #define ll_hw_set_tx_rx_release _symrom_ll_hw_set_tx_rx_release + #define ll_hw_trigger _symrom_ll_hw_trigger + #define ll_hw_trx_settle_config _symrom_ll_hw_trx_settle_config + #define ll_hw_tx2rx_timing_config _symrom_ll_hw_tx2rx_timing_config + #define ll_hw_update _symrom_ll_hw_update + #define ll_hw_update_rtlp_mode _symrom_ll_hw_update_rtlp_mode + #define ll_hw_update_trlp_mode _symrom_ll_hw_update_trlp_mode + #define ll_hw_write_tfifo _symrom_ll_hw_write_tfifo + #define LL_Init _symrom_LL_Init + #define LL_InitConnectContext _symrom_LL_InitConnectContext + #define LL_InitExtendedAdv _symrom_LL_InitExtendedAdv + #define LL_InitExtendedScan _symrom_LL_InitExtendedScan + #define LL_InitPeriodicAdv _symrom_LL_InitPeriodicAdv + #define LL_IRQHandler _symrom_LL_IRQHandler + #define ll_isAddrInWhiteList _symrom_ll_isAddrInWhiteList + #define ll_isFirstAdvChn _symrom_ll_isFirstAdvChn + #define LL_master_conn_event _symrom_LL_master_conn_event + #define LL_NumEmptyWlEntries _symrom_LL_NumEmptyWlEntries + #define ll_parseExtHeader _symrom_ll_parseExtHeader + #define LL_PeriodicAdvertisingCreateSync _symrom_LL_PeriodicAdvertisingCreateSync + #define LL_PeriodicAdvertisingCreateSyncCancel _symrom_LL_PeriodicAdvertisingCreateSyncCancel + #define LL_PeriodicAdvertisingTerminateSync _symrom_LL_PeriodicAdvertisingTerminateSync + #define LL_PhyUpdate _symrom_LL_PhyUpdate + #define LL_PhyUpdateCompleteCback _symrom_LL_PhyUpdateCompleteCback + #define LL_PLUS_AdvDataFilterCBack _symrom_LL_PLUS_AdvDataFilterCBack + #define LL_PLUS_DisableSlaveLatency _symrom_LL_PLUS_DisableSlaveLatency + #define LL_PLUS_EnableSlaveLatency _symrom_LL_PLUS_EnableSlaveLatency + #define LL_PLUS_GetAdvDataExtendData _symrom_LL_PLUS_GetAdvDataExtendData + #define LL_PLUS_GetScanerAddr _symrom_LL_PLUS_GetScanerAddr + #define LL_PLUS_GetScanRequestExtendData _symrom_LL_PLUS_GetScanRequestExtendData + #define LL_PLUS_PerStasReadByChn _symrom_LL_PLUS_PerStasReadByChn + #define LL_PLUS_PerStats_Init _symrom_LL_PLUS_PerStats_Init + #define LL_PLUS_PerStatsReset _symrom_LL_PLUS_PerStatsReset + #define LL_PLUS_ScanRequestFilterCBack _symrom_LL_PLUS_ScanRequestFilterCBack + #define LL_PLUS_SetAdvDataFilterCB _symrom_LL_PLUS_SetAdvDataFilterCB + #define LL_PLUS_SetScanRequestData _symrom_LL_PLUS_SetScanRequestData + #define LL_PLUS_SetScanRequestFilterCB _symrom_LL_PLUS_SetScanRequestFilterCB + #define LL_PLUS_SetScanRsqData _symrom_LL_PLUS_SetScanRsqData + #define LL_PLUS_SetScanRsqDataByIndex _symrom_LL_PLUS_SetScanRsqDataByIndex + #define ll_prd_adv_schedule_next_event _symrom_ll_prd_adv_schedule_next_event + #define ll_prd_scan_schedule_next_event _symrom_ll_prd_scan_schedule_next_event + #define LL_PrdAdvReportCback _symrom_LL_PrdAdvReportCback + #define LL_PrdAdvSyncEstablishedCback _symrom_LL_PrdAdvSyncEstablishedCback + #define LL_PrdAdvSyncLostCback _symrom_LL_PrdAdvSyncLostCback + #define LL_prdAdvTimerExpProcess _symrom_LL_prdAdvTimerExpProcess + #define LL_prdScanTimerExpProcess _symrom_LL_prdScanTimerExpProcess + #define ll_processBasicIRQ _symrom_ll_processBasicIRQ + #define LL_ProcessEvent _symrom_LL_ProcessEvent + #define ll_processExtAdvIRQ _symrom_ll_processExtAdvIRQ + #define ll_processExtInitIRQ _symrom_ll_processExtInitIRQ + #define ll_processExtScanIRQ _symrom_ll_processExtScanIRQ + #define ll_processMissMasterEvt _symrom_ll_processMissMasterEvt + #define ll_processMissSlaveEvt _symrom_ll_processMissSlaveEvt + #define ll_processPrdAdvIRQ _symrom_ll_processPrdAdvIRQ + #define ll_processPrdScanIRQ _symrom_ll_processPrdScanIRQ + #define LL_PseudoRand _symrom_LL_PseudoRand + #define LL_Rand _symrom_LL_Rand + #define LL_RandCback _symrom_LL_RandCback + #define LL_READ_Anatenna_Info _symrom_LL_READ_Anatenna_Info + #define ll_read_rxfifo _symrom_ll_read_rxfifo + #define LL_ReadAdvChanTxPower _symrom_LL_ReadAdvChanTxPower + #define LL_ReadBDADDR _symrom_LL_ReadBDADDR + #define LL_ReadCarrSens _symrom_LL_ReadCarrSens + #define LL_ReadChanMap _symrom_LL_ReadChanMap + #define LL_ReadFoff _symrom_LL_ReadFoff + #define ll_readLocalIRK _symrom_ll_readLocalIRK + #define LL_ReadLocalSupportedFeatures _symrom_LL_ReadLocalSupportedFeatures + #define LL_ReadLocalVersionInfo _symrom_LL_ReadLocalVersionInfo + #define LL_ReadMaximumAdvDataLength _symrom_LL_ReadMaximumAdvDataLength + #define LL_ReadNumberOfSupportAdvSet _symrom_LL_ReadNumberOfSupportAdvSet + #define LL_ReadRemoteUsedFeatures _symrom_LL_ReadRemoteUsedFeatures + #define LL_ReadRemoteUsedFeaturesCompleteCback _symrom_LL_ReadRemoteUsedFeaturesCompleteCback + #define LL_ReadRemoteVersionInfo _symrom_LL_ReadRemoteVersionInfo + #define LL_ReadRemoteVersionInfoCback _symrom_LL_ReadRemoteVersionInfoCback + #define LL_ReadResolvingListSize _symrom_LL_ReadResolvingListSize + #define LL_ReadRssi _symrom_LL_ReadRssi + #define LL_ReadSupportedStates _symrom_LL_ReadSupportedStates + #define LL_ReadTxPowerLevel _symrom_LL_ReadTxPowerLevel + #define LL_ReadWlSize _symrom_LL_ReadWlSize + #define ll_remain_time _symrom_ll_remain_time + #define LL_RemoveAdvSet _symrom_LL_RemoveAdvSet + #define LL_RemoveResolvingListDevice _symrom_LL_RemoveResolvingListDevice + #define LL_RemoveWhiteListDevice _symrom_LL_RemoveWhiteListDevice + #define LL_Reset _symrom_LL_Reset + #define ll_ResolveRandomAddrs _symrom_ll_ResolveRandomAddrs + #define LL_RX_bm_alloc _symrom_LL_RX_bm_alloc + #define LL_RxDataCompleteCback _symrom_LL_RxDataCompleteCback + #define ll_schedule_next_event _symrom_ll_schedule_next_event + #define ll_scheduler _symrom_ll_scheduler + #define LL_Set_ConnectionCTE_ReceiveParam _symrom_LL_Set_ConnectionCTE_ReceiveParam + #define LL_Set_ConnectionCTE_TransmitParam _symrom_LL_Set_ConnectionCTE_TransmitParam + #define LL_set_default_conn_params _symrom_LL_set_default_conn_params + #define LL_SetAddressResolutionEnable _symrom_LL_SetAddressResolutionEnable + #define LL_SetAdvControl _symrom_LL_SetAdvControl + #define LL_SetAdvData _symrom_LL_SetAdvData + #define LL_SetAdvParam _symrom_LL_SetAdvParam + #define LL_SetDataLengh _symrom_LL_SetDataLengh + #define LL_SetDefaultPhyMode _symrom_LL_SetDefaultPhyMode + #define LL_SetExtAdvData _symrom_LL_SetExtAdvData + #define LL_SetExtAdvEnable _symrom_LL_SetExtAdvEnable + #define LL_SetExtAdvParam _symrom_LL_SetExtAdvParam + #define LL_SetExtAdvSetRandomAddress _symrom_LL_SetExtAdvSetRandomAddress + #define LL_SetExtendedScanEnable _symrom_LL_SetExtendedScanEnable + #define LL_SetExtendedScanParameters _symrom_LL_SetExtendedScanParameters + #define LL_SetExtScanRspData _symrom_LL_SetExtScanRspData + #define LL_SetPeriodicAdvData _symrom_LL_SetPeriodicAdvData + #define LL_SetPeriodicAdvEnable _symrom_LL_SetPeriodicAdvEnable + #define LL_SetPeriodicAdvParameter _symrom_LL_SetPeriodicAdvParameter + #define LL_SetPhyMode _symrom_LL_SetPhyMode + #define LL_SetRandomAddress _symrom_LL_SetRandomAddress + #define LL_SetResolvablePrivateAddressTimeout _symrom_LL_SetResolvablePrivateAddressTimeout + #define LL_SetScanControl _symrom_LL_SetScanControl + #define LL_SetScanParam _symrom_LL_SetScanParam + #define LL_SetScanRspData _symrom_LL_SetScanRspData + #define LL_SetTxPowerLevel _symrom_LL_SetTxPowerLevel + #define LL_slave_conn_event _symrom_LL_slave_conn_event + #define LL_StartEncrypt _symrom_LL_StartEncrypt + #define LL_TaskID _symrom_LL_TaskID + #define LL_TX_bm_alloc _symrom_LL_TX_bm_alloc + #define LL_TxData _symrom_LL_TxData + #define ll_updateAuxAdvTimeSlot _symrom_ll_updateAuxAdvTimeSlot + #define ll_updateExtAdvRemainderTime _symrom_ll_updateExtAdvRemainderTime + #define LL_WriteSuggestedDefaultDataLength _symrom_LL_WriteSuggestedDefaultDataLength + #define ll24BitTimeCompare _symrom_ll24BitTimeCompare + #define llAdjSlaveLatencyValue _symrom_llAdjSlaveLatencyValue + #define llAllocateSyncHandle _symrom_llAllocateSyncHandle + #define llAllocConnId _symrom_llAllocConnId + #define llAtLeastTwoChans _symrom_llAtLeastTwoChans + #define llCalcMaxScanTime _symrom_llCalcMaxScanTime + #define llCalcScaFactor _symrom_llCalcScaFactor + #define llCalcTimerDrift _symrom_llCalcTimerDrift + #define llCheckForLstoDuringSL _symrom_llCheckForLstoDuringSL + #define llCheckWhiteListUsage _symrom_llCheckWhiteListUsage + #define llConnCleanup _symrom_llConnCleanup + #define llConnTerminate _symrom_llConnTerminate + #define llConvertCtrlProcTimeoutToEvent _symrom_llConvertCtrlProcTimeoutToEvent + #define llConvertLstoToEvent _symrom_llConvertLstoToEvent + #define llCurrentScanChn _symrom_llCurrentScanChn + #define llDeleteSyncHandle _symrom_llDeleteSyncHandle + #define llDequeueCtrlPkt _symrom_llDequeueCtrlPkt + #define llDequeueDataQ _symrom_llDequeueDataQ + #define llEnqueueCtrlPkt _symrom_llEnqueueCtrlPkt + #define llEnqueueDataQ _symrom_llEnqueueDataQ + #define llEqAlreadyValidAddr _symrom_llEqAlreadyValidAddr + #define llEqSynchWord _symrom_llEqSynchWord + #define llEqualBytes _symrom_llEqualBytes + #define llEventDelta _symrom_llEventDelta + #define llEventInRange _symrom_llEventInRange + #define llGenerateCRC _symrom_llGenerateCRC + #define llGenerateValidAccessAddr _symrom_llGenerateValidAccessAddr + #define llGetNextAdvChn _symrom_llGetNextAdvChn + #define llGetNextAuxAdvChn _symrom_llGetNextAuxAdvChn + #define llGetNextDataChan _symrom_llGetNextDataChan + #define llGetNextDataChanCSA2 _symrom_llGetNextDataChanCSA2 + #define llGtSixConsecZerosOrOnes _symrom_llGtSixConsecZerosOrOnes + #define llGtTwentyFourTransitions _symrom_llGtTwentyFourTransitions + #define llInitFeatureSet _symrom_llInitFeatureSet + #define llInitFeatureSet2MPHY _symrom_llInitFeatureSet2MPHY + #define llInitFeatureSetCodedPHY _symrom_llInitFeatureSetCodedPHY + #define llInitFeatureSetDLE _symrom_llInitFeatureSetDLE + #define llLtTwoChangesInLastSixBits _symrom_llLtTwoChangesInLastSixBits + #define llMasterEvt_TaskEndOk _symrom_llMasterEvt_TaskEndOk + #define llMemCopyDst _symrom_llMemCopyDst + #define llMemCopySrc _symrom_llMemCopySrc + #define llOneBitSynchWordDiffer _symrom_llOneBitSynchWordDiffer + #define llPduLengthManagmentReset _symrom_llPduLengthManagmentReset + #define llPduLengthUpdate _symrom_llPduLengthUpdate + #define llPendingUpdateParam _symrom_llPendingUpdateParam + #define llPhyModeCtrlReset _symrom_llPhyModeCtrlReset + #define llPhyModeCtrlUpdateNotify _symrom_llPhyModeCtrlUpdateNotify + #define llProcessChanMap _symrom_llProcessChanMap + #define llProcessMasterControlPacket _symrom_llProcessMasterControlPacket + #define llProcessMasterControlProcedures _symrom_llProcessMasterControlProcedures + #define llProcessRxData _symrom_llProcessRxData + #define llProcessSlaveControlPacket _symrom_llProcessSlaveControlPacket + #define llProcessSlaveControlProcedures _symrom_llProcessSlaveControlProcedures + #define llProcessTxData _symrom_llProcessTxData + #define llReleaseAllConnId _symrom_llReleaseAllConnId + #define llReleaseConnId _symrom_llReleaseConnId + #define llReplaceCtrlPkt _symrom_llReplaceCtrlPkt + #define llResetConnId _symrom_llResetConnId + #define llResetRfCounters _symrom_llResetRfCounters + #define llScanT1 _symrom_llScanT1 + #define llScanTime _symrom_llScanTime + #define llSecAdvAllow _symrom_llSecAdvAllow + #define llSecondaryState _symrom_llSecondaryState + #define llSetNextDataChan _symrom_llSetNextDataChan + #define llSetNextPhyMode _symrom_llSetNextPhyMode + #define llSetupAdv _symrom_llSetupAdv + #define llSetupAdvExtIndPDU _symrom_llSetupAdvExtIndPDU + #define llSetupAuxAdvIndPDU _symrom_llSetupAuxAdvIndPDU + #define llSetupAuxChainIndPDU _symrom_llSetupAuxChainIndPDU + #define llSetupAuxConnectReqPDU _symrom_llSetupAuxConnectReqPDU + #define llSetupAuxConnectRspPDU _symrom_llSetupAuxConnectRspPDU + #define llSetupAuxScanRspPDU _symrom_llSetupAuxScanRspPDU + #define llSetupAuxSyncIndPDU _symrom_llSetupAuxSyncIndPDU + #define llSetupConn _symrom_llSetupConn + #define llSetupCTEReq _symrom_llSetupCTEReq + #define llSetupCTERsp _symrom_llSetupCTERsp + #define llSetupDataLenghtReq _symrom_llSetupDataLenghtReq + #define llSetupDataLenghtRsp _symrom_llSetupDataLenghtRsp + #define llSetupDirectedAdvEvt _symrom_llSetupDirectedAdvEvt + #define llSetupEncReq _symrom_llSetupEncReq + #define llSetupEncRsp _symrom_llSetupEncRsp + #define llSetupExtAdvEvent _symrom_llSetupExtAdvEvent + #define llSetupExtInit _symrom_llSetupExtInit + #define llSetupExtScan _symrom_llSetupExtScan + #define llSetupFeatureSetReq _symrom_llSetupFeatureSetReq + #define llSetupFeatureSetRsp _symrom_llSetupFeatureSetRsp + #define llSetupInit _symrom_llSetupInit + #define llSetupNextMasterEvent _symrom_llSetupNextMasterEvent + #define llSetupNextSlaveEvent _symrom_llSetupNextSlaveEvent + #define llSetupNonConnectableAdvEvt _symrom_llSetupNonConnectableAdvEvt + #define llSetupPauseEncReq _symrom_llSetupPauseEncReq + #define llSetupPauseEncRsp _symrom_llSetupPauseEncRsp + #define llSetupPhyReq _symrom_llSetupPhyReq + #define llSetupPhyRsp _symrom_llSetupPhyRsp + #define llSetupPhyUpdateInd _symrom_llSetupPhyUpdateInd + #define llSetupPrdAdvEvent _symrom_llSetupPrdAdvEvent + #define llSetupPrdScan _symrom_llSetupPrdScan + #define llSetupRejectExtInd _symrom_llSetupRejectExtInd + #define llSetupRejectInd _symrom_llSetupRejectInd + #define llSetupScan _symrom_llSetupScan + #define llSetupScanInit _symrom_llSetupScanInit + #define llSetupScannableAdvEvt _symrom_llSetupScannableAdvEvt + #define llSetupSecAdvEvt _symrom_llSetupSecAdvEvt + #define llSetupSecConnectableAdvEvt _symrom_llSetupSecConnectableAdvEvt + #define llSetupSecInit _symrom_llSetupSecInit + #define llSetupSecNonConnectableAdvEvt _symrom_llSetupSecNonConnectableAdvEvt + #define llSetupSecScan _symrom_llSetupSecScan + #define llSetupSecScannableAdvEvt _symrom_llSetupSecScannableAdvEvt + #define llSetupStartEncReq _symrom_llSetupStartEncReq + #define llSetupStartEncRsp _symrom_llSetupStartEncRsp + #define llSetupSyncInfo _symrom_llSetupSyncInfo + #define llSetupTermInd _symrom_llSetupTermInd + #define llSetupUndirectedAdvEvt _symrom_llSetupUndirectedAdvEvt + #define llSetupUnknownRsp _symrom_llSetupUnknownRsp + #define llSetupUpdateChanReq _symrom_llSetupUpdateChanReq + #define llSetupUpdateParamReq _symrom_llSetupUpdateParamReq + #define llSetupVersionIndReq _symrom_llSetupVersionIndReq + #define llSlaveEvt_TaskAbort _symrom_llSlaveEvt_TaskAbort + #define llSlaveEvt_TaskEndOk _symrom_llSlaveEvt_TaskEndOk + #define llState _symrom_llState + #define llTaskState _symrom_llTaskState + #define llTrxNumAdaptiveConfig _symrom_llTrxNumAdaptiveConfig + #define llValidAccessAddr _symrom_llValidAccessAddr + #define llWaitingIrq _symrom_llWaitingIrq + #define llWaitUs _symrom_llWaitUs + #define llWriteTxData _symrom_llWriteTxData + #define log_clr_putc _symrom_log_clr_putc + #define log_debug_level _symrom_log_debug_level + #define log_get_debug_level _symrom_log_get_debug_level + #define log_printf _symrom_log_printf + #define log_set_putc _symrom_log_set_putc + #define log_vsprintf _symrom_log_vsprintf + #define move_to_master_function _symrom_move_to_master_function + #define move_to_slave_function _symrom_move_to_slave_function + #define NMI_Handler _symrom_NMI_Handler + #define numComplPkts _symrom_numComplPkts + #define numComplPktsLimit _symrom_numComplPktsLimit + #define numHostBufs _symrom_numHostBufs + #define osal_bm_adjust_header _symrom_osal_bm_adjust_header + #define osal_bm_adjust_tail _symrom_osal_bm_adjust_tail + #define osal_bm_alloc _symrom_osal_bm_alloc + #define osal_bm_free _symrom_osal_bm_free + #define osal_buffer_uint24 _symrom_osal_buffer_uint24 + #define osal_buffer_uint32 _symrom_osal_buffer_uint32 + #define osal_build_uint16 _symrom_osal_build_uint16 + #define osal_build_uint32 _symrom_osal_build_uint32 + #define osal_CbTimerInit _symrom_osal_CbTimerInit + #define osal_CbTimerProcessEvent _symrom_osal_CbTimerProcessEvent + #define osal_CbTimerStart _symrom_osal_CbTimerStart + #define osal_CbTimerStop _symrom_osal_CbTimerStop + #define osal_CbTimerUpdate _symrom_osal_CbTimerUpdate + #define osal_clear_event _symrom_osal_clear_event + #define osal_ConvertUTCSecs _symrom_osal_ConvertUTCSecs + #define osal_ConvertUTCTime _symrom_osal_ConvertUTCTime + #define osal_get_timeoutEx _symrom_osal_get_timeoutEx + #define osal_getClock _symrom_osal_getClock + #define osal_GetSystemClock _symrom_osal_GetSystemClock + #define osal_init_system _symrom_osal_init_system + #define osal_isbufset _symrom_osal_isbufset + #define osal_mem_alloc _symrom_osal_mem_alloc + #define osal_mem_free _symrom_osal_mem_free + #define osal_mem_init _symrom_osal_mem_init + #define osal_mem_kick _symrom_osal_mem_kick + #define osal_mem_set_heap _symrom_osal_mem_set_heap + #define osal_memcmp _symrom_osal_memcmp + #define osal_memcpy _symrom_osal_memcpy + #define osal_memdup _symrom_osal_memdup + #define osal_memset _symrom_osal_memset + #define osal_msg_allocate _symrom_osal_msg_allocate + #define osal_msg_deallocate _symrom_osal_msg_deallocate + #define osal_msg_dequeue _symrom_osal_msg_dequeue + #define osal_msg_enqueue _symrom_osal_msg_enqueue + #define osal_msg_enqueue_max _symrom_osal_msg_enqueue_max + #define osal_msg_extract _symrom_osal_msg_extract + #define osal_msg_find _symrom_osal_msg_find + #define osal_msg_push _symrom_osal_msg_push + #define osal_msg_push_front _symrom_osal_msg_push_front + #define osal_msg_receive _symrom_osal_msg_receive + #define osal_msg_send _symrom_osal_msg_send + #define osal_next_timeout _symrom_osal_next_timeout + #define osal_pwrmgr_device _symrom_osal_pwrmgr_device + #define osal_pwrmgr_init _symrom_osal_pwrmgr_init + #define osal_pwrmgr_powerconserve _symrom_osal_pwrmgr_powerconserve + #define osal_pwrmgr_task_state _symrom_osal_pwrmgr_task_state + #define osal_qHead _symrom_osal_qHead + #define osal_rand _symrom_osal_rand + #define osal_revmemcpy _symrom_osal_revmemcpy + #define osal_run_system _symrom_osal_run_system + #define osal_self _symrom_osal_self + #define osal_set_event _symrom_osal_set_event + #define osal_setClock _symrom_osal_setClock + #define osal_start_reload_timer _symrom_osal_start_reload_timer + #define osal_start_system _symrom_osal_start_system + #define osal_start_timerEx _symrom_osal_start_timerEx + #define osal_stop_timerEx _symrom_osal_stop_timerEx + #define osal_strlen _symrom_osal_strlen + #define osal_sys_tick _symrom_osal_sys_tick + #define osal_timer_num_active _symrom_osal_timer_num_active + #define OSAL_timeSeconds _symrom_OSAL_timeSeconds + #define osalAddTimer _symrom_osalAddTimer + #define osalDeleteTimer _symrom_osalDeleteTimer + #define osalFindTimer _symrom_osalFindTimer + #define osalTimerInit _symrom_osalTimerInit + #define osalTimerUpdate _symrom_osalTimerUpdate + #define osalTimeUpdate _symrom_osalTimeUpdate + #define osalTimeUpdate1 _symrom_osalTimeUpdate1 + #define ownPublicAddr _symrom_ownPublicAddr + #define p_perStatsByChan _symrom_p_perStatsByChan + #define peerInfo _symrom_peerInfo + #define PendSV_Handler _symrom_PendSV_Handler + #define pHciEvtMask _symrom_pHciEvtMask + #define phy_sec_app_key _symrom_phy_sec_app_key + #define phy_sec_decrypt _symrom_phy_sec_decrypt + #define phy_sec_efuse_lock _symrom_phy_sec_efuse_lock + #define phy_sec_encrypt _symrom_phy_sec_encrypt + #define phy_sec_init _symrom_phy_sec_init + #define phy_sec_key_valid _symrom_phy_sec_key_valid + #define prog_process_data _symrom_prog_process_data + #define prog_uart_command _symrom_prog_uart_command + #define prog_uart_fct_command _symrom_prog_uart_fct_command + #define prog_uart_handle _symrom_prog_uart_handle + #define pwrmgr_attribute _symrom_pwrmgr_attribute + #define read_current_fine_time _symrom_read_current_fine_time + #define read_ll_adv_remainder_time _symrom_read_ll_adv_remainder_time + #define read_LL_remainder_time _symrom_read_LL_remainder_time + #define receive_timeout_flag _symrom_receive_timeout_flag + #define reset_conn_buf _symrom_reset_conn_buf + //#define rf_calibrate _symrom_rf_calibrate + //#define rf_init _symrom_rf_init + //#define rf_phy_ana_cfg _symrom_rf_phy_ana_cfg + //#define rf_phy_bb_cfg _symrom_rf_phy_bb_cfg + //#define rf_phy_change_cfg _symrom_rf_phy_change_cfg + //#define rf_phy_direct_test_ate _symrom_rf_phy_direct_test_ate + //#define rf_phy_get_pktFoot _symrom_rf_phy_get_pktFoot + //#define rf_phy_ini _symrom_rf_phy_ini + //#define rf_phy_set_txPower _symrom_rf_phy_set_txPower + //#define rf_rxDcoc_cfg _symrom_rf_rxDcoc_cfg + //#define rf_tp_cal _symrom_rf_tp_cal + //#define rf_tpCal_cfg _symrom_rf_tpCal_cfg + //#define rf_tpCal_cfg_avg _symrom_rf_tpCal_cfg_avg + //#define rf_tpCal_gen_cap_arrary _symrom_rf_tpCal_gen_cap_arrary + #define rfCounters _symrom_rfCounters + #define rom_board_init _symrom_rom_board_init + #define rtc_clear _symrom_rtc_clear + #define rtc_config_prescale _symrom_rtc_config_prescale + #define rtc_get_counter _symrom_rtc_get_counter + #define rtc_mod_value _symrom_rtc_mod_value + #define rtc_start _symrom_rtc_start + #define rtc_stop _symrom_rtc_stop + #define rxFifoFlowCtrl _symrom_rxFifoFlowCtrl + #define s_prog_time_save _symrom_s_prog_time_save + #define s_prog_timeout _symrom_s_prog_timeout + #define s_rom_debug_level _symrom_s_rom_debug_level + #define s_spif_ctx _symrom_s_spif_ctx + #define SCA _symrom_SCA + #define scanInfo _symrom_scanInfo + #define scanSyncInfo _symrom_scanSyncInfo + #define set_access_address _symrom_set_access_address + #define set_channel _symrom_set_channel + #define set_crc_seed _symrom_set_crc_seed + #define set_gpio_pull_down_ate _symrom_set_gpio_pull_down_ate + #define set_gpio_pull_up_ate _symrom_set_gpio_pull_up_ate + #define set_int _symrom_set_int + #define set_max_length _symrom_set_max_length + #define set_sleep_flag _symrom_set_sleep_flag + #define set_timer _symrom_set_timer + #define set_whiten_seed _symrom_set_whiten_seed + #define setSleepMode _symrom_setSleepMode + #define slave_conn_event_recv_delay _symrom_slave_conn_event_recv_delay + #define sleep_flag _symrom_sleep_flag + #define spif_cmd _symrom_spif_cmd + #define spif_erase_all _symrom_spif_erase_all + #define spif_erase_block64 _symrom_spif_erase_block64 + #define spif_erase_chip _symrom_spif_erase_chip + #define spif_erase_sector _symrom_spif_erase_sector + #define spif_flash_size _symrom_spif_flash_size + #define spif_flash_status_reg_0 _symrom_spif_flash_status_reg_0 + #define spif_flash_status_reg_1 _symrom_spif_flash_status_reg_1 + #define spif_init _symrom_spif_init + #define spif_rddata _symrom_spif_rddata + #define spif_read _symrom_spif_read + #define spif_release_deep_sleep _symrom_spif_release_deep_sleep + #define spif_set_deep_sleep _symrom_spif_set_deep_sleep + #define spif_wrdata _symrom_spif_wrdata + #define spif_write _symrom_spif_write + #define spif_write_protect _symrom_spif_write_protect + #define sram_ret_patch _symrom_sram_ret_patch + #define supportedCmdsTable _symrom_supportedCmdsTable + #define syncInfo _symrom_syncInfo + #define timerHead _symrom_timerHead + #define tx_scanRsp_desc _symrom_tx_scanRsp_desc + #define update_rx_read_ptr _symrom_update_rx_read_ptr + #define update_rx_write_ptr _symrom_update_rx_write_ptr + #define update_tx_read_ptr _symrom_update_tx_read_ptr + #define update_tx_write_ptr _symrom_update_tx_write_ptr + #define verInfo _symrom_verInfo + #define WaitRTCCount _symrom_WaitRTCCount + #define wakeup_init _symrom_wakeup_init + #define wakeup_init0 _symrom_wakeup_init0 + #define wakeupProcess _symrom_wakeupProcess + #define whiten_seed _symrom_whiten_seed + #define zigbee_crc16_gen _symrom_zigbee_crc16_gen + #define WaitUs _symrom_WaitUs + +#endif +#endif +

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 literal 0 HcmV?d00001 diff --git a/src/components/ethermind/lib/meshlibs/phyos/keil/libethermind_mesh_models.lib b/src/components/ethermind/lib/meshlibs/phyos/keil/libethermind_mesh_models.lib new file mode 100644 index 0000000000000000000000000000000000000000..beb3aefa759ccc80ff478428998677d2d12d731b GIT binary patch literal 695304 zcmb<-^>JflWMqH=Mg|QA1doBCgOd{^#cBc~88jFKxOlmkJUKfU8yFM{+`)nj23tkl z+BYz{aeMH%F-%}k$aLc<m*b9;?*vh(w?+lACgGz1&gD%5`748ad1z;Hl z25Py570oRITlu^gl$#_NRk}7XXfa=4)Z)Crq{V)LL5b0g!-HW8$aP#B1om=OWV=Zf zdRBBYayd&CGAc8!diVTu?f?JuayK)EyOq7VHZ(~vs0cHF+{j_4sA$K^s;FqkU6JJ` zT*%eIsv^vlwR%1qK-8x}ZmUSPT7sKIf;NrUAg>jNe&^$W~esuviP?BV{y9V%TNV7VeMNQi-G zP>2rYBJ4$XYR*;g6OH(r-KwLZ^z|k>4&HIrA zM3l{y1q?YVvfKm;IXW1)0t%TF19d?8bq0V)*@ zIuFQjJ>aUyaAPXu=wRZ?aC0i`tY|D`R$zL-z{0>IaRHPsncWyBD!TDNb7sL_J~xgE zP~B$G!NBEFXw z-g$X>oSe3{d9bn^k$Sz5%Bao`POiWrHWfE`DrZM7^N~~{mu6m73|hJuPFH5RT`uCR z5-jFaQG@G8*aOQY5^yCq`I1poFzp zdAWiD82kB^LjVttiAgzeA?^bY74-7Q9;N)TfU840g`+-V|MbeC_jH|aesb1i@qv5qoYKoJ>1(rKWI$9T! zb(}7$KVa0ezbO6yQd)4>h}zh&vf4=5K=Qs!Z$7&JI8Fs@>DQ*>kVV3-OjYq&NP>}62;`kaAbS`!1q zBpTH1tT@sv6Iz%FY*j!>vqBa^LKa|b0RmiHii#Gf^`bO9?I659vRkTxGVwc%De zrWrmA|C^xrpD*6bEFJ|oP!B!qORyWRy zz73{+3<|8P`80Vi*lTKDh*30J0LtkM8lD$o6!pPu2N{B0&o zh5woY7c$%$OBYr!D==s>T~zF3&}6@$)OkZD5!^0O=sY0Pu*pkF_yL1rQU=chu?!yu zvsk$hu?&-FISCc61{qJ8l7fa!otvg~^fp?HCH<$qj4b2U%`{B>^Rj4;V`vOPF;eF2yKDgJXk1gY`m;Vg#7& zAj9w=Y{7p;EkjUBB5 z0PBaCR1O zSm0CSSixApxI+5@laBO-7)1lHsSq1It1|<2IL?~$3*(w-R7#JzIRurTrm!zg>>M6Js5Hc z8+hF~HMlRtD5`+tkwHWMLX4s!nC&2=^}r(|(~YTutCXqItF*C$Lz#;!)2*x2F@td} z7f+_!sZypYt}@0>kf>K#V+Kg9tBj%gM46l?>#F|>{6`f!874gLNa|SFp#U#GI2X)R zl=A`Q7O_Q&(A=V3Aq{7P$`6pAiH!TC#FCQKBBVk?rHRsVqk993n|eo%o8Y|VO%I!t znvw z94lE@EO6Iw3o(ic zV77yd`U3_<*40_yy1Hd zfGsY$7R*vq0LP^SJpQyRWZ`U3Trwz;R2L-YWTxho#A8+ll+^{0I2D|i*i0U-5|LHG$!nppw+?D&>+K7 z;8MWh#<8JbFAJ7<|G%|;!#p=rFTvS8ZVW1HZnGp9RfT3MxG`v%USQN>yuhSobWzW1 zvJ=BaMg{(gEVrF(oqU3YyEyaRstWBjnJ;K~?&|PrPNfRyPfU^b{sSM<1` zr~!^&1$dlhxG`6%zl}!-QhDBsT*$&Y7V4ip7od0lSBTOtTZ~MMh=TRR(U5K8}LhmFEl$pmA?L zX#WOO8WJ1-DXD3Rr8y<>B}IvO#hE3U`FZhqrMXF|Me+G*@x>*n1;x-N0!oR?zyOLX z;`1l+2o!30%Y-GKK>bTtdCQ1W-s&Qiw;B&TGP2wlD+Eg!L1QPShpLzq8MHVrG*yF2 z-GktA_EhPCDvmN%MI|o=O~nhWD?s^^X%fpsW*qr*v7$UU{>0%ird=TeXM^*n0!jHZ zC$%g!2dRn1z(H|&+rNQ9U3?zLbcX5d9inr^=480Fw;XI?YISZEnc3LNGnID=Tf3tN z(<*%lMg;~%YsgFlD;Jl)x_Wf9KWL;epirR90@UleHP3ytqiq|E|mD;60o`ZC1df%3r>%??1+byDy z@d0R*??D9v6Z3?{6%x)MIvGkUS4cQBPf)1LcAHVcuE%uYW{InU_JhRAn&UTY%T2L{g zgjJ9E!p#yl1xdGS&mUIYEK#hKEd36i|6qgV38LEu$UQLBw91Dwt=fRw23#7v7q~SH zFT^NXf@=^4jfe{|ie_N8gG?~IeZbfOZUdAuLfQZznh)GQsN^bZgvgaSLgYX+NUn^j zimRNVlYz^loJ-L`K?cLDri!joN3h;grA$cXG*xz$F;$%^1L@@`SMuOgWL*Wy1Mvm>4G{L20E5 z0cXYu4=Nd$m?m_A#h4~|R&Y3j_==Sr&P)>$s=)oPM#U;{|ErM;+>c>gVelZ+jiX%7 z)6=QXiRogdn@2e)$2*lLR4_7SxG^>k)Y;ZjV9aA8sEkORb083knKcj*RC~YdbLdOO2E--54UW^5$ z$&$blCQuqG@qmpCfWs2feu@CILG7nd57@{+2)q}p>=v=85&y^lSUMcK_7JT3ql4M80j;0Na?__zSrB#67k!EBJbMLb~R0>W?;LE{3ZaGo`ETmWRg z19)7(99n{58yA4hiQ#Jx!u!``^zA(u7#IlXr+VL>$*p|@qXGjn@`@J@Pv(gno-7kN zJlQ5PBaJK~uXzFG1!N4$_nZ|iYtXonhKX;eQHQ*hlMS}1L+0-73B@}z-?|dcsm=^XVQZ67!*Kl zK^9%s3xaL}MI0rJD_AFRKA2UJ>Bd!btHP`3>+>u(f#Seoff5a9K44kRyozfj`wCD^ z&Nk!zbI@7{rX~gkBF9KD!WLiN0gb)E(tlZEPHCz_ewu=Ro_|`J6=Y}?(Qnez(}RqK z5#Mh@o)JZDPjF(b$5`DsD(w9FHt@KyXh>gR)iA!mronrGUBe2gO&W&OCJlu5p%_53 z_oYmVb{=MMF-X6vsS?t!VyXo7t03*uQ>6`+pnjFH2ZKC=ru_v_dlb?aW9VQ~WZ()Y z)$wSM6NI!J~zXS8QhXfbUWB825QSq z<(typuI|C0s3pOu0GS!(WD^rJ6f|@;xLemKy_;Koh8im*pnVw4h=_39G)~g^8ss3IateD?p_Ky?N+(guSn|5Wx4@p%%U zK0CNYDG zqM;_Z)I}btYUl#Zn>cqV!^>V>4^SFm2en&@SXM9@h=E#jWrALlYn3tZar{J5J2QFbvA{6Wt zd=o3698d`hi!NX*D` z;{=UPsmOb=uKuscxK{2cX6t}+!DK~w0<8m(e~7HRAVGvyg9%Ywu0h6wNg3m3CNRbi zTjxf69N`|9VJ9Yzpg92?M_@K;90}r!BabPHg5Wsfgtyv2{ViB)4%C7J#Sy5SpggR5 zH!!F%O=Is6nJYXe!;QV!vAL=FaI?@%#ul!roKr++Hns|RC`d3~VAK$~$Ou~RUCQU_ z>D1%IZ~?UX+oM#Yf}@a0gXt!h2k(XtdzlqDiWyh1zxFT|1!V5t1l+&o)#SZkr>TA+M$r(QTNpIlFT^P7f!Pi+PFVWa z44Qlw5dCY83yB#FnyeRY$bj0|ka>GQqWjq1#PzYMKW|@JoLYosriRk_H)7`PS=!?L z85MlM{c~SE)(f#-n<6JowK zm<=-DV!?k!bMTzF8{GU1H|9=PyfgIL3;rtxfOX-Tp%*L+C`9dv^MdLp0yFfY3;ru6 zfz8D=L+=Uei5CVG+JSrGh#7iD)ERmP1`Y;?OT^F7la*Fr{Sb2I=n3ehY9IdpR#vz6 z4U+H~KGq^h4>3P+f3^v%iY(Kar-5epK(l)svq1Tq--AWbK?c+^VJT!S;`3mcE@Hqo z0ilW$tcuf(gWsRx6m_XW_LRi+yg&K{AD2dm-%8Bq)y(MR_iK&zU{6g=1z zISdH*pPnhof%{LQ@DW1g3Mn`nJX%Po|CE!No>8I?CgYP!kY=CMt0ln6$G3TN{N~M@ zH>YmS%G$qwGo%lrtq=kl5ihLtMxQxiX3B75Zd9mXb_UT8DnR_^#sy%0b7Ml~EGbr| z3^&#$g-TXu5WTdrwItJ{$w}gJjA8~jJwVE=R4^Mqdz%6*l>>U3}t`!U1g}|fopxHS^Z(a z<`$$DC6<&HrGh8HO(GQXOG`ilJkUM}Y>5+MWQRe)kAVSQudk<{zON&G&EPf|(d{p0 zq!CWkaUnLW0G z!2S3V$ZYnE2FPsoj0Q>NXvPClV%{^Hm@bQg+ZPWY^WBZ0ne}WpiAIG=iDGs=feR9D zk;P1jl=;EUUOza;#vOzQCP*#)IdHm662@D<#}!7QcEvzxMzC6lgvH zr!`PTNQLyqg)_ZD*2@`z(;IBP9G3MPm4c;>;Po3$)sS(!oHdf zG7dN$F%B46q6kVWB`=>(s{Q{zA38QeeE%GGnZ!*XjTjS3BUOT>jG(=qrSLRT1saQX zgs$;{q!Hpu9#9$~xCW23G*S$zA<$Pil+rP+7?Yh=WT3o(iT(7LY$QukG1&Qw5J z^ju|3m0r-bIbCHnLMawDn++2hE#6)(k^tM^O6~$m@ks_3C*v$TMhKUm&)ppya`(*dT}K zDKI?XdVqcP5BGxqicE%(7006RabWEVDLC7}?bUMzrJMNYThPl<_|l&`iu1+P4GgLx zQ|Gv`b;!<_o+C3m!;P)ovAwB1(d}TnzzV6Ej17WQgeI5ywKp!32K5!TIC)>-zf}d@pcn)m-F#z@+7SfkmtQqCJ?!tmS=yMXUA#t5)8{D)6{Snpcn< zWL^_C*Ah{|#FXL2)F@HGLiQUJs(T5^qT9p9l;PIaB2mHS45A^vKGXv7^`RDsJ&dgodl*}9RI)H-xVf~> zsAO>l(bJq5Z!842`9;7v4$|fq1hYYHe*Ohgo=V{Mpd>t<$-`Ni9vh#VfJ2XS#e(My z47E)R4CPITJ&-uY#&M=WO(q6{du1|8Q}q!Ay8c8*6^*6L3MQWF4-zsm-54r3N)0_36*%P;;e1_BMg5;Ggy1Xl1(<)7m1&DQWr z3RD`+byB(@bjQQXQhl}5R44BX?01rMQ!gazCSP#zy6O~iQSkwzw!;NxZU2j&53JQ8 z^TQn8tlpAxa^5-KS#AQQ7NFVR3oM}ZRHd129;M)ZL@6k|J<6>VI11TUNPkR;ukKBnzD}hN@Nq#cFX$-QEMyC8U60OZCb zUA_x}r3n=bOad*66-#6|oCR98$#G5*YqeDnDCAgi;(0*nd#G73RUkDW+4s+3dv)`% ztosA4{Sj7RV8XTbhZCu1jDPJ9n;VatM+PW=s9L)Da)Z}Nv$9C}8{1|uFoIUEK-ZN! zLDxTkM)(kGY#qSsA1pmYA23#Bxe?Po)dR1U2)>~5fUy>&qoE73QbNOnL00NPQypj@ zKvS((>A^10>fo+Yrn*z54Beo067rzgY*~&6jWr;B4p4nk9;j<43_2MmeC{af*w|qJ z-#rwg2q|MBcp1hkNXg$STQ0{65=dMIIN2L74)?kIQqJo!$m)B3*(9kczFV!#0kAY*A zU_n5Enu6j3&^|f?P!77tu_~Z|@d3vQ#{$Uui3yF6^%D~s7gPw8fY!YSmZ&KxKX_OX zSfW@tvE;{dh$*TH0);YQbL61;3d5uZs7VbADg=sH^@J`27O8?}910m%a7_>b=Nr}w zoU1v&`3BTmhvb}x6@f*Hl@p6zKy6Z2I0(*ZG!^zg2kqnbL2GjxK+l09XTL2Y z*7}3RjTf9h)cyK4XlU|Y(9{&cx$_N{qCqQvm=v`<1n{P3B~W@sS@(l|x71R~)}e#b zBXryk%!a1TlF|Z13Js%1`L8NC6|`y_lsehLBSVKNw?eVPU zUd0C*DVho@wckExU|3%J|9^B7WDO!{Xb9Ht$K8&heqW9UM>^!FhyeHHOf^z2m}%%< zFxT+BU@_?Wa>kH8B+@()_E{Sva9>OgLpAbfEAF1361eB5ask$6VwuQ5&%RtmCDPna z55;+BD!6=?a}$}&4C>9zm6?;_#*E&Zn<_M=y)ho8eCKoF$rr=%& z(+aBx4=Wu@6_NUE=14s?Q+Q9!4BAsO_2M)FwYU&HHRxW6Ht1f7Ht1f7Ht1f7Ht1f7 zHt1f7HgjlCO&OYF*;hk*YSR|DBYJAmUffviX>5Vm)7S#>>!B8iUk|k;RDx%?S`{EO zT&)i(L33cvtqUqab7Ib|6P*}u%ynYC$>wq9xdqtwoGW&N`dqdD|F=Nv9Ps!tbnF;X zKFA@><;r?Lvty$Z!^MmS28DlnJ!Kdt3TQsO%%t!Sde$Mx z+=8uqJ~9b>-W&zd9o_}fT-^oC$_yHO7rA_nF)WQ{&}F@FHe_k^ISE~^(t_DC4l)g! z1T;Qg7H$BYm*@%&JCHd)wu-s&xWy^4&6G+|C=l>qR(0w~DiGpYRM6DHpe1_YQGpPb zQlV1?t15#Q-vvfZ#tTV>oDZ_xPADD#uPSHIV7{2)#!!(^$fj!A@B{2Z(B4)C1r>i8 zH&Hh}H^vDE87iYTIx$~xkYSu4pz-~(fQI=60XGF_-isOF)**w2!o^HCjtb9;PIewX z7H17N1!wUK8E&mbM~WC{uuc&2V4fi4!7@R}lW7HL7GA)EQL#auvB0H(LD8|Ht${%S zG{4R`gUjat!vRT$3>IZpMTQAW}ZIBY=fm2_L-zMvzafk9zGgF*qzYSvXuD;Xw$e9fo; zT6fUg#k7jqg9W^b1$1^M$Uhtm3=A?`87Hv8O=R_8QD#;InfWAxan%BM8F0LS)cxN& zbpwN<{49kT*=~#zC7ZLodEI#2u1PT|X8F%@61~8AC)4|~MDhhjZJi5D+FBQwwQDb? zK48>ixe%e3aUoLgJBX(;%Zc#<;{!$&MpdT@whAGp3^y@n#%7iahHj!WKyFQY06S#^ z(%KJ&xAub;BzQJG@bhL=k(QqY+T9E_LCiVJO|V($0<)rEv*JuvP1y?!%2IAH^B5Ev zCJL`+TgAQ-WV+3R7)99X2v(%k5eyHk7kGH88U{T$T*0C!*vwRU?>QsrBvA!~UWEq? zNIc00+TM&R5yr?af%ruc>=%Xy)(=27BJ?xp8ePb6W9Sy1#l8}B&I;?4|B7-m7$-7K zVwfN?TWps2Oh^bYPLSO2VQ-A07})2KP=L%agZeyz3* z69WTiO(N*HST6vbgzyNAHhcq!Tfcl3KO$-cvO$-cOO$-d6 zc0pSc14Bm>0|Thsi(_D5&}m{|&~0L10Ph!KU|>*gVqoxRU|<04S?6zJVBl?HU;ypa zmTzKU zP-tRc5Nu*#5N={%5NTpy@L^zJ@MU0N&XQ1+M6cZl;u)H3CIL`)=)%}YULW@(26daS2 zQ;Ulg!a#e9AhH!k5y&M0&h;+n=S5*T;sIP-6~hjW!cnH7o0FTESDKcX3|bC@eH|;E z{RLU;4%@?n(yJ#rY#?U9*2|-r0XmC&1p@;^APWP7!Il!Y6gkz36q(gd43}ixl4GM8 z9!nVPk#N^w0QH*x|7T7t%1utzW?-t}6XIoHXJBV!XJTjOVBuipVB=tC=i%UEV30sc zBw`E<435GzEiA3fZA^Wjv%iTqM+V6p3$Qu0EzGS$kYWpnFw;Cjb1W?bAE0?eqL%`iIsw5 zkgo!Wo0*eZq+qINV5U%7kODfx%v?busWdYuMZwa{KvN+kKR?Gx0UQkq(IzRzW~M2z z3_J`jRxufc<@rU~po0iku4r1l3J3HT9liaml6ZE66`w|k;BNqzzpWFa12-fMuLMRGdUhLrsDGp zz#*5DSzN*(z{JSFzzPltT*|?R+Qnxi=B4DMG6=8}RG(N-kQ1Mr#2^4lln|pC7%m{f zn{~K`Hz+xQ$_Nl`cafR#C?gM!7)VZHU=;WQQpdo+0Mn8Q3*tU@28Kum1_l*@Zww3! z#fd2?MNoDMl+DA)z))P8l$Tlpix(9Ebw&n;#DaqC)Jm9GCM2R61lBS#Fo4b!%uGov zNsKQ@EK1B}0Gn;hz`y_z%t_5-5SYXWX=cX7#}}m*m*$i(fE~#gAi@|?lv+}jm;)6E z0dyzd#K^`5a?b+VyT=;p94AzFj0}|+KoTLIzF-MM11l3lD^sXwaEOa@e7u4oSP7UD z<{A|2>F);;w6wG|F!Vu4dH4s1xVnI35MrLe{_%zeW+rCw@d`!;24)84U^!P8cepwb z8)2#ml8Ru@DA)Lq$N-STO7n^{)ALeO6f*Nl;6?<51i5&+xxv)Hq>3}EQuEW|GxJIm zOu%ZP0y+74>8K(FB}GsH#~@#4=Xj_)6if}w3@ptIz?wrGgWO$1;++FR**Zi@8jtNR_E;I9`6j%;vekj6YuNJ!HxXODQZ;CNrC5@cbJ5fJl`MMFG7 zeVr7HkwXe>h@+Va*roCD$f_Mda>hoerUwN1yLtM!qFd_b>KGCl+odA3>YJFV8Tz#NH2uen70bui(85mg@bQmDz1_Q$tMh1ot47h4eP-hjC?G54T*Fe=1 zXzPPC*}*k|y12hUgV8uU2$)SxkO{VM6H*9Ti_yvf8Gw7-XK0LPA&-sOfXBw_TA2D6 zU4=`0xrFN+xpDiC@VM3=a2*W_C8Ec*aE-nW$#E`FN(PVaFc3Y?HRSydAIQS*6KH2G z9x@IlfjO>4Ks#!00?W7<0sZi9{yMnT3=AJg@7LkCW{8Z-g4(g5Tx$1`neh%{+zh|p zKm|9Vn+G$3&f{ooj0_Bvjia3yp>Yms`Ge#91lqV7fmo;dI2$MfQfZt`g9$#bKN_Yvg4D6l)?3m61I!}FkJ z4h&)|SU?kqRtyXbF(|U2pkinkq4^#ZV4wi7`_II}bv%*iF+YNqfyXZ4V}Q@V<3~h}0dAnb`zRh0JVAdq zL&petg_)~_nc2Vtgo2=f)g;hZD=&yu3}taLtFo!GvNE$nMqWADRKcpFz(bx=Y{F~` z%n~4_S&;F~273F2mH7xbeT;D)4eE!2#6dKuz-MBp zH2{@kAgsl}zyRVPjk~IV7QUg5HiCM(AYn!Z_%J1C* zIz&b}U_*>{XPFrfF~L{&A^QYW*dn^6Fb#AblLRd-q-;!b3F%`K$e}Pq;uAgsxdd$l z64@{D;JObHr!YP494d`BMvy+KF75L92mMi<{P*xf`MT}1X3-myfO zSr}u9=aI$|zc6ehVk{A~MGJi_aW>{y;sn&OL{R38LLW<<3>r&(#SH4}ftH3L#u7m@ z%AkP(28ln+h%rQvD1+E67Em{`0%R6^bP?37%LRp%#2OZadXOlC#6Bbu(1<33*bNqt zZcvaQ)PiL|Cd7=0G62+D2KmBbwo$#yJCgWbq6WbU7b^)rAa1AZ*WHSWoDge8p4l?!#S<6T>|Fbf$ z0;d<)NFzARLAegp@q>-Kff`FAa4jQf1Q0Z=2%@{7!;K&sR1bi}K{Tj@MjmbiWp9u; z(h9{Y1_lO@Fw)o}sCFm;4;8{k4?)vXkP-(j1hN;D>=+qBK(ZjK7#UF3V?tyDK^8(} z;d(()2$2l{>1_d97JyJVIxZPMy3TTRoh5jkC)VM|;jqpUH1`22$057?-XX2CL~cQV zI>w;lLLXejfmopZV<6Q?!+j_k!2K?eLd3vl3=;#x57af5C|aW8W}nQ*TLTeqQ_#98P2?K=g@- z-8Ve+{EHYRgk1y=i7M1lMSl43A5Qgz2NuyRfR8OsfEx~3y-n)aBC5GVWS9fg00w1J zyUWas6Oo1&Q9T1HND-Y+m>xQhFn(vCbk!pRIs1o)US0ylCv3#fZWS}5Im!qFTFioL zJVe~W^pQW(2+BrO8ELd2W1JDyb3-H#f+|Q*oWX_~KQh?uU}4P07i*Y}4n!2fjKdgh zoP;#m_?@91+h`-kF5*p$=%bAbF-IGxp^i3!GAgM3gR+S@5j5KPmKn6DC69rDArd}% z_!s1L28sVjLyce|vAHZDg-cL|8krd(r%^G8ZD&zpU|`sUvdj@A3pS0My~;x~pTh#lQ?9Z8Q-wmI&HUO#WCRMt%iHA8fBOs4GwYUS+fZz}T!j z8$3M3%E~OyCdr&G%q$66GM5P2eya!?sDf=)W?*Clr9x)#_E6fn#|ApON#15<$Z#HL zpr6+6`~cao3>r%W4<&*|7ePx3c|iepgMlrSO_+ImJ!E_kI*JGyO#}@Rf_7em*dPq! zOR=(wvT`!Zf#f9FgxO%?$h0WfG+{O=W_hGBMQzX~ZHT`iV~Mm(FRaWzAOob3jnSj~ zq8X+^_CU^XTN{}qbVbolkXaw1T4c=Zoy4QMiueGxW zc)RxKUTe^~1mJzw;Qi2G9xeA;>w*g#P!7Mr$iVOsc?=M>Spn+3f|MD-HGsCLf;1ox z1ET2x_lrQf?BTj>m>3v-qm2Zj>B4N6gN#6I*aoc)BVaK`I}K#Qa2gK;oiOVt4BKxV z2O18fXgrXNwS|zg93dl2L!^@kN(BrIp!5SBmm+p7aESR8KCp-EZq!jg&}tFTL1PRI z*cB5T0z@$yKK=(>uFh_X!?lsB;t_Pt~V^}IkEkx`cxg0^!oh&6+^ zDZ8PJ-+`AHf&zwtjCFv>AvQ$P0VsSx-UY1#yofS*hwK^ZkKDn|8HB9LA@iI;WG7O6 z9Uz+FsOtbB12Kem7*lB-AYQjnVIANRDy*Bt>qhuGK*a800r0_s$)HhAX0-jo=4`5L z!psri5jSbj>ObZ>VK!0Z1%Rxa%t}bZaH^nTI0i;W$QT@D>-q5bgO&Lj@&FuU+z*s{ zKB z1sseF;QhgnJ;uSHf*hh3WvehmA3A9*PF|=o?}k9tY++JQOY1hu%OHcQK3 zagQq!UWW%d-4Z$$MeO|@kegJHmro9nmO3c)f^ZG#Yw?DppWy>*n65`1i^Fn;Ar>tJ zN93^Rfse~gLt2*y8tI3oIb!$xVj4X}(j08C&F&^M<4(lVJWT(9iq`=jqXYHbDI25P zfXG|JK5pS7bsLx&Es+;`VToOEU5JQZm{#&v=z%g6RaWRRFcgqJUWe(!A(9_K^(Uwf zfQ{OHVX*ta!k9}S_Ar|zh^T~_h%t6|2x;u@7XxS^1jg7M+8Kkcpk)-OH?%M>$6Tp5 z2X&<$DAR(LaYZ0s_rVy#CiayXbRr0-=Z6@(18wM?2nqm+b{53eU63e)*isgdT98o) z^`L2*IABK%4r=UgL-9P}pc810y47Zyz)G>@o7!)nT;&b;R&6Y^k3< znF66v|!It}h*7-pP z44JFoyNE#x;aHhKr3EV|b01`c4z!F9x~xwTysQthrx>)N540Z`$6jKjwSQ8~l1KxL zpcvw0M%gx?4IQX24H_Q=jVgj@(DqxAeLD!8#EGuDRVEBi+QV@$q%&q~*6vUB4k6R)S z7Y~s>D=0yMFxlglL(I=;>p5pix>=nX`}PnLeLP%0F7HBhs6+yTiD>E-3GMN3$es5xL!oWFHGy87`Nmh zcieIa#u=#o1l0jZJUpZz-V0}QUS~y(sm6qFi>qw5iRUNegci(QEyBU%>vXh#V6pgF2bu2!RO9V zZ%h%dn1tAa4-77~y+(x@P4Jt0UKX;ct2&Il0#uSWzKg0?3ZavmUjfDmLfXk8;C1NgoY zh=$SezR~rFqw5ie`Fcb`<9)~_JE;2!Dk+E}cBF6g!aEzQ8vOy*13U0GhSh%bf9wsZBUlBp~Wn? z7DU7?Odt89d!TGYl~svb$Qav0_1q8{j0IJcpu7kh*!##}x0RK#0AH+OHbD?k2r~|2 zR1b8l9&A+aI|FF?jL>RC(AXUMR$?6I2KpdwJO*V{&>$Ylxq+Z#qr~1ZgVGmhM;l^P z4|GT%V<3ZA4+}^fw5|iO^bq7?(Dfz^67!Ij9)d&}BsL(4aDs+(Bn}~ofKHfY5PQG^ zT7?2yoPsb@l#zh}ax2OwB=sOs28k9{#E_yi*vx52B8ngpu`R5iqw+z4j4%@<0~!GZ z#UeRp77ooa1~zaAIY_%}d`SHjji3ca%nTHrS%?|t;Mjw$Wdsc~P%w6e8UPq) z7Cr+nNMmJXKF+`<$-KW_nE4IgOPzy>Z;DP`&2eu2mhA|AxXJBBM!N9-(Qi?Rp3A(QY zB#bo73952xz#8ELnV|jKAYn!ZxLKgW6J!@7Ljb7WgDi~<04V~Ee={-!fNGg3U}FM6 zc7kp~Vq^#axd`M^BqxAe2Qdk5A4mwg>JdbNDnLet5Ri!wy(m|-fLt=VW^(k-=Kxm) zU+2(xr%+!fSJ(K_JD;&$x-x|Be8zpQB3ca#8$bn3sYBL1VmVh4T@Se52r6d~=PK^N zJXaB27iPZ&WCZ9q3y8&_bMes5RYW&pSdN>5*1Us40)#;wGsOOGrXuhLZwkjupMd9s zL8jxpw>c*>J)=Y)OvWdd2ZQ3%ZWeSuHbzW>>n+4!8B7EDb=6u0m z*To9icMbLza(=^XCm^B>W)8;q<~5|<*6$cVOP~miZ-URkLfdUU5p%b78|rRrP)3Yo zU|_)5ZGE2^be9RJvxgWO1a16S3i7tZN2HrkK%xv{{VX80piOQF^`LdkpbK6YBo-nK zPl7}l#P+j*)PhD*5$ZuJA3;~ZFi2cPQV$Yk5PQ!8QhNhscQ$C>HmH}$AlAtWk^zM# zV$c&L3vz70FfS)SeO{11?JhDgUI!0dVkAL~b|xYP!gQ0iViGj+!^{9qatuVC)d+SJ zw)_rqJ7|q0XuBpe18C@(*s)58kqiuA8Y# zbU=+01+gV1n5)qYLo0<$I5&MdAJgkoJ;i8@98(Xc5|4o-2_d(fy!_Oh7*jC0tmgW0UL1C2A6H1!e9I6Lpf&G0i@R)ZWU;V2vjO!vkIfl2huv!*JL7(Eiy4OFd&UBRu90~ zVn*@E7+V}t{)CP#BHWBRwg{Tmhwie5+jX&D6Niw?&Gh0H|M>>L*M;=689tm;>XoVDw+;IT5 z+>ny{oINNUgTxa~U+|yn2ws-Sz{&(FJy65|bqLq(_(` zFdAyuDbT7`Hc1i&HCZ{Cb!j^ui8Cx&nP-919CZ04C|!ZlIjGAyIvxoccLa?`{sDKS zYYjj&=x8*MIGAQ+U_c&^1l2VlaisA`&^RDS7->8bR6jgJ9ghT6L!e_8kj4^0HCYj= zDo}C;t(!zr1&S+>Fe5`C$YM~%f+qV7Y(@Y=7Gy9;8yJI1)zR_D(RGlc>mWno-CP|* zLW5l6U3?+KzVIV3VG=`V9VD*tNJKpV>Vkuc06gQ7NQ%L|Jdkow{|;0+FfeRDACE** zj@jJ+>BTc1iKG{!4G7W-D&vOB9`Q}6d&HfEi0o%p>mf<*=XEXL=u5xT)WSWSyiyM>)LHoZ^c5#C?V~gEm=3`)BNI)4X{LBE` zRs8{JnIlM)L9Ckvq&ACzfdR4W`zI)f7$oK*jTwT4B-SH|{0AwLIEXGHc9#WYSQUza ztc(l{pl#&8SwP~T^=ODOM{Y(22GE9d2C=EEAQ@2DBE}p+vLK6)>eAs@?t{9wAaB~8 zXJXupwB!+y95Gs(h>8HFnY0l{1_n?Eo0$Q8sS!DA9^r0-T{Qz5lL2kshpeL{Z_OjJ zp{PTScfrfiSXr6zFL`8OWCW!m+PHzT<&L260ga*4#%-YGj-bua%)H=hcZ$JmcE}Yn zteniC%cupI)4=<&*@T&dVMC9gdxQ}yAVIsM#W3!oW&;iDs)N@uLWd3wz~hi?!fa4J zVxu<51n~Z9X7I*sR!(L%kV`-d8yT57*|foC6@bhF@4JSqUj(hYrEYp*W!?c!FRh#7=kudg9iJNc2a|uC4wp{q`^Lry>XDiK2U7{y)y=sX(1zv0U(P&4nVRD z}=`~kwC`DVoW#TxMPMcn=)eD^hIAt)*1grGgrd8x(4 zLvgqebPW;IuSAU%4n4oZh62%CjyiIPv6c~>|Bxazp3ndyy7BOF#G5GNh!;p4M?^Dr zhzxhYh6wG>Gc(?S4=1Ae1youhI+HLhbRJa%t(Kx}RFQ#U$%u$k`0(N~W=1Q-;v|fW z0q&jT9t@U4_ea*zQtPNE|PkXD1*d%BoWYP z3urGjNH-`15#x$r83qQ1m=RHCz(xq|?lLj%Mjl>7uL>~QsE8B@GlR5IMo^MrX7B-b z_sQ5-jV14c@)YDOLC}$D%nZJewl^Cu10y3Nc*u}}fl*ISKR2~FL%*OXvn;VBRUh1H zD27ZZ>%;pCXuikTWeq&Dw5*YlApju@ni>IV17lFh2lgMB2PHsbj!5ohWQdPvni7yT9w1$a;}b#qqJJRoiw4_~i# z=pw?+sN;&D?jB@QGp0gt-yl9CF)t-2l|g_VK1_(I5NL!bP@Y4{98&JIlDobFag)bQFZm}SrzliV=-j#_kbMTH6z9V~_ zkht>~L4!URYI<87IVc{vt>%s1Jxx4;n!PbtbW&zX(zbI)Wde z9yEdo9w!vL$pVrAg$`m25F`rQUkjtP#A2@d?2 zAg=w$h%z74-38@$Jo}N66oXe`fRuy!QlPSsfguKcKQfYX>?44Pm5HF`g`jCX_`oBQ z-eEcRhrGTJG)n_rU+5xSQYH-Q3E&>vq{{ljlFZ!H_{6-F_~PW$ywqZSFf|m{7y5wP zg`kAUf@^)@5cg{&a@^n?{XK%xv1TaiRS<}!$#X93Oaf_j07(LS&Y$OPnj z$Z*Zq41+WU>Y;+XYj>H6u@yY(hmz?rT8oI31k*{{NGsyjrF*nlJ z`k@=mz<}(3jJ1Ai!6P@UtjzLklFaGC%%E{6Rz~JT&{{u5O4s_4=oTBw*ZP5mS4dlr zNTM4*z}EUPR|$i+_%bpVgEklQf&%On16whhF!Q{6&^}-A{U^{-KPm8N9(2?XbE7dU zC$l}$x;||-VJ1dM{FA<(k0k%FGIxRFA2xCa*&PiYo&uko#{lZOfm%bLjkBOs3BsV^ z9wG235qzWxAp}~j22#X;5DEtK85od+P{x!%c7Vr}Kn&1W852V-4~T|rFRRr6(V!w0 zBn~qRM1#~YG6aDrkTfGhC`c5BK@MPK2n10OS(Ht(JYWxCxC1s`2`URfLw6v$3>+S{ z1|S+#+knJjmVowggUVZ^u{ls74q7;aG_D4!2Ow^MhZxAwpfxg#48b6G#ekg?3@ZE~ z#=!#(WD`g~l5rp*P{KeOBLoS7+zJjy5C?`q-bYdg8bl*@z24~9-00Zc=-AxAkIjMZ zGXfQjkh@DjD?X5GblA9@I=GYqW%~t)<#H$r!TlYO0?_hdh=CzY3=GhOT8{8m$ zpe`pwUjz;-Fj`k2ZRCzsvEW_bhPj3hwALA99|-RO-ziev!rIEx#@x=-$LJ`W!*r5M zxZ07M0k?ZF%|srDvjVTdt8HO!1+T&@ixjRU$t+~|Jph|k)56lq+{V<$=pvlQ6b3tE z5Y!cc_RVpf6PTWwms*sWtPiE*6H{_C^Wx#RQWvKdm8BL9k!gBRbb)aP;jucXe}}xk zBcUF_9&xCnc+BwOHv+nF4(s8!3_i~11hfNcWM~Ekh6=*tK2RqOi*N@O)1Yv-`^CcehLJ#Mql~=5bY?(9797e98O4byDMbtd zphLA8GE$H^#idDksU`6BuAr5%3>k?91=*>Ua6xs@dEpZoGV%+O^HWk81lEF9%Vee` zmL$d(Bo-y+G6={qGBAM3XNX`foY;kWKn8id{JUKgTP#{Km=Hzq_QBDL4bt~q{JaAwW0)KWpR7~g8=Aw08rN; zvbZF%Bo!*bAdm%C8~{1MjzM4sGXn$j#4Yuapn4!aGX@dXS<)@^^XQnU+Y-VI&hy)k&3<98K-AoffV^29FtIPm3oxt(-7P?Rrf4o7m zOld(%Vo53kBK}~eWG0tXFbIH30}Vz7hRo#BqN3Eil6Z(NaHcP25D;QyU;v%_r~+n{ zBo=|%xhP6hz{NmOYHng?US?i8s76R-PyuILL{`RHM8qKHMCNOlE0Huox>N zGkj@bt*{cCl!yqMFdGPqvk9~EGRuNS7xO{GvCJiG!fX<(jLd0Zo|GgjCo?;nEm#!~ z_>jReVdgrJ9x#U!v~`UW|otLJ0qW!ky#F8 z1}AeN*eN0)>sguE*d*B`SvlFHL7rpNL&VDp@V;hx#0#N8Xi#W~vI&DIVKyl?VPEW?Px)_Gz7Y42NY7w{A`k}jG&-|q$d$p0p<$Os5B@=Fftc{nEaq5WCD%? z=3q8$aN>d_02$|$hK0Ldebj2ba8Fn~_*Wn>5i6@rk}m7$;;Wk9VjMut#Ow1U4EzfQ$lNWDR1&%mT4thJn~HBS37J86ej{&W{WR83DQ? zn~@N3Kx&}l?;vU1XbpX*I zuP`&zo?rkmc7Q8|S^*FZs=&Y!FlTLHU|;}AFfs&y&ZNEr9#)5s@=s%608a!nG6aES zK)R6z?m?9vB_CI)~^1kFJ+G6W#3hC2-8d`M^pf+&z_j0_h8sA6<_dAD>v13teBGSd_if$?FHXjd1AGdJ-AQx0kFjIT8gbDG&qpHB1Z)-x&y*0^RTrD(@kdgK9RA zHs9d*bjXl1_Et4y2PMc#Q0WKJTL86^pk7Ev3fe;hnSpzN9{=K2P;&scUd+LL&_)Q5 zeIN{)w{{dpnJ_3w6Rsv{fFD#BfXo76P?hH>O#Wm6vfDt1EIA4zPZm^w=L$e~*O53; zkd# z0L7yj51#~ZM4ALh0XMBdsTt>`Lr~*}Zg_)z2O=047+|CS9~kVOF)>bHf{#a|1r}yu zix^h|l|dlm(1!iL;T!gMAbkK2)kQ;OrVmucg2Kk`5DVjJ#ArXNUr=XJU|LX)Wd$9S zpNTZmKO3~t6KSv?v}i69%Xoh&185?K)FFS+tzMu5)zF6g6B!sVXL0;ML$??s{vqH2 zexwoq1h4?|h<^auh`%5s19*TM>xjQg1oD_6W2heVXdY-?K^q{+x z`al^S`w%_o!lYF2y;C3-2}AUtoQ8Xd9<-yJ5p{_E1m+O^UeqCaP>I11i9FrL5Q#iK z&mcC3MSy{U0W>fKnY;rH&dY)(8$rPZT~O=?9=jm&@K9*T;;x5527?B;L4zF34F2FT z6g0DO93BcY8qs;cC^*0_haM`x$~>KkjS(_(%fQG8+Pq9t`xu$8B1Y0d8}AiFz=P*v zps{E+VdhdcNoE0I=0ag+e((iBnV|7TdGPQfXbcxLbPF1H76y$wgD&wAW@Tm5U}Y46 z4oHITW}&hBtq3f8hB^~OVHmsRq!zg0KX0HJdP-JS!`+EM(jlGT#6icm~A*NR1e?FnsMZFKB{-m6I8Hco=ff zEGYeg+E&;GhT(&kPzB&|VbItbGehkG@O59HW&~(l7-R|vgKA7KaQ*@*1BrkKGa(({ ziJ*}+bTQCaA6N`TfYc$4wt|E}CL)a%f`mXbY-p=?L4$jY3;`etbX^_Vz#gdI4EGC2 z4QRj>M1$<3^FS=z9iZ`7*f=cc-XidDD~JI)g8(D}qCrJ9SOVm45C*N221zh71b|98 zkUY{@J4gk{UyKak;Z9JWosl6Fq#mRg>o_v_vLlE>`1tGSz~<<{=IFp?kZb%9y7=50 z(((ZH#26VEK%3K`?F;kPJ^q#kj0=^93e zdZgh~J48`2ZB&pfVan+g)N|JcAhg#1YykYn@?Q2XGKno{<53;|MW> zpgzl9)KL9vJb5XsB%!O$IOgQ3`c1(~HqWLuc_L9m9Is1q-S zRe1pF62r;^@QD{t-$74VLf^~|%oxZZDK8@fgADF<%)*Qe44=V+q#zav zgQTFGNYWtb4a`B(v#5ilpb`aj9rJ$BT4m&MQqXv=*hLo5UUQH)5i6Bd85tNBf{xg@ zzyiAK6f__Zg|t$+85FJ{oB&@nO7==+>^TYPbXLep<#0&1hRl`9I4waPSe=19uzCXQ zH#*qM$b1dg04sADn=muCFq<%#!3ABJoCzN30}by%mN4TTVg;}E23^C=%s>~vP-Uhu6e}yi5&=Axh1dX?XXwWHKDcW@8j*&DLHZaOLP4$vDaJi43~@yW z!tfA~dWdI0js}?vUZ_ay$rq-hr_x%Q8GwTfy0+6fAT-|DKPbdCBHq^kZAE54Xne50 zTS%B&03iuqPv;d?#t82V3#0SpK@t`HF zkfoxdt6+!HV6ii#RR!7?4ceKDv7Uo07b7ALQ5NK;d*TEvjfkAsk zK$SkyI4}+uzz2~X;ckanN?7xN4JIQWO##|B;V4{=d~`+ulOyRzXCSX&1y%7#D_EU{ zOX7t=(|x!H%h{PYm^oNDSUK1@*g1GO_!t;KH3}#;K^RoCfEGbQJNv{AAg83JC6?xt z#FrE$<`rj_Waj6^gOAG^lB;2FkUo$+dm4 z5}4U&gVbz{cn;+7Abq7CeisgrcmUM_pm?x5#lkoRF<6b?Z=g9>L~z55KpC_KZC*rP zxvK^mt3q12>kr~%S-G1J6322_2WSu|6M4w!AZUdk@_`-Fj0_B~z(Zc3b2`8>pi?{0 z4(k9f^MfqKgXCeRi7vR$%K(ipMWWRq3<98yI!qHoqDu1PlTzaole1G(AcCM_EC$Ho zUC{b!MCEBv-49MnC(zE>Ads5CEh$8Lf*C{pU^S?K1vTj~&fakWO;`|l;0C0#I#SDL zP`e8pm#xf0-(W0ZZNZyO_;fyO_-SzEDcsE02*3kXHx|o z|G*~8$_XAT2AwCs%mFfxnFF*8mz9-Gnw6Kif(<;330^u1Iv&CZG=j+qK01OGd|ZVH zXjoa3m6f>;q?eTweEa|_7c(zgB1nc!3G50kHf_k-WAMN-XgfGvHG*0Hc2)q zQP8?w*nttOjLdnUgAqXMUqL5FXoEZ<1zM>r!U|b(3|Y+!xoVA$am~v75p=LIBXbQX zESb4M5yPg&$|%mt$y^2+Y370-Nes#lptck-D{)mo3fsUl6}1N#Kn&2{9MAwThz2zg zz$3#TBS9E+)B#9>ks;s)0|Ns{9%dDI(8a(2zRM9w7Sufi&G#@egn*0y z=|@^#3tGhrszI0-CNhAe4}r5W_zp&p#o*2*sAy+o2nI=S0u?t5!5~$j6Qz-cm_gP+ zhL{6E3PBD*8WRP{LL3nWlD!5t1~kZuW=RZ4b{|+a24o3DA?VZqutFr)rhrs}lrS+& zOaV(WK)S*Z*T#XQAqK^PR6z^^6^JmksK+~imNtXNib1p+I1FkHKr|$5YC*da;2I%A zvEbvCLDG!i<9Oh*AQKoN$16i*;pYv2lz;*PDRMwUpaP$jp_XCVG|({&AQ1+Tb)eZj zMuq?p&~zR+KtLV?%Yq1y3M6w#S@AnMh&y_G@#yiz1Alxm==uuC=xYZf0|OV*ATIva z5SGq7s6?;8JpfAG)xyXFygJyMndQa>s;UVT%_*g8myHN*jLAwLc25wOl6C9>RQ4JqxwTF+SWlZ!o`j{waj0LpX9&ItNGv*=2 zka1DadBtdl7!y3w0CW&B+L;FYj0_B*RU%l=H1L3pzG{PVP?ujt0K_6;6)z|Q;$FoI8U{c+ z>fi|GD&C!_t9U_03F<1|CiGRjpiv94h2R4ZK;A^G;ss63tOf-c16g;dLDz7=cS#}V z2iW>t@E{=M$OF(3E=&yM9(jOfIH>2q06*|x8#C;{1F(INbJS^OA0zW4*sv@oc$f}! zb}n{ARBlf7HlbGAHM`h8a(35DZ$Dr#>&fF z2sMFCgq4$77|LPgWm5(j0U5YulVFnvo%0LEpd%Ml@S73|8Xsk4Wq!s0KBNJ3CN2Do z23AgHU$A??jz+TuWIF_d&KW>x@(AYJI289E7oim65S|JRQ0MU?4TnpMA0rCg&3!sA#Ylh*A zm_f}baJ9$~2oi(D61J7npkW-)@^++j1+pC!aHwZofSd@j2=`)Uh$W*dnA74j^GXy< zz>AQJGpkbb)8cbRkGmK>?qX;icLC}`fyyq(h#qJOF|^GPkK9tgGUNg(K0q5FAetkX z7#Kho|6$b(9oW`~k4djU+|Gwp1GuvYvcMd!MFnaB(l9oP15x@dAg!PhkKV^zfO--r z$6PoG7vv4#F&D^#>Yy8^kXAT@F7!(Vk6JS@Fo5b|uL#;;MGjyi<>mw|x+eFz&(J>gMoG!2Ob1v#LhL;>VuEHcO#3_~?{h>Wv> zdIq2Z2sW1ek-_c-6XPbt`4u^+-ojG0BF0@{hM^5-f5$hR4LN!Un!br1&_;FC5D9Bg zfeQ+2yCW=&50J*RQ9T1ni-;hF=|NfdOWzZFK^L}whF{Rex3Qksn*dt-NsSYGg-AK9 z0<x>PLao(JE#}GnBDWw3GyHnIO^vC2Frdsjp&i;gmj$%&57dK)%vFI7?F9|&FffSi zW&y2V1089G7~Te5wwDeHNiYUo)Cf7BmF$(unCS^@G9x2ofE%=Kj)DPh)SQTMP2Nt} z*%J(mjG(oZ%-{|Cw6c$p`4w!8n+rUohJWHeuMfHh7`2h$!@uJMe7i!+s$vZz1RX(lRU=nXM@s1_lq33V_>tv~}la z0%O6f%-~Dqv>=zt#lZ)JL4(2|3>pUpg*Au`!Z5xRbhZI}J0P+IOaX`njmv{HgKno| z7R7r!1rsAA?m*cA)S?3o7=qX^4C+Ip4`zyh#^#d1qr0^S7(fhA!v!>O4ATXwqd^O4 zk=DI}^niwW(T}Epih&lr!gMo$#E{kvgTz7o`Qdal1#~qpD0o3*vY;VY5DglQ29M2x z7?;3947CCv8dNoaB|w1z!si$m7(fz?3<03B6C{r`f(j~WSAj}$a8UzN55}NKfDWpH z%40@`P>>NI{kR8JAqqo4CPJ2Wj~)vVKRT#7dMt!%NIdL9wIOtdFk%TX=tijDNQVHU zHIcCN{Xs>DF1Snru|WHKKjP639a;q)Fas*(7#KjO2!k{rkCURdoFIqnfeZ)rULd+a z7yJ;=h0>Y^=^lsyR?y@j$^fgQa0XMia5ZkXU|y<5%~ipm6ZAo00m7il6*R!g+{)Ak zT7Cg4@S&Y&G6q#kN(+YKvS0=V2GD|YsK3b=Tpd#W#x}%?@Br#SD`?FW?txY$U8D@R zB58vUx?V$CJzN5Ago9Ei@hcD!r3J$DAu==oYFmRm3mba<&S3Y2iE%a7p;v_GuoS|G z(E^x}Xalf+@ejbJP&62WaM}#!`0$R$F0Y7p<0CWHY(?lMOp|}}LSjS*Jz?Y;U-I@kjbBwq(jd|jpdbB0R zpfMa!wTpF$u>)k-hCx7rnSp_M;u1Vdj6tI{3=9mAm3*L}9})Q*6mlTX+HGTIw8Am; zhm_K&K3EGXTB$Nvdtzjj%b=zaINpvkGZqkzHkUV{u8e+8|K z%EUHiD*%!O-94OHl$x8EnU|TD4nAj#0bB%t&IQXr8oLz$Wm?Ru6hRvWL7oC_r)FjV zErO%Qz$qg6!j}j$FfxJ;$z%p^Z>GwCCW%j4Qz7d-Mojd&-7%85kKM$BWRz zt=~Z>J+Oj~(_m!gV3P-po`TkdGcYiKT4Q(zPoWCHt8S&hiMRFv1Bd}?Xdn-sf{u=b zoYfEty3$Jwbcs1Q6N9oe186u7B+JAwF##kE(LE8A)xq)z-C-c<4d6jQP|%>shJa*2 zyKj+}xq_5{dfn&)zC56D!vVNR4HTXr_kfC5&%MHPk(IeIwyxP|)%xnP%t*bh0j7ivFDql+)( z2w}KIFo_{FhzVMb4=NWJ7(fTdF(RE~fHa7SXh~q{MT4?FsFejVC4-59;XC%BOe9mF z1DcR>5M%)8$`p_`>;sxeI>D`dkPgtq7Q{->0SZLvMQL$@%)mXMNV{VX_Fy~q;N-v_ zdw{%x6f~<28sKDUWo~2YV+5@r4T7y81uYzg4*C&0*qNJ{SDKcXTvA$;T7-U?$PgL# z0HqWLh9%&328hiN@HMPz&b`602?Dc4jv=jQXdJr zZ8JVIB_2Ai`sV1{qof-Myv(I?x*X@eZK7*8YP} ztOl{LjjyVJiwU%`RTTkH#zq=fMLXgeT!f&miG6~(CiW)knpjW?g?hZhR`lZ?Kt+kz zK^6lB28JGx9JrhSEsX^odYq0Cd$ew0Y13_G$ITdFS8tYwJO*dpks#RKm*yF z%!Od5fKJk2Wd-SBLtP&X8Y2az4^ZXC%s|KZv88NW8RTXgdZ($ch-Jf)tc;+bWn~2& zCnCZsz+3@3lLR!2z{p$(VuBYC8-t^SIfPA{4HV0e1OZz2%O(mvRYD9j;ULN?2tHy$ z0hAy>kpxNwg3R2)th}H|BK`K0NQuS$PfxL5HzfVv>X;x zI)hANVwji#G75A`0*DPW3&e&Q24cgE0I^~I1-S-N3I~IX0L`s1G6aK60CheY8G>O3 zFfs&#^n?2CNQ2uT?GPV?fb>9|9fD8@Uy%#44-}$&@2OJ1s)?q04UBuYuFhX0zgA{pzvj62mq;vm>2*u5n^=! z!fLp~Ku!lunLw9XgG^&&2myHnq!`IckV42|&;cL{Vt6RR@KBI?h`&IyxFF@=F=b*e z;~Sl@7(K^%^c?4bKgSugsSZ>wLvE)6-Q)v1TmoN<7t0VAs00A@a3O~EFflNIDg>eo zgHB)ALmKGNOLaiHk)|*3x(3|Q1~~w9vL(a;4NwOVYXnLk4`kFpOlI6+U|>L7shz{* zOW9-wXj#3ZaBT~Cg|)MAS)_0+18%=zuKWfq>;Z)b2!pCM)X9uo@LUGy04@?IGV=5C z)6$0GVr??ca2{fQg-=uyo z0Oc&$L<8gu=j({Y*T{atQtBc`qhKbXO)OCR3}=V?9 z1DFO{OdOz`;SAnG4_-^1?gFQg|}Xa7Omq5Q!&Hs|6fSi&z-5amEu$0}v5kFwKxbe$alT z`?%LngHCSV1|H-Gu}B!?2WP;F63BF1F#}p&2er|uaE5a$XdoYX-V$_-H187|**#q@xX$E8}WNSZY@QTuNZ_x}#9f)rQ55$YY26|0E zB^U$f5FzqcX5+Dsk@+EP;2pXko0XBd1U$0N0~&h=pXH1gduNjat-%J3msWxYFxkOO z&=7n&h$RU+?gD(x9_TbjYUwd+hdbr1KqMG37S=41o;Ad&NFB%il%P-gctxvJwq83V}+o|GK8F=oB^JO zP==kKEW;)YiaIti+-E0)7QAyZCxc@pla-NK8e|%5w3?h%+@KZI;2~)c0~C9pL2M8W zYTAG$K$#GPLC4mDBp4Y2Ko|3YBuJKtVWJ02 z8pH;f3&J4Xkb)y*4+8_k5%7>FXv7jE$pDfCO*1kw1cNj~N1j1Lkr0K!U{wqZV1*!S z7#Ttl#=r+1L8?Gqe)zyLXt)w|t}%#)3`o>!fM`(73laxufMLi`DEKlwkTlZRI!Fb` z1n6aW5Lvj}L9(D?6Dg=bLLhhGI6eb3<_jJ`1~EY128}F(Xi&)umH-(5!k|-2KoX1$ z0ibIDA$JkN2XH~#bG*O-84QvE=|&rlhsXvYWZ}!s)fgBU?7(_amYqWaArM4?R4_7x zfUF1UM;i}@Ug`%@1hE8sVd^*qvzWpu8^i_GU+_U( zC(;LTkyoUH2G&srahX!VqqqzV3?IN->p&sLLhOq4g8cH-B9wElhe)>&O zETUJU4@p16hjlSsk2<&u+Ij~Wg~g|Z;1DksYv2RDu8gn)lo=R6r~N=D4~Si1j%oA| zNprA4TG(*!7Y4g`OpJ>W>&h{GhNaX+j84GJLmTw{h3}w^1kzW2V!CRGgg2-x2IXwK zM=Xp@h(UEs|DX;4!?e+S0Jst~mV`V23>tX>Ew4mdJbs#i0ew&iyz&z~){C}yJOC_+ zGyog}7CXP&qQ{e%tBgPeNv3AY+#arVocmxd3Vdf#a-$ z74>WlOdrLgG%68s2QvaPFbo>+^~b&X8#KPF#>l{+A^>8MFfa_tn7CJeV;LB}fVukn zDC+8OP!WT=`uimMz;G`E1B2LF7SQ+(sF*K+Dh&vbu~644_k?8N}LIL5tZy0f>+VZI1zsM}uO8fdRB4k(mKBa6$H< zGiFS})`T-KG8TZ_xu6jy@&|&kT7WwIyb3)0EW*SHTCwW`E)!{NCnIwY`0hVeR?rd3 zps{9A@Sz~shMqaWBh%%eu|_D9O_+%pe1r)DD-);~XXRvG3pS1oG(0TI$_ZI?4LNd| zSsc6=8zzIeWDqpk30lYt8q`L=TM#y2&CCsw1+VD_y8<-Ii@G=)JWvfD!Uhk2b23BL zeuJ$85BP!x44D~d9-b7Q0RoxmfJ{8l+^wK9K)}I?jFtIsxecMJ$Yl z7z#O!Mhra8&&w7HN(b17z6lI`BUbQ&TEUgW7ap z2}lXUzyKO)21y`|;erNNK`Vb58Nxs^AT3D4-5^=eaV3llp`h#BK*tL)GK7NeY=tO< z4@n~whJX};ia|z(5QK^FVPu5DaD>8ego)uWw}NQU7z=!m8#Gu88q5aKkZu398Xy|f zq5z45G{7)O4I=}1kQ*e8dypF<3wIqzKWODKQUHO3K<>aX$PHQ(3?9n{F|I)ZUjRgd z%6hN_$N&%qt(gW%Ffs&ycEN+z6Cqgx3Ng?EYa}61eF9pbjwA#+oem_-$PfUkbs)>o z13*TBtV2==s;Tn8IL1 z@IZv&@DX%SB?%c+hZ_#^ASBSigX$m^j0_Z60|ql4;0Yfv4roEfx(2b7^ib-0J|x; z*ahhZopTA&gR}%1i_PFJDM-03Tq9`lHern@{UVS712NbRx-bJ{uswQU2iuWXOoJM! zsDte_;IVd4@InVY$s1@#oZ&M>y4;`?!oUF98VB_^vB$okrr9CoZye+22tS|>yo0V) z!aMMeq>;qocO;$gLHPSfgYcl!s-W>g-hds#f+3O~L7fFqnuHC-|6;KF#l-js*B~*% ze^|pox(Nz%$bRIJmDfQXTae%F_Mjc#f-}W|TSbU$4KslJfqGD3OQnJOkP%m2fLc-D z_`8aBYzxl#Lus5M;t^&LWY8Wo77rSTz;TTsXzYC@cr`bOMZ%yxD9hp=v0}OB97(;4Z?eX z2jS^rHzV^Cq}AY%v$?^;@SxK$KqKEO;Gs`;@J)xH72u4_$m_mAr>cNfIAgB+1`Vl# zF!U&GW;W2V*~n|aJ=uiW+*ui!jUYp`LEv@8Qt+`^q>*}Mv?b*rV}-$D;89`bc#tM$ zbu8<`85kKsBXo3%M@D8U9GL>Su$@kEk91rL>S}TD;VGcy?chUFlpu$sq+uV4hYg&= zXyOLYL5uc5X&scOLG4lEk2u){o))XU!2n`_)>?x`)j>3<&4n^}4jQTiNiZ@5@G&wl zfaH+|TtP=zfCf;ZE4D$m4j_#>gGMz#vP=vUQ$S{bq(N+udqEha8?tOX3^cF~T9%G9 z3J;P6>1JdI0m(vc7epDe291~umVt7(J3yz4fR=oN=q5-opI`tnK-6NR+3UH*c zYLE&>h7gcrKo;U2tA?07IzT;o;Uf5;amaz*iAA~4Q@<07a^vHnZ0IrHprgd&&4SU7 z4F?N@?ra=As~j}TQ<71dn*Hqh!A z)IsY6@Sru>tHY5O=?{_NK~R{2Feqz42TMpBupVN5MjNU|c0KAKHO|%HC|Zado<`9F zAD9L$YJ`k~Q?NQ5+2|pX=0J^gP@01cNkdkLccBkSBm0b;!Dzgz!$EiFLeo2G69LGs z8Y1BhDuY4cZFh==@hJK*G_rp{)fHk838pPGBQY-}CzU~=y1u240z5M2aPa+wy{Ho zr{U*>Br-5yUb*H6Iu@cZ9&IEVa_u70D)9vHcr{{`IMc)cv?InrqhO$F2J1+)3(7KZ z#!%2@Ph_tGM-KZTl9oUL15QgDm>Erx51D|prI3Auek2G?EBS-VpaPRhgUc%94lX16 zaEQbisGS3jv!!SUgJ6j>ltv?>EPxpS8BhkT0tc;~#xbA_8gB;mo2k4C9JH1V?RXF( zSAj?7CKhF<7C~-sWI!8DUIIQC1hj4rvi$=zUJM?F1_c@QR%oN88<63k!7EU}GE-%B zFPa6Y!^0Ed!@~@Wj0eEuGSpb5i^onz=JT*&VJ`3jY6TGy(1@@YXt6e%FmoxJB(s1p zbD=OZKX{33CTM*&Xf#$Be2g+^NEmdMHTZ5s&@GI@tgLJrtc)U{qmAL0BhuUtRurCK z4W0-94IwtzGt?en05L#K2+-In$P^F;)t1mB6+m1N1`W!AR`fD4Oav_v1qm@AiGdd8 zg2g}tNFCBC5FjCtiAaYEgM>iG^&<@if`mW@GBN~!D9CXZgLWVl6waVA2GIB^Xt)$a zgF*~ETnb`Q08Pk)Bp4Y2Km{5|9`_h1=zI%Ch7gc?kYcnk zQ0O5T5OWzwI`i0k^peKWOB&&~8;%Zq#)Ahtp+lBnHh6FnJPb<9flop!bCGLrEFEl6 z)(6dDfr=vr1|KE{2GD9w)FDq4BZyy_i=qua%!yc;s{yqPW0(^~BT8Ep zE~e+>NgVn_vJyT33R)}%8vrGHWiF=EhDdq@wVFX`5;hD9S(&>M*Dxqj0Afy0A$saC zQ|YoYcgTi4sMH39J!oa_F(1ufxVZK`V33a1Waz{6+o2Q&3?`rNL7JN(WC7{v0Cl z2g~wy8(A20h>Aay#wljm0U1aIjg;aUNCnMAKn7AlEUK-{#WIje<6Rkv6zLLFA!03TKb5A;D64p3v|B|*CxnJ>VGS2@{) zajd#UU1=-HCJ8=bf|r?#O`f?5vS=23_%JgY_!NqKHeqJaxGN*GAVjhlyrNbFyf~H( z%i>tj05Zv0gSpZc6 z9+ve3kNMZ0U;r^dL$jb^Sr82>*}#K~FhfA&fglO&V~C)Ilc3|wkyfgL4#ortF)>U8 zEy)C%15yTBqlq-A2oi#r3tvqMQVMc2d>|P#Knpt70Yrladzl#MdfWpjJVEXO4Z4EH zSV1&s%oQ9yAO3OLs3YmE& za0LM&K`x$dZZI`4sp8D4)cmyg%)Al>6R=vSK+fo~2&2a$46S1k2(3EBtnF|N!4g_^ zip3!4Kr9ifPO)f)562=_oti+GyW$*C}VT$Dl+98-V@BVE2iM zu@`YlF*d(pDWws;dzgu6gRg(^ol{&v`d|t+cMXv+2bIjAFt_{3!uSR;@QTexsH;(7 z8fh`;if09?EF%NMC&(JtlEirUh%4w?dbA-|@Tdy5AynfqCMN`bbdOAD@{5xmSxp;4d=+1JlHm802MdQOL&^gI4i^VgYn?(#Xm0 z@IlxuXvZU9O?}{Y5F%^CG?Tx26;#ktX#kdtqg1f@afp-|pw<#7wSp#V@{k8#vH1zL z0g8w}m?4mXS8hfI1`XWj7z;8oF#HD}i2!1eFz^b>x44f)0F4l!tzf-^c_hL~)FTl< zB@pV72wOpC8z5hB2Rb)JY$FS3vBm_D9C)?}w2oDok%0kp%sPYED;ChQI8Y!U&P>o` zgzUN%d&!c)z`y{~8j+k|npXl@D9aeA1PXN!2JNwBW&kakBm2k%Y;lEhTmtBvQDz3v z*bw>0CE&0GbFL)4_lbI9D5d|H5 z3tr~w%q9#vsa66!lnXic0CXAxJDV`bGFdiZHqfqnDOOfdR$k^pHt-5ju*N`EPG(Uo zhN-i1f=+c1ft*t;3_1ZBaty8%b2Qjpa^SuGATyXl{Xv)Xsk1UN%YjVd1Y01?CIT8| z2CeRuWJ5g+8MdV#v;mwBX@M%oEm+Vi{U9B+06ts+oFcf`ghf~dm@7ahEr1dPBXc2$ z2|jee7#tDIA#B>kqSx?g3R2) zth}J86BGp}AW1f1HRgI@HW5}w=2~G^8ITkwGvsU!usV=dq*cXujy(oV9)QXgP@5Sv z@CstXFlZ1KBnG0P^59YI25?x{USI$*nn2r!7-~g8G^llma^GJaBLf3Sf{`I$2_pjo zNFHe=Ea-3r(2zAFLn!F5-810B1wx;Jw%Ia**1Co&F)}dNL71RwI|{-C8Mp|-gt-({ z=7LOOVwji#G75D1F^CN_3&e&Q24cgE0I^|afLsGQ37(N57-YmOuxo-rCV`HPU}Oje z83t;EGBO0i%wl8+1{u`{b`5A5JlHUhNuZk!p~o;o{1pPy4)II~LJz1g2kQY5pl}{6 zgYby+u0g}^pwV^^4LY0{JPZ$FfPw}j0ir=w8dw744-iH=?;3OzG2|{s(8L2sk^ywq zG3cBiMus4e3`jT9@^Mf#2w4jq1lq_3su7W7L7@wp#zdOb04+}k4H7Xj1b|Wk3>ple2k0FZi!iQrofAyx+9cy<5mXz2b8iW#{fcyK1-4c$mSHK7UQm$*D%=?u zYM2-pKpS?`Q}a@bGLz%68Umd-K-@&QgAt+&Y2+WPMsQ~tWFgX;bEt)cw4yAO0U3dN zfSz`j8QL&mOc-P^-6DO$0Qq={EC!I7>SJ^f&SNTsO&UA_Pw#_559fu3IhpAhCHi18KDi`kC{7bFFdz+B;X0-Q?8Bkx z&q%P#k>Un*Ismj_AF@~)MIqAE8)QfzJ}0xdghAjh1MKQS6y-%_sYSS#ZX>$@$zYr_ z49M!iCc|eHtdV9F7#J8LzzuhB`oy*36KvK{j5n~aKm-E=18gec1%urUCdOqfJYZiT z$7un^(L#tZDo|GkWDwf)!8?4@2Mi1)geMTdt{AFe3o4sIpfzuW{9G!&4wwa z`ZNJUCM0_?2&@GqZP3^uco8;utc^iHf{}s25-tdzCjd47iJd3#08btu9aVvOq2Utr zc>*Em5FVC!0?5QbVo_o)g8(N7Xrf>R^n%0ql+?7u(wq_o0c{S@M1ccjJ|Vs+F)uxp zL7*8d7=nBD;4COM7#KiDSrM2#7}DtuRDXkfYPX-6(H%7G4E7CjUIw>%5ZM=|0qYdO zOwc3}sNO{_OhIR=fELDQf~1O5L4_`+0??I}nJ7i84Ym_d(m*Gml$0grFbIGu3x=4y z{FK!A%oGNJ&5R5TkzjKf1VD8N6Ktg(5oaueeLYmm4p5s39EVp~82cHqMj}f46A_s( zosjtg(8efzQ1(tPEhjxg&Hxg#$1>Hs% z3O+lz9CB?Tc-)kg3AB!vm6Q1t*hKifg-B-}%Yx50mIN8ZCcy?;{0$oFhtkZPY{Jat zupwR06aX{3Fe|SjeA)ms`p*Fx-Q|T`u*k~E267;Do}dUcmJB+TLxh!+Ss26-5oO*~ z&nC=#g8?*_jLkiuSqC9EJ%kO4Z_OF3_28A7_!ct4VRVDAZM@%Gjo8g5(15mv$}x-gO!(=6Fg`Rn!R8H zO`WK*f>y(`axxc#eaXry3O*JCvg(~CY2++y%{UjEqzIcNo0J4|t*{6i=-d=xHZ?Y3 zW_C7JW)5NI3Qz)K6K0c=U=v}k7Z!oZf#!SIgxM58r>cNP^ug|hT+B!l_fCUNYvI3) z@c@G=C<2*1*tFS%LE#Qcbf7S2Q-VxFKxQOBX#q4L1qy8t4Z4ewm6cgvm^m1f8abIE z7cqjQU`jwVbXJ2EG}Q%}jRGAdgIyK1E@s3wK>->sVP>d(zyM6NEvzA0*GrFmXXW zNC9Y!2+Wzm2gAT~@R zhz-&M!k_{kG+NHc0KUf$v{sFgArw>xf@UZf8A3r;p8?NKz(=7$dO(h5WC#IS1@aRk zL&!VOI2Tx92uM4~Ba93oAnhRg(FVRj1vb(S2he~y6GN>Ehz7X^eDDm20cwhYb~u2X z3d5k@6(d71h=NE@1gV6{GJwPx8G=9*R2o#_ph*WJNrNWE;nL6%c{m^BDe#y~EyFaB zqd{{RpeYLw4LP8__5=fn0royatpJDyRj4R)8Lt=^7(fz?3<02{$3d+Hq(lO$osWR4 zR8Yu*tp-)+kZAz85U9om2{SSToMT{MxB$@rG74lJl5rp%kZGtu&|Ex3PatSI31kr? zL*Oa6_CSPo_@UdN84J*!2qY6hP69;@>YN71Lm>TVQ40-05Cw5#C`b{+jqoG{Ix}N* zA_HY_L_tXrbhCtGkgv0Ie3)xcu&2MDf~kSo=tRcoF*M-=K9PaAsWAq+m=e7`j$`ry zbU+oT>||g7t&x4ffZ31-EfED3GTPAMmVx02BLf3SrEhRNhArUkI!L)OTsi1GZCuJx zI))%^12HiHI@=5Fc$u6!$h^dW9WR4CDFM1c18paRGi*``k z3O+1W1=j#daiF_s!Mbr@HVAgiP>%p78O>40uCb&taO(y!eht%%but2U8ha*cc?+6| z2nVGOlmeA1`xS^dE@s%o8K^x3E*CbiFy<1BGn6JKBJN;@K;|Amr)@t6#SHej2hbTZ z`@nk@Kr9mG9zZ!0_uK<`>>l;{#!HxU564mG9zaD5>f8h9>MxYJ2hgC3*m@QL1_to$ zYl!&+(Aie2K|u$`pn(Wx2GIGzMDI8tDh+`Q2aTYEMk<&|I(HjlJaQidGZX41gBm*w z4DgAC2k--87#JB{z$0;>#k%BAU=XyEk@-GsK$a6c%ne#>&s-}EzLF6-WDFX~mt*Aw zE$(JzE(OgHfaU|h!|LUr%?61389BhCwIZUR#o(OGIA<3?L$DC61lj_?rq9aAtN|IX zjRueLLL@Q?T4wzx(WzGO;6lJbs6BcCyP0xULY(RDg&^#P%C_HQi z>{if3EX~syBl8#7qydgWcur#wxEnNo>C4(5CMeiU95Df}3umsd244^{>K@yA%0icQEZQziAhbE|; z1dRqWG6aESK)R7u#Df}&ppar@2n20{fG7+^D1;9VgN9B(qwTl{he0YB8A3rW0qIAI zACN;qqr%Vy?+{BuK#Cx)0XYDqW^|SN=rK7AqsQb7tz&XfSGoT~8RNxl>);qDMyzsA zfgT(VZmi)NXu??K4q8Ha;xkHz=m2sGxRU@%Avll18Pa}*j^?7q5$b^P5A>z$Xo^t> zE-(g)(Nv?1XMh$zg2I-8ApsH2#H>h1HFSs^oB(QGgM14c7=FWG_kfAX(|%p|mx>7VegOb;M!Kp53MLnMqrWhy9)?Jlt}UW5${4! z1tGNZ1ChOUFA?m#Sj029=_0}Z!= zXwdN^%nY?R7(fir>Q9gahz2!Wz!IQh4}@nhFff25kOuWYl@Mh8X*fs*q=oR{D`cf< z2tos>Yyern05T3DJER6*%OFG9Cm28sP%{iP_zI#S83O6TM$lj;NP>|e02bUxp$YOd zsOiMW5CjSwkZz>GS5V-9XXzLMLGxq~h2ZtN5QQj%ub_3_NG5|q7incKsPoUr5DIb$ z$RgZ>uMkVXQ3bIC9#y2Q%(Z|VJQ5t@;tW4a0nCA}T?GkRT3Q+y`hdrD!BQUn!6B|L zAQ^<1XRv>~p@Er+S$w>Lk%57kfjL+XbOL!i^uPuX8)2#ml8VtY$_*J98T^ACeSBSg z<9%I2f;^pr6$}^{8C+bQLfzv%{oMS)ff(Qs8Sm>H3O=h{0mN_$^>uP}jrRqqjgNPB zj&}_51*;q#d>vYYub|Z(pot>}2GFPz=yVY9&{8~V8wkt50I2u?UHbsh4BA8r+RA`c zGjy<3AJQOWU|;|p#|2UiA8bXl4cx5(S%5f&1aw(DJ}skztKflS%z;{B23JX3r3;F! zV$cHJ#FEVXyrH>B7kqpibU>MyV?>6kpOMB|F`^80$Q5+hDP(LEuO1>sUNJ3#55Vq4 zS)rQ)?mU4qI?;m!7-kQVu>w%D8st&fIP7NzyLV{guozy$QtBecdSC{k4afe(Hylgi z>fE84=0V{M>UMx=y9a1vvY4TavNji{kN!imQUfwHD?;6&Sq26YSLY7pGzRK@fz#Lq zj4@iwR0eL-AhIt^FZn~YprRDidW(yXFG?*2pXCCYg=P#e0}a~~c?Jk*lQ9E>4(XFL z7#hy1jrobbAza z=oVDO5HobU7R%7B0@BbeX!RU3188u8?15X1z=nY$Ot-GfcEh@uw%QR_y84Vptc}r1t^FO!=Qfo z=-@8=)BsShKvs|jf+$e+i+1<`59+E{kOoi~g2EL3H(1IAC5!2DZU6k{q zM+bLDk6jo&c46R;T>u?I4=TGLx4MCjgGG$bVl=?8j5dJEKtuSbEofma=wvv2WO;NncfqJXi}lfyhyq zdS^$cVV)g51H81Bfq?8-_oP+K3=yV1K1}sZ+L3dKZ4rhR@&0Tmb-0(qUVVDN2!@}V6qd|I63slgt z4dC;mK~nTTKbpj|=OK<9LS-|k-2{%q&n%1+kj{@rcm&rtF-#|9i7)76OK1G&M}x*^ zseFDkXnQW&eUs#z9}U_h;3s5?HmRjlZ%iA zjk1DHn_&>U!UB>3E$Kj&1sycWAohs`bfp$301>jF)1^Vj$bce)fq?Z5bSJQA;$-^@}eD{3_Uj*{TyjFVaQR|po5b^CV)4bkTX`dFmr(q6&7J$3^^ZqKI-|< zdaR6~VxmgKY2>4zK?XsV7l(jmlp*W2LqKN@gKi>ZWC#HbFn|vIWn>5eZSCX&+Y|z_v@3Y9BK)1cOWhIgk;2o)6eCgqy-attyB~ z;RrW{BTRxH4Fb{#8ht_vchC~)L4Ce7;wTm5DGDn{5;?&DVt}ry2Tf6cXi%LBp1T0~ z6@)>T*McM%83I6|m;{awcoG3s(4dKHq=n<4)CCe|WC#FVGy!U~Ffs&y^nuJqQV1&f zAh8BF4%8xmEH8%(fo`t^2{SSTg4Vx-G%+#+g6{2vSP}@D2!~h_h_D1S`3!PB1E>W8 zY84>a3laxK8}!U+kP1eIP>>%%`jL_~NFiu82zsmt#F7w@B8X2$SGLC&XI7==r^SyR zD>8blNa)a7*^cYXX+(Pp%U~L)L_nN54Z1KBRN5iUcz_$-pfMwmN<3#yBiRD(;)9eU z&YT8~xq%EuofUzYJt!tLLco&+)rgBL9fdQP+6LEz253YZ>D*~o;XI~zGAA^0l85Lj z_BG&Y9+bFtPW|?0dm%D4;yE?giZcEAMla~TA(z(RZALV5XVX$%5=V9_-& z(SoA<0tSH>T%g$w2i(_Uc7P%Yg!drIWnw1P;88h5(j%xt4f3YlZe~U=#JmRF8>CNb z--)^OeI4r3cTm}cy7YZ2 z0|Nuflm_@%>S-*Xu`W>2hM0JeWn^Hu4+<`^jVz!+DbV>Mk>F|D_yPt2W$-w^*cld( zFlaF-LP`@N^@;_wt_Ku!2s1%9iGohH1sMyU%y0$G?2>a?COqC?a~Yt4MUa0W6C~tK zG9ViY_6Yn)>r?Q#43IsbE8b{f4eUWOSWQGR%Un5#hIWpiCLLI<4vrb%y+?NgKmjrt^<$j^D?u6Y+**apc2An z6M;-dfXA0%=U|I~Mx;ftOd$w^E?k5d1)mWSVcrIsk>F*v0}mX-W<-P#W{87t>J(<> zlz=c$tptr%GaqKae%qx3$kiZ!u<|l?1Ic(pv)pb?@AR%N=#6Bq$?{?MA(Hv zDFrm?0J;(rGPS^J0*W(M$jLBLpy+0kWo2dN1)rl1N_MQQVqiz{vW0?Vq4N%zX!8!B za03-Rptd$>g*%81!=M3hkQj)D%7ahm23m;lWxfN0RYklg%Ln3_kb>S=`agL;+K^Bgg_{BUDQRg8bb)eO%Ekb#rwL0S)_mIQqDS`v<1ks6dw<@A13AE>x5m8Yea~vALx?O_#jtz&)^W(pm=BhP`?nUgB=5$gX2B@LR^Ce zeisF3{t#3~GcZIjGBA9EpHB{NA7dHK0+k%9;9?NOn!p6vA`F>FK2JK>&2&9B6z2A_$)%ctFDW;{>M& zm?om1KMuMT4|HrLmQ4;w7f?QA2h9yELEW~1b^&Dy=(J+c@pZ#LU4d#^aJpK?%xH@= z#*dz|zzq{bR)uN9x`TnJOD92vCDwy&EJ!@qMuNmad^Dd8k#ZK)iUG&d3>L;>Jn@9m zBt*m)Ogm&mpP7+?p#t|N1<*Z|mW&JxDgq!D2_yQT9Ef{FAIm0%W0)iQyHQ8-gbXl5TH^L+4FIV&qOCus1I z4aaqoDy*EKgTh%^nae>doH@aRrRAW3cW|gMurh%PPgYLm17PFWU_@@Fny~)C|aWI$5jJpmwDP>6tOkOiQm0yPmbQV*6v=tEuY4;^&} zpXd(WzJNCL4w{5wU|;~XXh8$1pi%>dL4yofkL&>rl!6D?K@8BSB533tM1vY~UuqO;;4@6HG!XAvlad?=3hFF;x zYI#63Xn8*qL#+mg2DLdr;;>Kv(U5W5AP@zTMjG)4$%0H^WB?xp1d)Y16eP=6As`JZV&@BX8@7_(V&_YECDuvfq~%>0|Ns{f{`HrbeftH z>PmZ1TN$!(A^5d83?*h zo{=E{WFTmU9C}?S=*Cn=h5(SyAn6Px;6M=oU5F2IEh9q+$WV|I85u%AhJrlH$Pfb3 z4ss0Is5;0oj0^!F3gY50kV4QUfs71cAoY;Ifu|W#2G}h}&!D$7Lm41;4hW5R_74hi zjfnR(KpVIX2#pW+cMAz~3m_!n>**Zi@8by>`E_=4k9US>0Ub0S@9Y%f>FXL4?-%MD zAL1D79Sk-NBsF>l{Rkakw}!NoLDP4jJ!*&ncC-!|mLVcg(W(R29>K)G0IDLv4QPxu zI%o_8q#kji(F#V0dc*)ax{ct@El3lnLkg+`7#L)rmf+Te($fNI2HmYe?~6V`#VW?& zdjMsF@1VLCKKSlL`rtcg85AfyKo~R`i?n**O*pR-JoXN1J3t3lNF8_wEfRzr>M=yR z?x1i0;TFVdQDV-b2Pbc6|8Pk88Oyjj!u_a&@eJ@0bNre}7?MY_3O+F32Db(j4+V&L zAa!6KVfYY9d!P;o$j`9h`7aE1AD9@QVjDn4_zg=5j2KCRnTR$>{|o;hJ&9-1581R2 z3TsfA45IBGvM}C&T@;GlN1)0I5wtLkG#{`>+zkpHum=sAfo=!QKs}a-X(A8WsYKw$ zJ$SKxa(-S(YDEcyfIKUBxja}9&ys$oi9S(?u|d$1TF}rQs8fn{ygmT3zLr4%>v%oN zF+=5`z-A!%OnU4wGDPwo%8B8y`9e|9B2k*#$;kW&JgN#F z(iawE1Dy^egS@O>3p4}|8X#uXU`_)K(1O+%Gcu=xn3AB;eRei;9LEHKhD*VinT<^z zG)&LQOvDJkGZLl}!&i z3&Oz22pW*0L%7+pF@i>lK}QX-GBTHe*(49LLlzeWL;9^0P7vWtSB%VGQHI(<1MIAf z%%xx_3koAf-dQ=B!27#9Sp}h>0MPj`AbF%wQqT%= z&^Ra3z%OVaA4mv!Avs7HXzZ7fAq+Ha2O5xMWPpz*f@C39fYgAB1uzD=89pct8sG#C zK7(k`3SrQoG>8V(r66&z4k!Uq!^i+0lmi()Bg%o)jlAPpdQAO@vD zqt>9YXAs>0zNMk|1Otcx8mk9MfM}3!PzI&z7#J8p5{wK1unBAjd-d9tff!#)N{b1=)!;7y>|{0Z|AK zhS9;@(bdzV7mNag>}pp$#!se2xOr>+|{6qM~Tsj(kcfTF%W~ktH3LoQI2g%W12(y zpfB=3EoiUzAU%h^qB3VFuD51j0HsIhAU81szC+5N(D7P?n^6aLL3s&fl{G{mQYM6S z{GcbdV4On_Q4ZdtPGIa8q7unqqSS*;hK~?=ISiFLlpp0Sh1>;)3-YdhoChq#gx3rkFt>3wq=W zY|M8#_-J|fIrK$|dFiPP0y5ykTHr^xq@<=Lg73rp1Ua1^_jxU_fh5qrD`umz+SwLk@($O77-n+cK{^ykn+965x_X3&wO;5bA( zhaTY(T!*&6bV5dkLFdq$<6hzo%IKi|`&2%M9(0~G70#gttu;eAv?UdB4n63cSj0Fn z=p6drpzy+Z4n1gEivfBL{VmYaad4pnntuYFG(Qcj7uz}Xpfl{7L9!4GTI~ioE`zK= zXhihE&TgT?IrJ!og2vAo;Agj-gP+~Pz{vOjJmC$B8}bIYaoU4&4!tCF!MGA=gqcm4 z4YUFobpE^?c#xTsO%k+Z9I{RvH0q96DE^Gdh2r4j+1V5+Jei((S3R3B^99Jtam;1h zpmXv;qoANA(?lJO4;mu|`IdPD=324Bam6N#`>LDIeid5PQNwdLZ@;>9geFlNzA))}Sc^5Dhw44?JZ6Vt}F>Bmts9?Fz62 zEUG~f36j8ml)M-t0|VrUb!>;lgKA(<(*!APfT9OWe^Nh65={P9!Vo~f&$O^ z@kol{lM;B&k4I7t89*s5NJ%UKb&eSD9FM}m#KFwL!okYH#=*|P!@zRs}SeVGvMY@yKocY&|1tG3lH@n!<7YsX7Rm~JC*iUp$XpHCW`YK?P$p{}g_D@J zKnx`%E0rdG{pTHi5xemQ%azAJ9J73 zrU+@)2W2`*8@}E@GPf8K>+zX+@g+rxdBr7}`FRWipwkbahQU>Ur87bD@t{ydR|G%( z7?g+@1SX-_0b5&%RSsk=!d&>-)<`D6JOmo3L^~lH>HHy>DkN{Cj?H3G3pNox(WQ>! zXoz`5sp-&JIAORf=(t7jpb@BKz;LAV0#U!rn31-C|<=!Nvm#8^}H* zEG+Z0#2_Gj3+#h3B)hqQuA=Xq09w@+m77?U4bll(Y7APvCbozf)R+OS;)}}6OG&MO*rEio9D*;5h&%vl zeS!RIf03E-97a4rV*wVZAcc@ySwSq!I0BuwjuJPi&7I);)_yq z6EpKN^U{&ZVNk0WB?dul7qJV>pfy9Fn*<}VmflPgGa`#pOBe(|>k&W>W?+~yBH|R( z3I_QXQLfofV`hB7h{%OV;gy`9Tac4lk_wuf25ABxm;+*DCgtQOF$jHO0PXdNgys=Y z_Fu+A)5L^GSW+gntID&dr zpm4PN#>Cjo!~?Heic9i~QW+4nGfZ7(Mq*w{PAY={X!?3Os04yk@Oh=VNuW9bln#?I zkEa7))qs}pBh!jfQ{z#>J%NFNVG5#cK8({ZsOJd|_o=Lm6IoGPNy$k_0S{A%67YXO z6VkSfCVJ=({zRu+i=4C~osVK%6%v2Fok{_Rx8lRY)otgsa z5`ZQIK%xbuNjaIt84y9xR541a#yoLBJ<2vkMn(pPn37DWA5pqM%`BI-NP=mp5PcE^|*r+}}zfy5-V z0S_KrLzD_I)mS$`&P0?BsJ$yt(E(oh0y7%a55rV~dR-AHnS#z9!q_QUMZz(Mpw=pA zJ;LxW*FmF3pm_9L#^eKD(ZIj}6UxtGWMC*}U|`5EXJlXiE!|G;Vq{uT{+Hs_nWDJ&e&|;8!!vt!agVxHp zgXF!y5*{Ei$h8b49(;VF22E3A%8IO;m)r9<BptB(IoNF3 zgrU0@LA57M-ExDGjgggA9Aq(D3=<=0-4p11Gn(4j4PH*g%E~6q$^|+!Q<#-kf|ZlG z7Id!^D4l7r*@0GMv4JiSf<_%EqF6;i8*o7p&nyhur3=}83zA`T0;N?}MhUPaXq6NA zP*Mg)M$lpnn)+onD|90+G{Lb6v&k`63X6bOy>K#v0+ttaxF;(sa}sF3G8l$R^CD%_hty&CCrxbyEavuQ(|2fzO;2 zVP$30W#we%0LiklvZ;gFsP-v@|x=fn|%Wqt4k|J!9Y*G@;wZbBx7Yd;@POXB2^CQ;;7(%hzd|&h|p`3>TXi zD<@>-pB|eqn=8mS%%F&56=YLn&I6fdrlZ{Q4RS>jK9CBeC8#v5C z=^Ye1!YUx2u}QJ=f>OFDE2kJF2wBiZdYA$R(26BS@R<#8A&7<` zga*)sU1+j_AX$)G(5`<1IR|O65l9!v{UASqXwV2L6GJUX6-bH!G|vfYmLhFw2JK^p z_yWFf8l)5=gyM8iU@d?0ZU4XSiO;$YpN(*Qvy0YdzRSmcFb1;nL+LJSNHpso}nLnx?21lmW! z$PfxL5~L3)EuIuf-%7(k3XPzQsdRs=+Y zhBlZPYJY&N0b@|d1SG-85CA%B5VU-eks)9oBLf3SDUyAlxoS`ufs}GVF$zf}A)xj& zXd^!(LkOsmbPpUR;1g3pW21}=As{-ZnVh|gq7L*=9qx6gnK_I1*z+MXinGXs@Mus4e4Umic;JFs02XvhSBSQd4 z59nZ9Mh5VqxuDzUphwYyj9_F40BMID5erW^peO_dEEB^-9+-X*8|EaCJkE>g0NP&$l19oVASEE17#YA8LJSWB zEn0#U-C>~Y57LKLc0v>efE0pOXF(6CfGEW6HjquQJP#T`2ZthvQ3l=}UMm8kL7i)` z1jub5T*Sb@0Fq#22mtkqLGoxmfVd_IM1gWC=(b7*1_n?jXJiNk^|e9z&`K>(eq>|_ z1W^z@VW2_}q9+WY2Yzx1$R!}f(6f_4dO&FyrU}FbDFNZpQ#D3U)fhchV`!bKfjGlB z26|*N@@N*8WhtPH4jK>z6~2%wUO)#Wqs@+i6oD2wKore@9(0UiGIZstI=BP`sXu`@ zLm5ROcwil*0My>Xe)uuwa!q(Unt_19 z5XQp5z|6qNC>$SOT#}NRAD^MXz$g+Q?-=Ck?BnSaALbeax?fVk)WFQZz{G@sQ3)jF z=;WyoAD@z%oKswonye8YpO;^fQIub<$-t-@A0Hgz;^`mn;_B=ZtiZse9v=@f$uF3J zQ5VKkU|_QG3-$3~V6+8MpzA8rtnw;(SuR{>d)f$<1qh;INw-5Ew#e>VjUT|-R<#!HOBuCCtk!LHz2JTF6d z&Y?k|6W*^tc&>gf3Puc!w?Gbc^7KC1GXqV9ko^1{D}}_O+~j11XpuS!DJjZKDlJKkkJr#h&d)0@ z(bQyMl!fW_^ABj;M@-?v!Nv~qh@@3 zXs~O%v!x}dNQPV`!2~aZ85m9AMJof7JE$CHVDtb{pyD{!HNrC_-p$d|2jn$F2F84_ zKyawDvukiLNJS%KkfWaqxC}F>Fi(R32F4CXU#EEI&>*mc2FUy1goF^(&{WW5U|hi* zAMfMn=N{_l?i%mo>E{iiojn}=++Bm?-9r7GLp=Tc;zJ?>Too7?m$HJgL~&8PXM`)H z)HVPW%*$ZHp>7~y3j?s|a+s(;Skwd}x&kKZ5(QFg1QA^c6ZP~5i5fygSHndkoWa&H zFs^|Kg}Q-+EEpKq!bJSRA|?!s>tG@-Q6M!&42`jq|gLqFr@PH0Ak4uvE?VkC{T$>-2#*eQD7ElsO35sXFJa)2D=f_~VGx=FE+mUm zb0JI?h5(4X&{GD+7){OXOgRufO#NbndJvO^ApojCNQ99wPG9pSQw~%>0BXZ(gboms zgCPK>LdcboG0{kK9&>yVct1o5X!p<)M&?P(LUR}xEkLDx1%ps0Ba<=%gXRh5ct^ir zPh_Pm%zMBp8K5dRgH`(7012uJ-C$G|dcYXQpd_?|K~QKPgObo4MkS#Wi~;fS8L5c{ z1w|zcLQfbOKQZxZE@p|3FHXrUGd4=9G&I8#HYm!3elarsXED%x$Pyo4imCe;!rve! z3qt^kG9e2l#s*eP&H1blL(NQ*Dvga8IOO1Q!2k_FP!xf6gPaIeCRE16*u-i8uSAbA zFquj*fSUp_EDQ{>EDQ{B&~jZARIV3+)~|vZt73S{bqQ!8iM?zE74Y%FAwiyg?(o*C zEUZjqU{rxI6&RSzLFFO?qXmdkFkoO|phCU{`2cIag&e{Qs?}JC%(qaZsGo1q8b0vY z>4L-#Bz_WD7#I>+7#NbE@xud(pOnO+ba1`Pizj{rz;%{m5F-4AV1drSC<$XKFfclo zC4$anDJs!OEYK-PEXwuMQ~)=yz-u@`f(j5(2FAd$#Q4ObbdVV6tR$#9sE7hsh=DN` ztT{Qqpi(0xwYWs5xF}guK|`Y~KQl#B11zMeV5^`35(ZV)*=33GL@O>WON>v=OVLOy zfZ7e^fXjQ(I2kj83q|F9Vo^FI-7r9waclrjL6VYQK#`-D!9ex&0x7wbgt{0s*E52H zI485Xgn>maK0dL4L1+S~00FrZl5RljiBee@7}B8Wh8vu2GV@Bn>4pbSx)F|#_w)-f zGf{|-&&(?^GXZy5!6Na_@xh^PZk`eG@d`OP42)v&@d1v(A+AOm6*`rg3Ka^<$_kYX zjN(vXh$xf;Qln6*$-pQ9H9p>1qXHC%uEEZZ0j}}!8c>BA6*>xVC2;#d2}LqKJ{0N> zTv|acD8;2;2GKkK*M(q$fl(QpPdxoX;N_GmEORh0>cE%^42;E|ejyg|zMg&xx`sv; z42&h7ej$ct5CLN&b2AGD#!^qe5Mv{-kVYM%<)+ENSO#%9NH^Sf$VwnhytFh;2F6N= zJ&q9yhDPQLj8#x;93vD!wwN<8Rzq!Zj8HH#G%+`^Fg7zWXJD*>S^?@hL!vO=S;NxE z$k^E2$iUdl!qmjv+|}&@WMJ$Sp!Ez%m%yL4IU53VWr8yI0r5batmgt&xOl_T!bk<4=xXK z5fPEH5Uv3dC&-C;5nK-B7*K#ArS!#cNsvp>B$vP?LCzo|a+X8F5*jY(iG2k^7U~j| zh**h`hPnksdKE$%?ixbTv*bbNk z$aIKH7#NR%O!9S%0Gkva4=-wwiY8bd$;r`VU_1#|4-PiCdMt$qSp6BW&0q^qHDF7C zrC=>r83RIsTs+;}z;1&20_3}E2nkg0-C_*(bdPro@%Qy~25Uk~wzpB_(GtT$#$eAV z$eefwVU;fxH4Y5M1YJGB7rR zg%QTW#GAn42*Y9G&0uka6(B>QJO;)#CQrW*P{g9w(%?!S9Fy%}{W#Ttqnl|H6STHt zVA{-tsDHuDH3n+5*D~`;P}*x8%%CxMP&#sG+2X)uQ_VqgqK2tkZo#K0Ja5Q7-Fh=DO2AqFvSB?Dsw)DpOPHyIeCk;EVd z-eh2mK@xvM?~@LBmxEJf0dH?-8%Sz^uZ=!mP^7!f5E|I@*ugEA=tqX|M5RXaGxGccMtd4_1@ zX)0(KmgXqf*eGb^fqGCD`3NdeAPd|-3om{Ydo~DA0f<~^Urh+{vKozXO90o>zU&jdS zigGnUiojtX?C2B>wq657+9()+Owk3gtw4rpGB8Fs1-UwUgZsF~MjB;_MLJHEC8>U; zAj`pNMpHurL>n7vYG{DuLGIMhfGg5cu+Y?0Py@|a8o0TETp#Te>gnSGGZCcF0Boiq zm^1>D#vrf3jfFG7ijhoH&{jaQ9VBarENf$G z0HoN>O_PB!)yE%2Ng~92uv|LAWfo9tbYPBv1d;`YyWAiihbo5{X5gj?audY6xuEu! zu~B@8KWNH0-p4Z}#K$$>)z8J#(NCkmsWeTeEHOt@Athg-T0sjepsB458b<>qg&a^) z03|7?`>k;)v4Gg@=B9~L2`G*T8DnIEWKOL@c?PKL&@cdvb2x>%f&2jV4W>81;SKVS zrh>Muf{CV%0wOexjWi%Wi`F%X)lq=4jgiXblapfWCr-W~_pmf>Rh&Koy)>>=i|q2u4Kyh@nbE`1CqCTKGbG;G-_OMp zG>ZqC^GpGs&!eeO4UPs4MIe^Zc#%WkI#)o+Ny84HPAQbC>_F93~8z@vO!0Q80 zHBgqAqhPCGU=4|8H1icQ(=OUb0&+@=<3Xz+pte~n)GE|6FwVo{ zp!jhAc*vwJZJd@=l$w|gb;kzA_;|;Vkf8WrSIC@baFC;Kd_1VSMV?nKPE7`#tfZk7 z4`sy{7bWI`kBEp@0v9M7(G8053?Rmwip&BeV?gUXK$Z&kWS- zvS1Lp&cLW932vBMFbF+kU{sd`Nf??j2z_T@)P%@@cnpk;T3{(-BL*QMMn)Zo6o@Cq z$fzqBkdc_oqTKw*ejQWzASD53I^K*0KQ_D)?OBi_MKrz7}qz#(Xlmj); z7=*4cGAXmj<)r38ggF?Lgq|@3AZZd>z{t3Uk=g$I4_X6Kz{0>#$il!-1a0&3I{W*&xVpuAC@?U~FtIQyh538BC_pB97#LMR z^Lg?9-UD{-GftT0PV+G}zTefq_xO-_Ivffq_vo$kovW%GL_@a0~*= zYJ0o7g4F8-x%xOpC@?VEIs5wshbVy8c`z_Kxx4zg26;LwFfh6W!`4nzfEF*f!`4<9 zR2UdCFnW0Ug*p0ox&$}|Ir_SWxCVimNJb2do>1}l5XWF|keD$8qnB^6JE#J7a}A33 z^ACx440H7K0m+##FnYt(gVY50d-_3*GG$=&fl0ZBx%!2~d%A$Mm@zQ=!o5dGH zfiTm3U47$016?51P7I7eeqr%WjxG>$d|bhc*qj*{lR>KhArABnc2_W{0Ilj^V9fM( zjf{sZ4^c3va0Ykd7(k22nHjQ4D2MWk6LUa?5oo=cJ_EeK(9_dLFRU1n^K(;D(;x*A zDBXg}Bv8@Az{m*N4FNqW09Uz#ViDY^p;7_`1eYY1lorRAFbKGVwz)*|gNg+s69$2N z5I05;Tx5XwH6VVhAfz8(!ot8%%EG`<2FrW?!Hz!hzOKIhL6P7LD9*$Jsy{$m8<-hD zn`AKVdcYASD8b3V05LZ;H@~P75<&0~1{DEppe>C#h_!=6#SyBJLnWeEFlvARP*C}% z=6a+Qd8B|xXS^914Vi%nY7n=W9s%2+7P%Edu3Q zc$(NiPMUxlGgQ(9Y!3bzBr-wn2Sud>Bcl#8IC?=MMM0^_Akk1pMpNeCt4u8Npmwpb z5hOV^!Q zpoN-39~eM&dumx~UP*jfPGUL(*i0s64!M%V;_P_PNj;#_g-Mx9t|&DpKQRU5Fpy4g zl4Mc_?K1+8W7V)QFx0XzFw{ZQ6$dyOfogPNCKhH9W)@~q78XWXP|A;1M;%9(z6i6pRR#(ALQ`Zjce?}#^34!sTdQqbgVuBWoVXFXYZ!j>bASrb94G4*Z zDbPSDg{aj8wMf9FXs~;HV7!N`qYH*wO;8&JrpCwB58*fs4Z=3)`gz5wUzoVYkgIPz%wR}f0d<=}tAHWB<{a?iU@#lHN)XJ3t^i|VV1TB2a7JNd zd;|6$xEqSA-Gt3UsE!yaIS3Mq3@t1S46Q5-3~kUfDg;TR{=uNsDaFLXC=2SkAobor z{Wm#RUvNhUv^*X(Cg$eGz@z}`5(T@)yGDdSdQA+BF|NMxAs(QvBXqrpG<6i<9I&2BsGdCNibY%~H5uU12~<;8=Pf;GbJ%q>7TwisP6#MT<9_T3<*CF2jNZ>XM#hf4yq|HJ~^>C6~(Ebn8?da&Mi;+YCxrwesNK(gg_sEnfol3K&)R0zgy5V73}xKqy4w3j?EucmQY;#sYK(GNYC_NEN8B z!OF;}BMg=S@%R`S^<+R&py5UZMn(f(uoQ@=&d6v4F~ZD*LCBnu(L^S|$=~0{)zJ@Z zq`A0~kS}9^t8YAX94_9&(a*)ll|kqRBcm-pNTMVIJVOlXE-(oBGBP^wA&G*vZpFi; zoRFn*OG{EK5OOYkwVe}lpPg-U{&Nnp_se!n(0p%YB1LQk0(l!SgWA(;>y;usVXALJhz z;_2tgAjHPZ7^(=84ss0+^$B4Rn#9N$Apq(7cd#%pbh0oobV2J-fq0L2-{5#RSI3ah zAXiXL$|xJ|>F44f9t;{w^$m_Uj5knVU^Mj&jt>a(5Ay`=G6rqL2o4Ph@DBo2Tz0;} z@t{%F$asX9J4AT|vREKO%rz(sT(`x*g`9mnT|w0#Q$ENwL7uLDE->R5m@0gO<9!1B z-~x=*&Tj6YPF7HeldEG$ysy8DD`-}0BBO6GOcAIKcJ_wti;nm7bMseVV4MX~0dBCm zMEW^`RslNu`?-0#D=;vw07<#HI)%E&I|c{4g1vSCEan;P=;Y%X?;9H83K}^+0V+|! zW}r5D&%?zbl{lzAS72a#05T&u#6QT<9kfU88HfvVun%bF4Px~tkeE{tsJ8zMV*0s) z!u1P?=@Sy8xhr~QB*jG1o^}Vc!$7DP+(xZ3{wD>a|`lwi4XAi0X42*Dd-laiqHTT#}HQ} zQyyZf333fYQt$#(fxjDQ=pEtI_n1nYeOw)bkWBf8ONq0e8I6o`lrKv5m!>gykd?AdMt8c-cG2}QMst0Od9z&*~i7o-A` zX5s@voqRllJs=HVn3otBk1~UkG_3sf_wxs>tMzwr^-*A8JcTOh;~M7b1I~3I$vYs! zUH!m$Bsc&x1#_Pnl#Eb>9x(g4hQy-?J!A$235w7oX2*a4R8_y3o&9}%{r%$oKt~lg zg@Ur`f3W#T0?jNS(~$()SU?#ESx*-W$TlP;eJmimkOU^P1cx|9AnTdV0u3`HRkK+@ z#UQe(`7Dq!1WAmAf%LI+Y)vB29Hc%2gKuzrT54iRX;CV)b;JN}3xN)O0(S=)SO~X; z5bZ3mp{PaIf%*WH$GXz|NiTVb|`-S?(`?-dM`v-Z0 zHn6w`xj8z!27``c5QEBs;t^h*f#=lVN>o5fTtniW9i2T~A+uq|1`LckzQLe6#3TC*bZ6a&>m~40DZ#G^iB7rEd;p*1gcX!13=4jkW!Ha1LG4$P=g3kdqF}7mJ~oE+MbR+AlnQW z7~g@c3kmXz2L&jo!bDN5UgE{g16noZ8{p^{37ws{NHT%8b71lTkZF4ZgER)l z8^{{NU=qflVM+$j*?P?213XFZYoitE;Cdn_GdHsYR!cB2GE!Jaz>OO^H3X!Nn83oo zFp-6UVG?Q`;TRn3>F($10xfyLwS}0kYp@4e=f*WC%+ncs)Px0S-=qXg38+JZEN8*M zC=Hf#Ml-?1F~l(*wC|_F$kD}#fl&sxDo}}T08-}6z$lBPEFv-<#S|9?Mma3faP6)P zjEZ1+M;Gt{^7sHJP_3b0P+?@rz^H^OvMiF;%_6M!-FmhsGR0B)6JBEZn zOoLXYpk*Nj42BxTINsDqFKm+sIq79?xH zz^IEV3-0rRqzoAt^-!gp{ry5b{X#*}XJEv@sE;ZOI+V$v!oZk;(a1MA9;ILdb;09< zJweM^KtspISmnc9{apOP%YF8OMMCA5UjT zP$>?QHDqA4K$3NFg{C!-V=a*+;K61LX;VPm3T+kko+{sGRQZl3{o!IC|~ z)u<|=T`GiPLk30%48@?D%^zBHf|DPplN$;;@e5{$5d)(mhBipe0Pb5rJPKMxACIuh zn1Rs=p$S^PI)?@Yf$ACzD@+&|oiS8H3SJDgrVNZO2(?fzBRWASP6}}hLGg+iq&bE) zU|n3n6+GMvkOfX&7*;{!0km=$S*;-hqYo~%;4UJvVj~7dKU|8@J#1kBO1l9F<=;u9#t;I^L;W0`z5V>deOz7KU0o2-Y++zv#=sbc zPd8c=SQr?XGcZOVbU-5zBN?K5%7TG03PTs96v7AqO9n>JNE2!_L)D`D-jRVZ4wt!D zqQZ%RF#$t4tPv0r;)CH9X9mV3yc*CQkh(H3reWxTjsl?vq#FZc1}?Q| zZZR}qV9dg)7Q-2ah76237|Ovl3b<%P4;w=x2F5&m>d~EJ%)nTHS3RbaOc)r8FtmWm z(I8j1AaFat!!g(u!)2xnj3q>9LwBGV17jI6+A!T|&cF!jL7^sD%t96|G7T*l7^^TW z#MFkFkPR&v7;A{oiQFJ}4F>O(LeBn%jtq=-IE;Y|c|kifDAksQfuR%V;0R(gViwDW z&Y)u?NYLx(%rz)H$TP$hMY}5lV;fQj3R-|c0v$y=mQZ&C z?av^_>FD8(7Ji`4SQk-_KsN|8JdMCxMaXd!*6=YhVqomUbQ-id84vEM`Fe(+XE`Hd z2F3|QXhX|#MkWl5lZerVk>!j`85pNv>VyoMqvbOrGtf>Lj39!jMR$=o1LF)_=3*uZ z&}lH>SqjwD80_f|8E^#+J_S1mL9-FMyDULRZ(z6!hi3F;@$<2+24LK?ip*zUx@ zxPTP>7!Gh|U|fW0fRBH8e1LyAcon^iD|qq%HrRpge-{SEB_tVuB?4R-7?&ZL0c~DE zTAz>s7o^sbksEa82pU~jRO4iH0d2vn7>}#W7#O$V){Bvwjm;StcOa>U zmde=s1?WL-!N9nSSiR_ev}9o1gHJC?jeu^kBj_k%L>yx{8bvd@%}$`>TZq<-8Dh>1 zjE68?4yngLQzcHGeke_SV;9i*$QTwPG+^c}V^`2YGI+Fv`eE4O1|3m_W-w@&__>CF zT5V|6poswk<0(u(Kow(FbtZ-kjAwAFM~fX3&=??2#pq?3i7^A?1)Qoeg9dbF_a&U_ z(fjTe1}3Hqj90Lz_jhrP_jCdE1VbXxbE}CN1LHM9deD*;=rph!1odE~CKK35Hd?fS zoEPMZZigl4RBVi70h)w}hbYDpUXBcm_b}assOmsT7Ci=?pwscFjzZOg5s}UejE^ua zLa7z8+2sNnq{r|RhBgfATp1W&AX$exA&crEBhX;mE1Zf^L)i#4yz~aIVw}aV5opK( zJe2?qIaF6+#Euc@oOAH11~m1MnPYTcm@+Ve7dv28jP46F21cYM5by;<5R*ZQ@%X}= zf$;~H5P<4MPsBzB77UEPu&8%&^$BrA9pJJsGOz@l#)OD)SP&r;<8hcH1LHp|7D1K; zxFXl>Mh2j+5@<#NEwtcj@mS-`z}SLCD}1~n2z1abcnk^Dz(OlNj0{{rhdE*MA*68x zZptGjT`&U3m4UH?1ltM3r5gid7b&J;#4czwqYsM-{(j)bW@rGq|3Tv!6Yy%l%m|<{ zjVbu`phmBuF$3c?f*Nqgv7rfc^$%L|0Q)H(lG4%gpP?xO;~XqjB5MIf2BO((WN5~~ zIFAS|c-(2uz_@^r37Bza0i7zu?mNd|^nRofXkcRrZhJsFu*8}p10#5W6jp0s*#$iq zofsHb;Is**35#XU42-LA>I(uLwT_VzT^JbG5YU3fB3A~+4LEhd9f+15-53}*5v2)t zT!Tg@w%{}a;zP6q1{#C_&(~s&0fZJjmKrfI?!scJ6KJ432)%7&1R8JHgGV`LaDs*! z4q(yY;}4wyarg0ea`ZuuJJ2}8AtJP)TL@~~f>-0Ag$Ud_5ChXTGX}nMrRj2dg8 zOKFI7cOpB7MHi?9jk!RgAt_z#ON z$oh4hiPXf6fw2L!P8Q9FnA*?-6twINynYy}GuYKH*gq)V#T7CL>>q?)3V{X{+mNin z)PP}yAp>IvrVg~`4QK$e3sV(_VMYv$J($Xz{e41x{V?1Lnj65W7{h4LlmMpcVAmil zg|V?Q10#50G-|j(6=N7}!oWBU(`aW$7gx~Y4)mZfVPKqrTQw-v!E-+7Z0=e3)#A$W zpqt6&;L(bfG)>JJ80TRs4|WX+@$_@YsI5Swu?z4h#|R=&(;KIHjF>fJU|fP*HEIx9 zGB7T~uNG$zIfAYzLUc)?i5==^&>j$!1s|qP42)}#Y{J&d1&ti9Lsx_9US|fz4HzoW zW5b1kaTB^C@NNwB#ALz1xCN_16iY3Pj4c@$w_#U^X19fru_FWH4s^9q{(k5)+eXGt z42-+5Dnz&4nSpT+c7>R>yD%{BLsskP86O$~+8quWH$nHmD+A*JoQlz1;l{vt2)AMk zmw+10$B@(qJG)|r0jSk_0z*-dt263Eu@R_cdJ301Tq)GT2-K`QgP{#0d$}?&p2JWT zK^9!&ay7HOdS z!ijn^li#T1ly=ZF4!1#v2goAFKIRj${K}}dJvtVHC!J`l6 zJM`GMWMJ$gQX8J=cVu9kfX5VwPtmP*Vqly^lqNhDJ2Nm&!!W}cW6`0JsS5++46F*# zUFFKaI18sjJT7r#V4QFfJje8!Z??7hNqQN)zrNH8W*kTtV0j%-}U+U|fY&A1o7~hmSb};~Kmg zu!M>Q1LFq#dQgYw%q$rgHxbl;Co~)x7`I^6kDO>A@sA!EP7I9ONYIMM5zY*ZyD&`h z2*wz6HFIHL+=Er2M<_-M+{~4MaUV{_=$>(7U_5|VF>dFZ8!#{)!mSr0C7ByCFdo6G zJ{Xio!P^Wnsy{_yey7ES5MjF#f`- z2NKojRyZ**{=uUhiv`XMj18>l&391r!hC@qdoB!&O$0UIiA7fi#ulvlAwEL4&W(Yw zjev68mRTAwFm_?+_HhO;9!9S#EJ5qcaVkc0mnCSV7_VYHt^$o4dV!GaffpHc#)sUVd?o zx_>~c#fi~_$77%c;{=Vs^dV@OI5uqoLH?krS&aE5OVF}#yc$sa2I?^^Bd8pgw?I9H z75H_d`3TfqSdF9ub`m?hvUh_52F8sbWsnuNo-WV>grM8hK|4zgK-*R~V^af}Xo9FQ zWMJHiq6WH_9J1XVqQ;1UaXU6O$mSR`Fz!ZC16%S2Nn>#1K<6SbFz&^p6mF`a0cc6% zeymC%YnPBsHDX{qh({^1sm2V9hp{S!6}y;=*T82~8B`b=fEF_zB}p@~&87^D$FXXL zEU&^0D>DYhlSF6;2@OERydiiSlU7 z4R{_95mMkoQ9ff+fodCg{q|+;sDMmCAzNn5!1xoZ5_H>47#M$JQHX4v zDFfqQG$pXf5@ajQ7#RQKREBP?IRj%O8|dT}&}m@to-Xmh&M-5Pt+rrbY(-H9X>fo^ z@H7O%0mh(us-1vhRA(52Vzv{n7KCGrK~da|MKNe_6xkWZ42-=vm7zPpgn_Xihhk)_ zO&J&`;!uV>ScU8iGX}=VShRqKmXMX1GcZoYsSMq<77UEjaVSQ1ttA8FOdQHUgH_1Z zJ2EiN#-S8xLhC=XQWEg z*uaf}aVaiUXcmJC>*d(hBH3$b2tL+_AqRXucM{~}YBpX5Mn*=^G3y{cj^n}+=f8mu zXiKdq$S*2ET!I5S1TL`{atm;LUTJO;(xn*;jEtZQ7>GU#4x0tO!SPs(A4{Bj`LYgdn&u?P7$kb3%xlfIQK|2s-8t z;RIu_ZGDW;CO=#?=BQ+y9{EHIhv;9AWh&4%V3+$om{~qI6hEYEYLKZ1Ze=d z!_nOpoNPdc?L*AAL{oYiq!fDEF!)k5=pm)9FdsOgX*dhg;OyuJat~w|B-9a3XbR6G zDTExT3RUQgrVxArAJjz9Zd0f-7c^y;LFR!f?D$Z~*`^`>(3{P`%gS7#+Fa4JT?J`_ znjY*L0#)UPrs_IKRj6NZfU7g;oPQTk2K5huC^iJ0?dTf}5{mb9(PUt}2~rG;M39R; z{oJ8S(UbRU#t=_m*C5DQ#VC1I12bpWC_og$^U+(VZj6ksfgysS_dQfE#2Vzh4z(Fs z2t)Tr6y2z01ynz(AchH_VJ6@zPc)zxoMDzU7-oHgnguz89CRf#=yC_7AV&+g?@;xi z1!GR2Gb24g=a2e8vx_09XhGBQ1F8dZ^dtCgA*k`7as^HCPZY&&p>TsiWeS?wUr@Es z4Zy*!jzP{I;5-S-VTPb`1x?p)s4kE<5yb;Ie}aN59Ih8szM$#-1Jw%>_74q-k8%z2 z$D$Kd$bgieSpi?X1&cqa|Q2;50C)7T$PK-o}Et#U|n*i1aF&;TR zLX#M>5SopXkaVJ^M5ta=K{VY{AiBv(nkep{4mJl?6u`@I&|M{=&;rR2R3xBingP~? zQ0yNX671>X8V?@-ho(AE5=GH86Re3~dH|(X6n(S6`rxPOf)fI`o`PBgO0p;#W`i|= znp&U|9<4TT1C^U7%2zXi+DVWYB$#GEO5tf{Em$W}X$D2#dayo-jmQZE8t=$LH3}#? zHzMgoO&(CasDfy^H$!xjlV(s{u?=hv;WUGyX**aG;WUGyX$M#nQE3K6-%hZ;kcfCl zX^2+9p(x#jsua241Qly2Y7c_d!aN=n0X~)@wDCPXL1R^%iOO}WTIH43PDZzJnPP2y19sDkMF??UyHlk!nr z@&IBIED0czbC{zKN_mN@?IA=PLOHGy6II(Ih&H0qKdR2h5S`#dPeUR=m-E54kV5-H z;I_0OsO&`5_?ZdR6@G=buZe_(S6rw9~H|G}CFrw0^G4dCkyh)NA8`WnIduoi_V>Y9+$ zp_hXw3Y)CHiPfEv8$I#$4RfX9X411zvTIIvET5vb9Nu6HF& zFU+=JXxjm5AE@j`*Ru+y2YPu#dj^%hwUSGsw@=CEni;bUzZ* zDp0EiUDFzvCYbZUV?oe!3P7urpuGnpP^L!Lybh)rU)Dy~w2v7)@CeCW1oJjnEj(u* zfaoPEU!&?g1knkx6*&V#b0o4*jRLCPBglGDvo2IOsvx@lV^IC%q5*VDI_LsSPzT=`-t`8JuNs09II5mAXnMdGWT9#T zrEpYDXHhlzc=~zA`vJl1+bR!4Y zE1>j@s^LB}bnF|FNC+lPsA_oPd7XYe9pm!4rOak3s z?=23x$rv<2I)jCQVI~U$!z`rvJ6GR$=)HUao}jCKg_u|vMc{%i{(d3xKK|~Y%a&Z@ z0~|v<6c`vqU43EKh`B(o?+Xg`1C2jIjDp@#4KWsUpPg$^5a`w-&<(-}!H^(l(1lT; zi(Kiys9oj~_pK`!bsVPG@@$vQ@$sDMan7%JG1NW8CO zu(w8TeoARhYJ6sjPC;Tih_2AdjZexfiO)?e&el|@R?vWnYbw|(Xdu*UD%ja6Xc!wQ z=;HB;rnQ0wvT-02kPNi3A#8#|oC1=in$`-n42-T&UqJ)V(*>adr#Ijph4_P1SJa?* z1mX-|SKs*5yu_rO)Oe`rDXB@N>G5efiRlOzX@bJ1v>+w11e-D>bvhu0kdzIHc1;HG zC9El##k8;knuatP7(+pqa(nu?#``(?x+-WCmlPExXB26~L-KIEj)HnjjJl?RJ?OS; ztTNgPh6+{+F!h=Y;QPBFVF9@|9#kkIe5!+f<-DtJJhEyHcshrc1viD<66B26t~fN8#%JcGk!zQypBrAg%HVc^YZT(G0S7ihxu%YSQcPa7 zmX-pj@YB+YwTf0P1`#Q-RtiesLb+4|j0;p8h)de|~Ecb%a0gADx>81g6 zK`g|{w?!_<`)xE6<_okHQ79bozo_n>m6+B!c z6tuNz<=$Q-_huHQCYMm^;<`EoAAfg+x;jw0#gaY=gx_R@d-6(iax{=aS5Hq*QvtM6 z46;rvk*qc*+V$q(`_m!GE3qIG(!_*ac@An?f$t3c0$!H}YHbm5XDFHl@Ztet{7`9b zf;I`ovw($xVId0x!y;(>2*rEEyZSm1>GYf|7!AYDIy9QbJ6g5~xN2S4Ht4 z7Q7y+1?5Zz=o(Jy<;}$6;?$xNcp?C2RS1ua`+PCu9d7(kig-|xU&6w`u#|;?VHq^u zdHjPNed3*+K;5;Vcu;pv8aB275dtr!baP{1lmqcWi%vi^bUme;D+8lCiV5HgK^=p= z!S|4Aqey{=je>*YUBg`cLNpRJ6*LqQ6*L)G7(&4L-;0F&4~~$`yyTqHlvI5N1`szs zIjJNwHx<_1XJcSw3TN;lU<0@WWGoV8Bos7wY5 z1kZ09fQFsnis056!-XLFP)9c*IzaApW(tFn z(0c|YfoyQ?VZaywi8n~$${=LG$XLJ}0P|aXMq*w{PAY>y1!yd}NI-KA3)s)`sd*)t zC6)2TB}JvlB@7;N$m*Ds8T_9ysS15%Pz8@cGbjl~Fv=w-=Hw(LCTBAUr7yqp>ANJe=Ex#E(K}!m3~g__=vP z#^x22;4>L|$@zI{N}yIYCH-IIZA^%}&{Hc)^cg_ArIPb=bMy1!3v!U#*nhzJ9TaRt z^nY<%;2Ru|Z2VBkT9CWZH?S};Y-C|z*aS^0-0>dq@a>)8$!74q=)%6iko7+BJ9Z#@ z)k72v7#Kw`Bq7rvA)r|lQ4C33yX-?i^DAN)$`Mzvgn;H+#4!{=_RfQj$JVXI>%c&N+H2D5>RCj`|8PUe7E<^!zp@;&VF9{6L>FBV^i*@G z+7JcM{iOPEMWDJ9yU4Q2>^!=%7FW zT|;S(MUAUpNKj-vWWQX90_enZ3!JJ#6pYOn7%k!Q;C<`J2dhGkoefa{9T0AXQyIKW zGPYn~w8p6nS}cLi^tQpN2vIVD&at+|sSZ{+fex~^!>KAn0d#=1J(@gdM|_9^=!|Ly zEHX$gFkxVH#G(SULk@OmXNUsmm}w^hs^G3QV_dTK*zQQ!&ShJ2STlUJY7IJ7qnFRx53|ta&B_OQ506H5r7A^3ZdmIlB6XAV-nl~c+CgCH3L-j8!)giWPsbn zab)#_k(LU9fBc z$$OA!V-RZKW^7_)##9AK8ZcFcJd6vlse%_IXg4~-^j+s+T#HQ~qTvlwnZnDs9h*u> zn-^N!!4%KqWxR@8F}TiyDfQ%IypLNc%>6Lct$d8naI1zCiZHdu`53?BR*M>bM*NK3 zOjtr0)?9~~d6J)T6*hICW;poVC}_JKroLW)aXVi1AdNopFy%i47*F9<4pTTmknuV; zh46wIrtq;K<2P&yQOjPK>RKVjZe}dOfL8v(l(PskF2bf9dl?MV)g#Qf6Pqr$+d(G_ zflD+7A!!lDV+7QKTJoUck3lF>gz*ZpVrU76&D@DLgaRLickU$NE zb_fube-UMzgIgUuhD*g5H)2r+>p;M4brNU1ibWZ?BLP$MT7vOE7B#4S0GQ&Zl8iH1 zk-P!!3&12_OEK=ikOcP$U@E3aGoHXuf!a5KDV306yp5q0+(&?^*eJvJ2w4TBa)tI4 zV2bX^Fuuf8gi@z52nonC{=!s*-gkf**(1x?!G;tDu%1H@{2(htbh67a_G4Fz+?Rlv z>@3GP4WDY5x>`BLJ;>@HjV&+>%i;DH^D)Gb0Sd-W9=r{Gf!3y>*_jC(QFf%+ma70F7B53s91ccHa1 z;|J_2k^3evb5|%cPT;`s56EU@)u_HIQDIz&sRz_oftmVSh4B=270~mKVG3E)7;j-$ zi0-W{HO5!iRf763F!L^|F@D6ZDj0D{J4`XFI^z%Qic$URuFg1>6C;d3eH)lb&(s+OHJFLaH2&-aj)l9TD<4XLBVeXuz&A0`k60{cwXB(eEh(m|*96}*ldDx=E zcpV}M-G&8{cSY_hghU3oG6=2HVf@I&tho_1SPE{I$ET;}r50r-$LHter=`JWN;u@e zT-YoFgIq~sQF>|#L=jAsQ7$L37)^{xt^_eT!7Nu&l$ckXS(2Hb2cGeO>12^hNzF;D zgmGEX)xqa;Kzjq2l-U?GuY<;JQ5~F0Sjm* zIV=hwhr7k+gQ6p~pcpp$1M(DxVZ|k>1@T3x#rZj3Si>aY250 zYEfwc%z8$-{5+@-OeX__=1Cb0onS@riOD6UiJ<-*ILx`^kVO$ekCXzKph_Ug2d0Dt zS2(kwhBG_5I<$1b!JyeHi^HklqzRq(gSi4E26F=ggXVEudSOw5rX4DbWWpxU_&jQS zLxQ9zF)uw87RYSSK!6D5X6C_7K$S?WfJrccW(iA5i(%=Hg+cQqXpA45Rp2xTvr0q` zmYpH)fJ7LB&}K#^Wd<}kaA*iUU}RF}LX&}cREV32Ntp*t66^~GAxkDEWj+SY|Dc%# zRA(h6mXxFx!6#h>;QC<_U>C!a8-_G!#x%YpKRzY1I5`7U?7-$uS#T;vRmXv$4zxQ0 zo{e}IG=G3*I#68=p5+CVQ|USRNr*JgBM0T@B$i~Bl%}M@9K!&Y$j?hhkzs+!B<8@h zKne&B2F(ee*$^BSgIs`=w;;o4yLOYp2sS3o;i3gDo(U+h^!=U*c zG^vB?)qzX;|sE;*gm;o-A4{B7ErN)=!=cE=T<|U`XlrX`RgIWhQJe6}hR2#id25xv6<2@dc?xnfWQOf`lEW1iH&C zGp{7Is4OuDCeMLZgK;uweg(~JqWHczwWK67FC88$JTOCX_#Lbokv-rs2l5f7Ts%q) zaxiEf(t~F>Xc$8s01JBo0``OB8>R<~8{vTuQ-fMcfSie9L{VZnq}bwsSq#%ylvs{j zbn&2tCLe?5YtVEpN@yl0rljU2!&@CHFf*|@ltC^H)N+UEfJAM4N@iJRaefgj3So_q z_>!W`^z_uCct~*!T9C!0%nWrATrwp!rz9~xCBHlm;w2W`3XpvUODAaNlomitfq5K5 z8rcj1m{p*{6Fngcp?WnZ9~$H$7~;rAN}$SSWTt0893+D&fvisf>J(VRO^HGCDQIdO zC8EF!y`XiB401sfZwSlA4050p0I9+ZAvUuh3nANyQkKOV!HnQSQf~w?f(Ka$*$4p? zSHRn+LP+YN(JF#0glvQan$M*eG+%?J_ECIZoLZEbS{$F8pHrHf2g`LbcoQl#ry_!* z0^%2VWh)23aSTP?!Q*mH-I_ zaLX1N@jT4^X5iwMkp2ygLTqHfRFRij4l|yS`L8*OZ}Zb2u1L-R^^_QdK1nkv zGcjmx1g*Y6as!GlUqWNHNJ3B&MWf=B2~j#lk$*65U7JqkPbd9Ru~vG zdqC?%kad9ArSOUoUP>nCgL)va5Qj!VJlGPLX-u%e2^3KlxuVqE#LPTUbq`90umXyW zL9-pS`~+lQD#W1pqSW-v;*wNQlO(YO;RtwHOq3(QwnJN1EOHPYMvZ(J+3Ji`(6InT z@x{py7Totta&RG-Cm9$t|6SmZMDOW`V6<#IFgN=x9&cR}qcP$q}D zg&m|dKdn49H5(?xA(x2K6yro60)Z*yf`lnFX~DvUhe7iLXnhaFcR88q871*xGB35b zI6fycFEtSqt>EDs4morgm?;cMGN>arD8qX=hjCa@hjG{#G?#)F4qHoK#a#oQ4B&q*g$m_*nA{eXaowW zvxC;mqsxNBN+^t-Nm&TPTv!kYHM27*i(p8DozEb&nVm^lOb*Ne4|F01%%m7JcY_vx zA$upe1U|aLCkNty9R$i4@Q{WTomgd=z?w=@a|=?75=%;p;C(I@WNldF*}xhh)kO*!$Mln2H3dw;uSmF&*3dduWWddu;D8)>V zAmvEnY+!}OptPF^>Fz^XMI5lu2C2uC=0ct#;lUN&yr|*LhprB-coksKe1$C_pdN)5 zI1m?O2@jA^4MlcdMI};F2XU~3IWz@em1U9x3B#vJ-~}&=C>vN2VssmpxGn%`9-hLng^#hO)}R9Ecb3YFee##$Q0%-Tm$GGpry}f-hz)HLem0{ zi4nLm@VFIZz=Q=cvIG`I9xUNt&};!MrcSK@?T1W>Ps~d}o+gJ{#sUckNdJlfGaMii zjIeNkaGB)t3qVy|VorQoW@=7KaXd5@U?I=Upt%laH^{e$ZZ0Fd9D^9ez@RxL8ninO z@4^ZJbcYqeD?D-V{!SE^gKUJ)Y{8ul+Pn&y=t5g60FP?_eNn1HjEoFQLT0+i))ki| z7L~*&Cou@w=`ty^_&u*F)}hK^ME!)g3rj= z!ot9?m4$&}8w&%&cIf^<(0L5tt(?BT{(hhX86=okn5CInnB`blm=#%Bm{r(VnAO=? zn6)@qm<>2tn2otun60^4z#A|SH=|+fJ4HLJ1+oPZbhsh-YGaUP==)DW#Vgc6&^A=K z0g!E|pb`=)3)+o}CYuad0q^V$IoBc74|e?<=*$8J#uQX(*ANfaAYV^E7qDv3aSMhF zj2XVc@otVjpyL}Dz&F8#1ckbSHat!Q-Ov;Oy7|Y)HQq4ZDKf-WBc-@Rr?@B?bSh1# zvxj4lLRn&tHHZM6Y6uq5)X>rZsnE0rO{1e~2VLo+0Ww2V2c!pb{ND^rYryK@R%vNy zfK67=(gf>O&{i-2ojzDxlx)qwI2&2J5vD6W{Xz`QK(-;A2^PZcPKW_u`@wc0xpNVw zMPPLV-3f8MCOA~A6|nfm5ab&qRiGmwEi|pcSI`B=!-CKltKW=`F#Kk0gxzlt1Hf)Z z_uE=zzagokncuJlgAtZsFf;>&!zN_snNS)I5CgD=!%j?#!0HA?IA9AiV=Q52WC9Aa z1IS*nK!jOYVh;Ey&D_-7_~iV8N(ESk)BwroC|GDRFoG}TgQYt|GvYNHnrSjH9z(X- z4@I+19$vdO@-#IW7*E0VJCRuKK=Kf%oB)?VNJS9bBye=1Cx7ted0_vdsv{WfkRs>` zvV$Qd2*?I_K?yEzFtVwk87P}-ghFJsAmxK5s+%E(VRiFuOiRJ)@VObipwYxy9Dxg0 zNKk?u1uu^7BU=e6CD8qevp53#)7S_{+&~NiyB}mCa`o^G(^9ZHeEvi)NwE79Jv5;H z#Fovl1qq~RdX4NnNXY{70dm}v872_JzOZn>GK#5*OuoVKp?=_E14{!5y`D!dsFCHMB^3kX z6jbvdSsxVhkhBES11~C4ic2&>25M=5TNMi03Wm`5#HIvM#6a}f*eF;)az2{s8e350 zfm{S`V_7pW&O~(-B%fk93X-oOh9etcgm4t95)G(tkVG{>r+Fisg(RbZ;w&VOBCD}g zpukK6P=&bw)vJ)~N3>UsY2ei%6@05ugAXYygVU3%Z#-s;10(}!ajZqvjhvZ5ia@8> z;nEInb8JA>kCdH@i;{7+IzUG2C_q{rTaZkEw*pY3AKc-Ac0xe84^~Hl5;IH=WTYl2 zIc-NZkHqY3fJjb;W}r$FDRYsRoee>b+JovS60Qxf6^APeX zsK^E-393bjF(~-Xq6Qy{+4%yhZj!U}WmNrSWaoAk-{5%2U-&ko7u{ zs}?}!%t2KIaUPQVB9J`DX7E@|JlG771xQL(peO;m5J`3&NEYG>(5aLd7Hmb8hu8r2 zKawGP&=du^hJ*(Bfv)BP9azc+hE8G~{}`mxH6kR)(K!Tkjfr2VFQ`+klayJKSDLG-prHZc zLT>zkifJmSDHv)pFg^ik4R*z$4b(FSwSpj5o@l`IYBDfB1?hA43Bqn2Sf84$f<_&> zPE7{J7a*?SDXk| zoCH$*9;DdQ-OoSBH9piYG}zSza{abOnWlmU=o~~%jWSIJ#!nz+KK}jz@oxS>u3@f0 z8k!1e`9&Jm)|w2AUqO=K+~e#II&2S=y3;b#H5FhC@M(LQ>7Y^UAlCpN$H;hRM`sV$ zc<|A+wxF>`3}I_*nqfOOo&9|S9Q`8WJzW&Qx-rG^Y7aoy7vSlFS3?-OhA>YT2F8CN zZ$o?>@8jv~84|2fp{bxzp~=A5z=|l*pa(NJ1_e1rLJF?3#3G$yO$AUPrcjnx6s=LL z8Oy-f4AJB4;~3-`k5f}>MM-K=9=hH(kX~>M;Lxa(2_MWUPA$;@xj;c9Q&UGlL!($z zK}(@Hvnn+|4eUHkP_kIZ3b}&NKfu}F#T9xUaZo(?R9H|^4e}`i<3{YNKnKriK#saB z0u=*WK&}f8337GxjSq4Si+A;N@pSY9?K{^f)=AOHLyS;oT7y!Rf<~r-t%8BILZ*TZ zsKsZkkg2T=Qlych8Lg40psQf0si3Qn84DW7F4m0BjI~y%1znPJ8e|cq*oIvHW1?VC zVFEf_8GPRGIV5Q(=xsppknwuZ_&P+LAp_%iZ0ekXf)I*~7#J^LQ{?9wf>30_z<3dx zBG3)G2vrsgjF+&f3JLOqD*_$GcNv=^$ea*d9q0tPD_GS91i%%6PV%~nO;K=&Qv_U< zg#iQOHEgON2_B}-(7=F!@j5njZo$4VMMfY+H?S!JU5p1)Wdc%l6Pqeu*I*COrBbe- zgRsG|WC2op2T3h_!bSnKeFrrO)PM>Ys1RDTYceq2MKuK!%|sgE6cnV%z<3W;KPUwd zso&2vM3aH>KB|6j;vmuhkXlU!#s{b-fD#Uo280CpX)-WAMAZ*XQ$!j8QLV|q_z2CE zfB<5n!Z9E~lY#Lus(x@{B+?BawV-+#)dXllCDIItYEUhWY6>VB6KRB7u&*Wq<1jQ4O1_JBy4Ffe|HOM%+wprN*)uwXy; zco)|&aQHK_^hS#s|6jI7WhW7%(t)B1;4W`A2{y3>g@^ktGn87%?#R zBFjLnFlJz!fGiyB>KyL}Y7)9SI{SkiVZy*T8KeSouNla8Lk7mFAQ9*-WFR2}2FBSS zAy9)GdZmCX*l$J*jPt+}t|8(6LEiBp5#aME!2xE#z_`)z{*l9 z3i69e^bwlT&R~X|{RTVgoC$n7b6P5Btr_@SIA*XwPG)Xq3Fw$O2sg2~I5RyjH3hoF z9VEdBRtG+$8g3%&5)~%!!RqiUP#|2;RtM1K8xR|j4{T-u8wFY)1X_}oSORtj=q?h_ z9UXtb@dR2DLE;(Fu*2`*r$Y~+TX-~=Fo8Md4!vj!H zCI@YZ1+9+(9Zv_<0lLv+Hyg9&Rc4Sekn)^?Lk@J%H;%3cd?h22BFwG?OcfIrRRNwZ zFliPn(x7evc;7DQ3=xo1p{^3LVPrhd#$1?N91q>z4{;@f&{al8Mg|6D1_lPu>H84s zIU@rDhDuQ40I!$X$-=;}i-mzVW&>buRE}@WW%FL93(FG(5J$DmS*MK}>z`*DV5(Zll1g?TW!iEft zZXjW3Z3Ghs-TLDR5)T14mJJygy+FJmFwcmAv5^tP4GwhzSA_14AtCXQdq+Xt{&;^k zw_w*01v3W5CS2-3mq|DqXfiN1W2*3jRR`dkOcgXVz*RlOlE?s8P!$BKEWgk1p| z&(Of34Aci~!L;8AT)ja(glRoQnmV?(V%iQ#Uy#tmv>Yr;9lP7G+8u_|-=KyYRcvNq zU?>5fg9WMsU_$gJ7T0<#_DFlP^l16bs8OG;r?7X!)$QYHqN zS;!iMt}`+|VPy6@%pw4~!BJHxiA5E>b5&J{ff0Uzi5e4FuV08;yt5O7kTVnGPew8S z7c3}>q9BUEAqY~H!Nl0bBp~#a73@%OkTQyZLJY)=2PtFVW`MS1NCD(on2w> zKuANnF`#l6<|c$3xIh9)dAcxgLtKX;>F?qSl7%=GEDLoT3xnnz4v5>3l9Y&C66oSq zNTf6PU0}zEj6aCmWHvL)C8Z{Uj!-F1%}Zery1)!to%@#^9Cz?oQx%F~0o{)VS6q~u zT*e^umzhbK!+#D3NHK$wkO&Lhten);0tO)&P^$Ak1eR9?-+RNLBxC|tRi2og3OYo= ziG@j7fI&$>3w(_Z8>HvKu$P5_VIKuGBamjv_+Kx4VwG7 zLcC|ez-Wgm3z{N=bUiH@7#+cKjy~@G@vhGCZk_?b@c~ArW+1m1Ffh7+Wg$L`_w$eU z_Xmdys2PPU0~I!8VDtbBJBEgMfYioAE~>8p4dHpB%76|H^mGPU18P>G%K3+e1cZVE z%7}r{8&wV*k|1ry42*tYDSyz|1*mc9?-%dn1281RJe`6Z zAwg!uz!-=j?-%Op8U%5%F#}@|hPDQiuVb)xJZ1z#rk+5J&p3oKXiWS2JAo<|1%#SJ zgc?Z9fua{pO$tH{W}G05O2wfJ6gd!8pqaNc?5bd~1W{4}z`(c~AqVT* z1-OKQY&B$HT!Sg;<{#wi2rGHkBIHB;Tq6QpokKuVrV#zc42WT}9~c79Zpq>>nEB>6;NWJ3nV?O0TRTnh?SBL>FZ5NU7MNKktSM1iM%4b2!B_dujT)X!4;!o={m(wmXC-Yvke^Zyj)ou!2au3c-aOVey1bOf z!QaoxKLRRm2=c-SGzFf1!JaOzNQyxIIEkjn-!H(^)!EhGEx<9rH3()L$UmphR6>jc z9i{K+15*d`*=aO&{(g{Y1(+I;=gvXYKzdN|(CnoExxV%lM9wuV1lp>GG}>I^Aw45d zQZZy;Y-9ol4@eb=0aoMb=MK7Y6EYHI#K1TKp#~I;E}p@lMFk)Oj2Rf`qe_BLO$SMt zFfeXJNP(OVX@B|q2Edv{rVNaS5K2JSgPK#|9uurgGh<-9j6(^?5_1N|N2t6GN=>l9?9?hYCbbCQ}v+5{lpxL?s%~rTa(-TWdz)mI0r=Us!w^#R}S&Hgau+3!q6=E}X&w^Jx zfh+?Z2vSs{Q2<#6p;M5XT9T2Uf*h53De(m^p;!&_ZTN?+DZrhm2D(eq|Dch&crXL4|(6gdi0FRP;AY z6jbOsyT%7I2t8tC>|ur)2`a+D6?rg&kTw(JbeK4}$L;Ck8RF?04AK+N#JCP72TT17 zLNAyY_rpXXiG@MPf|>CyOf1wh-p@b8(=8G_BE`ta_?20_5F8nZQ_~n3HJ7r0?%{$B z^uz}$Q73s6vQXyq=Sy!%g8N; zxrPZMQBazcomvSqodqIT40bhW#*9gsRW2XI6N+GDQf8COgtNIAG=uX@H+w<2|L0J9hQWSjQvH7hv|T_GlL9d zQjLLu;S4ha!v#hL21H^2jedg^9b#c%ILyMpaD;_{;V26z@59HZK$HB?c{LFx7G_aq z7DmvugpPa)1uug3E&wI-*?!k_Vl50GAK-^8`(PfhUVVopc3* z3JdV!HPFp&7^*;R3P;E?3a}#34R3HoV5^|!f!Zd9kS*hI`7qC*kWfb-WUHLPrsVks zgPQ5!ZbCdv6~ZcrdkT;hfvtk71X*Roz*vVY?;hkI8h~k0187?p+&vIQ2zwxoX+lv0 zwg{{cWQ{QcV;73FqmK_L!9{q2J5p|LZq5vhJs2t=t2;p5A2&BQ7f>e^*{vWmz)LHj z3S1c&Ctw)i=kEfu!i|A(0ZiTvy5a;p^b2yK0Rtm=FFMGRFiEiCAW1_8#-$*g0YRR= zjzN*}!J$r|o*{ zAp;|1J1^K`(70DiY8BK#{SOR*<41GJP4ZYE3tEbrsA9HtOqxq>~&Moha`KzP4*@(c#;@C7Zk3vx!b8dr=lFm6ZH=Mo%((5I7Jl0!nIY8X@)7%G5b z8l+ECp{52L(cm~yumvxd2e}Vg_JiUc5+!)z@iZtb3ySh9DnWhK`0|X*lGL2c;*$8Z z%$$9wbQMrKIM> zrxoSr#*=R$_F@y&N*0C|@EU?D>h_cJQcFYgs^s~ zbelj6y+FkPC~rZUsEo6j1VEyY3LaXEL#5_Hq)=*asMJD;6wEBh1U01nyo8Bg^8$FG z8%Wl})zQT@h=B*xPKF)V#2}XkYEVNCbz%gaj|r1uk}E06fpM7Sib1sogU~ky(DfxL z2oC79;6l*iN7$7!9N;Tsk?a$SWn?_W1n$K}M8Ya^Pzw#x8DKoh#1HBqMnr-OGmsUG zCzwP7{9Hpk-Qa-$avLc0a4nN)>%7*&PVGr`v`TwsLU&!QwW zfeCC1Y!$;+CdMyJV*XE9RfV1~L3A?U@-E@Y)Bm2vVXj9A{x*IKjfea1ym|U^x z*((5>b^@(31RZ&WL)wsm5p;7ws2@T<@}!j!1EU#=Ze&Sg21d~7+#u(Gg#*07%{oH{ zM$qBZAYrIepc0__ry=XEs64imQ&N;T!CZ zT&`IP2KWT{p%xAa{C+2yAo*5cH4_7assIlohy;yhs0w+)S08~(MkOH?#sF|agylqk zM#c&;2Jl+h(<}@OXIK~*&Z4GUkUOA#deB-~&{6v!A#l=x^m5|Cn-c>3eZV`AkkS!` zn$Q3j#DW1(&mXHv&J;o87)x;|^+Z-@$iP^RuFf+I61`wM4H+0Ka4PWg5At;c zCl&(+#!8&ZKr2+>%bGzWCZKc%@}RFvd|;?+s4Ha0CDh&ZNany5`1ymbjSYcyC|f`s zN{}f*u7UAE!NH)F-68%#u!YB_42-QfR6s|Y%nTS9+i)l`ggT@hmwdb_NQEH-V+Rfu z;3zO+VC=*t4>7@*fw3D!g>zWAr=OdnGm=+~p+h@x&myaVddAR#fw32-K``(1;Z^~0 zjv)hMKTb6;FM$V%usX&FVu~>X<0NELd_DaFgFT~Mef-^F(PO~CI2o4`sFw`P85pNv zQ-d_y3K~_Mid7BRv4#wc)3C~dw#ynAF)&WYDr*6XTVn=B@F9>ekHS0=ZwOuFenSt}(!6c)SaE`x$tr>~fGS zsGtMw)%JAs0jmO4EAT-c(C`juZ3ncBhPVVY>=qgTE5Z#xD?8BSAtg7s;D(l}h763G zVYWd{L8%Cg7#O#p$%lXs9CZwVufj2AV7$(ZsE^?(415+VXs3TXbl*GZ>OT zb~%HV+y!`tKnJm*edHNTf}oKBkOF8f1us}(5IVrhxSk1oe>g_st zpBv-=5eA|A?2OaU)c893Il8;T6licTZeV8CJj@E(um|@gO0Gs2$0%1)kp~%$01X*1 zDKmhFBM4~|>SSWv!OX0=o(*ORBF-UxVUf$s%PfgU8WUlVgY6B448(xuXkn3ru3P9G z6XRiKX3d@KF!MptAMD{70A4l(8oek@0`>YJ3qcsbeHYM#CwQPm;2WstuFNC{Dk;Im zRVsW|lSMAAC@%$aXB9$}4aL_8dxZR$8Lu!iYrf=wxdX|ip-w)Y&W_+EgrMcQ3|w-M zaUQ7k402$r<8$)UVZ%a9a?nc|k;Ish$BkGp!iY@{GNTK*{t6aykU=9*Ea7pF&^2bp zKg`UUOSv!|4@nN5kOh!X*F%P^;I2pU3}~BXXN`s)IVT zLUUMQgHh0~Yz?db9&VUX;O;JXHz|XX&@xud`8=?|LMb>nMl95fWs3N{RGcP5-91+NcrKzB+Rx+!Q4%II% zO#%(`$3vESK)lZ+S5#b_3Dd`nHG{J-Xx>M)9=YIU0lOFyRj|b*SjrA22F(=$D1Lw# zf+$XjH>g_>#UPX-oCl*&1}8Xh3yeYN4|qr!l;)5f%psRw0J*{s5-41tHV9;V<~$1n z!vz)whKno=440r|G<@+M@qS^!pi}<^nOGP_L2M^SKkxVe*Pvj};1KYXEd!$%NF21{ z9V8bFIuc(JBmy1h3l9SC>tSG&LJ|bc!-5pbg2bFa=dMBa37Z&LnlUiSfkeRuf@Fdf zj2IXdK|m^Z}UzT3eutkN|a3L5=W$;P@a{Xa69V zcxTXYVUQzrf}wp^1{MZ}Dd2gh4#+4m8!rPRcsDyJei;cK{7_nwnNzF}JHUYOxew?k zOEBb>L62xaI_3eow^f3aF;-NEKujGf&D+Afvf}u(oW$ac_@u<*R6|H<2%1Si5jTQ~ zGcYiifm$G-C}NOdWMFv7zyJzJ6f;045}=xE1Xd5pvsYLc7_PD~FkC~;uOa@>9Lp@k z%mU7xA^xCw9Z=gZ#1qsM305#=V3f-%D=x`LT=`j0tN|)8bs()JO$AhGa6SNKaHPzy zqX5hD1{X)-V>LiFVqq~^sJ6qkdl59onpFe5=yIE;fDqoV-I0muc2CIh1iior#x zi7Aws3(C%#42eggn)P>jr@;M<(Kx)Xc!vJDOacXKdk{ytHe_=iVNfI<1szsB5 z(F9^-YEdG#00s-=H%*g)(Hvq1IPBsxQWH}^%jRKm1v`@xQw@G|bwI~VmZpMMaa%$3 zf`TnRxhUDt49WA5s6dNFgh~Q-Afi$O9+RN;)N{b)_2dC7uS@bFM-U*D*pTuTG)Td~ z$OxLWVFs5qM2t~jl-pp_hf2vE;1?Dg;*UD$X z>Oe=HLg&g185ltqXhJ1|T|;0ya*P-leW0SC7L1Rl3+RAK$55Y;_>d6L6bz^};}2B< z3K58?fhhwc=)NYHgujcc56DQ+^mKekygTS5M+QdFg>5)gfX;CNZOTQ22;|62P{##4 zs~Hd8m&_NkVU~z>p&ym@xh+%;02pL8U^5^uyit0bW$^Pl9O}_N|WM~lXO6xhx`Ja z`~r}nU?rNmc3?U_Ger+{Xa?j2Sg4_p7yvCn0U2$r05uj_Pi6|pIhiS%$g&{ULl<9w zWK%OxWRsIXg2_oJf)EFSBp@slNrh1Kjfkl7Hsp)07Nwv+8@@D!FN17jD+ zWT@5T7!B2m;%b=LeIT=;u7(aSQR-}nF`5jFlR#!eEsuwYk`|Lty(kWcn4`(SI1OYv z)a9UwD@vX16976Pbr#4}sJ);`F3KGYF?SxwT&Qb7E4?XoE$S(hp!rRZ1u%z`Yy(sy zN=Rc^af-(`I3AJvpv&133ktGRD>aJqbP}^ObrQ4D@+eeQN-Fq5NT_0s;yh4aBQYCv zE;XX2aR#3$9uIA9Kt~rL%W^>TYT2Ns^G#Gopqfj4N4U6xb__!&a$t^NVPMz*Zci_V zwAx4<|3E&+lK4>&)J8A(Oi5^5AW#35Ag@9L_cHV{AO{RGGOl5#d>#$ zKA2}g1M`e`7{QB`p`qd88U|Wv1vdq(YB zY_OdLJaYv#6|P>$f{F1hBeUjj@FXCzEQ5?3tWClol+6S(4yl>OAatG)bcHPF+F1?I z1+t)BiQubcof(;w1;9i7&^8t%aG8`vpaajv3_^^|Ov(}rf&w6SDhd5&LJBpo%NT^( zm>Bz*m^F`srwyUbf(59HYp^o|lUz=IGR$bmTqHJSLbA+^Gntq*w}a;gp(>!k&LARJ zTAUi6lbDnWUyqG8W5c|X9elVJXcH<#ozOhcFe&W!%G)Qt{QkIY_Dye`>Qo@8J z!9tmNC8x#* zr8)cig}6q9FmTC1hU^%G*ugt=QKko(Q0F>9`(d%n$Fj*mLj!7(0BA;zNf|N&h}UwV z`7Df&n3y%^awCO0syl-m!x?y>i4T&CL5Uf(+daM@u_!T@L1+>?XdVtMf_%Uqa^PSZ zDdf(|_<@O8vjsd;ht-iG3{23I1tG!DAXkzfpOhM(n4F!O0*fz3+}4CJ2pwc){LRFy z`3ln#@bY}nc&?*wFle5;B(Wql9y!M|fUmMnWf1xgnh3(Q1;qd%H8#dJW@gQ^;MqhJ z-?&DEAglr3)?HbU3M*C^)zBlrvjP}v4qZovlIQ4E^A z1;q}i%LXcLQu9jS`;eLBijvEqSpzcp1}W3f%o6&*#<-A~*{_cuG9fI~$F2&VtA>$~ z<;$QHrV1{BRD~w7!)AVk*x}m{BH8`cA{im{A3PEU8XCL9!oYBsg@NH7bUX+&N9G$G z@9ydcI*lye$uT6vH7F9c6kmvm1#&lFdTL&3QD$;{QesI-YEfl;dTI%z8-gy8oRbN< z(jIhdV0=+(PG(|KPAcTE3Q+$E8aL>+fyQcJ%`(u&M{u(dhgwj~BervDg657OdzLDw z*LDJ(dy4KcJ5(A*e)FNL?S#|+sNx*36%7y*c)-OPhJQmGLqdb& zgF}KsokJLeHZd}GgLdVBQrQC*28M?$3=EHu@-Dh|s1Fqwn1z^Fn1z{H7-exNaSaM0 z=~jF2dC}mi1pQ`vZ5%d)1UZ9lbOaxB9}l_aUI&L#EO*}P;!p}PE~PZLAU>(GB(+!r zRQKtCh@8|sO$7!Ph6CWf)D|4&0l2qRP?TAgSdyv_ZYCD%LsNi0;kje5Zs?r>@V*uU zR6o3Ugp`7i845%n7gB^k4)jOY0hfc$JHG+@0aR>*=P$t4;&3#&QEMB$gQCA9#k14%`uT>&rpdY zSeN$=^t5Y82Z*_wN$3w~stpugVEP3M0|TQXgFZh41Ct^s4Kp$_ih7DMFtDgFaC6&n zGjlL7unICVbEt9%vr2OaG72#YurV;Op$aiDupq=g$M z08_z(EWp6P3*&+m^T9X_4E!)A!fXMA5J<708Ux5jLM)7oqRbrJ+zbrDASQ?*qQSt- zAtT1XAPQ#iGBAj7Gct;ToWQ^!&dmT}NPxr`7$mtF7#O5LY>=>_00V`1t$Z8JcP->pa5Z5aGLNiFet(}+}ym}JlqTnO8j7FDw~5T6;=jM zF;M8Mf*1@8Y9NYMRgK5bX;53=Ed2f*>I)gpj)!NWdB)0MW?6V1p{e zz+j6Ia2I1>utRVmT0pLHU}IpgN0opHJ0OH1&IPG;Lk%eklbASl_!$@?VH^gAC@7PSfgu{g1SyDt zFc}zPAq*yPc8G&By8@3&BJ~Zy?aLm}VKcD0 zG9@)Fu{5V7zN9EIuQ;}|WL!v$|3Eim zf(K;4vlWCwgDRc`tz&?7n!#3M>opVYOYptugxp=6S`uHHmzbQLmtUTfnv$NHq5-y< zzMc;Cb9DCh^AGoNb#ZrfflsA?U7`a$;0m${ zvC&7|Kn8BmVYKyqgX0N>6QnT@xi1BMtiU%o9^B~wo$^_NxVj6}p6sFG_yMl`1#y}) z%)3?!jzPW(AZ}((YLSAeo`IPHWQI+_9JKT+GbcsC(#$|pAtXOP$4ViwC^tD-A=)Ix z*vvE~mVt-C#VRJFuspvgJ10LmF(<~%$jB(BD5p5S%-GN{J~1b?A~8NCDLo#voFN`8 znUk3m0}ejWh#x3`<3S?uFpo(p&CE#w6;NR8w;nd0pwFl(WXh;2WX-55xNL`Np~0900UPm+Q4r9IZ_I*# zR>ET#55VQt6-X>#%m;%qjy{gz08p2goN^7ED>IYhaivN~rA5q`1}+mIWe@0fI>>nG zAFv-m8J*}c4qQgV9S17PzywDjw7m_i^Fx@pac70=^f$%qS~+!rDTL8$gw1}PZ<{=J1`|Rrz8=y2oX!G znhY1YxcY=Rg3fgP-LvR~_bW3qq zIaKNlzqzm;jx3|9kTRpHkS3$55Tv(5aK@AYr4s_p#EAZkHF&xeZbI(8Kq44aoI?96Y;s^B_`)W+63}`sNIwOoF9Vt#g>_Dt$olKz_=2L;;?%qnn0i)}NmH1YL*VnJYZw_TnKkc&ZiPoH_e&B>5R zpg<}~gt-bdN zR`9}{%LcL&;atdi7X~^c2Y5jUbL}=}#%qwyEU10@i-m#VHwy#9A8?t&2ySzs)_~9y zkFDnlNor69H0Yz5u%)UYFo=Ff6M<41!xcRB8>#{^@@#3=IE46*((t-4P?a z?>GS*4sAH33jL_zru)Gq|>5GQf29L1z$hM^KSuwLLRcrS1g zGia%k5fg}XWP$exXEO=$KzoFc_+$dbBP#;~3y5Zblut-&^L+fF2k}66ZGsl(%|UKt zg2rG$m1lf+a+4^9>2De#XmK-3>}O)K4y;KqN7>K(t^a zmgjg}O_Q_&b%!hL#5ElS=Wv60+yelwv|w2dV(n0=Q2Z9ax`+ylszPdv zszN%9szOGLszMfoC&8Fe`*pCyinOZM4%|y@!`4e|L+>S~V>b=jDh72Fdq5pUze`Zl zgs{0-Xe)M8f?Y#G1LBcfc8QTOMqKj?N~aSRh0rPv+V$j-gYt6{OEODJQ{YQ+8Q>E6 zdFd!JEHIhG9GDhJM+LHR1Kuxyg&4ddgRIMCWCE?r)!YEuT8xptKnoX`WFFCcS zBr!9uq!MNX4!1+g0O$^ZN|#Lz|P9Rz=71}!0@1((=x%ZEzo35h8NE>;ExZdL{c9!NTe_myUV`$|0!RTyKSc;gckq4*Twia6Bn z5-f_~0SnHR;Qb_MXOEF**HDQkShwjdyxUX)?l2iJ!#hkfn1ncC$HIX^iI0_mfuEIu zK>!k`;PD)!{*u3+zndHK9NIkOxvKoU{IoR8E)ql-5*bAHk0ACCGlvFIiP5~>gy}Bq zty;1jM^vW=hwF}Ebsgb$D@Beap-;oYK+|~)h&LbwD6WPo10y2~72B!ERt}ZyOT~E% zXgZ|EJO;!lXwwALJjF7P0SRrSc??!Lun=sNA7$X05!X076KKpEG0x6RXq+9g{S(&G zg18fuOJO6|YZw_z(B?6~t^zL`M9gD=&#DE@kHmvzk=zWK$3PKf#4(S-M98tsD3bzE z$3i-~F!zQsF-`>QiWpU~5o9Oou9^|$c*Je#%0A=85qP_85krW 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[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